Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
PHPでデータベースを作ってみた/create-data-with-php
Search
Ryo Tomidokoro
June 22, 2024
Technology
10
9.1k
PHPでデータベースを作ってみた/create-data-with-php
PHPカンファレンス福岡2024の登壇資料です。
Ryo Tomidokoro
June 22, 2024
Tweet
Share
More Decks by Ryo Tomidokoro
See All by Ryo Tomidokoro
集中して作業する技術/how_to_work_deeply
hanhan1978
61
40k
ADRを一年運用してみた/adr_after_a_year
hanhan1978
8
3.4k
B+木入門:PHPで理解する データベースインデックスの仕組み/b-plus-tree-101
hanhan1978
5
4.5k
ADRを一年運用してみた/our_story_about_adr
hanhan1978
5
2k
PHPで学ぶ Session の基本と応用 / web-app-session-101-2024
hanhan1978
12
5.5k
レガシー回避のPHP開発術/avoid_php_legacy
hanhan1978
16
12k
Laravel Collectionの計算量を調べてみた2023/laravel_collection_time_complexity_2023
hanhan1978
1
1.4k
PHP で学ぶ Cache の距離の話 / study_cache_with_php
hanhan1978
7
2.1k
Laravel を低速化する技術 / how to slow laravel
hanhan1978
2
3.9k
Other Decks in Technology
See All in Technology
誰も全体を知らない ~ ロールの垣根を超えて引き上げる開発生産性 / Boosting Development Productivity Across Roles
kakehashi
1
220
障害対応指揮の意思決定と情報共有における価値観 / Waroom Meetup #2
arthur1
5
470
Amazon CloudWatch Network Monitor のススメ
yuki_ink
1
200
ドメインの本質を掴む / Get the essence of the domain
sinsoku
2
150
TypeScript、上達の瞬間
sadnessojisan
46
13k
iOSチームとAndroidチームでブランチ運用が違ったので整理してます
sansantech
PRO
0
120
New Relicを活用したSREの最初のステップ / NRUG OKINAWA VOL.3
isaoshimizu
2
570
社内で最大の技術的負債のリファクタリングに取り組んだお話し
kidooonn
1
550
Terraform未経験の御様に対してどの ように導⼊を進めていったか
tkikuchi
2
430
iOS/Androidで同じUI体験をネ イティブで作成する際に気をつ けたい落とし穴
fumiyasac0921
1
110
BLADE: An Attempt to Automate Penetration Testing Using Autonomous AI Agents
bbrbbq
0
290
20241120_JAWS_東京_ランチタイムLT#17_AWS認定全冠の先へ
tsumita
2
230
Featured
See All Featured
Documentation Writing (for coders)
carmenintech
65
4.4k
The Invisible Side of Design
smashingmag
298
50k
Responsive Adventures: Dirty Tricks From The Dark Corners of Front-End
smashingmag
250
21k
Mobile First: as difficult as doing things right
swwweet
222
8.9k
Practical Orchestrator
shlominoach
186
10k
Visualizing Your Data: Incorporating Mongo into Loggly Infrastructure
mongodb
42
9.2k
Rails Girls Zürich Keynote
gr2m
94
13k
Statistics for Hackers
jakevdp
796
220k
XXLCSS - How to scale CSS and keep your sanity
sugarenia
246
1.3M
The Art of Programming - Codeland 2020
erikaheidi
52
13k
Helping Users Find Their Own Way: Creating Modern Search Experiences
danielanewman
29
2.3k
Designing the Hi-DPI Web
ddemaree
280
34k
Transcript
PHPでデータベースを作ってみた @hanhan1978 PHPカンファレンス福岡2024
@hanhan1978 名前 富所 亮 所属 株式会社カオナビ CTO室 BackEnd Re-architecturing Team
(BERT) Blog https://blog.hanhans.net Podcast https://podcasters.spotify.com/pod/show/yokohama-north-am 2
免責事項
この登壇への注意 本発表はRDBMSっぽく振る舞うプログラムを 気軽なノリで作っていくお話です。
この登壇への注意 • パーサー、オプティマイザ • ストレージエンジン • などなどのRDBMSの構成要素 取り扱いません!
そもそも目的は!?
目的 • データベースを深く理解する • プロトコルを深く理解する • プログラムへの解像度を上げる
目的 • データベースを深く理解する • プロトコルを深く理解する • プログラムへの解像度を上げる 全部ウソ!
(答え)なんとなく作ってみたかった
ではデータベースを自作するための 参考資料とは?
参考書1 WEB+DB PRESS Vol.122 作って学ぶRDBMSのしくみ - 技術評論社 2021
参考書2 詳説データベース - ストレージエンジンと分散データシステムの仕組み - O’Reilly 2021
参考書3 Software Design 2024年6月号 - 技術評論社
参考書4 https://speakerdeck.com/hanhan1978/b-plus-tree-101
否!!
まじめに作ろうとすると 大変な努力が必要になる
もっと迂闊に作りたい
真の参考書 ゼロからトースターを作ってみた結果 - 新潮文庫 2015
不格好でもいいので、動く完成品を作ること は学びにとって実に良いことです
駄目な例 Learn to draw fast - https://www.alibati.com/work/horse
動く完成品を作ろう https://blog.crisp.se/2016/01/25/henrikkniberg/making-sense-of-mvp
目標の具体化 ここまで4分
MySQLと何なのか?
PHPからみたMySQL よくみるPDOのサンプルコード
PHPからみたMySQL 3306ポートでTCP/IPのソケット通信
つまり
目標 同じ通信内容ならPHPからはデータベースに見える!
目標を具体化 1. 特定のポート番号でソケット通信を行う 2. MySQLと同じ通信内容を行う データベースを作る
余談
この考え方は様々なミドルウェアに対応 • Redis • ElasticSearch • Apache ようするにTCP/IPでソケット通信を行うアプリケーションは 既存の挙動を真似ることさえ出来れば同じように作れる
では!作っていく!
1. 特定のポート番号でソケット通信を行う 2. MySQLと同じ通信内容を行う やること
1. 特定のポート番号でソケット通信を行う 2. MySQLと同じ通信内容を行う やること ネットワークプログラミング
参考書 UNIXネットワークプログラミング Vol.1 ※もっと新しい本 でよいです
echoサーバー 今回の用途であれば 「echoサーバー」という検索ワードを使うと サンプル実装がいっぱい引っかかります
echoサーバー 今回の用途であれば 「echoサーバー」という検索ワードを使うと サンプル実装がいっぱい引っかかります が!
2年前に書いておきました PHPerKaigi2022 - パンフレット
具体的なコード
実際に起動してみると... うごくぞ...
MySQLの場合 3306番で動作してる
TCP/IPの状態確認 Mac Linux
1. 特定のポート番号でソケット通信を行う 2. MySQLと同じ通信内容を行う やること 進捗50%!
1. 特定のポート番号でソケット通信を行う 2. MySQLと同じ通信内容を行う やること
1. 特定のポート番号でソケット通信を行う 2. MySQLと同じ通信内容を行う やること ???どうやんの???
通信内容をみるには? • Wireshark • tcpdump • ngrep
通信内容をみるには? • Wireshark • tcpdump • ngrep 今回はお手軽な ngrep を採用
さっそくMySQLの通信を見る -x -q -d 通信の中身を16進数表記でdump、かつ右側にテキスト表示 header, payload 以外の通信内容はdumpしない 通信をみるネットワークインタフェースを指定
さっそくMySQLの通信を見る 引数は match と filter 上の例は match は無指定、filter に port
3306 を指定 これで3306番ポートにまつわるローカル ホストの通信が確認できる
通信内容をみる1
通信内容をみる1 まずサーバー側からスタート
通信内容をみる1 クライアントの認証リクエスト
通信内容をみる1 サーバー側からのOK応答
こんなもの読めるのか?
MySQL公式ドキュメント https://dev.mysql.com/doc/dev/mysql-server/latest/
Handshake https://dev.mysql.com/doc/dev/mysql-server/latest/page_protocol_connection_phase.html
Protocol::HandshakeV10
これで読めそうやん!
プロトコル読解 - Handshake
プロトコル読解 - Handshake いきなり違う!
おちつけ!
MySQL Packets
MySQL Packets 基本仕様
プロトコル読解 - Handshake 最初の3Byteは payloadのサイズ ▶ 4a 00 00 ▶
74 Byte 次の1ByteはシーケンスID ▶ 00 ▶ 0
プロトコル読解 - Handshake このパケットは Header 4 Byte + Payload 74
Byte の 78 Bytea MySQLのパケットを考える際は常にこの Header を考慮にいれる
プロトコル読解 - Handshake 0x0a ▶ 10進数の10
プロトコル読解 - Handshake サーバーバージョン文字列
ASCIIコード表 https://www.sciencebuddies.org/science-fair-projects/references/ascii-table
ASCIIコード表 https://www.sciencebuddies.org/science-fair-projects/references/ascii-table 8 ▶ 0x38
サーバーからの認証OKパケット
通信内容をみる1 サーバー側からのOK応答
General Response Packets
プロトコル読解 - General Response 7ByteのPayload header ▶ 0x00 affected_rows ▶
0x00 last_insert_id ▶ 0x00
プロトコル読解 - General Response 7ByteのPayload header ▶ 0x00 affected_rows ▶
0x00 last_insert_id ▶ 0x00 君はここにいたのか!!
PDO::lastInsertId https://www.php.net/manual/ja/pdo.lastinsertid.php
読める!読めるぞ!
だが、このまま細かくプロトコルを 実装するのは骨が折れる 第一面倒くさい。俺はデータベースっ ぽいやつを早く作りたい
こうして...
こうじゃ! ※良い子はマネしない
さらに、こうして...
こうじゃ!!!! ※良い子はマネしない
クライアント側のソースコード なんと、こんなものでも PDOをコロッとだますと接続できる
このままDEMOになだれ込みたいが... 結果セット返却の解説は必要 もうちょっと我慢してくれ 残り15分以上
SELECTの通信
SELECTの通信 Header ▶ Payloadサイズは37
SELECTの通信 Header ▶ Payloadサイズは37 Payload ▶ 先頭に 0x03 ▶ ETX
制御コード
SELECTの通信 Header ▶ Payloadサイズは37 Payload ▶ 先頭に 0x03 ▶ ETX
制御コード Payload残り ▶ クエリの文字列 SELECT id, value1, value2 FROM items
SELECTの通信 結果セットの送信パケットを適切に理解することが大切 このパケットは合計8つのMySQLパケットで構成されている
SELECTの通信 1Byte の Payload 最初のパケットは結果セットのカラム数 0x03
SELECTの通信 40Byte の Payload 2番目以降はカラム定義 x コラム数のパケット
SELECTの通信 40Byte の Payload 03 646566 ▶ 3byte の文字列メッセージ def
固定値
SELECTの通信 40Byte の Payload 04 74657374▶ 4byte の文字列メッセージ test データベース名
SELECTの通信 40Byte の Payload 04 74657374▶ 4byte の文字列メッセージ test データベース名
05 6974656d73▶ 5byte の文字列メッセージ items テーブル名 05 6974656d73▶ 5byte の文字列メッセージ items オリジナルのテーブル名
SELECTの通信 40Byte の Payload 04 74657374▶ 4byte の文字列メッセージ test データベース名
05 6974656d73▶ 5byte の文字列メッセージ items テーブル名 05 6974656d73▶ 5byte の文字列メッセージ items オリジナルのテーブル名 02 6964▶ 2byte の文字列メッセージ id カラム名 02 6964▶ 2byte の文字列メッセージ id オリジナルのカラム名
SELECTの通信 40Byte の Payload 0c ▶ 固定値 3f00 ▶ キャラセット
binary
SELECTの通信 40Byte の Payload 0c ▶ 固定値 3f00 ▶ キャラセット
binary 0b000000 ▶ カラムサイズ int(11)
SELECTの通信 40Byte の Payload 0c ▶ 固定値 3f00 ▶ キャラセット
binary 0b000000 ▶ カラムサイズ int(11) 03 ▶ データ型
SELECTの通信 40Byte の Payload 0c ▶ 固定値 3f00 ▶ キャラセット
binary 0b000000 ▶ カラムサイズ int(11) 03 ▶ データ型 0350 ▶ ビット演算されたフラグ
SELECTの通信 40Byte の Payload 0c ▶ 固定値 3f00 ▶ キャラセット
binary 0b000000 ▶ カラムサイズ int(11) 03 ▶ データ型 0350 ▶ ビット演算されたフラグ 000000 ▶ Packet終端
SELECTの通信 結果で返却するカラム数の数だけカラム定義のPacketを返す 今回は3カラム分
参考資料 - データタイプ https://github.com/mysql/mysql-server/blob/trunk/include/field_types.h
参考資料 - データタイプ https://github.com/mysql/mysql-server/blob/trunk/include/field_types.h
参考資料 https://dev.mysql.com/doc/dev/mysql-server/latest/group__group__cs__column__definition__flags.html
フラグのビット演算例 NOT NULL 0110
フラグのビット演算例 PRIMARY KEY 0350
SELECTの通信 カラム定義と結果セットの間のデリメター(だと思う) fe00002200 ▶ シーケンス番号以外は固定
SELECTの通信 結果行 - 1行目 0131 ▶ idカラムの結果 文字列 1 05686f676531
▶ value1カラムの結果 文字列 hoge1 05686f676532 ▶ value2カラムの結果 文字列 hoge2
SELECTの通信 結果行 - 1行目 0131 ▶ idカラムの結果 文字列 1 05686f676531
▶ value1カラムの結果 文字列 hoge1 05686f676532 ▶ value2カラムの結果 文字列 hoge2 intは文字列で返ってくる PDO, ORMなどで型変換の不具合イシューが上がっ てくるのはここらへんの仕様が関係ありそう
SELECTの通信 最後にもう一回デリミタが入ってくる 以上で長かった結果セットの説明も終わりです。
簡単にまとめると... Handshake ▶ OKパケット DML, 更新系クエリ ▶ OKパケット 参照系クエリ ▶
カラム定義を含む、結果セットのパケット 細かくはもっといろいろあるのだけど 偽データベースを動作させるには十分
余談
クエリのパース https://github.com/greenlion/PHP-SQL-Parser
クエリのパース ここまで理解できれば、作れるはず だ!雑なRDBMSが!
ore no database
ore no database
ore no database
DEMO 残り2分
今後の展開 • テストを拡充 • データの保存・読取 • IO多重化 • インデックス •
Information Schema対応
クエリのパース 最低限の動作を満たした動くDB そこから正しい形に整形していけばいい
まとめ
自作は楽しい!
みんなも変なモノ作っていこうな!