Slide 1

Slide 1 text

CodeCrafters にチャレンジして PHP で Redis を作ってみる 2023/03/24 @PHPerKaigi 2023
 げんえい (@gennei)


Slide 2

Slide 2 text

こんなことで悩んでいたりしませんか?
 🤔🤔🤔
 2

Slide 3

Slide 3 text

悩み
 ● チュートリアルを終えたけど次なにをしたらいいかわからない
 ● WAFを使ってアプリは作れるけど0から作る自信がない
 ● PHP以外の言語を学んでみたいけどなにをしたらいいかわか らない
 ● 複雑なアプリケーションの裏側を知りたい
 3

Slide 4

Slide 4 text

今日はそんな悩みを
 解決できるかもしれない話をします
 4

Slide 5

Slide 5 text

自己紹介
 $profile = [
 '名前' => 'げんえい', 
 '所属' => 'カオナビ', 
 'ロール' => 'テックリード', 
 '好き' => ['コーヒー', 'サンフレッチェ広島', '読書'],
 ];
 5

Slide 6

Slide 6 text

6

Slide 7

Slide 7 text

Code Crafters とは
 ● 複雑なソフトウェアを作る練習ができるサイト
 ● “車輪の再発明” を通してプログラミングを学べる
 7

Slide 8

Slide 8 text

どんなものを作るのか
 ● Redis
 ● Docker
 ● Git
 ● SQLite
 ● grep
 ● etc…
 8

Slide 9

Slide 9 text

9

Slide 10

Slide 10 text

CodeCrafters の学習サイクル
 1. アカウント作成
 2. 課題のリポジトリをClone
 3. 課題に沿ってコードを書く
 4. PUSH すると CI が動きパスすると次の課題に進む
 10

Slide 11

Slide 11 text

PHP で Redis を作ってみました
 11

Slide 12

Slide 12 text

Redis
 ● インメモリデータストア
 ● Key-Value でデータ取得、保存
 ● 有効期限の設定ができる
 12

Slide 13

Slide 13 text

RESPとは
 ● Redis Serialization Protocol の略
 ● 特徴 
 ○ Simple to implement.(実装が簡単)
 ○ Fast to parse. (パースが速い)
 ○ Human readable. (人間が読むことができる)
 13

Slide 14

Slide 14 text

*2\r\n$4\r\nECHO\r\n$3\r\nphp\r\n
 14

Slide 15

Slide 15 text

RESPの読み方
 先頭の記号はデータのフォーマットを表す
 15 記号
 意味
 +
 Simple String (改行コード許容しない) 
 -
 Error
 :
 Interger
 $
 Bulk String (改行コード許容する。バイナリセーフ。) 
 *
 Array


Slide 16

Slide 16 text

Simple String
 ● +PING\r\n
 ○ + から始まり \r\n で終わる
 16

Slide 17

Slide 17 text

Error
 ● -Error message\r\n
 ○ - で始まり \r\n で終わる
 17

Slide 18

Slide 18 text

Integer
 ● :1000\r\n
 ○ : で始まり \r\n で終わる
 18

Slide 19

Slide 19 text

Bulk String
 ● $5\r\nhello\r\n
 ○ $ は Bulk String を表す
 ○ $ の次の数字は文字列の長さを表す
 19

Slide 20

Slide 20 text

Array
 ● *2\r\n$4\r\nECHO\r\n$3\r\nphp\r\n
 ○ * は Array を表す
 ○ * の次の数字は配列のサイズ
 ○ $ の次の数字は文字列長
 20

Slide 21

Slide 21 text

*2\r\n$4\r\nECHO\r\n$3\r\nphp\r\n
 21 *2 = 配列のサイズが2
 $4 = 4文字(ECHO)
 $3 = 3文字(php)


Slide 22

Slide 22 text

RESP完全に理解した
 22

Slide 23

Slide 23 text

CodeCraftersチャレンジしてみる
 23

Slide 24

Slide 24 text

7つのステップ
 1. 6379 port で待受
 2. ping を送ると pong が返ってくる
 3. 複数回コマンド対応
 4. 並列でクライアントからのリクエスト処理
 5. ECHO コマンドの実装
 6. SET, GETコマンドの実装
 7. Expire の実装
 24

Slide 25

Slide 25 text

7つのステップ
 1. 6379 port で待受
 2. ping を送ると pong が返ってくる
 3. 複数回コマンド対応
 4. 並列でクライアントからのリクエスト処理
 5. ECHO コマンドの実装
 6. SET, GETコマンドの実装
 7. Expire の実装
 25

Slide 26

Slide 26 text

1. 6379 port で待受
 ● cloneしたらすでにコードが書かれているので詳しく知らなくても大丈 夫
 ● 主に socket_xxx() 系の関数を利用します
 ○ socket_create() // ソケット作成
 ○ socket_bind() // 作成したソケットをaddress、portにバインド
 ○ socket_listen() // 接続待ち
 ○ socket_accept() // ソケットへの接続許可
 26

Slide 27

Slide 27 text

27

Slide 28

Slide 28 text

7つのステップ
 1. 6379 port で待受
 2. ping を送ると pong が返ってくる
 3. 複数回コマンド対応
 4. 並列でクライアントからのリクエスト処理
 5. ECHO コマンドの実装
 6. SET, GETコマンドの実装
 7. Expire の実装
 28

Slide 29

Slide 29 text

2. ping を送ると pong が返ってくる
 ● +ping\r\n がクライアントから送られてくる
 ● +pong\r\n をクライアントへ返せば終わり
 ● レスポンスを返すときは socket_write() を使う
 29

Slide 30

Slide 30 text

30

Slide 31

Slide 31 text

7つのステップ
 1. 6379 port で待受
 2. ping を送ると pong が返ってくる
 3. 複数回コマンド対応
 4. 並列でクライアントからのリクエスト処理
 5. ECHO コマンドの実装
 6. SET, GETコマンドの実装
 7. Expire の実装
 31

Slide 32

Slide 32 text

3. 複数回コマンド対応
 ● while で無限ループしてコマンドを待つ
 32

Slide 33

Slide 33 text

33

Slide 34

Slide 34 text

7つのステップ
 1. 6379 port で待受
 2. ping を送ると pong が返ってくる
 3. 複数回コマンド対応
 4. 並列でクライアントからのリクエスト処理
 5. ECHO コマンドの実装
 6. SET, GETコマンドの実装
 7. Expire の実装
 34

Slide 35

Slide 35 text

4. 並列でクライアントからのリクエスト処理
 35 ● どのクライアントからの通信かを判定してレスポンスを返す
 ○ JavaScript で作っているとなにもしなくていいぞ
 


Slide 36

Slide 36 text

36

Slide 37

Slide 37 text

37

Slide 38

Slide 38 text

7つのステップ
 1. 6379 port で待受
 2. ping を送ると pong が返ってくる
 3. 複数回コマンド対応
 4. 並列でクライアントからのリクエスト処理
 5. ECHO コマンドの実装
 6. SET, GETコマンドの実装
 7. Expire の実装
 38

Slide 39

Slide 39 text

5. ECHO コマンドの実装
 ● RESP フォーマットをパースして文字列を取得
 ● socket_write() で入力された文字列を返す
 39

Slide 40

Slide 40 text

*2\r\n$4\r\nECHO\r\n$5\r\nworld\r\n
 40 *2 = 配列のサイズが2
 $4 = 4文字(ECHO)
 $5 = 5文字(world)


Slide 41

Slide 41 text

41

Slide 42

Slide 42 text

*2\r\n$4\r\nECHO\r\n$5\r\nworld\r\n
 42 *2 = 配列のサイズが2
 $4 = 4文字(ECHO)
 $5 = 5文字(world)


Slide 43

Slide 43 text

7つのステップ
 1. 6379 port で待受
 2. ping を送ると pong が返ってくる
 3. 複数回コマンド対応
 4. 並列でクライアントからのリクエスト処理
 5. ECHO コマンドの実装
 6. SET, GETコマンドの実装
 7. Expire の実装
 43

Slide 44

Slide 44 text

6. SET, GETコマンドの実装
 ● PHPの1プロセスが起動している状態なのでストレージとなる シングルトンを作成し読み書きする
 44

Slide 45

Slide 45 text

45

Slide 46

Slide 46 text

7つのステップ
 1. 6379 port で待受
 2. ping を送ると pong が返ってくる
 3. 複数回コマンド対応
 4. 並列でクライアントからのリクエスト処理
 5. ECHO コマンドの実装
 6. SET, GETコマンドの実装
 7. Expire の実装
 46

Slide 47

Slide 47 text

7. Expire の実装
 ● Expire
 ○ SET KEY VALUE 単位 (時間) で指定する
 ○ 指定は ex(秒) または px(ミリ秒) で指定する
 ○ ex) SET lang php px 100
 47

Slide 48

Slide 48 text

48

Slide 49

Slide 49 text

49

Slide 50

Slide 50 text

時間があればデモ
 50

Slide 51

Slide 51 text

まとめ
 ● RedisはRESPがわかれば作れる!
 ● 順番に小さく作ることでコア機能は作れる
 ● 新しい言語を習得するときはCodeCraftersでやってみるのい いかもしれない
 51

Slide 52

Slide 52 text

参考文献
 ● Redis 公式ドキュメント
 ○ https://redis.io/docs/
 ● 実践Redis入門 技術の仕組みから現場の活用まで
 ○ https://gihyo.jp/book/2022/978-4-297-13142-5
 52

Slide 53

Slide 53 text

おわり
 53

Slide 54

Slide 54 text

おまけ
 54

Slide 55

Slide 55 text

RESP3
 ● Redis6.0 以降ではRESP3を使うことができる
 ● 主な変更点
 ○ CRLF -> LF に変更
 ○ データ型の追加
 ■ Map、Set、Boolean、etc..
 55