RubyWouldConference2018にてngx_mruby v2のノンブロッキングインターフェースについてトークしました。
ʙ͋Εͬʁ࡞ऀɾɾɾ͋Εͬʁʁʁฤʙ!QZBNB(.01FQBCP *OD3VCZ8PVME$POGFSFODFOHY@NSVCZWʹ͓͚ΔϊϯϒϩοΩϯάͳNSVCZ࣮ߦͷ࣮ৄࡉ
View Slide
γχΞɾϓϦϯγύϧΤϯδχΞࢁԼ!QZBNBϗεςΟϯάࣄۀ෦νʔϑςΫχΧϧϦʔυIUUQTUFOTOBQPODPN
ϗεςΟϯάࣄۀ &$ࢧԉࣄۀ ϋϯυϝΠυɾͦͷଞࣄۀ
ϩϦϙοϓʂϨϯλϧαʔόαʔϏεఏڙ։࢝ ϔςϜϧαʔϏεఏڙ։࢝1ࢁ͕ϖύϘʹೖࣾʂʂ݄̍ࣛࣇౡݝग़ਫࢢʹ͓͍ͯ1ࢁരʂʂ̍ ݱࡏɾۀϜʔϜʔυϝΠϯαʔϏεఏڙ։࢝
45/4-JOVY/444FSWFSTUOTKQ
45/4
ࠓ͢͜ͱwOHY@NSVCZwOHJOYͷجຊwOHY@NSVCZWͷ՝wOHY@NSVCZWʹ͓͚ΔϊϯϒϩοΩϯάॲཧ
લఏwOHJOYͷΠϕϯτϞδϡʔϧFQPMMલఏͰ͠·͢w3VCZͷΛ͠·͕͢ɺ3VCZߏจͷ͋·Γग़͖ͯ·ͤΜ
OHY@NSVCZ"'BTUBOE.FNPSZ&⒏DJFOU8FC4FSWFS&YUFOTJPO.FDIBOJTN6TJOH4DSJQUJOH-BOHVBHFNSVCZGPSOHJOYIUUQOHYNSVCZPSH
OHY@NSVCZWʹίϯτϦϏϡʔτ
OHY@NSVCZNSVCZ@TTM@IBOETIBLF@IBOEMFS@DPEFTTMOHJOY44-OFXDFSUJpDBUF@EBUB'JMFSFBE QBUIUP\TTMTFSWFSOBNF^DSULFZ@EBUB'JMFSFBE QBUIUP\TTMTFSWFSOBNF^LFZTTMDFSUJpDBUF@EBUBDFSUJpDBUF@EBUBTTMDFSUJpDBUF@LFZ@EBUBLFZ@EBUBOHJOYͷ͋ΒΏΔΠϕϯτʹϑοΫͯ͠ɺNSVCZͷίʔυΛ࣮ߦ͠ɺϓϥΨϒϧʹτϥϑΟοΫίϯτϩʔϧग़དྷΔ
ϖύϘͷࣄྫಈతূ໌ॻཧඦສυϝΠϯͷূ໌ॻΛ.Z42-ͰཧίϯςϯπΩϟογϡΩϟογϡϙϦγʔΛ)551"1*ܦ༝Ͱऔಘ͠ɺOHJOYͷΩϟογϡͷ0/ɾ0''Λίϯτϩʔϧ
OHJOYNSVCZ
Πϕϯτۦಈඇಉظ*0OHJOY
ΠϕϯτۦಈOHJOYFQPMMFWFOUFWFOUFWFOUDMJFOUDMJFOUDMJFOUBDDFQUBDDFQUBDDFQUFQPMM@XBJU ଓϨεϙϯεΛ*0Πϕϯτͱͯ͠ॲཧ͢ΔIUUQTMJOVYKNPTEOKQIUNM-%1@NBOQBHFTNBOFQPMM@XBJUIUNM
ඇಉظ*0શͯϑΝΠϧͰ͋ΔOHJOYFQPMMFWFOUFWFOUFWFOUDMJFOUDMJFOUDMJFOUBDDFQUBDDFQUBDDFQUFQPMM@XBJU ϑΝΠϧσΟεΫϦϓλͦΕͧΕΛϒϩοΫͤͣFQPMMͰඇಉظʹ*0ॲཧΛߦ͏GEGEGE
OHJOYXPSLFSOHJOYFQPMMFWFOUFWFOUFWFOUDMJFOUDMJFOUDMJFOUBDDFQUBDDFQUBDDFQUFQPMM@XBJU ΫϥΠΞϯτ͔ΒͷϦΫΤετXPSLFS͕ॲཧXPSLFSXPSLFSNBTUFSFQPMM@XBJU
OHY@NSVCZOHJOYFQPMMFWFOUFWFOUFWFOUDMJFOUDMJFOUDMJFOUBDDFQUBDDFQUBDDFQUFQPMM@XBJU )551ϦΫΤετ࣌ͷNSVCZ࣮ߦXPSLFSͰߦΘΕΔXPSLFSXPSLFSNBTUFSMPDBUJPOIFBEFST\NSVCZ@DPOUFOU@IBOEMFS@DPEFSOHJOY3FRVFTUOFXSDPOUFOU@UZQFUFYUIUNMOHJOYSQVUTIFBEFST\SIFBEFST@JOBMM^CSCS^
OHY@NSVCZͷ՝SFRVFTUSFRVFTUSFRVFTUNSVCZNSVCZNSVCZSFTQPOTFSFTQPOTFSFTQPOTFXPSLFSXPSLFS͋ͨΓͷNSVCZ࣮ߦͰඇಉظ*0͕ϒϩοΫ͞ΕΔ
ࠓͷओSFRVFTUSFRVFTUSFRVFTUNSVCZNSVCZNSVCZSFTQPOTFSFTQPOTFSFTQPOTFXPSLFS͜͏ͳͬͨʂʂ͍̍ͯ͏Λ͠·͢
Ϧιʔε͕͏·͘׆༻Ͱ͖ͳ͍έʔεcontainer.boot!loop dobreak if container.boot?sleep 1000endOHY@NSVCZ͔ΒίϯςφϓϩηεΛىಈ͠ɺىಈྃΛTMFFQͰͭΑ͋͘Δॲཧ
՝Λղܾ͢ΔϊϯϒϩοΩϯάΠϯλʔϑΣʔε/HJOY"TZODTMFFQ/HJOY"TZOD)551TVC@SFRVFTU
/HJOY"TZODTMFFQ
/HJOY"TZODTMFFQSFRVFTUSFRVFTU NSVCZSFTQPOTFSFTQPOTFMPPQEP CSFBLJGDPOUBJOFSCPPU /HJOY"TZODTMFFQFOENSVCZTMFFQTMFFQ࣌ʹNSVCZͷϒϩοΫΛ։์͢Δ
/HJOY"TZODTMFFQwOHYFWFOUMPPQwOHY@BEE@UJNFSw'JCFS
OHJOYFWFOUMPPQpOEUJNFSFQPMM@XBJUFYFDFWFOUIBOEMFSFYFDUJNFSIBOEMFSۙͰൃՐ͢ΔλΠϚʔΛ୳͢*0ΠϕϯτΛͭ*0ΠϕϯτͷϋϯυϥΛ࣮ߦ͢ΔλΠϚʔͷϋϯυϥΛ࣮ߦ͢Δ
OHJOYFWFOUIBOEMFSwOHJOYͰFWFOUʹIBOEMFSΛఆٛग़དྷΔwUJNFSͷIBOEMFSίʔϧόοΫͷΑ͏ͳΠϝʔδwϢʔβʔͷҙͷΦϒδΣΫτΛ֨ೲɺऔΓग़͢͜ͱ͕Մೳ
OHY@BEE@UJNFSev = (ngx_event_t *)p;ev->handler = ngx_mrb_timer_handler;ev->data = re;ngx_add_timer(ev, (ngx_msec_t)timer);FWEBUBʹNSC@TUBUFͳͲ3VCZͷใΛอ࣋͠ɺIBOEMFS࣮ߦ࣌ʹऔΓग़͠ɺ3VCZΛ࣮ߦ͢Δ
3VCZͷίϯςΩετͲ͏ͳΔ͔ʁputs "1"Nginx::Async.sleep 1000puts "2"/HJOY"TZODTMFFQ͕࣮ߦ͞ΕɺQVUT͕࣮ߦ͞Εͯ͠·͏ˠ3VCZͷॲཧΛఀࢭ͢Δඞཁ͕͋Δ
'JCFS
'JCFSfiber = Fiber.new {puts 'Ruby is'Fiber.yieldputs 'Good'}fiber.resumefiber.resume͍ΘΏΔίϧʔνϯͰɺ'JCFSZJFMEͷ࣌ͰॲཧΛఀࢭͤ͞Δ͜ͱ͕ग़དྷΔɻ'JCFSSFTVNFʹΑͬͯॲཧΛ࠶։
3VCZJT(PPE
OHY@NSVCZ'JCFS *NBHFMPDBUJPOIFBEFST\NSVCZ@DPOUFOU@IBOEMFS@DPEFQVUT/HJOY"TZODTMFFQQVUT^MPDBUJPOIFBEFST\NSVCZ@DPOUFOU@IBOEMFS@DPEF'JCFSOFXEPQVUT/HJOY"TZODTMFFQQVUTFOE3VCZͷίʔυΛ'JCFSͰ҉తʹแΉ
OHY@NSVCZ'JCFS *NBHFEFG@OHY@NSC@QSFQBSF@pCFS OHJOY@IBOEMFSpCFS@IBOEMFS'JCFSOFX\OHJOY@IBOEMFSDBMM^MBNCEBEPSFTVMUpCFS@IBOEMFSSFTVNFFOEFOE'JCFSΛ͞Βʹ1SPDͰแΉ
/HJOY"TZODTMFFQclass Asyncclass << selfdef sleep(*args)__sleep(*args)Fiber.yieldendendend@@TMFFQ UJNFS࡞ΔϝιουͰ'JCMFSΠϯελϯεΛ$ͷίϯςΩετʹอଘ͠ɺOHJOYͷλΠϚʔϋϯυϥʔʹઃఆޙɺ'JCFSZJFMEͰ3VCZΛఀࢭ
OHY@BEE@UJNFSOHY@NSVCZ@UJNFS@IBOEFS'JCFSZJFME'JCFSSFTVNF'JCFSΦϒδΣΫτΛίʔϧόοΫؔͷϙΠϯλͱڞʹλΠϚʔʹηοτλΠϚʔηοτ࣌Ͱ3VCZͷίϯςΩετΛఀࢭ͠ɺOHJOYͷΠϕϯτϧʔϓΛ࠶։λΠϚʔΠϕϯτൃՐ࣌ʹ࣮ߦ͞ΕɺλΠϚʔΠϕϯτ͔Β3VCZͷίϯςΩετΛऔΓग़͢3VCZͷ࣮ߦΛ࠶։͢Δ/HJOY"TZOD4MFFQ
/HJOY"TZOD)551TVC@SFRVFTU
OHY@IUUQ@TVCSFRVFTUlocation / {# subrequest}location /subreqest {puts "hello"}# http://localhost/=> hello͋ΔϩέʔγϣϯʹདྷͨϦΫΤετΛଞͷϩέʔγϣϯʹϦΫΤετͨ݁͠ՌͰԠ͢ΔΑ͏ͳ͍ํ
SFRVFTUSFRVFTU NSVCZSFTQPOTFSFTQPOTFNSVCZϦΫΤετΛ͛ΔͱϒϩοΫΛ։์͠ɺϨεϙϯε࣌ʹίʔϧόοΫΛड͚औΓ࠶։TVCSFRFTU3FRVFTU 3FTQPOTF/HJOY"TZOD)551TVC@SFRVFTU
/HJOY"TZOD)551TVC@SFRVFTU3FEJTlocation / {# subrequest /redis}location /redis {puts redis get key}3FEJTͷϦΫΤετͪ࣌ؒ֎෦"1*ΛOHY@NSVCZͰ࣮ߦ͢ΔΑ͋͘Δέʔε
/HJOY"TZOD)551TVC@SFRVFTUdef sub_request(location, query_param = nil)if query_param.is_a?(Hash)__sub_request(location, ::nginx::Utils....)elsif query_param.is_a?(String)__sub_request(location, query_param)elsea__sub_request(location)endFiber.yieldendTMFFQͱಉ͘͡ɺ@@TVC@SFRVFTUͰίʔϧόοΫΛઃఆ͠ɺ'JCFSZJFME
/HJOY"TZOD)551TVC@SFRVFTUps->handler = ngx_mrb_async_http_sub_request_done;ps->data = actx;if (ngx_http_subrequest(r, actx->uri, args, &sr, ps, NGX_HTTP_SUBREQUEST_IN_MEMORY) != NGX_OK) {mrb_raise(mrb, E_RUNTIME_ERROR, "ngx_http_subrequest failed for http_sub_rquest method");}ίʔϧόοΫΛઃఆ͠ɺαϒϦΫΤετΛ࣮ߦ͢Δ
/HJOY"TZOD)551TVC@SFRVFTUstatic ngx_int_t ngx_mrb_async_http_sub_request_done(ngx_http_request_t *sr, void *data, ngx_int_trc){ngx_mrb_async_http_ctx_t *actx = data;ngx_mrb_reentrant_t *re = actx->re;ngx_http_mruby_ctx_t *ctx;re->r = sr->parent;...ίʔϧόοΫͰฦ٫͞ΕΔOHY@IUUQ@SFRVFTU@Uߏମ˞͔ΒαϒϦΫΤετͷϨεϙϯεϘσΟϔομ͕औಘͰ͖ͳ͍˞֤ΠϕϯτͰ࣋ͪճΒΕΔɺϦΫΤετͷใ
XBJUJOHTVCSFRVFTUpOBMJ[FCPEZpMUFS/HJOY"TZOD)551TVC@SFRVFTUNBJOSFRVFTUOHY@IUUQ@SFRVFTU@UTVCSFRVFTUOHY@IUUQ@SFRVFTU@UPUIFSFWFOUOHY@IUUQ@SFRVFTU@UNBJOpOJTISFRVFTUNSVCZαϒϦΫΤετͷϨεϙϯεɺϝΠϯϦΫΤετͷώʔϓʹॻ͍ͯ͋͛Δඞཁ͕͋Δ
/HJOY"TZOD)551TVC@SFRVFTUlocation /async_http_sub_request {mruby_rewrite_handler_code 'Nginx::Async::HTTP.sub_request "/sub_req_dst"res = Nginx::Async::HTTP.last_responsenginx.rputs res.body';}Ϩεϙϯεͷड͚औΓϝΠϯϦΫΤετͷ(FUUFSΛ௨ͯ͠ɺαϒϦΫΤετ͕ॻ͍ͨώʔϓͷΛऔಘ
ੑೳධՁ
IUUQTICNBUTVNPUPSKQFOUSZ
ଌఆڥw.BD#PPL1SP.JEw$16()[*OUFM$PSFJw.FNPSZ(#w7JSUVBM#PYw$16$PSFw.FNPSZ(#w046CVOUV9FOJBM
TMFFQNTFDSFUVSOMPDBUJPO"CMPDLJOHIUUQSFRVFTUMPDBUJPO#OPOCMPDLJOHIUUQSFRVFTUBC$ ab -n 10000 -c 100 http://127.0.0.1:58080/PSJHJOʹ)551ϦΫΤετ͢ΔڥIUUQSFRVFTUIUUQSFRVFTU
OPOCMPDLJOH͕ഒఔߴͰ͋ΔCMPDLJOHIUUQSFRVFTU OPOCMPDLJOHIUUQSFRVFTU3FRVFTUTQFSTFDPOE<TFD> NFBO5JNFQFSSFRVFTU5JNFQFSSFRVFTU5SBOTGFSSBUF<,CZUFTTFD>SFDFJWFE3FRVFTUTQFSTFDPOE<TFD> NFBO5JNFQFSSFRVFTU5JNFQFSSFRVFTU5SBOTGFSSBUF<,CZUFTTFD>SFDFJWFE
࠷ޙʹ
NSVCZ࠷ߴʂʂ̍NSVCZʹΑͬͯΤϯδχΞͱͯ͠ɺҰஈਂ͘જΕΔΑ͏ʹͳͬͨ
5IBOLZPV࠷৽ͷ࠾༻ใΛνΣοΫˠ !QC@SFDSVJU