サクサク読めて、アプリ限定の機能も多数!
トップへ戻る
WWDC24
sdyuki.hatenadiary.org
イベント駆動型のプログラムでは、エラー処理の記述が面倒になることがある。これを何とかしたい。 例えば、keyからidを引き、idからdata引くプログラムを書きたいとする。 手続き型で書くと以下のようになる: def doit(key) id = get_id(key) data = get_data(id) return data end ここで、get_id と get_data は長くブロックするので、イベント駆動型にしたいとする。 そうするとプログラムの正常系の処理は↓このようになる。 def doit(key, &callback) get_id(key) {|id| get_data(id) {|data| callback.call(data) } } # futureを返すのは良いアイディア end ここまでが前提条件。 このプログラムのエラー処理を愚直に書くと、↓このよう
更新ログをマスタからスレーブに送ることでデータをレプリケーションする、いわゆるログシッピングを、分散データストアに実装する方法について。 ログシッピングは、操作を同時に複数箇所に送信するレプリケーションと比べると、次のような実装上の利点がある: オリジナルに対する変更とレプリカに対する変更の適用順序が一致する オリジナルとレプリカの整合性を維持しやすくなる。設計が簡単になるので嬉しい。 ダブってレプリケーションされない at-most-once。どこまで更新ログを受け取ったかをスレーブ側で管理している前提。 CPUにやさしい バースト的に更新クエリが発生した時でも、レプリケーションクエリの数は(激しくは)増えない。その代わりログに溜まって一度に送信される。バッチ処理はCPUにやさしく、スループットが高い。 一方、更新ログを管理しなければならない欠点があるが、ストレージのデータ構造自体がログ
レプリケーション*1は分散トランザクションと紙一重で、複数のサーバに分散された複数のデータを同時に書き換えたい。 もしこれが同時でないと、クライアントによって異なるデータを読んでしまう可能性がある: しかし実際には同時でなくても良い。サーバ2からデータを読み出される前に、サーバ2にデータを同期してしまえば「まったく問題ない」: もう一点、サーバ1から新しいデータが読み出される前ならば、サーバ2から古いデータを読み込んでも「まったく問題ない」: つまり、整合性のない(それぞれのサーバが異なるデータを持っている)状態が発生したとしても、それが観測されなければ、実質的にすべてのデータは同時に更新されたように見える。 そこで、次の2つのルールを設定する: ルール1:クライアントは、整合性がない状態を観測したら、すべてのクライアントが古いデータを読み出さなくなるまで、データを読み出さない ルール2:
kumofsは、本来小さいサイズのvalueを大量に入れることを想定した分散KVSで、高解像度の画像など、サイズの大きいvalueを入れることは想定されていない。と言うかテストされていない。 でも、実は入れてみたら案外うまく動くんじゃないか?というわけで試してみた。 結論 データ総量30GB、物理ホスト1台で試した限りでは、実は問題は無さそう 物理ホスト1台というのが不十分なので微妙… ノードを追加したり復旧したりするとき、数時間の間、速度が半分くらいに劣化する データ量1TB、サーバ4台の構成で、2時間くらいかかる推定 データの再配置がタイムアウトしてしまう可能性があるが確認できていない。3台以上の構成で追試する必要あり 速度は、サーバ1台につき、Get 6.7 req/sec、Set 3.8 req/sec くらい ほぼ線形にスケールアウトすると仮定すれば、4台投入すれば Get 26
このあたりの内容を卒業研究にする予定で、中間報告書まで書いたけど、整理と裏付けが全然追いつかなくて卒論なんて書けそうにないので、とりあえずテキトーにブログに書いておくなど。 データストアには、状態を永続化して共有する機能と、データモデル(状態を操作する意味論)を規定する機能の、2つの機能がある。この2つの機能を、より使いやすく、より高速に、よりスケーラブルに提供することが求められる。そうでないとシステム全体が成り立たない。 冗長化とか負荷分散とか、ハードの質に頼らない高性能なシステムを構築したいときは、「状態を持たないようにする」のが定石になる。同じ状態を2台のホストで同期し続けたり、状態を分割しながら整合性を保ち続けるのは、非常に難しい。このため、状態は共有データストアに保存しておくのがもっとも簡単で、現実的な解になる。 MVCアーキテクチャにおけるViewとControllerはMod
今流行のkey-value storageの利点と欠点など。小さいデータをたくさん扱うタイプで、単純なkey-value型のデータモデルを持つ分散KVSについて。 Webアプリをとりまく最近のKVS事情、雑感を読んで、ちゃんと整理して把握しておかないといけないな、と思ったので少し整理。 それは違うぞーという事があったらコメントくださいm(_ _)m ※2009-11-17 追記:現在、KVSという用語の意味は定義されておらず、使う人によって揺れています。ここで言うところの分散KVSは、Dynamo や kumofs や ROMA など を想定しています。 分散KVSの利点 スケールアウトできる 簡単にサーバーを追加して性能を上げられる 単体の性能が高い スキーマレス 最初は少ない台数で安く、後からサーバーを足してスケールアウト!という運用ができる。アプリケーションに影響せずに、ストレージ側
非同期プロトコルとは、サーバーから返ってくる応答が、必ずしも要求した順番通りに返ってこないプロトコル(ソース無し。オレオレ定義)。 順不同で返ってくる応答と要求を対応づけるのはクライアントの仕事で、典型的には要求の中にシーケンス番号を入れておき、サーバーは要求と同じシーケンス番号を応答の中にも含める。 例:MessagePack-RPC 非同期プロトコルの特徴: イベント駆動型のサーバーの場合、サーバーの実装が簡単になる 同期プロトコルだと順番を揃えてから返さないといけない。サーバーの実装が(要求1つに対してスレッドを割り当てて処理するのではなく)ソケット1つに対してスレッドを割り当てて処理する方式だとあまり関係なくて、特に実装は簡単にならない。 処理が重い要求と軽い要求を続けて送っても、重い要求に詰まって後の応答が返ってこなくなることが無い 同期プロトコルだと、応答を送り返すにはその前の
図解求む。 以下「プロトコル処理」と「メッセージ処理」を分けて扱っているが、この差が顕著に出るのは全文検索エンジンや非同期ジョブサーバーなど、小さなメッセージで重い処理をするタイプ。ストリーム指向のプロトコルの場合は「プロトコル処理」を「ストリーム処理」に置き換えるといいかもしれない。 シングルスレッド・イベント駆動 コネクションN:スレッド1。epoll/kqueue/select を1つ使ってイベントループを作る。 マルチコアCPUでスケールしないので、サーバーでは今時このモデルは流行らない。 クライアントで非同期なメッセージングをやりたい場合はこのモデルを使える: サーバーにメッセージを送信 イベントハンドラを登録;このときイベントハンドラのポインタを取っておく イベントハンドラ->フラグ がONになるまでイベントループを回す イベントハンドラ->結果 を返す 1コネクション1スレッ
サーバーサイドの分散ストレージについて。広域P2Pとかデータセンター間で同期するとかCDN云々は知らない。 kumofsのアプリケーション-Gateway間のインタフェースは Get(key) だが、Gateway-Server間のインタフェースは実は GetByHash(key, partitioning-id)(とGetByHashIfModified(key, partitioning-id, time))だったりする。(実際の名前は違うけど意味は同じ) 現状ではpartition-idはkeyにハッシュ関数を掛けて自動生成するが、実際には任意の値を指定できる。 つまり関連するkeyには同じpartitioning-idを指定して同じノードに保存されるようにして、partitioning-idが同じkey同士ならトランザクションできるようにすることも、案外に容易にできる。 Consi
futex(2) を使ってせっせとmutexとconditionを実装していたら、意外なところに盲点が。 Linux では pthread_mutex と pthread_cond がプロセスを越えられる。移植性は無いようで、Mac OS Xでは動かなかった。 やり方は mmap(2) に MAP_SHARED フラグを渡して2つのプロセス間でメモリ空間を共有しておき、そのメモリを pthread_mutex_t や pthread_cond_t にキャストして使う。ただしアドレスはページサイズの倍数でないとうまくいかない。(※動くかも?) ※追記:pthread_mutex/condはfutexで実装されていたのでした ※追記:これは linux-2.6.22.9 + glibc-2.6.1 での挙動ですが、おそらくバグです。少なくとも linux-2.6.27 + glibc-2.8
勝手に命名。 システムコールの呼び出しが多くなることでソフト割り込みの回数が毎秒10万回を越え、ソフト割り込みの処理だけでCPU資源の大半が消費されてしまう問題。 ソフト割り込みが1つのCPUコアに集中し、コアを増やしてもスケールしなくなる。 epoll/kqueue/event ports等によって1台のサーバーで大量のコネクションを捌くようになり、HDDのシーク速度の遅さがSSDで解決されると、TCP/IPのソフト処理の重さも相まってボトルネックがCPUへと移り、ソフト割り込みの重さが顕在化する。
ネットワークブートシステムを構築するために Linuxカーネルや initramfs を作成しているとき、本物のハードウェアを使って実験していると再起動が面倒すぎてイヤになる。VMを使うのが次善策だが、BIOSの初期化には時間がかかる。 そこで qemu のlinuxカーネルを直接起動する機能を使うと、BIOSの初期化が速いので快適にテストできる。ブートローダーをインストールしたHDDイメージを用意しなくていいのも好都合。 kvm -kernel /path/to/vmlinuz -initrd /path/to/initramfs -append "kernel boot parameter" -hda /dev/zero initramfsができたら、今度はそれをPXEでロードできるかどうかテストする必要がある。しかしうまくいかなかったとき、DHCPサーバーやtftpサーバーの設定に問
新しいディレクトリを作る /devを作る /dev/consoleなどは必須 何が必須で必須でないのかを判定するのは面倒なので、必要っぽいデバイスノードは全部作っておく 作りすぎで困ることはあまりない /binを作る スタティックリンクしてコンパイルしたbusyboxをインストールしておく busyboxはとっても多機能なので、変わったことをやろうとしない限りはbusyboxだけで事足りる 古いbusyboxだと圧縮されたカーネルモジュールに対応していないかも知れない(最新のバージョンでも対応していないかも知れない) (スキップ可。基本的に圧縮は不要) /bin/shや/bin/mount、/bin/modprobeなどのシンボリックリンクを/bin/busyboxに向けて作っておく。busyboxのドキュメントに作り方が書いてあった気がする /lib/modulesを作る 利用するカーネ
ネットワークIOのバッファリングを行うコードを書く必要があったので、確保するメモリのサイズによってmalloc(3)にかかる時間がどれくらい違うのか調べてみた。 環境は: Linux vcore.local 2.6.22.9-vcore16 #1 SMP Sun Oct 14 22:13:32 JST 2007 x86_64 AMD Athlon(tm) 64 X2 Dual Core Processor 5000+ GNU/Linuxmalloc() → free() を 1,000,000回繰り返し、かかった時間を計測した結果: $ ./a.out 8 16 32 64 128 256 512 1024 8192 16384 32768 bytes: seconds 8: 0.042706 16: 0.042608 32: 0.042998 64: 0.042607 128: 0.09
Wikipedia RDMA:リモートホストのメモリにCPUを介さず直接値を書きこむ。CPUへの負荷が非常に小さく、かつ極めて小さい遅延で通信できることが期待できる。 速いのは良いことであるのはもちろんだが、ネットワーク通信の遅延は非常に大きいという前提が崩れることで、従来では考えられなかった分散プログラミングモデルが現実的になってくるかもしれない。 元々はHPC向けで物理層にはInfiniBandを使うことを想定していたようだが、探してみるとTCP/IPでRDMAをサポートしたNICが思わず買ってしまいそうなお値段で手に入る。 NTT-X Store NetXtreme II 1000 Express デュアルポート Ethernet アダプター ぷらっとオンライン IBM NetXtreme II 1000 Express イーサネットアダプタ (39Y6066) Broadcom N
またしても書きながら考えるメモ。 dRuby+Ringか、mDNS+DNS-SDか。今はDNS-SDの方が良さそうな気がしている。なんというか普通にDNS-SDそのもの。ただしSRVレコードは勝手に定義。そう堅いこと言わずに。 mDNSは、DNSをマルチキャストで行う。いわゆるクライアントサーバー型ではない。個々のノードが、マルチキャストされてくるmDNS要求に対して、マルチキャストで応える。そしてキャッシュ。どうやらmDNSは、通常の(ユニ/エニーキャストの)DNSとは異なり、プッシュ型でレコードの変更を伝播させることができる。ココポイント。 DNS-SDは、DNSのSRVレコードとTXTレコードにいろいろと情報を書き込んで、ネットワークプリンタなどのサービスを発見するのに使おうというもの。 mDNSとDNS-SDは互いに依存しているわけではないが、組み合わせると効果的。 で、このmDN
memcached Night in Tokyo #1によれば、mixiはmemcachedサーバーを135台使っているらしい。多い! 話に依れば一番最初に足りなくなるのはメモリの容量(3GBほど割り当てられている)で、ネットワークやCPUはボトルネックになっていないらしい。 ではメモリの代わりにHDDを使うのはどうか。HDDのランダムアクセス時の遅延がかなり大きいので、影響が出るほど遅くなりそう。 そこでSSDを使うのはどうか。ランダムリードで700Mbpsくらい出るらしいので、スループットに関してはCPUの方が先に限界に来ると思う。遅延はどれくらいか良く分からないが、アプリケーション側でget_multiを使っていれば隠蔽できないか。 バイト単価はDRAMよりはずっと安い。 実装としては以下: 32GBくらいのSSD 2GBくらいのメモリ(多ければ多いほどキャッシュに載りやすいので、平
HTMLと言うかXMLの自動インデント。1行でべたっと書かれたXMLに、かしこく改行とインデントを付ける。StringScannerが便利。 require 'strscan' src = %[<html><body><h1>chapter</h1><div><dl><dt>hoge</dt><dl>fuga</dl></dl></div><p>pi<img src="piyo.png"/>yo</p></body></html>] no_indent_tag = %w[html head body] # インデントしない要素 indent_str = ' ' # インデントに使う文字(半角スペース2つ) s = StringScanner.new(src) slash = '/'.unpack('C')[0] indent = 0 body = '' while len = s.exis
もし~/.vimrcを無くしてしまったら、その日は一日中立ち直れないだろう。 vimでディレクトリを開いたときに出てくる:Exploreが何気に便利なわけですが、表示されるファイルのソート順のデフォルト値は、Myカスタマイズにしておくと便利。 ↓Myカスタマイズ map :Explore let g:netrw_sort_sequence="[\\/]$,*,\\.\\(mv\\|old\\|cp\\|bak\\|orig\\)[0-9]*[\\/]$,\\.\\(mv\\|old\\|cp\\|bak\\|orig\\)[0-9]*$,\\.o$,\\.info$,\\.swp$,\\.obj$ " 1. /で終わるファイル名(=ディレクトリ) 2. その他のファイル 3. *.mvとか*.oldとか*.old1とか*old2とかで終わるディレクトリ 4. *.mvとか*.oldとかとか
このページを最初にブックマークしてみませんか?
『sdyuki-devel』の新着エントリーを見る
j次のブックマーク
k前のブックマーク
lあとで読む
eコメント一覧を開く
oページを開く