第 13 回の目次 前回: Web サーバー 今回: RDB (MySQL プログラミング) トランザクション処理 DB 高速化 (memcached,その他) 【参考書 1: MySQL 全機能バイブル (他にも沢山ある)】 【参考書 2: 伊藤ほか: サーバ/インフラを支える技術, 技術評論社】 【参考書 3: 西田ほか: Google を支える技術, 技術評論社】 1 / 23 本日のソースコード testmysql.rb: mysql を ruby で呼び出す testmem.rb: memcached を ruby で呼び出す 2 / 23 なぜデータベースが必要か? 複雑な処理には状態が必要 利用者登録,利用者課金,サービス状態 Web サーバーには状態は残せない/残すべきではない 3 層アーキテクチャが一般的 ブラウザ (プレゼンテーション) Web サーバー s (ビジネスロジック) データベース 有名なデータベースソフト MySQL PostgreSQL SQLite MariaDB (MySQL 互換) 3 / 23 MySQL の概要 Relational Data Base (SQL) Oracle が買収 一つの独立したシステム.つまり, 各サーバに一つだけ存在 セキュリティ管理は独自 ユーザ管理も自前 Web サーバと連携させるには言語から呼び出す (→次頁) ストレージエンジンを InnoDB にすればトランザクション可 (デフォルトでは MyISAM) 4 / 23 Web サーバから RDB を使う MySQL/Ruby を使った例【→ testmysql.rb】 5 / 23 testmysql.rb の出力例 "5.1.53" ["information_schema", "demo_development", "demo_test", "mydb_development", "mydb_test", "mysql", "nchak_development", "nchak_test", "sampledb", "test"] ["engtable", "mathtable"] "id" "name" "score" ["1", "yamazaki", "50"] ["2", "shibaura", "70"] ---result of join--["yamazaki", "50", "60"] ["shibaura", "70", "80"] 6 / 23 SQL injection RDB をプログラムする時は要注意 重要なデータはデータベースに入っており,まず間違いなく SQL でアクセスされる システムを柔軟に作ろうとすると SQL を実行時に合成せざ るを得ない 利用者の入力から SQL 文を作ることが多い ありがちな例: q="select name, score from engtable where name="+username+";" result=ms.query(q) username は,”’yamazaki’”などであることを想定しているが,も し次のような値だったら? username="’dummy’ OR true" 7 / 23 SQL injection 対策 (SQL だけでなく一般の injection 対策) 入力が危険なのでなく出力が危険 (×サニタイズ ) 入力対象は意外と広い (ヘッダーや Cookie も) 出力文字列中にメタ文字がないようにする (htmlspecialchars) 出力もいろいろある (HTML 出力,DB への出力,DB へのコ マンド) 入力文字列はその目的が決まったところでチェックをする ファイルパス名,ユーザ名,… 8 / 23 MySQL でのトランザクション処理 トランザクションとはデータベースに対する一連の操作 START TRANSACTION; ∼ COMMIT; または ROLLBACK; トランザクションが満たすべき性質: ACID Atomicity: トランザクションは all-or-nothing で動作 Consistency: DB が矛盾した状態にならない Isolation: 2 つのトランザクションは独立して動く Durability: Commit されたデータは永続する Isolation のレベルは TRANSACTION ISOLATION LEVEL コマンド で設定可能 9 / 23 MySQL の Isolation Level 以下の 4 つのレベルに設定可能 Serializable: 全部なし Repeatable Read: phantom Read Committed: non-repeatable, phantom Read Uncommitted: dirty, non-repeatable, phantom それぞれの read の意味 dirty read: まだ commit されてないデータが見える non-repeatable read: 別 Tx が書いて commit した値が見える (2 回読んだら違う値だった) phantom read: 新しいデータの挿入が見える (2 回同じ SELECT 文を実行したら結果が違う) 10 / 23 Snapshot Isolation H.Berenson: A critique of ANSI SQL isolation levels, SIGMOD 95 MVCC (Multi-Version Concurrency Control) の考え方: 値にバージョンを導入する ある Tx 内の read は,その Tx 開始時点のバージョンを read することにする First-Committer-Wins 利点: read も write もブロックしないので高速 Read Skew: r1[x]...w2[x]...w2[y]...c2...r1[y]...(c1 or a1) Write Skew: r1[x]...r2[y]...w1[y]...w2[x]...(c1 and c2 occur) SI: Read Skew は起きないが,Write Skew は起きる. RR: 両方起きない. RC:両方起きる. ゆえに RR > SI > RC Write Skew は,Serializable Snapshot Isolation (2008 年) で解決 11 / 23 CAP 定理 E.Brewer が 1999 年に発表 ∗ 分散データシステムは,高々次の 2 つしか満たせない: Consistency: 全ノードが同じデータを参照する Availability: 操作は必ず (成功か失敗で) 終了する Partition tolerance: ネットワーク分割しても動作する つまり, 矛盾状態を許すなら,分割状態での操作は可能 分割状態での矛盾を許さないなら,操作を遅延するしかない 分割を考えなくて良いなら,矛盾ない操作が可能 Partition Tolerance は大規模分散では必須なので,Consistency と Availability の間で解を見つけるしかない (*) ここでは E.Brewer: CAP Twelve Years Later, Computer 2012 を参考 12 / 23 ACID vs BASE Consistency first, Availability second: ACID Atomicity: トランザクションは all-or-nothing で動作 Consistency: DB が矛盾した状態にならない Isolation: 2 つのトランザクションは独立して動く Durability: Commit されたデータは永続する Availability first, Consistency second: BASE∗ Basically Available: 正しい答えでなくても,すぐ返事が返っ てくることの方が重要. Soft-State: 状態は,(コストが高い) 別の手段で復旧できるの であれば,失われてしまっても良い. Eventual Consistency: 一時的に古いデータが見えてしまって も良い.それほど長くない時間内に最新になれば良い. (*) A. Fox: Cluster-Based Scalable Network Services, ACM SOSP 97. 13 / 23 BASE の考え方 例えば一つのトランザクションの中で送金と銀行のもつ総額を数 えるとする. 送金と銀行の総額カウントの増減: 総額カウントは概算値だと考えてしまう (eventual consistency の例であり,soft sate の例でもある) 送金と受金: 送金中という概念を入れる (persistent message) 送金メッセージの喪失: 再送可能なようにメッセージ ID 付与 (idempotent update) 「BASE」的設計方針であり ACID のように厳密な話ではない Serializable Snapshot Isolation ができたので BASE は古いという人も BASE でよければ,いろいろなやり方が → 次のページ 14 / 23 memcached 背景: 多くのデータは,write は少なく,read は多い read さえ早く実行できれば,かなり楽になる 汎用のキャッシュサーバ memcached: 名前と値の組みを登録できるサーバ すべてをメモリ上で行うので高速 使い方は自由 (普通は,Web サーバーと DB の間に挟む) クライアントが頑張る シャーディング 冗長化 15 / 23 簡単な実験 $ telnet XXXX 11211 set name 12345 0 9 testvalue STORED get name VALUE name 12345 9 testvalue END ← ← ← → ← → → memcached サーバに接続 キーが name の長さ 9 の値を保存 長さ 9 文字の値 memcached の出力 キーが name の値を取得 memcached の出力 memcached の出力 16 / 23 幾つかのコマンド 保存: set キー フラグ 有効時間 バイト長 そのバイト長のデータ 取得: get キー 取得 (CAS 付き): gets キー 削除: delete キー 前回 get してから誰も set してないことを check して set: cas キー フラグ 有効時間 バイト長 cas 値 そのバイト長のデータ 不可分での 1 増加,1 減少: incr や decr 17 / 23 memcache クライアントの例 (ruby) memcache-client の例 【→ testmem.rb】 (memcache-client は非推奨で後継は Dalli) 次のように生成すると適当に分散してくれる: MemCache.new(ホスト 1, ホスト 2, ホスト 3) また次のように書けるのは mc["foo"]="foo’s value" p mc[”foo”] ruby では次のように演算子も再定義可能だから: def []=(key, value) ∼ end def [](key) ∼ end 18 / 23 testmem.rb の実行結果 "foo’s value" 1234 "this is a pen" "value" "this is a pen" 19 / 23 ごく簡単なベンチマーク ruby でリモートサーバにアクセスし測定 時間は 1 回当たりの elapse time チューニング等は何もやってない MySQL: insert into engtable values (I, ’y’+I.to_s, I); → 0.48 ミリ秒 (I=1..10 万) select name, score from engtable where name=’y0’; → 0.47 ミリ秒 (I=1..10 万) select name, score from engtable where name=’y’+I.to_s; → 1 回目 13.4 ミリ秒 (I=1..1 万) → 2 回目 0.47 ミリ秒 (I=1..1 万) memcached: mc["y"+I.to_s]=I → 0.5 ミリ秒 (I=1..10 万) x = mc["y"+I.to_s] → 0.49 ミリ秒 (I=1..10 万) たぶん通信 (+パース) がほとんど MySQL もキャッシュ的な効果が効く範囲ではかなり早い 20 / 23 Twitter サーバのアーキテクチャ 引用元: http://www.infoq.com/news/2009/06/Twitter-Architecture 21 / 23 近年の動向 1: NoSQL とは? これまで: データベース = RDBMS (つまり SQL) とにかくでかい (ペタバイト級) 非定形データ 多様な処理 SQL じゃ駄目 → NoSQL (Not Only SQL) 代表的な NoSQL 技術 巨大データ + Key-Value Hadoop → これについては次回 BigTable Cassandra その他: MongoDB, CouchDB 22 / 23 近年の動向 2: 高速化 インメモリ DB 主記憶上にデータベースを構築 (最大数十 GB 程度) 高速 (応答時間μ秒のレベル) ハードディスク上に (非同期で) ログを取ることで永続性を担保 Oracle TimesTen など フラッシュメモリの利用 カラム型 DB トランザクショナルメモリ IBM PowerPC A2, Intel Haswell トランザクション技術の進展 Serializable Snapshot Isolation SI を Serializable にする (ただしわずかに false-positive あり) Google Spanner 世界規模のトランザクションに全順序 (=物理時刻) .通信因果関係 でないので論理時間ではない.GPS と原子時計を使う. 23 / 23
© Copyright 2025 ExpyDoc