Slide 1

Slide 1 text

ຊ൪؀ڥͰPHPίʔυʹ৮Εͣʹ ʮ࢖ΘΕ͍ͯͳ͍ίʔυʯΛௐ΂Δʹ͸ Ͳ͏ͨ͠ΒΑ͍͔ʁ 2026/04/11 PHPΧϯϑΝϨϯεখాݪ2026 Sohei Iwahori (GREE, Inc.)

Slide 2

Slide 2 text

who? » Sohei Iwahori (@egmc) » גࣜձࣾάϦʔ γχΞϦʔυΤϯδχΞ » Πϯϑϥͱ؂ࢹγεςϜ » SRE NEXT ίΞελοϑʢ2024ɺ2025ʣ » eBPF Japan MeetupӡӦϝϯόʔ » PHPͷΧϯϑΝϨϯεͰʮτʔΫʯ͢Δͷ ͸͸͡Ίͯ » খాٸઢͰདྷ·ͨ͠

Slide 3

Slide 3 text

ϐηΧʢ2025ʣͷ࿩ » τʔΫ͸ͨ͜͠ͱͳ͍͕ϫʔΫγϣοϓ͸΍ͬͨ » 2025/02/28 PHP Sessionless Conference » eBPFͱपลٕज़Λར༻ͯ͠PHPΞϓϦέʔγϣϯίʔυΛมߋ͠ ͳ͍ՄࢹԽΛ΍ͬͯΈΔ » ຊ೔ͷ࿩ʹؔ࿈ͨ͠ϫʔΫγϣοϓࢿྉ͋Γ·͢1 1 https://github.com/egmc/php-sessionless-conference-ebpf-workshop

Slide 4

Slide 4 text

ࣗࣾͷࣄۀͱPHP » ήʔϜɾΞχϝࣄۀΛத৺ͱͨ͠ϞόΠϧΠϯλʔωοταʔϏε » Ψϥέʔͷ࣌୅͔Βଘࡏ͢ΔϓϩμΫτʙݱࡏ·ͰجຊతʹPHPΛར༻ » όʔδϣϯ͸શମతʹ͸গ͠ݹΊɺ7.x΋·ͩ͋Δ » ྺ࢙ͷ௕͍ϓϩμΫτ΄ͲڊେͳίʔυϕʔεΛ͍࣋ͬͯΔ » APMͱͯ͠͸NewRelic->DatadogΛར༻

Slide 5

Slide 5 text

͸͡ΊΔલʹલఏͷڞ༗ » ίϯςφͰ͸ͳ͘ϗετ্Ͱ௚઀ಈ͔͢લఏʹͳͬͯ·͢ʢ࠷ޙʹิ଍͋Γ

Slide 6

Slide 6 text

Ͱ͸վΊͯ

Slide 7

Slide 7 text

ΞδΣϯμ » ՝୊ɿσουίʔυΛݕग़͍ͨ͠ » php-dcrʢσϞʣ » ཁૉٕज़ղઆ » DTrace » eBPF » ऴΘΓʹ

Slide 8

Slide 8 text

՝୊ɿσουίʔυΛݕग़͍ͨ͠

Slide 9

Slide 9 text

σουίʔυͷ໰୊ » όʔδϣϯΞοϓͷোน » σϓϩΠ࣌ؒ΁ͷӨڹ » ຊ౰ʹ࢖ͬͯΔͷʁΛ֬ೝ͢Δͷ͕େม » Web͚ͩ͡Όͳ͍ » ͨ·ʹ͔͠ಈ͔ͳ͍όονͳͲ » ࣗ৴Λ࣋ͬͯʮ࢖ͬͯͳ͍ʯͱݴ͍੾Εͳ͍ͳΒ࢒͢΄͏͕҆શ

Slide 10

Slide 10 text

Ͳ͏ʹ͔͍ͨ͠

Slide 11

Slide 11 text

php-dcr https://github.com/egmc/php-dcr2 2 https://github.com/egmc/php-dcr

Slide 12

Slide 12 text

php-dcr(Ͱ͖Δ͜ͱ) » ಛఆύεҎԼͷPHPϑΝΠϧΛϦετԽ » phpϑΝΠϧͷcompileΠϕϯτΛه࿥ » apacheϞδϡʔϧ/php-fpm/php-cli » ϓϩμΫγϣϯ؀ڥͰ௕ظతʹಈ࡞ͤ͞Δ͜ͱΛ૝ఆ » ϨϙʔτΛHTTP APIͰఏڙʢJSONܗࣜʣ » compileΠϕϯτΛOTelͰϩάͱͯ͠ૹΔ͜ͱ΋Ͱ͖Δ

Slide 13

Slide 13 text

σϞλΠϜ

Slide 14

Slide 14 text

σϞࣦഊ࣌༻εϥΠυ1

Slide 15

Slide 15 text

σϞࣦഊ࣌༻εϥΠυ2 $ curl -s http://localhost:8080/v1/stats | jq . { "uptime_seconds": 39398.365603362, "total_files": 6634, "compiled_files": 469, "code_coverage_rate": 7.069641242086222 }

Slide 16

Slide 16 text

σϞࣦഊ࣌༻εϥΠυ3 $ curl -s http://localhost:8080/v1/report | jq . | head -n20 { "script": { "start_time_unix": 1774486040, "start_time_rfc3339": "2026-03-26T09:47:20+09:00" }, "report": [ { "filepath": "/var/www/html2/error.php", "compiled_time_unix": 1774486057, "compiled_time_rfc3339": "2026-03-26T09:47:37+09:00" }, { "filepath": "/var/www/html2/exception.php", "compiled_time_unix": 1774486057, "compiled_time_rfc3339": "2026-03-26T09:47:37+09:00" }, { "filepath": "/var/www/html2/mem.php", "compiled_time_unix": 1774486057, "compiled_time_rfc3339": "2026-03-26T09:47:37+09:00"

Slide 17

Slide 17 text

σϞࣦഊ࣌༻εϥΠυ4 $ curl -s http://localhost:8080/v1/report | jq '.report[] | select(.compiled_time_unix == -1)' | head -n10 { "filepath": "/var/www/html2/path1/a.php", "compiled_time_unix": -1, "compiled_time_rfc3339": "" } { "filepath": "/var/www/html2/path2/a.php", "compiled_time_unix": -1, "compiled_time_rfc3339": "" }

Slide 18

Slide 18 text

σϞࣦഊ࣌༻εϥΠυ5

Slide 19

Slide 19 text

php-dcrͷ֓ཁ

Slide 20

Slide 20 text

php-dcrͷ֓ཁ » Go੡ͷϝΠϯ࣮૷ʢϢʔβʔεϖʔεͰಈ࡞ʣ + eBPFϓϩάϥϜʢΧʔωϧ ಺Ͱಈ࡞ʣͷ૊Έ߹Θͤ » main.go(650ߦ͘Β͍)ɺphp.bpf.cʢ30ߦ͘Β͍ʣͷ૊Έ߹Θͤͷγϯϓ ϧͳݸਓ։ൃπʔϧ » γϯάϧόΠφϦ » ϙʔλϏϦςΟʢҟͳΔΧʔωϧόʔδϣϯɺPHPόʔδϣϯͰಈ࡞ʣ

Slide 21

Slide 21 text

php-dcrͷ֓ཁ(ಈ࡞֓ཁ) » ىಈ࣌ʹҎԼΛߦ͏ » τϨʔεϙΠϯτ(DTrace)ͷcompileΠϕϯτʹϑοΫ͢ΔeBPFϓϩάϥϜΛϩʔυ » ύεΛ୳ࡧͯͦ͠ΕͬΆ͍PHPόΠφϦΛΈ͚ͭͯΞλον͢Δ » ର৅ͱͳΔPHPϓϩηεͰDTrace͕༗ޮԽ͞ΕͯΔඞཁ͕͋Γ·͢ʢޙड़ʣ » ίϯύΠϧΠϕϯτ͕૸ΔͱϑοΫͨ͠eBPFϓϩάϥϜ͕ಈ࡞ͯ͠BPF_MAPΛߋ৽ʢϑϥά͕༗ޮ Ͱ͋Ε͹OTelϩά΋ੜ੒ʣ » goroutineͰఆظతʹMAP͔Β৘ใΛऔಘͯ͠ঢ়ଶߋ৽ » HTTP APIΞΫηε࣌ʹϨϙʔτΛJSONͰฦ͢

Slide 22

Slide 22 text

php-dcrͷ֓ཁʢσʔλϑϩʔʣ php-dcr (Go) Linux Kernel PHP ϓϩηε USDT probe USDT probe USDT probe BPF Map εΩϟϯ HTTP Apache (mod_php) PHP-FPM PHP CLI eBPF USDT: compile__file__return → ϑΝΠϧύε + ࣌ ࠁΛه࿥ BPFϚοϓಡΈऔΓ (5ඵ͝ͱϙʔϦϯά) HTTP API :8080 /v1/report, /v1/stats ର৅σΟϨΫτϦ *.php ֎෦ΫϥΠΞϯτ

Slide 23

Slide 23 text

ཁૉٕज़ղઆ

Slide 24

Slide 24 text

DTrace

Slide 25

Slide 25 text

͜ΕͰ͢

Slide 26

Slide 26 text

isԿ » ྺ࢙తʹ͸2000೥୅ͷSolaris޲͚ʹ։ൃ͞ΕͨτϨʔεͷ࢓૊Έ͕ىݯ » STDʢStatically Defined Tracingʣͱ͍͏੩తͳτϨʔεϙΠϯτΛ࢓ࠐΉ࢓૊Έ͕͋ΓɺUserland༻ͷ΋ͷ͸ USDTͱݺͿ » Linux؀ڥʹ͓͍ͯ͸SystemTap͕ఏڙ͢Δػೳ͕࢖ΘΕ͍ͯΔ » ΦϦδφϧͷDTraceͱͷΠϯλʔϑΣʔεʹ͓͚Δޓ׵ੑ͕ҙࣝ͞Ε͍ͯΔ » Ϣʔβʔۭؒʹ͓͍ͯ͸SystemTap͕ఏڙ͢ΔCϚΫϩ܈ sys/sdt.h Λ࢖ͬͯ੩తͳτϨʔεϙΠϯτΛ࡞੒͢Δ » ֤ݴޠϥϯλΠϜͷ --enable-dtrace Φϓγϣϯ͸͜ΕΛߦ͏ » τϨʔεϙΠϯτͷΞυϨεɺҾ਺ͷ৘ใͳͲ͕όΠφϦͷELFηΫγϣϯʹຒΊࠐ·ΕΔ » PHPʹ͓͍ͯ͸2010೥ࠒɺ5.3͋ͨΓ͔Βଘࡏ

Slide 27

Slide 27 text

όΠφϦΛ֬ೝͯ͠ΈΔ $ readelf -n /usr/bin/php ... Displaying notes found in: .note.stapsdt Owner Data size Description stapsdt 0x00000042 NT_STAPSDT (SystemTap probe descriptors) Provider: php Name: request__startup Location: 0x000000000027b1bf, Base: 0x0000000000440aa0, Semaphore: 0x00000000005487a8 Arguments: 8@%rax 8@%rdx 8@%rcx stapsdt 0x00000043 NT_STAPSDT (SystemTap probe descriptors) Provider: php Name: request__shutdown Location: 0x000000000027b7b1, Base: 0x0000000000440aa0, Semaphore: 0x00000000005487a6 Arguments: 8@%rax 8@%rdx 8@%rcx stapsdt 0x0000003f NT_STAPSDT (SystemTap probe descriptors) Provider: php Name: compile__file__entry Location: 0x00000000002d01bf, Base: 0x0000000000440aa0, Semaphore: 0x00000000005487a4 Arguments: 8@%rax 8@%rdx stapsdt 0x00000040 NT_STAPSDT (SystemTap probe descriptors) Provider: php Name: compile__file__return Location: 0x00000000002d01dc, Base: 0x0000000000440aa0, Semaphore: 0x00000000005487a2 Arguments: 8@%rdx 8@%rcx ... $ readelf -n /usr/bin/python3 ... Displaying notes found in: .note.stapsdt Owner Data size Description stapsdt 0x00000033 NT_STAPSDT (SystemTap probe descriptors) Provider: python Name: audit Location: 0x0000000000074b61, Base: 0x00000000004eb5f0, Semaphore: 0x00000000005a9d96 Arguments: 8@%rbp 8@%r13 stapsdt 0x00000035 NT_STAPSDT (SystemTap probe descriptors) Provider: python Name: gc__start Location: 0x000000000007815a, Base: 0x00000000004eb5f0, Semaphore: 0x00000000005a9d8e Arguments: -4@36(%rsp) stapsdt 0x00000030 NT_STAPSDT (SystemTap probe descriptors) Provider: python Name: gc__done Location: 0x00000000000781fc, Base: 0x00000000004eb5f0, Semaphore: 0x00000000005a9d90 Arguments: -8@%r12 stapsdt 0x00000045 NT_STAPSDT (SystemTap probe descriptors) Provider: python Name: function__entry Location: 0x000000000007ea33, Base: 0x00000000004eb5f0, Semaphore: 0x00000000005a9d80 Arguments: 8@%r14 8@%r15 -4@%eax ...

Slide 28

Slide 28 text

༗ޮʹ͢ΔʢPHPͷ৔߹ʣ » --enable-dtraceͰϏϧυͨ͠όΠφϦΛ༻ҙ͢Δʢ༗ޮԽ͞ΕͨύοέʔδΛ࢖͏ or ΦϓγϣϯΛ͚ͭͯϏϧυ » ؀ڥม਺ USE_ZEND_DTRACE=1 Λλʔήοτϓϩηεʹηοτ͢Δ » ଞݴޠͷ࣮૷Ͱ͸୯ʹprobe͕Ξλον͞Ε͔ͨͲ͏͔Ͱ൑ఆ͞ΕΔ » PHPͷΈ͜Ε͕ඞཁʢ7.0.14͔Βʣ » ౰࣌ͷίϝϯτͱͯ͠significant overhead͕ൃੜ͢Δͱͷ͜ͱΒ͍͠3ʢݸਓత ʹ͸ٙ໰ʣ » ಺෦తʹ͸؀ڥม਺ΛΈͯɺτϨʔεϙΠϯτΛؚΉؔ਺ʹϙΠϯλΛมߋ͍ͯ͠Δ ʢޙड़ʣ DTrace: . Disabled PHP call tracing by default (it makes significant overhead). This may be enabled again using envirionment variable USEZENDDTRACE=1. (Dmitry) $ php -i |grep -i dtrace DTrace Support => available, disabled $ USE_ZEND_DTRACE=1 php -i |grep -i dtrace DTrace Support => enabled USE_ZEND_DTRACE => 1 3 https://github.com/php/php-src/commit/0c78fe4bb55a9d39afc79cbcbadb9a273f2ec2ef

Slide 29

Slide 29 text

ؔ਺ϙΠϯλΛτϨʔεΛؚΉϥούʔʹ Zend/zend.c4 #ifdef HAVE_DTRACE /* build with dtrace support */ { char *tmp = getenv("USE_ZEND_DTRACE"); if (tmp && ZEND_ATOL(tmp)) { zend_dtrace_enabled = 1; zend_compile_file = dtrace_compile_file; zend_execute_ex = dtrace_execute_ex; zend_execute_internal = dtrace_execute_internal; zend_observer_error_register(dtrace_error_notify_cb); } else { zend_compile_file = compile_file; zend_execute_ex = execute_ex; zend_execute_internal = NULL; } } #else zend_compile_file = compile_file; zend_execute_ex = execute_ex; zend_execute_internal = NULL; #endif /* HAVE_DTRACE */ Zend/zend_dtrace.c5 ZEND_API zend_op_array *dtrace_compile_file(zend_file_handle *file_handle, int type) { zend_op_array *res; DTRACE_COMPILE_FILE_ENTRY(ZSTR_VAL(file_handle->opened_path), ZSTR_VAL(file_handle->filename)); res = compile_file(file_handle, type); DTRACE_COMPILE_FILE_RETURN(ZSTR_VAL(file_handle->opened_path), ZSTR_VAL(file_handle->filename)); return res; } 5 https://github.com/php/php-src/blob/PHP-8.5.0/Zend/zend_dtrace.c#L44-L52 4 https://github.com/php/php-src/blob/PHP-8.5.0/Zend/zend.c#L972-L993

Slide 30

Slide 30 text

eBPF

Slide 31

Slide 31 text

eBPFͷ֓ཁ(1/2) eBPFͱ͸ʁ6 6 eBPFͱ͸ https://ebpf.io/ja/what-is-ebpf/.

Slide 32

Slide 32 text

eBPFͷ֓ཁ(2/2) eBPFͰ࢖͑ΔProbe Types

Slide 33

Slide 33 text

PHPͰͷ࢖͍ॴ

Slide 34

Slide 34 text

PHP͸άϧʔͰ͋Δ(1/2) https://www.php.net/manual/ja/faq.installation.php

Slide 35

Slide 35 text

PHP͸άϧʔͰ͋Δ(2/2) » PHPຊମ͔ΒϦϯΫ » libcryptoͳͲ » γεςϜϥΠϒϥϦʢlibxxxʣʹϦϯΫͯ͠PHPଆʹΠϯλʔϑ ΣʔεΛఏڙ͢Δ » memcached.so + libmemcached » curl.so + libcurl » ... » C֦ுϨΠϠʔࣗମͰͷػೳఏڙ » mysqlnd » apcu » phpredis » ...

Slide 36

Slide 36 text

PHPͰ࢖͏ » C֦ு/ڞ༗ϥΠϒϥϦ΁urpobe/uretprobeΛ࢖͏ » APMͰΧόʔ͞Εͳ͍෦෼΁ͷϐϯϙΠϯτͰͷௐࠪ » PHPόΠφϦʹରͯ͠urpobe/uretprobeΛ࢖͏ʢ૊ΈࠐΈؔ਺ͳͲʣ » USDTʢDTraceʣͰPHPຊମͷ੩తͳτϨʔεϙΠϯτΛར༻͢Δ » ࠓճ͸͜Ε » ͳʹ͕خ͍͠ͷ͔ʁ » ӡ༻தͷϫʔΫϩʔυʹରͯ͠มߋΛՃ͑ͳͯ͘ྑ͘ɺʢجຊతʹ͸ʣΦʔόʔϔου͕গͳ ͍

Slide 37

Slide 37 text

͜Μͳ͜ͱ͕Ͱ͖·͢ྫ

Slide 38

Slide 38 text

php-dcrͷeBPFίʔυ php.bpf.c #include "vmlinux.h" #include #include #define MAX_STR_LEN 512 char filename[MAX_STR_LEN]; struct { __uint(type, BPF_MAP_TYPE_LRU_HASH); __uint(max_entries, 65536); __type(key, char[MAX_STR_LEN]); __type(value, u64); } php_compile_file SEC(".maps"); SEC("usdt//usr/lib/apache2/modules/libphp8.1.so:php:compile__file__return") int BPF_USDT(compile_file_return, char *arg0, char *arg1) { // ࣌ࠁʢىಈ࣌ࠁ͔Βͷܦաɺφϊඵʣ u64 ts = bpf_ktime_get_ns(); static const char fmtstr[] = "compile file return: %s, %s\n"; bpf_trace_printk(fmtstr, sizeof(fmtstr), arg0, arg1); bpf_probe_read_user_str(&filename, sizeof(filename), arg0); bpf_map_update_elem(&php_compile_file, &filename, &ts, BPF_ANY); return 0; } char LICENSE[] SEC("license") = "GPL";

Slide 39

Slide 39 text

php-dcrͷeBPFίʔυʢ͜Ε͚ͩʣ

Slide 40

Slide 40 text

ཁૉٕज़͜͜·Ͱ

Slide 41

Slide 41 text

૝ఆQA » DTrace͸Φϓγϣϯ͚ͩͲ࣮ࡍʹ࢖͑Δʁ » PHPʹ͓͍ͯ͸ओཁͳσΟετϩͷύοέʔδͰ༗ޮԽ͞ΕͯΔ » ʢௐ΂ͨൣғͰ͸DebianͷύοέʔδҎ֎ʣ7ʣ » ίϯςφରԠ » k8sʹ͓͍ͯ΋Ξϓϩʔν͸͋Δ͕೉͍͠ » ϓϩηεͷ௥੻ɺΞλονઌͷಛఆ » ίϯύΠϧΠϕϯτ͕ىಈޙ͙͢ʹ૸ΔͷͰΞλον͕ؒʹ߹Θͳ͍ͱࠔΔ » ؔ਺΍Ϋϥε୯ҐͰͷௐࠪ » function-entry΍function-retrun͕͋ΔͷͰݪཧతʹ͸Մೳ͕ͩ » ͕͢͞ʹΦʔόʔϔου͕໨ʹݟ͑ΔΑ͏ʹͳΔͱࢥΘΕΔ 7 DTraceͷ༗ޮԽঢ়گௐࠪ2026

Slide 42

Slide 42 text

ऴΘΓʹɺͳͥ͜ͷτʔΫΛͨ͠ͷ͔

Slide 43

Slide 43 text

ར༻ऀΛ૿΍͍ͨ͠ » Ubuntuͷ࠷৽LTSʢ24.04 nobleʣͰ͸DTrace ͷαϙʔτ͕੾ΒΕ͍ͯΔ » UpstreamͰͷϏϧυΤϥʔ͕ݪҼ » Debian͕ݱঢ়Φϑͳͷ΋ଟ෼͜Ε » IssueΛ͋͛ͨΒϝϯςφͷํʹରԠ͍͚ͨͩ ͨ » ࢖ΘΕͯͳ͍ػೳ͸੾ΒΕͯ΋࢓ํ͕ͳ͍ » ͔͠͠΋͍ͬͨͳ͍ » ࢖ͬͯΔΑʂͱ͍͏੠͸େࣄ

Slide 44

Slide 44 text

DTraceɺeBPFͷ࢖͍ॴ͸৭ʑ͋Δʢͱࢥ͍·͢ʣ » uprobeʹΑΔΞυϗοΫௐࠪ » ಺෦ϝτϦΫεΛऔಘͯ͠GrafanaͰϏδϡΞϥΠζ » ͳͲͳͲ » ؾʹͳΔͱ͜Ζ͕͋Ε͹ͥͻ͓੠͕͚͍ͩ͘͞ » ʢϛʔτΞοϓ΋΍ͬͯ·͢8ʣ 8 eBPF Japan Meetup

Slide 45

Slide 45 text

Thank you for listening