分散システムデザインパターン読書メモ2
シャーディングされたサービス
レプリカされたサービスではリクエストはどのレプリカでも処理することができた、
それに対してシャーディングされたサービスでは一部のリクエストを特定のレプリカのみが処理できる。
代表的な例として、データサイズが一台で処理するには大きすぎる場合に使われる。
シャーディングされたキャッシュ
- シャーディングされたキャッシュは、完全なレプリカではできなかった数のキャッシュを行い、シャードを増やした分だけキャッシュヒット率をあげることができる
シャーディングされたキャッシュのレプリカ
- シャーディングのレプリカはキャッシュサーバーの更新時のデプロイ時にも負荷の増大を防ぐことができる
- シャーディングされた各ノードのレプリカを作ることは、耐障害性だけでなく、特定のノードに負荷が集中する「ホットシャーディング」に効果がある
- ホットシャーディング時に、特定のノードのみレプリカを増やして負荷を分散させることができる
シャーディング関数をためしてみる
- 一番シンプルな例はmod関数
- 決定性: 同じ入力に対して常に同じ結果を返す
- 均一性: 出力に対する出力の分散具合は均一
- シャードのキーを決めるには、どのようなリクエストが来るのかの理解が必要
- シャードへのルーティングについて次の2つが紹介されていた
- コンシステントハッシュでは、キー数/スケール後のキャッシュノード数のみキーの移動が発生する
スキャッタ・ギャザー
処理時間をスケールさせるためのデザインパターン 複数台で1つのリクエストを分割処理してマージすることによって処理を高速化させる
ルートによる分散とスキャッタ・ギャザー
リーフをシャーディングしたスキャッタギャザー
シャーディングされたデータを各リーフが自分の持つデータ範囲から検索を行いルートノードでマージする仕組み
適切なリーフの決め方
信頼性とスケーラビリティのためのスキャッタギャザーのスケール
ほとんどの処理を99%高速に返していても、残り1%で詰まっている場合は、遅い方に足を引っ張られる。 各リーフノードの対象外性をあげるために、過去の章でも登場したシャーディングのレプリカの作成は有効である。
9. オーナーシップの選出
- etcd
- 分散ロックでは、あらゆる処理時間がロックのTTLよりも短くなるようにすることが重要
Reactを書くときのパターンメモ
Render Props
- propsに、RenderするReactElementを返す関数を渡す
- メリット
- 親が子のなかでレンダーする内容(孫)を動的に変更することができる
- 親が子の中の孫のレンダー内容を指定しつつ、子と孫で値の共有ができるようになる
- 参考例 mae.chab.in
- オブジェクト指向のデザインパターンでいうと、ストラテジーパターンに近い?
- 下記のように子から何か(stateのようなもの)を受け取って孫を表示することで、孫の内容は動的にしつつも、子と孫で状態を共有することができる。
render() { retrun ( <div> {this.props.render(this.state)} </div> ) }
分散システムデザインパターン読書メモ1
シングルノードパターン
1つのインスタンスの中でメインのコンテナと他のコンテナを組み合わせるときのデザインパターン
- サイドカーパターン
- メインのコンテナに機能を付与したり、改善したりするためのコンテナを組み合わせる
- 例) gitリポジトリへのpushによって、コードをデプロイする機能を追加するコンテナ
- gitリポジトリを定期的にpullして、アプリケーションのコンテナと共有したパスにgit pullしたコードを反映させる
- アンバサダーパターン
- アダプターパターン
- メインのコンテナのインターフェースを規格化した統一されたものにするためにコンテナを組み合わせる
- 例) 監視用のメトリクスの出力(送信)(prometheus)
- 例) ログデータの出力(fluentd)
- メインのコンテナのログ出力形式は同じとは限らない。ログファイルへの出力だとしてもJSONや、LTSVなどフォーマットは異なる。それを一定のフォーマットに変換した上でログの集約や送信時のバッファリングの機能を追加することを可能にする
分散デザインパターンのマイクロサービスへの活用
パターンを使うことでシステムデザインがしやすくなる。同じパターンを開発者感で共有することでデバッグしやすくなる。 分散デザインパターンを使う・知ることでマイクロサービスにおけるデメリットを補うことができる。
- メリット
- 分割した個々のサービスごとにスケールの方法を選択することができる。
- スコープが狭まることでピザ二枚分の小さな開発チームに保つことができることで、様々なオーバーヘッドを減らすことができる
- デメリット
マルチノードパターン
レプリカがロードバランスされたサービス
sendagaya.rb #330 rake db:rollback時のソースコードリーディング
sendagaya.rb #330 では、 rails db:rollback
のときのコードを読んだ。
もとは、 @sanfrecce_osaka がきになって調べてくれていた内容
こちらで用意するmigration
ファイルのchange
のなかのメソッド呼び出しを行うときに
rake db:migrate
では、ActiveRecord::ConnectionAdapters
の各adapter(下記コードでいうと connection
)
をレシーバーとして実行するのにたいして、rake db:rollback
時は、connection
を recorder
に書き換えて
changeメソッドのなかで実行されるメソッド呼び出しをrecorder
に一旦記録させて
すべて記録した後に、逆の動作に変更して replay
で実行しているのが面白かった。
rake db:migrate
時のchange
の実行
[823, 832] in /Users/jun-fukaya/.rbenv/versions/2.7.0/lib/ruby/gems/2.7.0/gems/activerecord-6.0.3.3/lib/active_record/migration.rb 823: @connection = conn 824: if respond_to?(:change) 825: if direction == :down 826: revert { change } 827: else => 828: change 829: end 830: else 831: send(direction) 832: end
(byebug) puts @connection #<ActiveRecord::ConnectionAdapters::SQLite3Adapter:0x00007f9df54c8098> nil
rake db:rollback
時の change
の内容を反転させるための connection
の差し替え部分
recorder.replay(self)
でrecorderで記録したchange
の処理内容逆にして実行している
[689, 708] in /Users/jun-fukaya/.rbenv/versions/2.7.0/lib/ruby/gems/2.7.0/gems/activerecord-6.0.3.3/lib/active_record/migration.rb 689: # This command can be nested. 690: def revert(*migration_classes) 691: run(*migration_classes.reverse, revert: true) unless migration_classes.empty? 692: if block_given? 693: if connection.respond_to? :revert 694: connection.revert { yield } 695: else 696: recorder = command_recorder 697: @connection = recorder 698: suppress_messages do => 699: connection.revert { yield } 700: end 701: @connection = recorder.delegate 702: recorder.replay(self) 703: end 704: end 705: end
(byebug) puts connection #<ActiveRecord::Migration::CommandRecorder:0x00007f82315ccfa0> nil (byebug) puts recorder #<ActiveRecord::Migration::CommandRecorder:0x00007f82315ccfa0> nil (byebug) puts recorder.delegate #<ActiveRecord::ConnectionAdapters::SQLite3Adapter:0x00007f8231d1ce90> nil (byebug) puts @connection #<ActiveRecord::Migration::CommandRecorder:0x00007f82315ccfa0> nil
最近読んだ記事
初めての「技術ブログ」書き方のご紹介 – SORACOM公式ブログ
- ブログの書くコツについて、何かテンプレートを作るのは良さそう
- ブログ設定して燃え尽きるのは本末転倒というのはわかる
- 1つのことにしぼる、 タイトルと対になる結論を書くとかも忘れがち
Amazon RDS/Auroraをクローンするシステムを作った話 - クックパッド開発者ブログ
- クックパッドでは本番DBをマスク&クローンして各開発者がワンタッチで作れる仕組みを用意している
- SRE系の仕事としてよく依頼される内容を効率化しようとしてるのは良い
- 自動化大切
- マスクする情報が完全な状態になっているかどうか不安が残るけどマスク列の設定ファイルが管理しやすくなってれば良さそう。
コンポジション vs 継承 – React
- よくみるchildrenを内部でレンダーするやつ
-
<Parent><Child /><Parent />
- あるコンポーネントに機能や表示を付け加えるのには便利そう
- ある特化したコンポーネントを作るときに利用すると便利そう
Ruby M17N の設計と実装
- rubyの内部エンコーディングは決まってないということがわかった
- エンコーディングの話は難しい
- Rubyのエンコーディング - @tmtms のメモ
gem pryを掘る(pry-rails編)
pry-railsで使えるコマンドについて調べてみる
pryのプラグインである、pry-railsを追加することで使えるコマンドについて調べてみた
show-models
あたりが一番便利そう
show-routes
rails routesを表示
show-models
modelの一覧、各modelの属性、各modelのリレーションを見ることができる
Category id: integer packing_list_id: integer name: string created_at: datetime updated_at: datetime description: text position: integer belongs_to :packing_list has_many :packing_items
show-model <モデル名>
show-modelsで表示される内容をmodel名を指定して見ることができる
show-middleware
rails middleware と同じでrack middlewareの一覧を表示してくれる
use Webpacker::DevServerProxy use Rack::Sendfile use ActionDispatch::Static use ActionDispatch::Executor use ActiveSupport::Cache::Strategy::LocalCache use Rack::Runtime use Rack::MethodOverride use ActionDispatch::RequestId use ActionDispatch::RemoteIp ...
recognize-path url
urlで指定したパスを担当するcontroller Actionを表示してくれる。
find-routes
rails routes
から keywordが含まれたルートを探してくれる
gem pryを掘る(watch)
Rubyのデバッグに便利なことで有名なgem pry
に調べてみる
watch
監視したい値を watch <値>
のようにして登録すると
値に更新があったときに教えてくれる
[5] pry(main)> a = 1 => 1 [6] pry(main)> watch a Watching a watch: a => 1 [7] pry(main)> a => 1 [8] pry(main)> a += 1 watch: a => 2 => 2
何かを実行するたびに監視対象を実行して、結果を調べてくれているらしい 試しにメソッドの結果を監視したら、毎回監視対象のメソッドが実行されてた
[2] pry(main)> def count [2] pry(main)* puts 'count invoked' [2] pry(main)* 1 [2] pry(main)* end => :count [3] pry(main)> watch count Watching count count invoked watch: count => 1 [4] pry(main)> 1 + 1 count invoked => 2 [5] pry(main)> count count invoked count invoked => 1
裏で更新されているようなものについて監視できるんだろうか? 気になるので、Threadを起動して並列で更新してみたが更新を教えてくれなかった。 どうもpry上でなにか実行したときに値を確認して変わってたら教えてくれるだけらしい。