lasciva blog

開発して得た知見やwebビジネスのストック

「RDBMS解剖学」を読んだ

RDBMS解剖学 よくわかるリレーショナルデータベースの仕組み (DB Magazine Selection)

RDBMS解剖学 よくわかるリレーショナルデータベースの仕組み (DB Magazine Selection)

目的、モチベーション

  • DBの処理の一連の流れを俯瞰して理解したい
  • 特に、実行計画やトランザクション管理など

全体の感想

SQLを解析して、どのようなプランでデータを制御し、トランザクション排他制御、マルチバージョンをどのように行うかなどを俯瞰的に解説されてました。
SQL周りは特に目新しい情報もあまりありませんでしたが、特にトランザクションの制御やログなどはなかなか基礎的なところから説明した書籍等があまりないので、重宝しました。
廃版になってしまってるので手に入れにくいですが、DBの中の基礎知識がない方にはオススメです。

目次

概要

第1部 はじめに

全体の処理の種類や流れは以下の図のように整理できる。

f:id:hacking15dog:20191007180715p:plain

Chapter 1 データベースの基礎とディスクアクセス

ディスクはメモリと比べて安価だが、数万とかのレベルで遅い。

第2部 SQLの処理

Chapter 2 SQLをどう料理するか(1) SQL構文解析

構文を解析して、構文ツリーを作成する。

Chapter 3 SQLをどう料理するか(2) SQLから演算へ

論理プラン: SQLを操作手順に解釈して、代数の演算に変換し、どれが効率的に行えるか選択する
物理プラン: 論理プランをコンピュータ上の実行手順に書き換えたもの

Chapter 4 カタログとインデックス

カタログとは
  • データベース情報
  • テーブル情報
  • ビュー情報
  • カラム情報
  • インデックス情報
  • 制約情報
  • データベースユーザ情報
  • 統計情報(カラムの最大値、最小値、種類数など)
  • ストアドプロシージャ/トリガー情報
  • 性能情報

重要な用途は、「SQL構文解析の整合性チェック」と「最適プランの選択」。

Chapter 5 SQLの実行エンジン

テーブルスキャンやマージの種類が複数紹介されていた。
これらのアルゴリズムとカタログ情報から最適なプランを評価する。

Chapter 6 物理プランの生成

物理プランの最適化方式

有名なものは2種類ある。

ルールベース方式
事前に優先順位のルールを用意して、選択する。
テーブルの容量等が考慮されていないため、データの増減などの環境変化に対応できない。

コストベース方式
各統計情報から、「コスト」と呼ばれる最適化のための指標を算出して、最小なプランを選択する。

コストベース方式の例

第3部 システム化のサポート

Chapter 7 トランザクションの基礎

トランザクションをどのように保証するか

追記型では、古い値と新しい値を保持して、COMMITやROLLBACKの時点でどちらかを無効にする。
そのため、更新時には対象データの容量だけ余分にストレージが必要になる。

同時実行制御~複数のトランザクションが同時に実行される場合~

パフォーマンスを出すには平行して処理する必要がある。
一方でトランザクションが干渉しあうと、次のような問題が発生するので制御する必要がある。

  • 更新の消失
  • ダーティーリード
  • 非再現リード

Chapter 8 トランザクション制御とMVCC

インデックスなどの内部ロック

Bツリーの場合はルートノードからリーフノードを探索するため、二相ロックに従うと一連のノードをロックしなければならない。
そのため、ツリープロトコルで実装されることが多い。

  1. あるノードのロックを獲得
  2. ロックを獲得しているノードの子ノードのロックだけ獲得できる
  3. 個別のノードのロックはいつでも解放できる(ほかのトランザクションがロックできるようになる)
  4. いったんロックを解放したら、このノードのロックは獲得できない
タイムスタンプを使った同時実行制御

ロック以外の方法の一つとしては、タイムスタンプをそれぞれのトランザクションに発行して、その順番を使って強制的に実行を制御することができる。
タイムスタンプの順番に従ってない場合はabortする。abortが連鎖することもあり、あまりよろしくない。

マルチバージョン同時実行制御

マルチバージョン同時実行制御(MVCC)は、タイムスタンプをベースとしている。
タイムスタンプでは、結果が正しくても実行順序に問題があると強制的にアボートされてよろしくない。
この問題に対して、古いデータを保持しておいて、トランザクションの一貫性を担保する。
データの書き込み中にも、古いデータを返すことで並列で処理を行える。

Chapter 9 ログ機能によるパフォーマンスの向上

データ更新処理の仕組み

ログファイルに書き込んだらcommitされる。
この時点では、データファイルにはまだ保存されていない。

ログ機能の構成と役割

パフォーマンス改善と、バックアップの2つの側面がある。

性能上の課題

ログの書き込みは、シーケンシャルなので、都度データファイルに書き込むよりもパフォーマンスがよい。

ディスクへの書き出しの性格の違い

バイナリログと実データのディスクを分離すると、ディスクヘッドのオーバヘッドが減り、パフォーマンス改善につながる。
複数のトランザクションを1度に書き込める可能性がある。

Chapter 10 ログによる障害からの復旧

データファイルへの書き込み記録であるチェックポイントをもとに、復旧時にREDOなどを行う

第4部 複数データベースをまとめる

Chapter 11 クラスタリングによる性能向上

Chapter 12 データベースのパーティショニング

パーティションを行うことで、各ノードでの全データアクセスのデータ量が減るので、パフォーマンスが上がる。
一方で、どのようにパーティションを行うか、どのレイヤーで制御するかなどの複雑性が上がるので、キャパシティプランニングが非常に重要。
また、パーティション間のデータを結合する際には余計にコストがかかる場合もあるので、設計も重要。

次のアクション

RDBMS解剖学 よくわかるリレーショナルデータベースの仕組み (DB Magazine Selection)

RDBMS解剖学 よくわかるリレーショナルデータベースの仕組み (DB Magazine Selection)

「NETFLIX コンテンツ帝国の野望 :GAFAを超える最強IT企業」を読んだ

NETFLIX コンテンツ帝国の野望 :GAFAを超える最強IT企業

NETFLIX コンテンツ帝国の野望 :GAFAを超える最強IT企業

目的、モチベーション

アメリカの大手テック系の中で、Netflixのことはビジネス的に全然知らなかったので、どういう歴史があり何が強みなのかを知りたかった。

全体の感想

ストリーミングに本格的に参入し始めた2011年までの話なので、もう少し最近の話を知りたかったです。
Netflixが古い会社だったのが意外でした。
基本的にはブロックバスターという競合との対比が多かったです。
社内政治はTwitter級にドロドロしてると感じました。

目次

概要

プロローグ

第1章 暗闇でドッキリ

1997〜1998年

DVDが普及しておらず、VHSからDVDに移行し始めてた時期に、DVDの宅配レンタル形式でスタート。

メンバーの1人は郵便局で3カ月働き、郵送のフローを把握して、いかにDVDの破損をなくすかを学ぶ。

サービスローンチ前は、狭いオフィスに泊まり込みをして体臭が漂い、他の会社の管理職級のメンバーが多く、人生を賭けた勝負という雰囲気。

サービスリリース直後は、テストに協力してくれてたインフルエンサーのお陰もあって、サーバが捌き切れないぐらいユーザ数と注文数がきた。サーバ増強の担当以外はDVD送付の対応に追われた。

第2章 続・夕陽のガンマン

1998〜1999年

DVDの規格化が進み順調だった一方で、レンタルは伸びずに、販売しか伸びてなかった。
共感力のないヘイスティングスが共同CEOとしてジョインして、社内のメンバーから反感を買いながらも、戦略的に物事が進むように。
レンタル事業に転換するために、Amazonと提携し、販売はAmazonに送客してAmazonNetflixを宣伝してもらうように。

第3章 黄金狂時代

1999〜2000年

ヘイスティングスに経営権が渡ると、創業期のメンバーも徐々に退職して、社内の雰囲気も変わってく。

ブロックバスターに買収の話を持ちかけるも同意に至らず、真っ向から勝負することに。

第4章 宇宙戦争

2001〜2003年

ドットコムバブルが崩壊し、IPOが厳しくなったため、Netflixの価値を証明する必要が出た。
そのためには、大手レンタルのブロックバスターにとって脅威になる印象を与える必要があった。
そんな状況の中、ブロックバスターは店舗でのサブスクリプションサービスを開始し、Netflixの印象が変わった。
IPO前にはバーンレートが高く黒字化が厳しいため、4割の社員は一斉に解雇された。
無事IPOに成功し優秀で鋭い社員も増えた。家族的な雰囲気で経営する趣向があり、社内で権威を失いつつあった創業者のランドルフは退職することに。

第5章 レオン

2003〜2004年

Netflixは3桁成長を続けて絶好調だった。
ブロックバスターもオンラインを検討し始め、ビジネスプランを練ったがNetflixのクローンに行き着いた。
物流の基盤を整えるために、友人や親族に頼り、ネットフリックスの会員を装って物流センターを盗み見させたりもした。
Netflixは軽視して、値上げまでした。

第6章 お熱いのがお好き

2004〜2005年

ブロックバスターがオンラインに踏み出した。
別会社をつくって採用も別途行った。 社内では既存の実店舗の方が稼ぎ頭のため、カニバらないように実店舗より目立つ宣伝は行わないなどの制約はあった。 見た目はほぼ完璧にNetflixをコピーしたものをリリース。 しかし、システムの設計が悪く、エラーも噴出。

第7章 ウォール街

2004〜2005年

ブロックバスターのキーマンである、アンティオコスたちの話や、失敗に終わった同業他社の買収の話。

第8章 キック・アス

2004〜2005年

噂されていたAmazonの参入の対策を進める一方で、ブロックバスターは攻勢を強める。ブロックバスターは新規ユーザ獲得のため、赤字前提の値下げやスーパーボウルでCMを出すなどして、ユーザの獲得を順調に進める。

財務的にも長期的な継続は不可能だと見切り、特に対策を打たなかったことなども悪影響し、マスコミによるNetflixのネガティブな報道が増えた。

当時はSNSもなく、個人の発信はあまり影響力はなかったが、人気ブロガーは徐々に影響力をつけていた。

キューという在庫切れの作品を後で登録リストの機能では、定着しているヘビーユーザは後回しにして、新規ユーザを優先させるアルゴリズムになってる疑いがオンラインコミュニティ主導で騒動になった。

また、キューを家族のメンバーごとに区切れる機能や、自分のキューをシェアできるフレンズという機能をユーザに告知なくクローズして騒動になった。

第9章 我等の生涯の最良の年

2005〜2006年

ブロックバスターの実店舗の売上はどんどん落ちていき、閉店も相次いだ。その結果、オンラインでの値下げやキャンペーンの予算が大幅にカットされ、攻勢が終わった。更に、DVDを買うお金すらなく、あと払いを拒否された会社の最新作も十分な在庫を確保できなくなった。

Amazonはイギリス等ではDVDのオンラインレンタル事業を行なっていたが、国内では展開しないという話も流れた。

Netflixの株価は逆転して時価総額15億ドルをつけた。

第10章 帝国の逆襲

2006〜2007年

ブロックバスターは「延滞料金の終わり」キャンペーンで少し立て直して、オンラインのマーケティング予算を追加して、また値下げ合戦が始まった。

更に、実店舗で返却できたりするハイブリッドのサービスを提供し始めると、新規獲得ユーザ数はNetflixを上回り、本格的に潰しにかかった。

一方、Netflixブランディングを強化して、論理的でない部分で、ユーザとの繋がりを強化した。 また、品揃えが少ないながらも、ストリーミング配信をスタートした。ストリーミングによって、どの部分で再生が終わったか、繰り返し見られてるかを計測できるようになり、より細かい分析が行えるようになった。

第11章 Mr. インクレディブル

2006〜2009年

シネマッチの精度を上げるために、アルゴリズムコンテストを開催した。膨大なデータの提供と賞金で多くの参加者を集めることに成功する。 AT&Tのチームが優勝した。 このアルゴリズムでは、会員が評価せずとも会員の行動のみで推薦でき、ストリーミングとも相性が良いものだった。

第12章 真昼の決闘

2007〜2008年

会員をブロックバスターに奪われ始め、打つ手なしになり、ブロックバスターオンラインの買収を提案するも、ブロックバスターに断られる。 ブロックバスターはCEOと株主の対立が深まり、CEOが退任することに。 Netflixは上場後初めて下方修正することに。ヘイスティングも疲弊し、社員も士気が低下していた。

第13章 大脱走

2007〜2009年

ブロックバスターの新CTOはセブンイレブン出身で小売業の人となった。デジタル音痴でオンラインでの成長よりもオフラインを重視する路線に。ブロックバスターの幹部達は次々に退職した。 ついには、倒産まで噂されるように。

思わぬ形でNetflixは救われ、ユーザの獲得も加速。 KUROというハードウェアをリリースして、テレビでデジタル配信のコンテンツを気軽に見れるように。売行きは好調で、波に乗って次々にコンテンツ提供会社と契約を結ぶ。

第14章 勇気ある追跡

2009〜2010年

第15章 ニュー・シネマ・パラダイス

2011年

海外進出に本格的に乗り出す。
一方でブロックバスターの二の舞にならまいと、ストリーミングに舵を切る方針に。
オンラインレンタルは別の会社にしてサービスも別々にするという徹底した方針や、リーマンショック後で不景気の中、オフラインレンタルを値上げしようとして、ユーザから大反発を買ってしまい大炎上する。
経営陣もブロックバスターを相手に闘っていたときに比べて、利己的になってしまう。

エピローグ

NETFLIX コンテンツ帝国の野望 :GAFAを超える最強IT企業

NETFLIX コンテンツ帝国の野望 :GAFAを超える最強IT企業

「Amazon Japan Tech Night #2」に参加してきた

amazonjapantechnight2.splashthat.com

Amazonのサービスを開発している方の話を聞けるのが珍しいので、参加してきました。
以下の目的で、四半期に1回ぐらいのペースでやっていく予定だそうです。

東京拠点の開発チームは主に4つあるそうです。

  • marketplace
  • INTech(小売)
  • Search
  • device(Alexa/Kindleなど)

発表内容以外の点で、他のミートアップと違うと感じたところは下記です。

  • NDA契約が必要
    • 確認したところ、スライドのシェア等は大丈夫で、懇親会等で知り得た機密情報とかが禁止という意味だそうです。
  • 閉会のときに抽選会があり、Kindle系の商品が貰える

発表

※ 客観的に記述したつもりですが、私の理解不足等で誤っている可能性もありますので、予めご了承ください。

Amazon Points

Amazon Pointsチームという、ポイント関連の開発を行ってる方々の発表でした。

登壇者

Matsuiさん

komodaさん

The Feature
  • Japan-first
  • 東京がメインのチーム
  • 顧客視点から見た機能
    • 商品ページのポイント表示
    • キャンペーン(本のまとめ買いなど、PrimeDay)
    • クレカのポイントバック
The Tech

f:id:hacking15dog:20190912121328j:plain

f:id:hacking15dog:20190912121340j:plain

デザイン

  • SOA, Microservices
  • 他のサービスと密接なcollaboration
  • 他システムと疎結合にすること
  • 求められるスキル
    • 他のサービスを含めコードを読むことが多いため、素早く理解すること
    • 大規模システムにおけるハイレベルな設計

インフラ面

  • (もちろん、)AWSフル活用
    • EC2, Lambda, S3, DynamoDB, SNS, SQS, Kinesis, SWF, Step Function, EMR, Redshift, Glue...
    • 公開されてない機能もあり
  • ほぼすべてのものがAmazon自身によって開発されたもの
    • AWSだけでない
    • OSSコミュニティと比較しても、社内の開発コミュニティは大きい
      • Web Framework, Build Tool, Monitoring, Alarming, ML...

Fulfilment By Amazon Preorder Enhancement

自己紹介

JP Seller Tech Team

  • 前職: KDDI
  • 2016年入社
  • チームは10人以上いる
Mission

Innovate on behalf of third-party sellers and to improve both cusromer and seller ecperiences across Amazon Marketplaces

最近の事例

FBAの予約注文の改善

f:id:hacking15dog:20190912121357j:plain

背景
  • 予約商品が売りづらい
    • 発売日の設定、変更がseller自身でできない

f:id:hacking15dog:20190912121405j:plain

解決方法

f:id:hacking15dog:20190912121421j:plain

f:id:hacking15dog:20190912121456j:plain

f:id:hacking15dog:20190912121501j:plain

  • SNSと SQSQueueでサーバレスなのでスケーラブル
  • Downstreamがサブスクライブして処理を行う
  • DeadLetterQueueに失敗したメッセージを突っ込む

f:id:hacking15dog:20190912121505j:plain

f:id:hacking15dog:20190912121510j:plain DynamoDBにrequestを保存することで、workflowで複数の通知を一つにまとめることができる

Customer Service By Amazon

自己紹介

JP Seller Tech Team

  • 日本に9年
  • 1年間は群馬にいた
CSBA Overview
  • sellerのCS代行サービス
    • 中国のsellerが日本で販売するときなど
Seller

f:id:hacking15dog:20190912122133j:plain

Notification

考慮したこと

  • セキュリティ
    • 個人情報などはNotificationサービスでは持たない
  • スケーラビリティ
    • Queueを使って非同期にしたり、サービスを分割して適切にリリースを調整できるように

f:id:hacking15dog:20190912122142j:plain

Tech1 Release Gating

リリース時の下のような課題に対して、QAゲートを使って解決

fn existingMethod() {
  ...
  if (releaseGate.useFeature("new_feature_42")) {
    newFeature.doStuff();
  }
  ...
}

Gradual Release

  • 何%か指定することができる
  • 本番環境でE2Eテストするために、QAだけに許可できる
  • 障害が起こった際に影響を最小限に抑えるために、徐々にリリースできる
Tech2 Service Mocking

たくさんの他のマイクロサービスに依存したり、環境が異なったりして辛い。
そこで、依存しているサービスのモックをフレームワークによって作成して解決。

f:id:hacking15dog:20190912122400j:plain

f:id:hacking15dog:20190912122405j:plain

Katana

Applied Scientist

f:id:hacking15dog:20190912120439j:plain

f:id:hacking15dog:20190912120503j:plain

f:id:hacking15dog:20190912120606j:plain

Katana はJapanese Text Tokenizerのこと。
既存のトークナイザーは辞書を持っているタイプのものが多く、以下の要件に対応できない。

  1. MultiDomain(Product,音声デバイスなど)
  2. (検索ワードなどの)新しい言葉などに対応しないといけない

f:id:hacking15dog:20190912120625j:plain

f:id:hacking15dog:20190912120647j:plain

懇親会

  • 基本的には英語を使っている
  • Javaを使ってるサービスが多く、社内専用のフレームワーク等もある
  • 中には、社内のサービスを扱うため専用の言語があったりもする
  • 攻めた開発やリリースができるような仕組みを整えられてる
    • リリース時に、段階的にリリースできる仕組み
    • 恐れずRollbackもできる仕組み
  • いわゆるSREチームはなく、アプリケーション担当が自分のサービスのインフラも見る

「マイクロサービスアーキテクチャ(Building Microservices)」を読んだ

マイクロサービスアーキテクチャ

マイクロサービスアーキテクチャ

目的、モチベーション

  • マイクロサービスのサービスに携わり始め、基礎を学びたかった
  • 英語のお勉強

全体の感想

モノリスとマイクロサービスの比較から始まり、どのようにマイクロサービスに移行していくか、設計や実際の運用する上での話などが一通り網羅されていて、全体感を掴めました。
一方で、個別の細かいレベルでのツールや技術の選定や導入、運用方法は別途学ぶ必要があると思います。
マイクロサービスの導入によって生まれる課題も想像以上にあるので、安易に流行ってるというだけで導入するのは危ないなと思いました。

マイクロサービスやってるバックエンドエンジニアには前提となる知識が網羅されていて、必読な感じの本に思えました。
マイクロサービスの経験のないチームで導入の検討をしているときは特に参考になると思います。

今回は英語版を読んだのですが、いつもの5倍前後ぐらい時間がかかった気がします。
効率がかなり悪かったので、今後は暇な時期か日本語版がないときだけにしようかと思います。

目次

概要、気になったところ

前提として、私はマイクロサービス歴は数ヶ月で、モノリスでの経験も中規模程度で、モノリスでかなり苦しんだ経験もないです。
その中で、気になったところを中心にまとめました。

1章 マイクロサービス

1.1 マイクロサービスとは
  • 単一の役割の責任を満たすぐらい小さいこと
    • 十分小さい状態とは、大き過ぎない状態のこと
    • 小さくし過ぎると、恩恵が最大化される一方でデメリットも最大化される
  • 自治的であること
    • 他のサービスを意識せずに独立してデプロイ等を行えるか
1.2 主な利点
  • 適材適所な技術を使える
    • 試験的な導入も影響範囲を狭めて試す
  • resilenceでエラーを局所化できる
  • 必要な部分だけスケールさせられる
  • デプロイが速く、安全に行える
  • 少人数のチームで開発効率を維持できる
  • リプレイスが容易
1.4 他の分解テクニック

共有ライブラリ

  • どのプラットフォームでも動くようにしないといけないので、言語をサービス間で同じにしないと辛い面もある
  • ライブラリの更新によって、デプロイの独立性が阻害されないように工夫が必要
  • ライブラリの種類によってはサービス間が密結合になってしまうかもしれない
1.5 銀の弾丸などない

マイクロサービスも良いところばかりでないので、考慮した上で導入すること。

2章 進化的アーキテクト

2.1 不正確な比較

よく建設の設計者に例えられるが、ソフトウェアエンジニアは歴史が浅く、何か明確になるような比較対象を求めがちだが、役割に誤解を招いて幅を狭めるのでよくない。

2.2 進化するアーキテクト像
  • もし例えるなら、市の設計者が適切である。
  • 市は外部の影響を受けるし、長期的な時間を見越してみんながハッピーになれるよう考える必要がある。
  • 地域や、インフラ整備なども似ている。
2.3 区画指定
  • zone間でのやり取りに気を配るべき。
  • zone内での技術等はzoneに任せるべき。
    • ただし、zone毎に最適化しすぎて様々な技術を使いすぎると、採用や人の異動を行いにくくなる
2.4 原則に基づいたアプローチ
  • ビジネス的な戦略を把握する
    • 考える形では、アーキテクトは関わらないことが多い。
  • 原則
    • 戦術を遂行するためのもの
  • 実践
    • 原則を実現するための方法
2.10 チームの構築

偉大なソフトウエアは偉大な人から生まれるので、人を育てるのは重要。マイクロサービスはモノリスよりもサービスのライフサイクルや成長を自主的に把握しやすいので、相性がいい。技術だけしか興味を持ててないのは、成長の半分にしか貢献できてない。

3章 サービスのモデル化方法

3.2 優れたサービスにするには

各サービスが他のサービスとの調整なしに、独立してデプロイでき、影響範囲を局所化するために、疎結合と高凝集性が重要。

3.3 境界づけられたコンテキスト

DDDなどを参考に、ドメインを切り分けていく。
一気にサービスを独立させるのではなく、まずはモノリスでモジュールレベルで分解して検討していく。
誤ってサービスを切り分けると開発コストがよりかかるため、モノリスで十分様子を見てからサービスを独立させる。

4章 統合

4.1 理想的な統合技術の探索

下記を満たすべき。

  • 破壊的変化を避ける
  • 特定の技術に限定されない、変更可能
  • 他サービスからシンプルに使えるように
  • 詳細の実装を隠蔽
4.3 共有データベース

以下の理由からアンチパターン

  • スキーマ変更するだけで、大きな影響を与える
  • サービス毎に適切な技術選定が行えない
  • 変更箇所が各サービスに渡る
4.5 オーケストレーションとコレオグラフィ
  • オーケストレーションだとシンプルだが、それぞれのレスポンスを束ねる神サービスができて、密結合になりがち
  • もう一方では、それぞれの処理を各サービスに委譲できて疎結合サービスになるが、全体で適切に処理が行われたか監視しないといけない。
4.13 バージョニング
  • 原則として、破壊的な変更はなるべく行わないこと。
  • Tolerant Readerを使って変更に強くする。
  • protobufでネームスペースを使うと、変更がないバージョン変更が辛いので、オススメしない。
4.15 サードパーティソフトウェアとの統合
  • カスタマイズ
    • ベンダーの提供するカスタマイズを行うには、スクラッチで作るよりもコストがかかりうる。
    • ベンダー側に合わさせるのではなく、ベンダーに合わせる。
    • アップグレードで動かなくなることも多々ある。
  • CMSの例
    • カスタマイズしようとして、秘伝のCSSなどができがち。
    • コンテンツの取得、更新をAPI経由で行い、フロントエンドは自前で対応するとよい。
  • CRMの例
    • CRMは社内の組織に大きく影響を及ぼし、後々に肥大化する。
    • CRMのサービスは何でも対応できて、巨大で一つに集約されてしまう。
    • facadeパターンで、ドメインの関心ごとにサービスをつくり、外部からはシンプルなインターフェースで使えるようにする。
  • レガシーなサービスとの共存
    • リプレイスや機能削除を行おうにも、どこが使われてるか不明で、進めにくい。
    • 他のパターンと同様に中間のサービスを用意して、直接参照しないようにする。
    • 徐々にリプレイスもでき、ビッグバンリリースを避けれる。

5章 モノリスの分割

全体としては以下の順に進める。

  1. コードの境界を定めて、パッケージなどで分割していく
  2. 分割できたら、一つ一つ徐々にサービス毎に切り出す
5.3 モノリスを分割する理由
  • 変更できるスピードが上がる
  • チームごとに責任を持って進めやすくなる
    • 例えば、ロンドンとハワイにチームが開発者が別れてるケースなど
  • セキュリティを個別に強化するなど、個別に必要な機能追加を行いやすい
  • サービスごとに適切な言語選定や新しい技術の導入が行いやすい
5.5 データベース
  • まず、DBへの参照や更新をそれぞれの境界ごとにリポジトリレイヤーに切り出す
  • 境界間で外部キーなどの依存関係がある場合は、SchemaSpyで依存関係を可視化する
5.7 例:外部キー関係の削除
  • DBは別々にして、API経由で参照する。
  • パフォーマンスが低下するかもしれないが、トレードオフなので、どれだけパフォーマンスが求められるか考慮する。
  • 外部キー制約が失われるが、別のサービスで監視するなどの工夫が必要。また、データを本当に削除してもよいかなどの挙動の取り決めも必要。
5.9 例:共有データ

別々のサービスが同じデータを参照する場合は、そのデータのサービスを別途切り分ける。

5.10 例:共有テーブル

列の多いテーブルはそれぞれのサービス毎に縦に分割する。

5.11 データベースリファクタリング

他の例はデータベース・リファクタリングを読むべし。

5.11.1 段階的な分割

段階的に移行すべし。

  • 初めにDBの分割を行ってから、アプリケーション側の分割を行うことで、リバートできるようにしておく
  • ただし、DB間のトランザクションを扱ったりする必要がある
5.12 トランザクション境界

DBが分割されると、整合性を保つのに工夫が必要。

  • あとでリトライして、結果整合性を担保する
  • ロールバックを実現するために、delete文を発行する
  • 分散トランザクション
    • 上述の方法だと、複雑なものに対応できなくなる。
    • 2段階コミット
      • 1段階目でそれぞれのDBでコミットできるか確認する
      • 2段階目で全てokなら実際に各DBで実行し、NGなら実行しない
      • 1つでも障害が起こると死んでしまうなどの欠点がある。
  • 複雑なので、本当に整合性を守らないといけないのかの検討をする
5.13 レポート
  • モノリスのDBを直接参照するのはデメリットがある
    • スキーマの変更に影響される
    • 本番環境のパフォーマンスに影響を及ぼしうる
    • 適切な技術選定ができない
  • マイクロサービスのAPIコールで実現するには工夫が必要
    • バッチ用のAPIを用意して、ポーリングし続けてCSV等の形式で共有データに出力されたものを参照するなどの方法がある
    • アプリケーションレイヤーで処理するには、データ量が多く危険な上、処理中に整合性が保てなくなる
  • 各サービスがデータをpushして一箇所で管理する方法の方がベター
    • 疎結合ではなくなるが、反するメリットの方が大きい
5.21 根本原因の理解
  • まず分割の重要性を理解した上で開発すること
  • 対応困難なレベルになる前に分割すること
  • 徐々に進めていけるものなので、恐れないこと

6章 デプロイ

サービス毎にリポジトリを分割すべき。

  • CIでのテストの短縮や、デプロイの時間短縮につながる
  • インフラは出来れば1サービス毎に1ホスト用意すべき
    • 複数のサービスが同一ホストにあると、依存関係ができる
    • 1サービスがメモリを喰ったりすると、他のサービスも道連れになってしまう
    • 監視が困難
  • 1ホストに対して1サービス提供するために、dockerなどの軽量なコンテナを使うべき
    • VMはオーバーヘッドが大きく、サービスの数が増えるとスケールしにくい
    • 各サービスに必要なミドルウェアなどはバージョン管理等のことを考えるとイメージとして保存しておくべきだが、容量が大きくなってしまう
  • コンテナ間の制御はk8sなどを使う

7章 テスト

テストは分類でき、何を目的にしてるのかを明確にする

ユニットテスト

  • 関数単位とかのレベル
  • 実行時間は短いので、どんどん書くべき

サービステスト

  • stubやmockを活用

E2Eテスト

  • 全体でちゃんと動くか保証できるので安心感がある
  • マイクロサービスでは実現するのにコストがかかる
  • 複数のサービスにまたがると、全部ビルドしないといけないので、実行時間がかなりかかる
  • どのサービスでE2Eのテストをカバーするのかの取り決めを行わないと、サービス間でテスト内容が重複したりする
  • 後述のCDT(Consumer Driven Test)を増やして、必要最低限に数を減らすこと
7.8 救いとなるコンシューマ駆動テスト
  • サービス間で期待するインターフェースを取り決めておき、それに従うようにテストを行う
  • PactPactoなどでは、JSONなどでインターフェースを定義しておけて、モックも提供してくれる
    • JSONなどの形式だと、サービスの言語に依存しないので嬉しいケースが多い
7.10 本番リリース後のテスト
  • デプロイとリリースのタイミングを分離することで、内部でテストを行うことができる
    • ブルーグリーンデプロイなどのこと
    • テストを行ってから、新しいサービスにリクエストを投げ始める
    • 古いサービスは少しの間は残しておいて、エラーが発生したら切り戻せるようにしておく
  • canary releasing
    • 新旧のサービスを共存させて、徐々に新サービスへのリクエストの割合を増やしていく
    • 新旧でレスポンスを計測して、パフォーマンスに問題がないかなどをウォッチできる

8章 監視

  • サービス間で共通の形式でログを出力すること
  • ログは一つのサーバに集約させて調査しやすいようにすること
  • 外部からのリクエストはどのサービスでも同一だと認識できるように共通IDをログに含めることで、調査できるようにすること

9章 セキュリティ

9.2 サービス間の認証と認可

大抵のパターンでは、ユーザ名・パスワードをセキュアに管理する必要があり、そこが厳密には難しい。
また、サービス間をHTTPSで通信を行う場合には、それぞれのサーバのSSL証明書を用意する必要がある。

9.2.1 境界内のすべてを許可する

一旦ネットワーク内に侵入されてしまうと、中間者攻撃を防げないので、あまりよろしくない。

9.2.2 HTTP(S)ベーシック認証

HTTPの場合は、ベーシック認証の情報がセキュアでないため、基本的にはHTTPSで行うべき。

9.4 徹底的な防御
  • ファイアウォール
  • ロギング
    • 攻撃されたあとの調査の材料になる
    • セキュアな情報は残さないこと
  • 侵入検知(および侵入防止)システム
    • 侵入者の検知のみならず、ファイアウォールとは異なり、内部での不審な動きも検知することができる
  • ネットワーク分離
    • AWSVPCのようなサービスで分離すること
  • OS
    • アプリケーションレイヤーが完璧に対策されていても、OSが古ければ脆弱性がある状態になるので、最新の状態に更新し続けること
9.6 節約する

不必要なデータを削除することは、データを盗まれる可能性を減らす上に節約につながる。

10章 コンウェイの法則とシステム設計

コンウェイの法則の事例等が紹介されていた。

11章 大規模なマイクロサービス

マイクロサービスで、扱うサーバやノードが増えれば増えるほど、問題の起こってる状態は増える。
GoogleNetflixでは、自らエラーを発生させてシステムが動き続けるかどうかの確認を行なっている。

11.5 アンチフラジャイルな組織

ハードウェアやネットワークに問題が起こる前提で、反脆さに強い分散システムをつくる必要がある。

  • タイムアウトを適切に設定すること
  • サーキットブレーカー
    • タイムアウトや5xxエラーが増えた時に、サービス間の通信を遮断して即座にエラーを返すようにする仕組み。
    • 遮断している間に、少しだけリクエストを送って回復したかを検知して、回復したは復旧する。
11.8 データベースのスケーリング
  • Read: replicaを増やす
    • ただし、結果整合性を許容することになる
  • Write: シャード
    • 集合を扱うとき、シャード毎の結果を結合しないといけない
    • シャードを増やすとき、リバランスを行わないといけない
  • Shared Database Infrastructure
    • 便利な反面、SPOFになりうるリスクがある
  • CQRS(Command-Query Responsibility Segregation)
    • TODO
11.10 オートスケーリング

トラフィックの増減に応じてインスタンス数をコントロールするだけでなく、最低値を設定して自動で復旧させるのも便利

11.11 CAP定理

「一貫性(Consistency)」「可用性(Availability)」「分断耐性(Partition-tolerance)」の3つを同時に完璧に満たすのは不可能だという定理。
分散システムにおいては、分断耐性を犠牲にすることはできない。そのため、通信の遅延が起こった際に、システムの要件に応じて一貫性と可用性のトレードオフのバランスを取ることが求められる。

11.13 動的サービスレジストリ

下記のサービスが紹介されていた。

  • ZooKeeper: 本番運用もされてることが多く信用性は高いが、ヘビーで理解が難しめ
  • Consul: 本番運用例はあまりないが、有名なコミュニティが開発してるらしく、一見の価値あり
  • Eureka: Netflixによるもので、上記の2つよりは用途を限定している

12章 まとめ

12.2 マイクロサービスを使用すべきでない場合
  • 境界を適切に区切るのに十分なドメイン知識がないとき
    • 間違って境界を設定すると、よりコストがかかる
  • サービスの数が増えれば増えるほど、マイクロサービス特有の監視などの課題は重くなっていくので、徐々に進めていくべき
12.3 最後に

マイクロサービスにすることは、決断ではなく旅のように長くコツコツやっていくつもりで対応すること

次のアクション

概要はわかった気にはなれたので、サービス運用しながら学んでいこうと思います。
サービスの切り分けや、サービス間のデータの整合性の保ち方などは特にもう少し深堀りたいなと思います。
マイクロサービスの課題も少しは掴めたので、k8sで何を解決しているのかをもう少し理解したいと思います。

マイクロサービスアーキテクチャ

マイクロサービスアーキテクチャ

「分散システムデザインパターン」を読んだ

分散システムデザインパターン ―コンテナを使ったスケーラブルなサービスの設計

分散システムデザインパターン ―コンテナを使ったスケーラブルなサービスの設計

目的、モチベーション

  • 分散システムの記事等を見たときに、サイドカー等の理解してないキーワードを散見するようになり、理解したかったため。
  • コンテナを使ったマイクロサービスを運用しており、理解を深めたかったため。
  • Faasなどのクラウドサービスの使い分けを把握したかったため。

全体の感想

シングルノードのときや、マルチノードのときなど幅広く取り扱われており、なんとなく単語レベルでは知ってるパターンの理解を深めることはできた。
インフラ寄りのデザインパターンがほとんどだが、アプリケーションにも関与していて開発しているときにも他の選択肢が増えて視野が広がった気がする。
マルチノードパターンでは、負荷対策などのためのスケール方法が多く記載されていて面白かった。
全体的に解決しようとしてる課題感は掴めたが、現場でSRE的な役割で運用してみないと。

目次

概要

1章 はじめに

分散システムが前提となった時代において、アルゴリズムオブジェクト指向などと同様にパターン化して公式化することが本書のゴール。

第Ⅰ部 シングルノードパターン

シングルノードパターンを使う理由

  • リソースの分離
  •  関心の分離・影響範囲の局所化
  • デプロイやロールバックを容易にする

2章 サイドカー

1台のマシン上で動く2つのコンテナから構成されるパターン。
ホスト名、ネットワーク、ディスクなど多くを共有する。

  1. サイドカーの例:レガシーサービスのHTTPS 対応
    • nginxなどのSSLのプロキシを挟んで、localhost上でアプリケーションを動かしてアクセスする。
    • アプリケーションがレガシーでHTTPSの対応が難しいときなど。
  2. サイドカーによる動的な設定
    • クラウドネイティブな場合、設定はAPIで更新する方が便利。
    • 既存のアプリケーションを拡張するよりも、サイドカーに設定を更新させるようにさせた方が容易なことがある。
  3. モジュール化されたアプリケーションコンテナ
    • コンポーネントのモジュール化と再利用性の例
    • プロセス情報を取得するためにAPIを提供する場合
      • 各アプリケーションで統一的に対応するのは言語が異なったりして困難。
      • サイドカーを利用して一貫したインターフェースで情報を提供できるようになる。

3章 アンバサダ

アプリケーションが外部サービスに接続する際に、プロキシとなるコンテナを経由させるコンテナグループを作るパターン。

1. サービスのシャーディングへのアンバサダの利用

Redis等でシャーディングさせてる際に、ノードを増やす度にアプリケーションをデプロイし直す必要がなくなり、ロジックを共通化できてアンバサダコンテナを独立してデプロイすることができる。

2. サービスブローカとしての利用

開発環境や、本番環境などで外部サービスのホストやポートの設定が異なる可能性が高いが、そのロジックをアンバサダコンテナに委譲できる。

3. 新システムの実験的運用やリクエスト分割への利用

バージョンアップなどで新システムを本番環境に導入する際にも、試験的に導入することができる。
例えばアンバサダの設定を変更して、既存のシステムを稼働させつつ、新システムにも同じリクエストを裏側で送って負荷を確認することができる。

4章 アダプタ

コンテナグループ外に対して、外部インターフェイスを提供する際にアダプタコンテナを経由して提供するパターン。

  1. 監視
    • 監視ツール用のインターフェースに変換することで、アプリケーションの責務を分けることができる。
    • 監視コンテナを提供する開発者と、アプリケーションの開発者を切り分けることができる。
  2. ロギング
    • 監視と異なり、ログはレベルごとにファイルが異なったり、標準出力してるだけのことがあり、フォーマットがバラバラ。
    • アダプタパターンで、モジュール化して再利用して、フォーマットを統一することができる。

第Ⅱ部 マルチノードパターン

6章 シャーディングされたサービス

1. シャーディングされたキャッシュ

シャーディングされてる場合は、一つのノードが死んだ場合に特定のユーザへのレスポンスが遅くなるリスクがあるため、キャッシュのレプリカを用意したほうが高可用になる。

2. シャーディング関数を試してみる

キーの選択
異なる国からリクエストがある場合、言語ごとにキャッシュを切り替える必要があるため、単にIPアドレスを元にハッシュを生成するのは良くない。

コンシステントハッシュ関数
ノードの数を増やすと再シャーディングする必要がある。このとき、シンプルなハッシュ関数だと再シャーディングのコストが高くなる可能性があるが、コンシステントハッシュ関数を使うと効率的に再シャーディングできる。

7章 スキャッタ・ギャザー

バックエンド内で、複数のノードを使って処理を分散させて高速化させるパターン。ただし複数のノードを使うことによるデメリットもある。

  • ノードごとのオーバヘッドがあるので、並列性を上げても必ずしも処理速度が上がるとは限らない
  • 落ちこぼれ問題(一部のノードでレスポンスが遅くなって全体のレスポンスが遅くなる問題)のため、並列度を上げても処理速度が上がるとは限らない。
  • 一つのノードで障害が起こると全体が止まるので、シャーディング毎にレプリカは必須。(バージョンアップを行う際などでノードは必ず止めないといけないタイミングがある。)

9章 オーナーシップの選出

マスタの選出の実装は困難なため、 etcdApache ZooKeeperConsulなどのコンセンサスアルゴリズムを利用する。

第Ⅲ部 バッチ処理パターン

Apache Kafkaを使ったPub/Subのパターンや、MapReduceフレームワークでの協調する手法が紹介されていた。

分散システムデザインパターン ―コンテナを使ったスケーラブルなサービスの設計

分散システムデザインパターン ―コンテナを使ったスケーラブルなサービスの設計