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
11
9.7k
PHPでデータベースを作ってみた/create-data-with-php
PHPカンファレンス福岡2024の登壇資料です。
Ryo Tomidokoro
June 22, 2024
Tweet
Share
More Decks by Ryo Tomidokoro
See All by Ryo Tomidokoro
100分で本番デプロイ!Laravelで作るWebアプリケーション作成/100min_web_app_cicd
hanhan1978
1
61
PHPerのための計算量入門/Complexity101 for PHPer
hanhan1978
6
1.9k
集中して作業する技術/how_to_work_deeply
hanhan1978
62
46k
ADRを一年運用してみた/adr_after_a_year
hanhan1978
8
3.8k
B+木入門:PHPで理解する データベースインデックスの仕組み/b-plus-tree-101
hanhan1978
5
4.9k
ADRを一年運用してみた/our_story_about_adr
hanhan1978
5
2.1k
PHPで学ぶ Session の基本と応用 / web-app-session-101-2024
hanhan1978
13
5.7k
レガシー回避のPHP開発術/avoid_php_legacy
hanhan1978
17
13k
Laravel Collectionの計算量を調べてみた2023/laravel_collection_time_complexity_2023
hanhan1978
1
1.6k
Other Decks in Technology
See All in Technology
【詳説】コンテンツ配信 システムの複数機能 基盤への拡張
hatena
0
210
Reading Code Is Harder Than Writing It
trishagee
2
120
偏光画像処理ライブラリを作った話
elerac
1
160
Raycast AI APIを使ってちょっと便利な拡張機能を作ってみた / created-a-handy-extension-using-the-raycast-ai-api
kawamataryo
0
200
Cracking the Coding Interview 6th Edition
gdplabs
14
28k
アジャイルな開発チームでテスト戦略の話は誰がする? / Who Talks About Test Strategy?
ak1210
1
390
Perlの生きのこり - エンジニアがこの先生きのこるためのカンファレンス2025
kfly8
2
260
プロダクトエンジニア構想を立ち上げ、プロダクト志向な組織への成長を続けている話 / grow into a product-oriented organization
hiro_torii
1
350
遷移の高速化 ヤフートップの試行錯誤
narirou
6
1k
データベースの負荷を紐解く/untangle-the-database-load
emiki
1
440
Two Blades, One Journey: Engineering While Managing
ohbarye
3
1.4k
AIエージェント入門
minorun365
PRO
30
16k
Featured
See All Featured
Done Done
chrislema
182
16k
Practical Orchestrator
shlominoach
186
10k
Into the Great Unknown - MozCon
thekraken
35
1.6k
Building Applications with DynamoDB
mza
93
6.2k
It's Worth the Effort
3n
184
28k
Learning to Love Humans: Emotional Interface Design
aarron
273
40k
How to train your dragon (web standard)
notwaldorf
91
5.9k
The Cult of Friendly URLs
andyhume
78
6.2k
Faster Mobile Websites
deanohume
306
31k
Fashionably flexible responsive web design (full day workshop)
malarkey
406
66k
Dealing with People You Can't Stand - Big Design 2015
cassininazir
366
25k
We Have a Design System, Now What?
morganepeng
51
7.4k
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 そこから正しい形に整形していけばいい
まとめ
自作は楽しい!
みんなも変なモノ作っていこうな!