Post on 21-Mar-2020
第 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 > RCWrite 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 ← memcachedサーバに接続set name 12345 0 9 ← キーが nameの長さ 9の値を保存testvalue ← 長さ 9文字の値STORED → memcachedの出力get name ← キーが nameの値を取得VALUE name 12345 9 → memcachedの出力testvalue → memcachedの出力END
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-ValueHadoop→これについては次回BigTableCassandra
その他: MongoDB, CouchDB
22 / 23
近年の動向 2: 高速化
インメモリ DB
主記憶上にデータベースを構築 (最大数十 GB程度)
高速 (応答時間μ秒のレベル)
ハードディスク上に (非同期で)ログを取ることで永続性を担保Oracle TimesTenなどフラッシュメモリの利用
カラム型 DB
トランザクショナルメモリ
IBM PowerPC A2, Intel Haswell
トランザクション技術の進展
Serializable Snapshot IsolationSIを Serializableにする (ただしわずかに false-positiveあり)
Google Spanner世界規模のトランザクションに全順序 (=物理時刻).通信因果関係でないので論理時間ではない.GPSと原子時計を使う.
23 / 23