7つのデータベース7つの世界
- 作者: Eric Redmond,Jim R. Wilson,角征典
- 出版社/メーカー: オーム社
- 発売日: 2013/02/26
- メディア: 単行本(ソフトカバー)
- 購入: 3人 クリック: 56回
- この商品を含むブログ (15件) を見る
読了。 Cassandraを「使うのが目的」のことがあるんだけど、やっぱり間違ってると分かった。
第8章 Redis
- 速度に関していえば最高
- 超高速なキーバリューストア
- 何であるかを正確に分類するのは難しい
- 応用的なデータ構造をサポート
- ブロッキングキュー
- スタック
- Pub/Sub
- 有効期限/永続レベル/レプリケーションのオプションが設定可能
- 便利なデータ構造のアルゴリズムやプロセスのツールキット
% brew install redis % redis-server -v Redis server v=3.0.5 sha=00000000:0 malloc=libc bits=64 build=78b12a45f78ec0e % redis-server % redis-cli 127.0.0.1:6379> PING PONG 127.0.0.1:6379> SET 7wks http://www.sevenweeks.org/ OK 127.0.0.1:6379> GET 7wks "http://www.sevenweeks.org/" 127.0.0.1:6379> MSET gog https://www.google.co.jp/ yah http://www.yahoo.co.jp/ OK 127.0.0.1:6379> MGET gog yah 1) "https://www.google.co.jp/" 2) "http://www.yahoo.co.jp/" 127.0.0.1:6379> SET count 2 OK 127.0.0.1:6379> INCR count (integer) 3 127.0.0.1:6379> GET count "3" 127.0.0.1:6379> SET bad_count "a" OK 127.0.0.1:6379> INCR bad_count (error) ERR value is not an integer or out of range
127.0.0.1:6379> MULTI OK 127.0.0.1:6379> SET prag https://pragprog.com/ QUEUED 127.0.0.1:6379> INCR count QUEUED 127.0.0.1:6379> EXEC 1) OK 2) (integer) 4 127.0.0.1:6379> MULTI OK 127.0.0.1:6379> INCR count QUEUED 127.0.0.1:6379> DISCARD OK 127.0.0.1:6379> GET count "4"
- 複雑なデータ型
- リスト・ハッシュ・セット・ソート済みが保存できる
- ハッシュ
- ネストできない
- HDEL 削除
- HINCRBY インクリメント
- HLEN フィールド数
127.0.0.1:6379> MSET user:eric:name "Eric Redmond" user:eric:password s3cret OK 127.0.0.1:6379> MGET user:eric:name user:eric:password 1) "Eric Redmond" 2) "s3cret" 127.0.0.1:6379> HMSET user:eric name "Eric Redmond" password s3cret OK 127.0.0.1:6379> HVALS user:eric 1) "Eric Redmond" 2) "s3cret" 127.0.0.1:6379> HKEYS user:eric 1) "name" 2) "password" 127.0.0.1:6379> HGET user:eric password "s3cret"
- リスト
127.0.0.1:6379> RPUSH eric:wishlist 7wks gog yah (integer) 3 127.0.0.1:6379> LRANGE eric:wishlist 0 -1 1) "7wks" 2) "gog" 3) "yah" 127.0.0.1:6379> LREM eric:wishlist 0 gog (integer) 1 127.0.0.1:6379> LRANGE eric:wishlist 0 -1 1) "7wks" 2) "yah" 127.0.0.1:6379> LPOP eric:wishlist "7wks" 127.0.0.1:6379> LRANGE eric:wishlist 0 -1 1) "yah" 127.0.0.1:6379> RPOPLPUSH eric:wishlist eric:visited "yah"
% gem i redis
Successfully installed redis-3.2.1
1 gem installed
- リストのブロック
- 別でコンソールを立ち上げブロッキングコマンドを実行
127.0.0.1:6379> BRPOP comments 300
127.0.0.1:6379> LPUSH comments "Prag is great! I buy all my books there." (integer) 1
127.0.0.1:6379> BRPOP comments 300 1) "comments" 2) "Prag is great! I buy all my books there." (30.38s)
- セット
127.0.0.1:6379> SADD news nytimes.com pragprog.com (integer) 2 127.0.0.1:6379> SMEMBeRS news 1) "pragprog.com" 2) "nytimes.com" 127.0.0.1:6379> SADD tech pragprog.com apple.com (integer) 2 127.0.0.1:6379> SINTER news tech 1) "pragprog.com" 127.0.0.1:6379> SDIFF news tech 1) "nytimes.com" 127.0.0.1:6379> SUNION news tech 1) "pragprog.com" 2) "apple.com" 3) "nytimes.com" 127.0.0.1:6379> SUNIONSTORE websites news tech (integer) 3 127.0.0.1:6379> SMEMBErS websites 1) "pragprog.com" 2) "apple.com" 3) "nytimes.com"
- ソート済みセット, 範囲
127.0.0.1:6379> ZADD visits 500 7wks 9 gog 9999 prag (integer) 3 127.0.0.1:6379> ZINCRBY visits 1 prag "10000" 127.0.0.1:6379> ZRANGE visits 0 1 1) "gog" 2) "7wks" 127.0.0.1:6379> ZRANGE visits 0 -1 WITHSCORES 1) "gog" 2) "9" 3) "7wks" 4) "500" 5) "prag" 6) "10000" 127.0.0.1:6379> ZREVRANGE visits 0 -1 WITHSCORES 1) "prag" 2) "10000" 3) "7wks" 4) "500" 5) "gog" 6) "9" 127.0.0.1:6379> ZRANGEBYSCORE visits 9 10000 1) "gog" 2) "7wks" 3) "prag" 127.0.0.1:6379> ZRANGEBYSCORE visits (9 (10000 1) "7wks" 127.0.0.1:6379> ZRANGEBYSCORE visits -inf inf 1) "gog" 2) "7wks" 3) "prag"
- 和
127.0.0.1:6379> ZADD votes 2 7wks 0 gog 9001 prag (integer) 3 127.0.0.1:6379> ZUNIONSTORE importance 2 visits votes WEIGHTS 1 2 AGGREGATE SUM (integer) 3 127.0.0.1:6379> ZRANGEBYSCORE importance -inf inf WITHSCORES 1) "gog" 2) "9" 3) "7wks" 4) "504" 5) "prag" 6) "28002"
- 有効期限
- カウントダウンは EXPIREAT (絶対時間)
- EXPIRE は相対時間
127.0.0.1:6379> SET ice "I'm melting..." OK 127.0.0.1:6379> EXPIRE ice 10 (integer) 1 127.0.0.1:6379> EXISTS ice (integer) 1 127.0.0.1:6379> EXISTS ice (integer) 1 127.0.0.1:6379> EXISTS ice (integer) 1 127.0.0.1:6379> EXISTS ice (integer) 0 127.0.0.1:6379> SETEX ice 10 "I'm melting..." OK 127.0.0.1:6379> TTL ice (integer) 4 127.0.0.1:6379> SETEX ice 10 "I'm melting..." OK 127.0.0.1:6379> PERSIST ice (integer) 1 127.0.0.1:6379> EXISTS ice (integer) 1
- データベースの名前空間
127.0.0.1:6379> SET greeting hello OK 127.0.0.1:6379> GET greeting "hello" 127.0.0.1:6379> SELECT 1 OK 127.0.0.1:6379[1]> GET greeting (nil) 127.0.0.1:6379[1]> SET greeting "guten tag" OK 127.0.0.1:6379[1]> SELECT 0 OK 127.0.0.1:6379> GET greeting "hello" 127.0.0.1:6379> MOVE greeting 2 (integer) 1 127.0.0.1:6379> SELECT 2 OK 127.0.0.1:6379[2]> GET greeting "hello" 127.0.0.1:6379[2]> SELECT 0 OK 127.0.0.1:6379> GET greeting (nil)
% telnet telnet> open localhost 6379 Trying ::1... Connected to localhost. Escape character is '^]'. SET test hello +OK GET test $5 hello SADD stest 1 99 :2 SMEMBERS stest *2 $1 1 $2 99
% (echo -en "ECHO hello\r\n"; sleep 1) | nc localhost 6379 $5 hello % (echo -en "PING\r\nPING\r\nPING\r\n"; sleep 1) | nc localhost 6379 +PONG +PONG +PONG
- 出版/購読
127.0.0.1:6379> SUBSCRIBE comments Reading messages... (press Ctrl-C to quit) 1) "subscribe" 2) "comments" 3) (integer) 1
127.0.0.1:6379> PUBLISH comments "Check out this shortcoded site! 7wks" (integer) 1
127.0.0.1:6379> SUBSCRIBE comments Reading messages... (press Ctrl-C to quit) 1) "subscribe" 2) "comments" 3) (integer) 1 1) "message" 2) "comments" 3) "Check out this shortcoded site! 7wks"
- サーバ情報
127.0.0.1:6379> info # Server redis_version:3.0.5 redis_git_sha1:00000000 redis_git_dirty:0 redis_build_id:78b12a45f78ec0e redis_mode:standalone ...
- 永続性
- SAVE
- BGSAVE
- スナップショット
- 追記型フィールド
- めちゃくちゃ遅い
- セキュリティ
- パラメータの調整
% redis-benchmark -n 100000 [252/576] ====== PING_INLINE ====== 100000 requests completed in 3.33 seconds 50 parallel clients 3 bytes payload keep alive: 1 0.86% <= 1 milliseconds 83.00% <= 2 milliseconds 99.95% <= 7 milliseconds 99.96% <= 8 milliseconds 100.00% <= 9 milliseconds 100.00% <= 9 milliseconds 30012.00 requests per second ...
- マスタスレーブレプリケーション
% redis-server redis-sl.conf 37908:S 24 Oct 21:38:41.265 * Increased maximum number of open files to 10032 (it was originally set to 256). _._ _.-``__ ''-._ _.-`` `. `_. ''-._ Redis 3.0.5 (00000000/0) 64 bit .-`` .-```. ```\/ _.,_ ''-._ ( ' , .-` | `, ) Running in standalone mode |`-._`-...-` __...-.``-._|'` _.-'| Port: 6380 | `-._ `._ / _.-' | PID: 37908 `-._ `-._ `-./ _.-' _.-' |`-._`-._ `-.__.-' _.-'_.-'| | `-._`-._ _.-'_.-' | http://redis.io `-._ `-._`-.__.-'_.-' _.-' |`-._`-._ `-.__.-' _.-'_.-'| | `-._`-._ _.-'_.-' | `-._ `-._`-.__.-'_.-' _.-' `-._ `-.__.-' _.-' `-._ _.-' `-.__.-' 37908:S 24 Oct 21:38:41.268 # Server started, Redis version 3.0.5 37908:S 24 Oct 21:38:41.268 * The server is now ready to accept connections on port 6380 37908:S 24 Oct 21:38:41.268 * Connecting to MASTER 127.0.0.1:6379 37908:S 24 Oct 21:38:41.269 * MASTER <-> SLAVE sync started 37908:S 24 Oct 21:38:41.269 * Non blocking connect for SYNC fired the event. 37908:S 24 Oct 21:38:41.270 * Master replied to PING, replication can continue... 37908:S 24 Oct 21:38:41.270 * Partial resynchronization not possible (no cached master) 37908:S 24 Oct 21:38:41.271 * Full resync from master: d5f7d1c8d4640c774e1c747b7cec1bd169e092c9:1 37908:S 24 Oct 21:38:41.397 * MASTER <-> SLAVE sync: receiving 400726 bytes from master 37908:S 24 Oct 21:38:41.400 * MASTER <-> SLAVE sync: Flushing old data 37908:S 24 Oct 21:38:41.400 * MASTER <-> SLAVE sync: Loading DB in memory 37908:S 24 Oct 21:38:41.451 * MASTER <-> SLAVE sync: Finished with success
- ブルームフィルタ
- セットに存在しない項目をチェックする確率的データ構造
- Ruby の神童 Ilya Grigorik
- SETBIT と GETBIT
127.0.0.1:6379> SETBIT my_burger 1 1 (integer) 0 127.0.0.1:6379> SETBIT my_burger 2 1 (integer) 0 127.0.0.1:6379> GETBIT my_burger 3 (integer) 0 127.0.0.1:6379> GETBIT my_burger 1 (integer) 1
- ポリグロット永続亜kサービス
- ノンブロッキングコード
- 時間のかかるプロセスの終了を待たずにメインコードを実行し続けること
- Ruby: EventMachine
- Python: Twisted
- Java: NIOライブラリ
- C#: Interlace
- JavaScript: Node.js
- Redis の強み
- Redis の弱み
- スナップショットをとる前にシャットダウンするとデータが失われる
- 追記型ファイルを設定しても期限切れの値を扱うリスクがある
- 使用可能な RAM より大きなデータセットは扱えない
第9章 まとめ
- データの保存方法は大きく5つに分類
- リレーショナル
- キーバリュー
- カラムナー
- ドキュメント
- グラフ
- リレーショナル
- データが変わりやすかったり、データ階層が深いものには適していない
- キーバリュー
- カラムナ-
- 水平スケーラビリティが高いので、ビッグデータの問題に最適
- データ使用パターンが事前に決定できていないければ適していない
- ドキュメント
- 変化の大きなドキュメントの問題に適している
- 事前にデータがどのようになるか正確に分からない場合
- インピーダンスミスマッチが少ない
- 結合に該当するものがないので正規化できない
- グラフ
- レコメンテーションエンジン
- アクセスコントロールリスト
- ジオグラフィックデータ
- ネットワーキングアプリケーション
- オブジェクト指向にも完璧に対応
- ネットワーク分割には適さない
- データベースの選択はドメインのデータに適したデータベースの分野を考えるより複雑