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
170
PHPerのための計算量入門/Complexity101 for PHPer
hanhan1978
8
2.8k
集中して作業する技術/how_to_work_deeply
hanhan1978
63
49k
ADRを一年運用してみた/adr_after_a_year
hanhan1978
8
4.1k
B+木入門:PHPで理解する データベースインデックスの仕組み/b-plus-tree-101
hanhan1978
5
5.3k
ADRを一年運用してみた/our_story_about_adr
hanhan1978
5
2.3k
PHPで学ぶ Session の基本と応用 / web-app-session-101-2024
hanhan1978
13
6k
Other Decks in Technology
See All in Technology
AWS Summit Japan 2025 Community Stage - App workflow automation by AWS Step Functions
matsuihidetoshi
1
300
AWS Organizations 新機能!マルチパーティ承認の紹介
yhana
1
210
生成AIで小説を書くためにプロンプトの制約や原則について学ぶ / prompt-engineering-for-ai-fiction
nwiizo
4
3.3k
急成長を支える基盤作り〜地道な改善からコツコツと〜 #cre_meetup
stefafafan
0
150
本が全く読めなかった過去の自分へ
genshun9
0
670
低レイヤを知りたいPHPerのためのCコンパイラ作成入門 完全版 / Building a C Compiler for PHPers Who Want to Dive into Low-Level Programming - Expanded
tomzoh
4
3.4k
解析の定理証明実践@Lean 4
dec9ue
1
190
生成AI開発案件におけるClineの業務活用事例とTips
shinya337
0
170
AIとともに進化するエンジニアリング / Engineering-Evolving-with-AI_final.pdf
lycorptech_jp
PRO
0
140
Oracle Audit Vault and Database Firewall 20 概要
oracle4engineer
PRO
3
1.7k
ドメイン特化なCLIPモデルとデータセットの紹介
tattaka
1
350
20250625 Snowflake Summit 2025活用事例 レポート / Nowcast Snowflake Summit 2025 Case Study Report
kkuv
1
360
Featured
See All Featured
Fantastic passwords and where to find them - at NoRuKo
philnash
51
3.3k
YesSQL, Process and Tooling at Scale
rocio
173
14k
Adopting Sorbet at Scale
ufuk
77
9.4k
How STYLIGHT went responsive
nonsquared
100
5.6k
How GitHub (no longer) Works
holman
314
140k
The Art of Programming - Codeland 2020
erikaheidi
54
13k
How to train your dragon (web standard)
notwaldorf
94
6.1k
Dealing with People You Can't Stand - Big Design 2015
cassininazir
367
26k
Evolution of real-time – Irina Nazarova, EuRuKo, 2024
irinanazarova
8
800
Keith and Marios Guide to Fast Websites
keithpitt
411
22k
The Myth of the Modular Monolith - Day 2 Keynote - Rails World 2024
eileencodes
26
2.9k
Building Better People: How to give real-time feedback that sticks.
wjessup
367
19k
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 そこから正しい形に整形していけばいい
まとめ
自作は楽しい!
みんなも変なモノ作っていこうな!