Share
Embed
RubyKaigi 2014 mod_mruby ngx_mruby
なぜ僕はmod_mrubyを作る必要があったのか、そこからどう応用させたのかについて、自分が作った、mrubyによるWebサーバの新しいリソース制御を軸にお話します。
MATSUMOTO Ryosuke PRO
September 19, 2014
Transcript
53 slides
-
ࣗݾհ • ژେֶͷത࢜՝ఔֶੜ – Πϯλʔωοτج൫ٕज़ͷݚڀ – ୈճຊ044ྭड – ത࢜՝ఔͷલϑΝʔεταʔόͰӡ༻ •
NSVCZίϯτϦϏϡʔλ – NPE@NSVCZɾOHY@NSVCZɾBCNSVCZ – ࠷ۙͰ5SVTUFSE)5518FC4FSWFS – NHFNMJTUʹొࡁͷNHFNݸͰੈքҐ 3VCZ,BJHJ -
NHFNMJTU3BOLJOH 3VCZ,BJHJ $ mgem info | grep Author |
sort | uniq -‐c | sort -‐nr | head 26 Author: MATSUMOTO Ryosuke 25 Author: maCn 12 Author: ppibburr 10 Author: iij 7 Author: ksss 6 Author: Internet IniJaJve Japan., Inc. 5 Author: Takeshi Watanabe 3 Author: h2so5 2 Author: kyab 2 Author: crimsonwoods -
8FCαʔόͷϦιʔε੍ޚͱ • طଘͷϦιʔε੍ޚΞʔΩςΫνϟ – ίϯϐϡʔλϦιʔεΛᮢॲཧͰ੍ޚ – ᮢΛ͑ΔͱϦΫΤετॲཧΛڧ੍அɾڋ൱ – ड͚Δ͔ड͚ͳ͍͔ͷ୯७ͳ੍ޚ •
– ΫϥΠΞϯτͷҹ͕ѱ͍ɾ͍߹Θͤࡴ౸ – αʔόͷ࣭ΛอͭͨΊͩͱઆ໌͢Δ͕ɾɾɾ – ࣭Λ্͛ΔͨΊͷϦιʔε੍ޚ͕શମͱͯ͠ αʔϏε࣭͕Լ͍ͤͯ͞Δ߹͕͋Δ 3VCZ,BJHJ -
͕ཉ͔ͬͨ͠Ϧιʔε੍ޚ • ཧऀ͕ϓϩάϥϚϒϧʹ੍ޚϧʔϧΛهड़ – ॊೈͰՄಡੑͷߴ੍͍ޚϧʔϧΛදݱ͍ͨ͠ – αʔόϓϩηεͷ࠶ىಈͳ͘ϧʔϧΛมߋ͍ͨ͠ – ϧʔϧ͕ΦʔόʔϔουʹͳΒͳ͍Α͏ʹ͍ͨ͠ •
ϦΫΤετ୯ҐͰϦιʔεΛׂΓͯΔ – ϦΫΤετͷதஅͰͳ͘ܧଓతʹॲཧ͍ͤͨ͞ – ಛఆͷϦιʔεൣғͰॲཧ͍ͤͨ͞ – ಛʹ੍ޚࠔͳ$16%*4,*0Λ੍ޚ͍ͨ͠ 3VCZ,BJHJ -
͕ཉ͔ͬͨ͠Ϧιʔε੍ޚ • ཧऀ͕ϓϩάϥϚϒϧʹ੍ޚϧʔϧΛهड़ – ॊೈͰՄಡੑͷߴ੍͍ޚϧʔϧΛදݱ͍ͨ͠ – αʔόϓϩηεͷ࠶ىಈͳ͘ϧʔϧΛมߋ͍ͨ͠ – ϧʔϧ͕ΦʔόʔϔουʹͳΒͳ͍Α͏ʹ͍ͨ͠ •
ϦΫΤετ୯ҐͰϦιʔεΛׂΓͯΔ – ϦΫΤετͷதஅͰͳ͘ܧଓతʹॲཧ͍ͤͨ͞ – ಛఆͷϦιʔεൣғͰॲཧ͍ͤͨ͞ – ಛʹ੍ޚࠔͳ$16%*4,*0Λ੍ޚ͍ͨ͠ 3VCZ,BJHJ -
NPE@NSVCZ • "QBDIFIUUQEͷ%4-੍ޚΤϯδϯ • ߴ͔ͭলϝϞϦʹ8FCαʔόΛ੍ޚՄೳ 3VCZ,BJHJ # mrubyTranslateNameFirst “/path/to/proxy.rb”!
! backends = [! "http://192.168.0.101:8888/",! "http://192.168.0.102:8888/",! "http://192.168.0.103:8888/",! ]! ! r = Apache::Request.new! backend = backends[rand(backends.length)] ! r.reverse_proxy backend + r.unparsed_uri! -
NPE@NSVCZͷϑοΫϞσϧ 3VCZ,BJHJ ɾ ɾ ɾ αʔόϓϩηε ࢠαʔόϓϩηε" ϦΫΤετॲཧ༻ΠϯλϓϦλ
ىಈ࣌ॲཧ༻ΠϯλϓϦλ ϦΫΤετҎ֎ͷॲཧ༻ΠϯλϓϦλ εΫϦϓτ εΫϦϓτ εΫϦϓτ εΫϦϓτ εΫϦϓτ ੑೳ͕ཁٻ͞ΕΔϑοΫ ΠϯλϓϦλΛڞ༗ -
NPE@NSVCZΞʔΩςΫνϟʢ௨ৗʣ 3VCZ,BJHJ ߏจղੳ όΠτίʔυੜ 7.্Ͱ࣮ߦʢ"QBDIFΛ੍ޚʣ ϦΫΤετຖʹαʔόϓϩηε͕εΫϦϓτΛϑοΫ εΫϦϓτಡΈࠐΈ ΠϯλϓϦλͱ ϥΠϒϥϦΛڞ༗
όΠτίʔυɺάϩʔόϧมɾΫϥεɺྫ֎ϑϥάΛ։์ • αʔόϓϩηεىಈ࣌ ʹΠϯλϓϦλΛ֬อ • ෳͷεΫϦϓτͰಉ ҰͷΠϯλϓϦλΛ࠶ ར༻ • εΫϦϓτؒͰͰ͖Δ ͚ͩঢ়ଶ͕ׯব͠ͳ͍ Α͏ʹ͢Δ ഉଞॲཧ ϚϧνεϨου8FC αʔόΞʔΩςΫνϟ ʹରԠ -
NPE@NSVCZΞʔΩςΫνϟʢΩϟογϡʣ 3VCZ,BJHJ ߏจղੳ όΠτίʔυੜ 7.্Ͱ࣮ߦʢ"QBDIFΛ੍ޚʣ ϦΫΤετຖʹαʔόϓϩηε͕εΫϦϓτΛϑοΫ εΫϦϓτಡΈࠐΈ ΠϯλϓϦλͱ ϥΠϒϥϦΛڞ༗
άϩʔόϧมɾΫϥεɺྫ֎ϑϥάΛ։์ αʔόϓϩηεىಈ࣌ ʹίϯύΠϧ όΠτίʔυςʔϒϧ ʹอଘ όΠτίʔυ*%͔Β औΓग़͠ όΠτίʔυ ςʔϒϧ -
"QBDIFIUUQEઃఆྫ ʢNPE@NSVCZʣ 3VCZ,BJHJ # Normal hook! <Location /mruby-test>! mrubyHandlerMiddle
/path/to/test.rb! </Location>! ! # ByteCode Caching at Start up! <Location /mruby-test-cache>! mrubyHandlerMiddle /path/to/test.rb cache! </Location> -
OHJOYઃఆྫ ʢOHY@NSVCZ 3VCZ,BJHJ # Normal hook! location /mruby-test
{! mruby_content_handler /path/to/test.rb;! }! ! # ByteCode Caching at Start up! location /mruby-test-cache {! mruby_content_handler /path/to/test.rb cache;! } -
OHJOYઃఆྫ ʢOHY@NSVCZ 3VCZ,BJHJ # Inline code hook! location
/mruby-hello {! mruby_content_handler_code ‘! r = Nginx::Request.new! c = Nginx::Connection.new! ! r.content_type = “text/plain”! Nginx.echo “Hello #{c.remote_ip} World”! ‘;! } -
3FWFSTF1SPYZ NPE@NSVCZ 3VCZ,BJHJ # mrubyTranslateNameFirst “/path/to/proxy.rb”! ! backends
= [! "http://192.168.0.101:8888/",! "http://192.168.0.102:8888/",! "http://192.168.0.103:8888/",! ]! ! r = Apache::Request.new! backend = backends[rand(backends.length)] ! r.reverse_proxy backend + r.unparsed_uri! -
3FWFSTF1SPYZ OHY@NSVCZ 3VCZ,BJHJ # location /proxy {! #
mruby_set $backend "/path/to/proxy.rb";! # proxy_pass http://$backend;! # }! ! backends = [! "http://192.168.0.101:8888/",! "http://192.168.0.102:8888/",! "http://192.168.0.103:8888/",! ]! ! backends[rand(backends.length)]! -
#BTJD"VUIXJUI3FEJT NPE@NSVCZ 3VCZ,BJHJ # <Location /basic/>! # AuthType
basic! # AuthName "Message for clients"! # AuthBasicProvider mruby! # mrubyAuthnCheckPassword /path/to/authn_basic.rb! # require valid-user! # </Location>! ! anp = Apache::AuthnProvider.new! redis = Redis.new "127.0.0.1”, 6379! ! if redis.get(anp.user) == anp.password! Apache.return Apache::AuthnProvider::AUTH_GRANTED! else! Apache.return Apache::AuthnProvider::AUTH_DENIED! end -
$POUSPMOHJOYWBSJBCMFT OHY@NSVCZ 3VCZ,BJHJ # http://example.com/vars?name=matsumotory! # location /vars
{! # set $hoge ”100";! # mruby_set_code $foo ‘! # r = Nginx::Request.new! # r.var.hoge.to_i * 2 #=> 200! # ’;! # mruby_content_handler /path/to/var.rb;! # }! r = Nginx::Request.new! Nginx.echo “name: #{r.var.arg_name}” #=> “matsumotory” ! Nginx.echo “hoge: #{r.var.hoge}” #=> “100”! Nginx.echo “foo : #{r.var.foo}” #=> “200”! Nginx.echo “uri : #{r.var.uri}” #=> “/vars”! r.var.hoge = “ngx_mruby”! -
NPE@NSVCZͱOHY@NSVCZ 3VCZ,BJHJ "QBDIF "1* 3VCZTDSJQU NPE@NSVCZ 3VCZTDSJQU ɾ ɾ
ɾ ɾ 3VCZTDSJQUO /HJOY "1* OHY@NSVCZ 3VCZTDSJQU "QBDIF $PSF /HJOY $PSF 3VCZ %4- GPS8FC "QBDIF 5SB⒏D 4FSWFS "1* UT@NSVCZ "QBDIF 5SB⒏D 4FSWFS $PSF SFGIUUQTHJUIVCDPNTZVDSFBNUT@NSVCZ -
ಉҰͷهड़ྫʢ)FMMP8PSMEʣ 3VCZ,BJHJ # Output Hello World! if server_name ==
"NGINX"! Server = Nginx! elsif server_name == "Apache"! Server = Apache! elsif server_name == "ApacheTrafficServer"! Server = ATS! end! ! Server.rputs "Hello #{Server.module_name}/ #{Server.module_version} world!"! # mod_mruby => "Hello mod_mruby/1.9.3 world!"! # ngx_mruby => "Hello ngx_mruby/1.3.2 world!"! # ts_mruby => "Hello ts_mruby/0.0.1 world!" -
ಉҰͷهड़ྫʢ0VUQVU'JMUFSʣ 3VCZ,BJHJ SFGIUUQICNBUTVNPUPSKQFOUSZ # Markdown convert! if server_name =
“NGINX”! Server = Nginx! elsif server_name == “Apache”! Server = Apache! end! ! f = Server::Filter.new! css = “https://example.com/style.css”! title = “markdown file”! md = Discount.new css, title! ! f.body = md.md2html f.body -
ͦͷଞͷԠ༻ • ίʔυͷγϯλοΫεϋΠϥΠτ – 0VUQVUϑΟϧλʔ • ଓʹԠͨ͡ॲཧͷΓସ͑ – ಉ࣌ଓ੍ݶ – ϦόʔεϓϩΩγͷΓସ͑ • %PDLFSͱͷ࿈ܞ
– NPPLKQQPPM – ಈతʹίϯςφݕग़͢ΔϦόʔεϓϩΩγ 3VCZ,BJHJ -
͕ཉ͔ͬͨ͠Ϧιʔε੍ޚ • ཧऀ͕ϓϩάϥϚϒϧʹ੍ޚϧʔϧΛهड़ – ॊೈͰՄಡੑͷߴ੍͍ޚϧʔϧΛදݱ͍ͨ͠ – αʔόϓϩηεͷ࠶ىಈͳ͘ϧʔϧΛมߋ͍ͨ͠ – ϧʔϧ͕ΦʔόʔϔουʹͳΒͳ͍Α͏ʹ͍ͨ͠ •
ϦΫΤετ୯ҐͰϦιʔεΛׂΓͯΔ – ϦΫΤετͷதஅͰͳ͘ܧଓతʹॲཧ͍ͤͨ͞ – ಛఆͷϦιʔεൣғͰॲཧ͍ͤͨ͞ – ಛʹ੍ޚࠔͳ$16%*4,*0Λ੍ޚ͍ͨ͠ 3VCZ,BJHJ -
NPE@NSVCZ NSVCZDHSPVQ • NPE@NSVCZ͔ΒDHSPVQΛ੍ޚ͢Δ – ࢦఆͷ$16ൣғͰॲཧΛܧଓతʹॲཧ 3VCZ,BJHJ r = Apache::Request.new!
! # CPU使用量を1コア10%に制御したい場合! if r.hostname == “matsumoto-r.jp”! cpu = Cgroup::CPU.new “httpd-limited”! cpu.cfs_quota_us = 10000! cpu.create ! cpu.attach! end -
৽͍͠Ϧιʔε੍ޚ֓ཁ 3VCZ,BJHJ "QBDIF1SPDFTT NPE@NSVCZ NSVCZ MJCNSVCZB NSVCZDHSPVQ MJCDHSPVQ
-JOVYDHSPVQT • ֤ػೳ୯ମͰಈ࡞Մೳʢૄ݁߹ʣ • NPE@NSVCZ"QBDIFΛNSVCZͰ੍ޚ • NSVCZDHSPVQMJCDHSPVQΛNSVCZͰ੍ޚ • NSVCZ NSVCZDHSPVQ • 3VCZ$ίʔυͰϦιʔεΛ੍ޚՄೳ • ͜ͷϧʔϓ$16Ͱ • ͜ͷॻ͖ग़͠%*4,ॻࠐ.#TFDͰ -
৽͍͠Ϧιʔε੍ޚ࣮ 3VCZ,BJHJ "QBDIF4FSWFS1SPDFTT $MJFOU
DHSPVQT DQVDHJ $16 3VCZ%4- $POpH 5BSHFUDQVDHJ $16 $POpH 5BSHFUJPDHJ $16 %JTL8SJUF.#TFD $SFBUF "UUBDI NPE@NSVCZ NSVCZ 3FRVFTU DQVDHJ NSVCZDHSPVQ 3VO 3FTQPOTF %FUBDI -
3VCZ%4-ʹΑΔ੍ޚϧʔϧྫ 3VCZ,BJHJ r = Apache::Request.new! ! if r.filename ==
“/path/to/cpu.cgi”! cpu = Cgroup::CPU.new “cpu_group”! # CPUを10%に制御したい場合! cpu.cfs_quota_us = 10000! cpu.create ! cpu.attach! end -
3VCZ%4-ʹΑΔ੍ޚϧʔϧྫ 3VCZ,BJHJ r = Apache::Request.new! ! if r.hostname ==
“example.com”! cpu = Cgroup::CPU.new “cpu_group”! # CPUを10%に制御したい場合! cpu.cfs_quota_us = 10000! cpu.create ! cpu.attach! end -
3VCZ%4-ʹΑΔ੍ޚϧʔϧྫ 3VCZ,BJHJ r = Apache::Request.new! ! if r.user== “matsumotory”!
cpu = Cgroup::CPU.new “cpu_group”! # CPUを10%に制御したい場合! cpu.cfs_quota_us = 10000! cpu.create ! cpu.attach! end -
3VCZ%4-ʹΑΔ੍ޚϧʔϧྫ 3VCZ,BJHJ r = Apache::Request.new! ! if r.method== “POST”!
cpu = Cgroup::CPU.new “cpu_group”! # CPUを10%に制御したい場合! cpu.cfs_quota_us = 10000! cpu.create ! cpu.attach! end -
3VCZ%4-ʹΑΔ੍ޚϧʔϧྫ 3VCZ,BJHJ r = Apache::Request.new! ! if r.finfo.user ==
500! cpu = Cgroup::CPU.new “cpu_group”! # CPUを10%に制御したい場合! cpu.cfs_quota_us = 10000! cpu.create ! cpu.attach! end -
3VCZ%4-ʹΑΔ੍ޚϧʔϧྫ 3VCZ,BJHJ r = Apache::Request.new! ! if r.finfo.group ==
300! cpu = Cgroup::CPU.new “cpu_group”! # CPUを10%に制御したい場合! cpu.cfs_quota_us = 10000! cpu.create ! cpu.attach! end -
3VCZ%4-ʹΑΔ੍ޚϧʔϧྫ 3VCZ,BJHJ r = Apache::Request.new! ! if r.finfo.size >
3000! cpu = Cgroup::CPU.new “cpu_group”! # CPUを10%に制御したい場合! cpu.cfs_quota_us = 10000! cpu.create ! cpu.attach! end -
3VCZ%4-ʹΑΔ੍ޚϧʔϧྫ 3VCZ,BJHJ if resource.most_heavy_hosts.include? r.hostname! # 1コアの100%固定でしか使えない、全タスクが1コア内で処理 c =
Cgroup::CPU.new "httpd-static-limited"! c.cfs_quota_us = 100000! Apache::Resource.attach_cgroup c, "httpd-static-limited"! elsif resource.heavy_hosts.include? r.hostname! # 全CPUの25%(コア含む)のリソースを分配、コアが24個の場合最大6コア内で分配 # httpd グループと競合しない場合は100%(全コア)使用 c = Cgroup::CPU.new "httpd-limited"! c.shares = 25! Apache::Resource.attach_cgroup c, "httpd-limited"! else! # 全CPUの75%(コア含む)のリソースを分配、コアが24個の場合最大18コア内で分配 # httpd-limited グループと競合しない場合は100%(全コア)使用 c = Cgroup::CPU.new "httpd"! c.shares = 75! Apache::Resource.attach_cgroup c, "httpd"! end SFGIUUQTHJUIVCDPNNBUTVNPUPSNPE@NSVCZDPOUSPMDQVGPSWIPTU -
࣮ݧڥ ΫϥΠΞϯτ $16 *OUFM$PSF%VP&()[ .FNPSZ (# /*$ 3FBMUFL35-#(CQT 04 'FEPSB-JOVYLFSOFM
3VCZ,BJHJ αʔό $16 *OUFM$PSFJ,()[ .FNPSZ (# /*$ *OUFM*7(CQT 04 'FEPSB-JOVYLFSOFM .JEEMF8BSF 8FCTFSWFS "QBDIF -
ධՁʢ̍ʣ • Ϧιʔε੍ޚಋೖʹΑΔΦʔόʔϔουͷධՁ – l)FMMP8PSMEzΛग़ྗ͢Δ͚ͩͷ)5.-ϑΝΠϧ – Ϧιʔε੍ޚΛಋೖ͠ͳ͍߹ – Ϧιʔε੍ޚΛಋೖ͢Δ͕Ϧιʔε੍ޚ͠ͳ͍߹ –
BCίϚϯυͰಉ࣌ଓɺ૯ଓສ • ݁Ռ – ఏҊख๏Λະಋೖ࣌ɿ SFRVFTUTFD – ఏҊख๏Λಋೖ࣌ ɹ SFRVFTUTFD 3VCZ,BJHJ -
ධՁʢ̎ʣ • Ϧιʔε੍ޚͷਫ਼ධՁ – $(*Λ$16༻ʹϦιʔε੍ޚ – $16ˋ༻͢Δϧʔϓ$(*Λ༻ – ϦΫΤετॲཧ͕࣌ؒ$16༻࣌ؒͱݟͳͤΔ –
ϧʔϓճʹΑͬͯϦΫΤετॲཧ࣌ؒΛมԽ – ϦΫΤετॲཧ࣌ؒΛมಈͤ͞ੑೳ੍ޚΛଌఆ ˞ੑೳ੍ޚɿ ϦΫΤετॲཧ࣌ؒ ੍ޚແ͠ ϦΫΤετॲཧ࣌ؒ ੍ޚ༗Γ 3VCZ,BJHJ -
ੑೳ੍ޚ
ੑೳ੍ޚʢʣ $(*ͷ$16༻࣌ؒʹϦΫΤετॲཧ࣌ؒʢNTFDʣ ੑೳ੍ޚ 3VCZ,BJHJ -
ߟ • Ϧιʔε੍ޚΑΓ੍͘ޚ͞ΕΔ߹ – ϦΫΤετॲཧ͕࣌ؒNTFDҎԼ – ϓϩηεΛԾϦιʔεྖҬʹ͢Δॲཧ͕ Φʔόʔϔου • దʹϦιʔε੍ޚͰಈ࡞͢Δʹ
– ൺֱతॲཧ࣌ؒͷ͍ίϯςϯπ – ຊ࣮ݧڥͰNTFDҎ্ ʢ$16༻࣌ؒʹϦΫΤετॲཧ࣌ؒͷ߹ʣ – ͱ͍͑ҎԼͳͷͰؾʹ͠ͳͯ͘ྑ͍ʁ 3VCZ,BJHJ -
·ͱΊ • ϦΫΤετ୯ҐͰϦιʔε੍ޚ – MJCDHSPVQΛNSVCZͰ੍ޚ͢ΔͨΊͷNHFN – ͦͷNHFNΛNPE@NSVCZʹϦϯΫ͢Δ • ཧऀ͕ϓϩάϥϚϒϧʹ੍ޚϧʔϧΛهड़ –
ͦͷͨΊʹNPE@NSVCZ͕ඞཁͩͬͨ • NPE@NSVCZͱOHY@NSVCZ – Ϣʔεέʔε͕ͪ´ – ϗεςΟϯάେखࣾͰͷ࠾༻ࣄҊ – ͕ࣗब৬ͯ͠ӡ༻ͯ͠ΈΔ 3VCZ,BJHJ -
ٕज़ऀ͔Βݚڀऀ • େࡕͷখ͞ͳϚϯγϣϯͰਓͰݚڀ – ձࣾʹߦ͔ͣاۀͱͷͳ͍ – େֶʹߦ͔ͣʹͻͨ͢Βࢠҭͯ – ՈͰͻͨ͢ΒݚڀɾϒϩάΛॻ͍ͯ –
ਓͩͱࢥ͍ͬͯͨ • Πϯλʔωοτͷӟຊͩͬͨ – ίʔυΛެ։͠ϒϩάΛॻ͘ – ͍͔ͭ୭͔͕ؾ͍ͮͯ͘ΕΔ – ϒϩάͷڞ༗ϑΟʔυόοΫΛͯ͘͠ΕΔ – ਓͰͳ͔ͬͨ 3VCZ,BJHJ -
ٕज़ऀͱݚڀऀͷڱؒ • ݚڀͷΞΠσΞਐΛϒϩάʹॻ͘ – Ұ෦ͷݚڀऀ͔ΒආΛड͚Δ – ॴɾॴ྆ํ͕͋ΔͷͰΜͩ • ݚڀࣨͷϘε͜͏ݴͬͯԼͬͨ͞ ʮੲͷΓํʹनΘΕͳͯ͘ྑ͍Ͱ͢ɻদຊ͞Μ͕ྑ͍
ͱࢥ͏ΓํͰ͖ͳΑ͏ʹͬͯԼ͍͞ɻࠓͷΓ ํɺྑ͍ͱࢥ͍·͢Αɻʯ • ٹΘΕͨ – ͜Ε͕ແ͚Ε͜͜ʹ͍ͳ͔ͬͨ – اۀ͔Βେֶʹ࠷ॳͷҰาΛ౿Έग़ͯ͠ྑ͔ͬͨ 3VCZ,BJHJ