「Amazon Japan Tech Night #2」に参加してきた
amazonjapantechnight2.splashthat.com
Amazonのサービスを開発している方の話を聞けるのが珍しいので、参加してきました。
以下の目的で、四半期に1回ぐらいのペースでやっていく予定だそうです。
東京拠点の開発チームは主に4つあるそうです。
- marketplace
- INTech(小売)
- Search
- device(Alexa/Kindleなど)
発表内容以外の点で、他のミートアップと違うと感じたところは下記です。
- NDA契約が必要
- 確認したところ、スライドのシェア等は大丈夫で、懇親会等で知り得た機密情報とかが禁止という意味だそうです。
- 閉会のときに抽選会があり、Kindle系の商品が貰える
- 途中で帰らないインセンティブを与えるため?
発表
※ 客観的に記述したつもりですが、私の理解不足等で誤っている可能性もありますので、予めご了承ください。
Amazon Points
Amazon Pointsチームという、ポイント関連の開発を行ってる方々の発表でした。
登壇者
Matsuiさん
- 2019/4入社
- 前職:Linkedin
- ロッククライミング
komodaさん
The Feature
- Japan-first
- 東京がメインのチーム
- 顧客視点から見た機能
- 商品ページのポイント表示
- キャンペーン(本のまとめ買いなど、PrimeDay)
- クレカのポイントバック
The Tech
デザイン
- SOA, Microservices
- 他のサービスと密接なcollaboration
- 他システムと疎結合にすること
- 求められるスキル
- 他のサービスを含めコードを読むことが多いため、素早く理解すること
- 大規模システムにおけるハイレベルな設計
インフラ面
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の予約注文の改善
背景
- 予約商品が売りづらい
- 発売日の設定、変更がseller自身でできない
解決方法
- SNSと SQSQueueでサーバレスなのでスケーラブル
- Downstreamがサブスクライブして処理を行う
- DeadLetterQueueに失敗したメッセージを突っ込む
DynamoDBにrequestを保存することで、workflowで複数の通知を一つにまとめることができる
Customer Service By Amazon
自己紹介
JP Seller Tech Team
- 日本に9年
- 1年間は群馬にいた
CSBA Overview
- sellerのCS代行サービス
- 中国のsellerが日本で販売するときなど
Seller
- sellerが適切かどうか
- アクティベーションのバッチJOB
Notification
考慮したこと
- セキュリティ
- 個人情報などはNotificationサービスでは持たない
- スケーラビリティ
- Queueを使って非同期にしたり、サービスを分割して適切にリリースを調整できるように
Tech1 Release Gating
リリース時の下のような課題に対して、QAゲートを使って解決
fn existingMethod() { ... if (releaseGate.useFeature("new_feature_42")) { newFeature.doStuff(); } ... }
Gradual Release
- 何%か指定することができる
- 本番環境でE2Eテストするために、QAだけに許可できる
- 障害が起こった際に影響を最小限に抑えるために、徐々にリリースできる
Tech2 Service Mocking
たくさんの他のマイクロサービスに依存したり、環境が異なったりして辛い。
そこで、依存しているサービスのモックをフレームワークによって作成して解決。
Katana
Applied Scientist
Katana
はJapanese Text Tokenizerのこと。
既存のトークナイザーは辞書を持っているタイプのものが多く、以下の要件に対応できない。
- MultiDomain(Product,音声デバイスなど)
- (検索ワードなどの)新しい言葉などに対応しないといけない
懇親会
「マイクロサービスアーキテクチャ(Building Microservices)」を読んだ
- 作者: Sam Newman,佐藤直生,木下哲也
- 出版社/メーカー: オライリージャパン
- 発売日: 2016/02/26
- メディア: 単行本(ソフトカバー)
- この商品を含むブログ (1件) を見る
目的、モチベーション
- マイクロサービスのサービスに携わり始め、基礎を学びたかった
- 英語のお勉強
全体の感想
モノリスとマイクロサービスの比較から始まり、どのようにマイクロサービスに移行していくか、設計や実際の運用する上での話などが一通り網羅されていて、全体感を掴めました。
一方で、個別の細かいレベルでのツールや技術の選定や導入、運用方法は別途学ぶ必要があると思います。
マイクロサービスの導入によって生まれる課題も想像以上にあるので、安易に流行ってるというだけで導入するのは危ないなと思いました。
マイクロサービスやってるバックエンドエンジニアには前提となる知識が網羅されていて、必読な感じの本に思えました。
マイクロサービスの経験のないチームで導入の検討をしているときは特に参考になると思います。
今回は英語版を読んだのですが、いつもの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の例
- CRMの例
- レガシーなサービスとの共存
- リプレイスや機能削除を行おうにも、どこが使われてるか不明で、進めにくい。
- 他のパターンと同様に中間のサービスを用意して、直接参照しないようにする。
- 徐々にリプレイスもでき、ビッグバンリリースを避けれる。
5章 モノリスの分割
全体としては以下の順に進める。
- コードの境界を定めて、パッケージなどで分割していく
- 分割できたら、一つ一つ徐々にサービス毎に切り出す
5.3 モノリスを分割する理由
- 変更できるスピードが上がる
- チームごとに責任を持って進めやすくなる
- 例えば、ロンドンとハワイにチームが開発者が別れてるケースなど
- セキュリティを個別に強化するなど、個別に必要な機能追加を行いやすい
- サービスごとに適切な言語選定や新しい技術の導入が行いやすい
5.5 データベース
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コールで実現するには工夫が必要
- 各サービスがデータをpushして一箇所で管理する方法の方がベター
- 疎結合ではなくなるが、反するメリットの方が大きい
5.21 根本原因の理解
- まず分割の重要性を理解した上で開発すること
- 対応困難なレベルになる前に分割すること
- 徐々に進めていけるものなので、恐れないこと
6章 デプロイ
サービス毎にリポジトリを分割すべき。
- CIでのテストの短縮や、デプロイの時間短縮につながる
- インフラは出来れば1サービス毎に1ホスト用意すべき
- 複数のサービスが同一ホストにあると、依存関係ができる
- 1サービスがメモリを喰ったりすると、他のサービスも道連れになってしまう
- 監視が困難
- 1ホストに対して1サービス提供するために、dockerなどの軽量なコンテナを使うべき
- コンテナ間の制御はk8sなどを使う
7章 テスト
テストは分類でき、何を目的にしてるのかを明確にする
- 関数単位とかのレベル
- 実行時間は短いので、どんどん書くべき
サービステスト
- stubやmockを活用
E2Eテスト
- 全体でちゃんと動くか保証できるので安心感がある
- マイクロサービスでは実現するのにコストがかかる
- 複数のサービスにまたがると、全部ビルドしないといけないので、実行時間がかなりかかる
- どのサービスでE2Eのテストをカバーするのかの取り決めを行わないと、サービス間でテスト内容が重複したりする
- 後述のCDT(Consumer Driven Test)を増やして、必要最低限に数を減らすこと
7.8 救いとなるコンシューマ駆動テスト
- サービス間で期待するインターフェースを取り決めておき、それに従うようにテストを行う
- PactやPactoなどでは、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 徹底的な防御
- ファイアウォール
- ロギング
- 攻撃されたあとの調査の材料になる
- セキュアな情報は残さないこと
- 侵入検知(および侵入防止)システム
- 侵入者の検知のみならず、ファイアウォールとは異なり、内部での不審な動きも検知することができる
- ネットワーク分離
- OS
- アプリケーションレイヤーが完璧に対策されていても、OSが古ければ脆弱性がある状態になるので、最新の状態に更新し続けること
9.6 節約する
不必要なデータを削除することは、データを盗まれる可能性を減らす上に節約につながる。
10章 コンウェイの法則とシステム設計
逆コンウェイの法則の事例等が紹介されていた。
11章 大規模なマイクロサービス
マイクロサービスで、扱うサーバやノードが増えれば増えるほど、問題の起こってる状態は増える。
GoogleやNetflixでは、自らエラーを発生させてシステムが動き続けるかどうかの確認を行なっている。
11.5 アンチフラジャイルな組織
ハードウェアやネットワークに問題が起こる前提で、反脆さに強い分散システムをつくる必要がある。
- タイムアウトを適切に設定すること
- サーキットブレーカー
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で何を解決しているのかをもう少し理解したいと思います。
- 作者: Sam Newman,佐藤直生,木下哲也
- 出版社/メーカー: オライリージャパン
- 発売日: 2016/02/26
- メディア: 単行本(ソフトカバー)
- この商品を含むブログ (1件) を見る
「分散システムデザインパターン」を読んだ
分散システムデザインパターン ―コンテナを使ったスケーラブルなサービスの設計
- 作者: Brendan Burns,松浦隼人
- 出版社/メーカー: オライリージャパン
- 発売日: 2019/04/20
- メディア: 単行本(ソフトカバー)
- この商品を含むブログを見る
目的、モチベーション
- 分散システムの記事等を見たときに、サイドカー等の理解してないキーワードを散見するようになり、理解したかったため。
- コンテナを使ったマイクロサービスを運用しており、理解を深めたかったため。
- Faasなどのクラウドサービスの使い分けを把握したかったため。
全体の感想
シングルノードのときや、マルチノードのときなど幅広く取り扱われており、なんとなく単語レベルでは知ってるパターンの理解を深めることはできた。
インフラ寄りのデザインパターンがほとんどだが、アプリケーションにも関与していて開発しているときにも他の選択肢が増えて視野が広がった気がする。
マルチノードパターンでは、負荷対策などのためのスケール方法が多く記載されていて面白かった。
全体的に解決しようとしてる課題感は掴めたが、現場でSRE的な役割で運用してみないと。
目次
概要
1章 はじめに
分散システムが前提となった時代において、アルゴリズムやオブジェクト指向などと同様にパターン化して公式化することが本書のゴール。
第Ⅰ部 シングルノードパターン
シングルノードパターンを使う理由
- リソースの分離
- 関心の分離・影響範囲の局所化
- デプロイやロールバックを容易にする
2章 サイドカー
1台のマシン上で動く2つのコンテナから構成されるパターン。
ホスト名、ネットワーク、ディスクなど多くを共有する。
3章 アンバサダ
アプリケーションが外部サービスに接続する際に、プロキシとなるコンテナを経由させるコンテナグループを作るパターン。
1. サービスのシャーディングへのアンバサダの利用
Redis等でシャーディングさせてる際に、ノードを増やす度にアプリケーションをデプロイし直す必要がなくなり、ロジックを共通化できてアンバサダコンテナを独立してデプロイすることができる。
2. サービスブローカとしての利用
開発環境や、本番環境などで外部サービスのホストやポートの設定が異なる可能性が高いが、そのロジックをアンバサダコンテナに委譲できる。
3. 新システムの実験的運用やリクエスト分割への利用
バージョンアップなどで新システムを本番環境に導入する際にも、試験的に導入することができる。
例えばアンバサダの設定を変更して、既存のシステムを稼働させつつ、新システムにも同じリクエストを裏側で送って負荷を確認することができる。
4章 アダプタ
コンテナグループ外に対して、外部インターフェイスを提供する際にアダプタコンテナを経由して提供するパターン。
- 監視
- 監視ツール用のインターフェースに変換することで、アプリケーションの責務を分けることができる。
- 監視コンテナを提供する開発者と、アプリケーションの開発者を切り分けることができる。
- ロギング
- 監視と異なり、ログはレベルごとにファイルが異なったり、標準出力してるだけのことがあり、フォーマットがバラバラ。
- アダプタパターンで、モジュール化して再利用して、フォーマットを統一することができる。
第Ⅱ部 マルチノードパターン
6章 シャーディングされたサービス
1. シャーディングされたキャッシュ
シャーディングされてる場合は、一つのノードが死んだ場合に特定のユーザへのレスポンスが遅くなるリスクがあるため、キャッシュのレプリカを用意したほうが高可用になる。
2. シャーディング関数を試してみる
キーの選択
異なる国からリクエストがある場合、言語ごとにキャッシュを切り替える必要があるため、単にIPアドレスを元にハッシュを生成するのは良くない。
コンシステントハッシュ関数
ノードの数を増やすと再シャーディングする必要がある。このとき、シンプルなハッシュ関数だと再シャーディングのコストが高くなる可能性があるが、コンシステントハッシュ関数を使うと効率的に再シャーディングできる。
7章 スキャッタ・ギャザー
バックエンド内で、複数のノードを使って処理を分散させて高速化させるパターン。ただし複数のノードを使うことによるデメリットもある。
- ノードごとのオーバヘッドがあるので、並列性を上げても必ずしも処理速度が上がるとは限らない
- 落ちこぼれ問題(一部のノードでレスポンスが遅くなって全体のレスポンスが遅くなる問題)のため、並列度を上げても処理速度が上がるとは限らない。
- 一つのノードで障害が起こると全体が止まるので、シャーディング毎にレプリカは必須。(バージョンアップを行う際などでノードは必ず止めないといけないタイミングがある。)
9章 オーナーシップの選出
マスタの選出の実装は困難なため、 etcdやApache ZooKeeper、Consulなどのコンセンサスアルゴリズムを利用する。
第Ⅲ部 バッチ処理パターン
Apache Kafkaを使ったPub/Subのパターンや、MapReduceフレームワークでの協調する手法が紹介されていた。
分散システムデザインパターン ―コンテナを使ったスケーラブルなサービスの設計
- 作者: Brendan Burns,松浦隼人
- 出版社/メーカー: オライリージャパン
- 発売日: 2019/04/20
- メディア: 単行本(ソフトカバー)
- この商品を含むブログを見る
「SQL実践入門」を読んだ
SQL実践入門──高速でわかりやすいクエリの書き方 (WEB+DB PRESS plus)
- 作者: ミック
- 出版社/メーカー: 技術評論社
- 発売日: 2015/04/11
- メディア: 単行本(ソフトカバー)
- この商品を含むブログ (7件) を見る
目的、モチベーション
- パフォーマンス改善する際に考える材料として、実行計画周りの原理を理解したい
全体の感想
実行計画周りは思ってたより記載されていなかったです。
WINDOW関数などについても言及されており、効率的なSQLを学びたい初心者と中級者の間ぐらいの方にはオススメです。
メモ
効率的なSQLの書き方もたくさん記載されていましたが、あくまでも原理を理解することが今回は目的だったため、割愛してます。
第1章 DBMSのアーキテクチャ──この世にただ飯はあるか
1.1 DBMSのアーキテクチャ概要
- クエリ評価エンジン
- SQLを解釈して実行計画を行う
- バッファマネージャ
- メモリ領域の使い方を管理する
- ディスク容量マネージャ
- 永続的にデータを保存できるように管理し、読み込みや書き込みを制御する
- トランザクションマネージャとロックマネージャ
- リカバリマネージャ
- バックアップやリカバリの制御
1.2 DBMSとバッファ
I/Oアクセスを避けて、いかにメモリ上で処理を行うかが、パフォーマンス改善においてはキーになる。
1.3 DBMSと実行計画
データへのアクセス方法はどう決まるのか
- パーサ(parser)
- オプティマイザ(optimizer)
- インデックス、データの分散や偏り度合い、DBMSの内部パラメータなどの条件から実行計画を作成して、それらのコストを計算して、実行計画を決定する
- カタログマネージャ(catalog manager)
- テーブルやインデックスの統計情報をオプティマイザに提供する
- 遅延が発生すると適切な計画が練れない一方で更新コストも高いため、適切な設定が重要
- プラン評価(plan evaluation)
第3章 SQLにおける条件分岐──文から式へ
3.1 UNIONを使った冗長な表現
UNIONを使うのは、条件分岐という手続き型の発想から脱していないことに原因があることが多い。
SELECT中のCASEで分岐したほうがテーブルのスキャン回数が減るのでパフォーマンスがよい。
3.3 それでもUNIONが必要なのです
CASEによってINDEXスキャンができなくなるときなどは、UNIONを使ったほうがパフォーマンスが良いケースがある。
第6章 結合──結合を制する者はSQLを制す
6.2 結合のアルゴリズムとパフォーマンス
Nested Loops
駆動表とするテーブルを1行ずるループしながら、もう一方の内部表となるテーブルをスキャンして結合条件に合致するものを検索する方法。
アクセスされる行数は、レコード数の積になる。
内部表の結合キーの列にインデックスが存在すると、ループがスキップできるようになりパフォーマンスが改善される。
このとき、内部表が大きい方がスキップされる行数が多くなり、よりパフォーマンスが良くなることが期待できる。
Hash
小さいテーブルからメモリ上でハッシュテーブルをつくり、もう一つの大きいテーブルをスキャンしてハッシュ値が存在するか調べる。
メモリ内に収まらないとTEMP落ちが発生してパフォーマンスが悪化するので注意。
Sort Merge
対象テーブルをソートして、一致する結合キーがあれば結果に含める。
そのため、片方のテーブルのみハッシュテーブルをつくるHashよりもメモリを消費する。
INDEXなどでソートしなくて良い場合には時間とリソースを節約できるため有効だが、基本的には上述の他のアルゴリズムが優先となる。
6.3 結合が遅いなと感じたら
ケース別の最適な結合アルゴリズム
種類 | メリット | デメリット |
---|---|---|
Nested Loops | ||
Hash | ||
Sort Merge |
そもそも実行計画の制御は可能なのか?
MySQLは結合アルゴリズムがNested Loops系しかない。
揺れるよ揺れる,実行計画は揺れるよ
データ量が変更されることで実行計画が変化され、急にパフォーマンスが悪化することがある。
WINDOW関数や非正規化などで、結合をなるべく避ける。
第10章 インデックスを使いこなす──秀才の弱点
10.4 インデックスが使用できない場合どう対処するか
インデックスオンリースキャンによる対処
通常ならテーブルのフルスキャンが発生するようなケースにおいても、選択した列を網羅するINDEXを貼ることで、テーブルスキャンを避けることができる手法。
CREATE INDEX IdAndName ON users (id, name); SELECT id, name from users;
次のアクション
思ったより深ぼれなかったので、SQLパフォーマンス詳解あたりを読んでみようと思います。
SQL実践入門──高速でわかりやすいクエリの書き方 (WEB+DB PRESS plus)
- 作者: ミック
- 出版社/メーカー: 技術評論社
- 発売日: 2015/04/11
- メディア: 単行本(ソフトカバー)
- この商品を含むブログ (7件) を見る
Rubyスタイルガイドを読んだ
RoboCopのRubyスタイルガイドからforkされたスタイルガイドを発見しました。
結構前からあるみたいなので、今更感はあります。。
CookpadやMoneyforward、Airbnbなど色んな企業のコーディングスタイルガイドがありますが、
それらと比べて、細かくボリュームもありブレもなくなりそうで良さそうに思いました。
また、宗教戦争が起こりそうなところは、どちらもアリでプロジェクトの中での決めが重要というスタンスなのも良いなと思いました。
いくつか知らないものもあったので、メモ代わりにまとめます。
&&=
ruby-style-guide/README.ja.md at japanese · fortissimo1997/ruby-style-guide · GitHub
# bad if something something = something.downcase end # bad something = something ? something.downcase : nil # ok something = something.downcase if something # good something = something && something.downcase # better something &&= something.downcase
使ったことなかったですが、somethingのnilチェックがスマートに行えます。
Array#reverse_each
ruby-style-guide/README.ja.md at japanese · fortissimo1997/ruby-style-guide · GitHub
# bad array.reverse.each { ... } # good array.reverse_each { ... }
パフォーマンスが良いそうです。
Exceptionのメッセージ
ruby-style-guide/README.ja.md at japanese · fortissimo1997/ruby-style-guide · GitHub
# bad raise SomeException.new('message') # `raise SomeException.new('message'), backtrace`とする書き方が存在しないことに注意しましょう。 # good raise SomeException, 'message' # `raise SomeException, 'message', backtrace`の用法と一貫性があります
Kernel#raise
は下記のように2つの呼び方があり、後者に統一しようとのことのようです。
# [https://docs.ruby-lang.org/ja/2.6.0/method/Kernel/m/raise.html:title]参照 raise(message) -> () raise(error_type, message = nil, backtrace = caller(0)) -> ()
Hash#values_at
ruby-style-guide/README.ja.md at japanese · fortissimo1997/ruby-style-guide · GitHub
# bad email = data['email'] username = data['nickname'] # good email, username = data.values_at('email', 'nickname')
Hashから複数の値を取り出す際には、 values_at
を使った方がスマートに書けます。
Object#__send__
メソッド名の衝突を避けるために、 send
よりも __send__
を使った方がよいというルールです。
例えばEmailクラスで独自のsendメソッドを定義した際に、衝突を回避できます。
(そもそもあまり send
使いたくないですが。)