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
10k
PHPでデータベースを作ってみた/create-data-with-php
PHPカンファレンス福岡2024の登壇資料です。
Ryo Tomidokoro
June 22, 2024
Tweet
Share
More Decks by Ryo Tomidokoro
See All by Ryo Tomidokoro
フロントエンドがTypeScriptなら、バックエンドはPHPでもいいじゃない/php-is-not-bad
hanhan1978
9
13k
どうすると生き残れないのか/how-not-to-survive
hanhan1978
17
14k
100分で本番デプロイ!Laravelで作るWebアプリケーション作成/100min_web_app_cicd
hanhan1978
1
180
PHPerのための計算量入門/Complexity101 for PHPer
hanhan1978
8
3k
集中して作業する技術/how_to_work_deeply
hanhan1978
65
50k
ADRを一年運用してみた/adr_after_a_year
hanhan1978
8
4.3k
B+木入門:PHPで理解する データベースインデックスの仕組み/b-plus-tree-101
hanhan1978
5
5.4k
ADRを一年運用してみた/our_story_about_adr
hanhan1978
5
2.4k
PHPで学ぶ Session の基本と応用 / web-app-session-101-2024
hanhan1978
13
6.1k
Other Decks in Technology
See All in Technology
GCASアップデート(202506-202508)
techniczna
0
210
いま、あらためて考えてみるアカウント管理 with IaC / Account management with IaC
kohbis
2
420
MCPサーバーを活用したAWSコスト管理
arie0703
0
130
20250818_KGX・One Hokkaidoコラボイベント
tohgeyukihiro
0
110
夏休みWebアプリパフォーマンス相談室/web-app-performance-on-radio
hachi_eiji
1
270
JAWS AI/ML #30 AI コーディング IDE "Kiro" を触ってみよう
inariku
3
400
Amazon Bedrock AgentCoreのフロントエンドを探す旅 (Next.js編)
kmiya84377
1
160
Rethinking Incident Response: Context-Aware AI in Practice - Incident Buddy Edition -
rrreeeyyy
0
120
EKS Pod Identity における推移的な session tags
z63d
1
150
いかにして命令の入れ替わりについて心配するのをやめ、メモリモデルを愛するようになったか(改)
nullpo_head
7
2.7k
[OCI Technical Deep Dive] OCIで生成AIを活用するためのソリューション解説(2025年8月5日開催)
oracle4engineer
PRO
0
120
LLM 機能を支える Langfuse / ClickHouse のサーバレス化
yuu26
9
2.6k
Featured
See All Featured
How to Think Like a Performance Engineer
csswizardry
25
1.8k
Optimising Largest Contentful Paint
csswizardry
37
3.4k
How to train your dragon (web standard)
notwaldorf
96
6.2k
RailsConf 2023
tenderlove
30
1.2k
The Web Performance Landscape in 2024 [PerfNow 2024]
tammyeverts
9
770
Fight the Zombie Pattern Library - RWD Summit 2016
marcelosomers
234
17k
Music & Morning Musume
bryan
46
6.7k
Build The Right Thing And Hit Your Dates
maggiecrowley
37
2.8k
Building Flexible Design Systems
yeseniaperezcruz
328
39k
Principles of Awesome APIs and How to Build Them.
keavy
126
17k
The World Runs on Bad Software
bkeepers
PRO
70
11k
Let's Do A Bunch of Simple Stuff to Make Websites Faster
chriscoyier
507
140k
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 そこから正しい形に整形していけばいい
まとめ
自作は楽しい!
みんなも変なモノ作っていこうな!