SRE NEXT 2024 参加してきた
8/2, 8/3 に行われていた SRE NEXT 2024 に参加してきたのでそれの感想など。
SRE NEXT 2024 について
SRE NEXT は今年で 4 回目の SRE に関するイベントで、同じく SRE に関する勉強会の SRE Lounge が中心なって開催している。
自分はこれが 2 回目の参加で、最後の参加は 2022 の回。動画のみ視聴だったせいかあまり記憶に残っていない。 今回は久しぶりに現地参加ということもあってか結構影響を受けることができたのではないかと思う。
参加したセッション
Reliable Systems through Platform Engineering
キーノートではSRE を導入するにはどこから始めるか、またどのような指標を持つべきか、という話がメインだった。
印象的だったのは最初に提示された「99.99 を 99.9 の上に達成することができるか」というお題。 最初にはできないと考えてたが、提示されたように RAID のことなどを考えると確かに達成できるなという感想だった。
どこから SRE 始めるかとして次の順序でやるとよいと紹介されていた:
- SLO,エラーバジェットを可視化
- 振り返り
- 定期的な振り返りのレビュー
- リスク評価と優先順位付け
- 信頼度のためのバックログ作成
ここらへん自分の組織でどの程度できているかな? SLO のダッシュボードはあるが、それが活用できているかはあやしい。 そもそも開発チーム側からフィードバックはあまりない気もする。
またDORA 指標を紹介していた。
- 速度に関する指標
- Deploy 頻度
- 変更にかかる時間
- 安定性に関する指標
- 変更失敗率
- 復旧にかかる時間
この指標はあまり意識していなかった。こういうのも意識するべきか。
工学としてのSRE再訪
このセッションは工学的あるいは学術的な見地から SRE をどのように扱うかという話だった。
論文をさがしてみるか、という気になったのでこのセッションはかなり感謝がある。
また印象にのこった言葉として書籍からの引用であるが「ウェブオペレーションは技芸であって科学ではない」というのがあった。 実際自分としても一部の指標を勘と経験、度胸(よくいう KKD)で決めることもあるので、なるべく「科学」側に倒したいというのはあったりする。
工学からの貢献として以下のものが紹介されていた。
- 信頼性の予算化(=エラーバジェット?)
- オブザーバビリティ
- 開発生産性の指標
- 開発組織の設計
このあたりのアイディアが工学から来ているのはちょっと以外だった。
また工学から見た SRE のオープンチャレンジとしてつぎの問題が挙げられた。
- オオカミ少年アラート問題
- トレースデータがほとんど参照されない問題
- インシデント対応の改善がなかなかできない問題
- インシデント対応がソフトウェアで扱えていない問題
ココらへんは SRE あるあるという感じである。
いくつか論文も紹介されていたのでこれから目をとおしていきたいところだが、 まず SREcon に目を通すといいらしい。
おすすめされていたトピックはつぎのようなもの:
- Gray Failure
- Cross-system interaction Failures
- A policical Scientist's Insights
- "Only Complexity Can Reduce Complexity"
- Measuring Reliability Culture
- Irones of Automation
- 人間を排除して自動化するほど、人間に高度なスキルを要求する皮肉
- また自動化システムが人間の能力不足を隠蔽してしまう新しい皮肉
- Process Feeling
- Controlling the Costs of Coordination
DevSecOpsの内回りと外回りで考える持続可能なセキュリティ対策
セキュリティ対策の話。 ここでの内回りはShift Left 戦略で、一方外回りは運用でのセキュリティ対応している。
比較すると、内回りは低負担・非網羅的、外回りは網羅的だが高負担となる。 連携としてはまず外回りからはじめてある程度落ち着いたら内回りに着手というのがよいとこのこと。
宇宙科学研究所の探査機運用システムにおけるSREのプラクティスの導入と月着陸実証機SLIMでの利用
Isas/Jaxa で、探索機運用システムや月着陸時のモニタリングに SRE のプラクティスを導入したという話。
Grafana の見慣れた画面で宇宙船のモニタリングをしているのには素直に驚いた。
この手の組織に Grafana とか OSS を導入するにはやはりそこそこ苦労があったっぽい。
オブザーバビリティのマクロからミクロまで〜あるいはなぜ技術書を翻訳するのか
SLO はボトムアップで設定するか?トップダウンで設定するか? => ユーザに近い方 = トップダウンのほうが良い
マクロレベルではラムズフェルドの4象でいう unkonwn-unkonwn を減らすことが重要。 マクロレベルのオブザーバビリティでは複数のコンポーネントとの関係性、他のシグナルとの関連付け、また長期的な観点で分析可能であることが必要となり次のようなシグナルが重要になる:
- 分散トレース
- メトリクス
- ログ
- 継続的プロファイル
一方ミクロ側では確実に信頼性を担保したい。つまり known-known を確実にして、knwon-unknown を減らしたい。
そこで TFBO フロー(test -> fix -> benchmark -> optimiazaiton) が重要となる。
またミクロレベルでも SLO が必要( RAER (Resource-Aware Efficiency Requirements) といったもの)
ところで詳解システム・パフォーマンスでタイムスケールと紹介されいたものが、効率的な Go ではナプキン計算と紹介されているらしい。 どういう経緯でそうなったのかわからん。
のようにおおよそのコストを把握するのも重要。
SLO を満たせなくなったら
SLO を満たせなくなったらどうするか?
対応例:
- カナリアリリース
- マルチリージョン化
- SLO の見直し
やるべきなのは
- incident を理解する
- ポストモーテム
- リスク分析
incident の影響については次の指標を使うのが役に立つ:
- ETTD = Estimated Time To Detection
- ETTR = Estimated Time To Resolution
- ETTF = Estimated Time To Failure
また障害時に対応できる playbook を作っておくのが理想
徹底的な自動化とトイルの撲滅で実現する効率的なSREの実践例
mixi の SRE は embedded + central の形式
対象は webサイトで、運用方針として少人数のため徹底的に自動化、割り切りができる。
実践していること
- Iac (Teffafrom + in house tool)
- モジュール化、テンプレート化
- モノレポ
- CI/CD 効率化
- 脆弱性対応
- モニタリング・アラート
- 障害対応
500万人が利用する「友達と遊べるたまり場アプリ パラレル」におけるデータベース基盤の継続的改善
パラレルでの構成は CLB -> Rails -> Sidekiq -> CloudSQL という流れ。
サーキットブレーカーのテスト -> toxiproxy コネクションプーリングプロキシ -> vitess
SREの技術トレンド2024
このセッションは公開の予定はないのであんまり詳しく書かないほうがいいのかな?
話題として LLM の話が多かった。
SRE における LLM の活用例として障害対応の slack スレッドを AI に要約させるというのがあった。 これにより後から参加する人も障害の対応状況に追いつきやすくなる利点がある。 (これは試してみたい
また LLM は要約、分類が得意なので、ポストモーテムやラベリング、将来的には障害対応訓練などに使えるかもしれないという話があった。 ただやはり LLM をワークフローに組み込めないといいサービスができないのではという話もされていた。
他の話題として:
- SRE のトレンドを追いかけるなら SREcon America をみるとよい
- SRE のトレンドとして incident management 関連の話が多い
- 分散トレーシングはゴミ
という話があった。 あと SRE のプラクティスがサービス化されるなら将来的に今の職は危ないのかも。
敵対的SRE: 300個のジョブをAIチーム全員で支える技術
AI を提供する企業での大量かつ重さもそれぞれな学習ジョブが走っている環境で SRE を導入した話。
ここでの「敵対的」は GAN からの流用で SRE と AIチームとのフィードバックループのこと。
単純なアラートから、詳細化、スロージョブを検出するための SLO の設定、ジョブの軽重による SLO の適用方法変更をフィードバックループをまわして適用していったとこのこと。
まとめとしてはチームと SRE が互いに学習しながら成長するのが良く、一方的に設定するのはアンチパターンである。
個人的な感想
感想としては SRE 一般のトピックが多かった印象で、あまり個別の技術要素についてはふれられていなかったかもしれない。 これは社内の情報になるのでパブリックに出せないのも仕方ないのかも。
また現在コスト関連の作業をしているのでそのあたりの話も聞きたかったが全然話題になってなかった。 これはどちらかというと AWS 関連の勉強会で話題になることなのでしかたないかもしれない。
その他:
- 会場に wifi がなかったのでメモを取るのに苦労した。
- 久しぶりの現地参加というのもあるが、メモをとる環境がイマイチできていない気がする。
個人的な TODO
- 論文探してみる
- SRECon 2024 の発表に目を通してみる
boost::outcome::result
ここ最近仕事で C++ を書くことになってそこで困った話。
経緯として、C++ で例外を投げたくないので関数型言語の Either みたいな直和型が欲しいとぼやいていたら、
https://twitter.com/cpp_akira さんから boost::outcome
というのがあると教えていただいた。
これは良さそう!ということで早速試してみたのだが、ドキュメントを見ながらコードに落としてみてもどうにもビルドできない。 ドキュメントにあるコードをビルドしてみても同じようなエラーになってしまう。
prog.cc:68:12: error: no viable conversion from returned value of type 'ConversionErrc' to function return type 'outcome::result<int>' (aka 'basic_result<int, boost::system::error_code, boost::outcome_v2::policy::error_code_throw_as_system_error<int, boost::system::error_code, void> >') return ConversionErrc::EmptyString;
ドキュメントにあったとおりオレオレエラーコードの std::error_code
への変換を行う処理も書いたのになんで?と一晩ぐらい悩んだ。
で、ふと boost には boost::systemm::error_code
というのがあるのを知ったので、もしかしてと思いオレオレエラーコードの変換先をこちらにしてみた。
やはりというかそれで動いてしまった。
おそらくドキュメントがoutcome
のboost
入り前で更新が止まっているらしく、std::error_code
とある部分は boost::system::error_code
に読み替えないといけないらしい。
ということでなんとか解決はできたが疑問が残る。仕事で C++ を使うのはこれが初めてなんだが、Boostライブラリの使用時には std
にあるものよりも boost
にあるものを優先して使うのがお約束だったりするんだろうか?そうでもないと自分と同じ問題にあたっている人が全然いないように思える。
AtCoder Panasonic 2020
祝水色。
まだまだレーティングを上げる余地はありそうだ。
ただし青以上のパフォーマンスは一度も取っていないので、青になるためにはかなり精進が必要っぽい。
まず 5 完を安定してとれるようにならないといけないか。
A
配列を問題文からのコピペでつくって出力するだけ。
B
1 WA だしてしまった。
基本的に h * w / 2 で、h * w が奇数なら +1でよい。
しかし、h か w が 1 の場合は例外になるのでこれを考慮する必要があった。
C
4 WA だしてしまった。
精度の問題にはしたくないので式変形して (c - a - b)2 > 4ab の形にもっていく。
なんで WA 食らったかというと、c - a - b < 0 の場合を見落としていたから。
若干パニックになって必要のないところをいじってまた WA くらったりしてた。
D
全ての並び替えを出す要領で、1 文字目は{a}、2 文字目は {a,b}、3 文字目は {a,b,c} という感じの組み合わせを全列挙する。
このままでは条件に合わない組み合わせが含まれるので、一文字飛ばして新しい文字が出現するようなものはフィルタアウトする。
たとえば "aac" は 'b' を飛ばして 'c' が出現しているが、これは辞書順で出現済みなはずの "aab" が同値なので外さないといけない。
たぶんもっとスマートな方法があるとは思う。
ちなみに WA は入力を読み込み忘れたまま提出してしまったため。粗忽だ。
E
解法が思いつかず総当りっぽく解こうとしたが無事 TLE。
解説みるとやっぱり総当りだったが、自分の実装より時間がかからずになっていたのでまあそうなるか。
AtCoder Beginner Contest 157
今回は A から E までの 5 完。わりと調子良かった。
入水できるんじゃないかなと期待もしたが、思っていたよりレーティングは上がらなかった。 もう 2 回位は水パフォーマンスが必要そう。
A
n を 2 で割ったものに、n が奇数ならさらに 1 加算する。
B
愚直に 3x3 の2次元配列を作って、それがビンゴの条件を満たしているか確認する。
ちょっと実装がめんどいぐらい。
C
調べればいい範囲がたかだか 1000 以下だったので、総当りで条件にあっているものを探す。
こっちも愚直な実装になった。
D
Union Find 木を使って、グループ分けをする。
その後 1 から N までについて、グループのサイズから「直接の友人関係にある人数」と「グループ内でブロックしている人数」、「自分自身」の数を引く。 Union Find 木のテンプレートを持ってなかったので0から実装したがなんとか間に合った。テンプレ実装は用意しておいたほうが良さそう。
なお、自分はこれよりも E を先に解いていた。他にも同じような判断をした人はそこそこいるっぽい。
E
競技プログラミングでよくある発想の転換が要求される問題だと思う。
最初に考えた 2 個目のコマンドの「l 文字目から r 文字目までで含まれる文字種のカウント」は、愚直にやっていたら計算量が大きくなりそう。
最悪の場合は N x Q で 1010 かかるので、時間内に終わらないと判断した。
考えを変えて、ある文字が「l 文字目から r 文字目までで含まれる」かどうかを 26 回高速に判定できれば良さそう、と考えた。
なので 26 個アルファベットごとに std::set<ll>
を用意して、出現位置を入れておく。
コマンド 1 は set
への追加と削除で済ませて、コマンド 2 の方は l より大きい出現位置を lower_bound
でとってそれが r 以下なら条件を満たすとしてそれぞれカウントすればよい。
int main() { ll n; cin >> n; string s; cin >> s; vector<set<ll>> d(26, set<ll>()); for (ll i = 0; i < n ; ++i) { int c = s[i] - 'a'; d[c].insert(i+1); } ll m; cin >> m; for (ll j = 0; j < m; ++j) { int com; cin >> com; if (com == 1) { ll i; int idx; char c; cin >> i >> c; idx = c - 'a'; for (ll k = 0; k < 26; ++k) { d[k].erase(i); } d[idx].insert(i); } else { ll left, right; cin >> left >> right; ll count = 0; for (ll k = 0; k < 26; ++k) { auto iter = d[k].lower_bound(left); if (iter != d[k].end() && *iter <= right) { ++count; } } cout << count << endl; } } }
Object Oriented Conference 2020 参加してきたメモ
2/16 に行われた Object Oriented Conference に参加してきた。
OOC は名前の通り、「オブジェクト指向」についてのカンファレンス。 セッションは大小 34 あり、設計やアーキテクチャの話が多かったし、DDD も結構テーマに上げられてた。 CfP 倍率は 3 倍程度で結構応募があったらしい。
全体的には、キーノートでも言われていたが、多様性により OO といっても立場や考えが色々異なる視点からの話が聞けた。
以下聞いてきたセッションの話。
キーノート Object Oriented Diversity
OOC keynote: Object Oriented Diversity - Speaker Deck
OO が様々な意味を持つようになってしまい、 同じ OO の話をしていても行き違いが発生しやすくなってしまった。 ということで OO について話すときには「コンテキスト」を意識しましょうという話だった。
実際 OOP にしてもメッセージパッシングのことを OO と言っていたり、抽象データ型を使うことを OO と言ったりもするので、文脈を共有するのは大事そう。
DDD はオブジェクト指向言語でどのようにメンテナンス可能なコードを書くか
DDDはオブジェクト指向を利用してどのようにメンテナブルなコードを書くか
DDD の話。
- モデリングが重要
- {ドメインエキスパートからの知識 → モデルに反映 → 運用からのフィードバック}の改善ループが重要
- モデルの継続的な改善のためにも高い拡張性が必要
- 軽量 DDD でベストプラクティスを取り入れるのでも効果はある。そこからモデリングに進むと良い
DDD を導入する際にはお手本となるコードを作ってから、それを参考にして残りをつくる、というやり方がおすすめ
モデリング手法
- 決まった方法はない
- よく使われるのは
- RDRA2.0
- ユースケース駆動分析設計
ユースケース駆動のポイントとしては:
- ユースケース図
- ユースケースの具体化・言語化
- ドメインモデル図作成の範囲を狭める
- ドメインモデル図
- メソッド不要・属性も代表的なものだけ
- 業務の「ルール・制約」=ドメイン知識を引き出しで記述する - 集約の範囲を明記すると良い
紹介されていた DomainLanguage.com https://domainlanguage.com/ はよくまとまっているし参考にしたい
数理的システム設計
ソフトウェアシステム設計における アレグザンダー理論の活用 数理的システム設計手法の提案 #agileto2019 - Speaker Deck
アーキテクチャ設計の話だが、ちょっとついていけなかった。
自分もアレキザンダーの本とかやっぱりちょっとは目を通してみるべきかも。
アジャイル時代のモデリング 平鍋健児
アジャイルでのモデリングの話。手法というよりもどうモデリングを続けていくかのプラクティスの話か。
紹介されていたアイディアとしては、モデルを作成した際に出来る図・資料を保存するもの = KEEPS とすぐ破棄するもの = TEMPS に分けると良いとのこと。
KEEPS にするものは価値を生み出すもの:
TEMPS にするものはほとんど価値を産まないもの: - カジュアルモデリングの成果物 - クラス図、シーケンスダイアグラムなど
他に Impact Mapping というモデリング手法や C4 Model というものが紹介されていた。
「モジュールとしてのマイクロサービス」と「分割単位としてのドメイン」について考える
「モジュールとしてのマイクロサービス」と 「分割単位としてのドメイン」について考える - Speaker Deck
システムをどのように分割するかの話。
- 複雑なものは分けて考える
- 重要な設計要素は、モジュール性とビジネスの関心事
- 人間のコミュニケーションを阻害しないようにシステムとチームを構成する
- 分散システムの難易度などの落とし穴に注意
- モノリスが常に不利益を生むわけではない
- モジュラモノリスという内部的に分割を行うパターンも採用例がある
- MSA していてもフロントエンドがモノリス化してしまうことが多々ある
- フロントエンドもモジュラモノリスにするとよい
オブジェクト思考プログラミングの過去・現在・未来
OOP とはなにか?に対しては「データの抽象化」がそれに当たるという主張。 データ抽象により、語彙(ユビキタス言語か)、自己文書化、関心事の分離などできる。
後半は OOP の歴史の話。
黎明期から始まり、型を軽視や怪しげな例え話などによる混乱があったが、現在はその混乱が収束しつつある。
型がない言語で OOP できっこない、という話があったが、個人的にはちょっと反対したい。
AtCoder Beginner Contest 156
今回は A から D まで。ランクは少し上がった。
今回の問題では、組み合わせを高速に計算する手法は学習済みだったのが役に立った。
E は考え方は合っていたが時間がなくてコンテスト期間中に回答が間に合わなかったので悔しい思いをすることになってしまった(後日 AC 済み)。
特に「 r 個を n 部屋に 1 つ個以上ずつ分ける」というのがとっさに出てこなかったのが痛い。
ところで、E では k が 1 の場合には「すべての部屋に1個ずつある状態」が実現できないんじゃないかと思ったんだが、解説でも触れられてないし他の人のブログ記事でも触れているものがない。
そういうようにコードをいじっても AC になるのでなんかちょっとモヤモヤするなあ。
(追記) よく見たら問題分の方で k は 2 以上になっていた。問題文を微妙に見落としているのは良くない。
Go の名前付き返り値
Go の名前付き返り値の扱いでちょっと迷ったのでメモ。
名前付き返り値を使うとローカル変数扱いにされるとはわかっていた。
return
文で新しいインスタンスを作って返した場合もちゃんとケアされるか不安だった。
仕様見ても明記されている箇所が見つけられずよくわからんかったし。
で下のようなコードで確認してみると杞憂だったのがわかった。よかったね。
どうもreturn
文の時点で名前付き返り値に代入されるようなイメージで良いらしい。
package main import ( "errors" "fmt" ) func f1() (err error) { return errors.New("hoge") } func f2() (err error) { defer func(){ err = errors.New("huga") }() return errors.New("hoge") } func f3() (err error) { defer func(){ err = errors.New("huga") }() err = errors.New("hoge") return err } func main() { fmt.Println("Hello, playground") fmt.Printf("f1: %v\n", f1()) // hoge fmt.Printf("f2: %v\n", f2()) // huga fmt.Printf("f3: %v\n", f3()) // huga }