振り返り
長らくブログを書いていなかったので、メモがてら勝手に振り返りを書こうと思います。 自分は金融系SaaSのSREとして活動していました。 platformかreliabilityかでいうとreliabilityのSREで活動していました。 所属チームは主に信頼性の階層の部分の根っこの部分、信頼性と観測性の部分を担当しSRE practiceを開発チームに移譲するために活動するチームでした。 具体的にはアラートの改善活動、SLI/SLOの普及活動、アラート対応効率化 etc ... みたいな感じです。 また所属会社はkubernetesをベースとした基盤を構築しておりkubernetesのpodのライトサイジング、HPAの調整などをサブタスクとして行ってました。 また、datadogは頻繁に活用しており、それなりに使いこなせるなと実感してます。最近だとworkflow automationを頻繁に活用してアラート通知の刷新を行いました。
そんなSREとしての活動をまとめます。だいたい2年くらい活動したかな。
1年目 - 2 年目になるまで
入社してから半年くらい
SREとして入社しました。自分はジュニアで経験が浅く入社して、周りの方々のレベルの高さにびっくりしました。そんな中でSREのガバナンスチームに一時配属となりました。 当時はAWSのマルチアカウント戦略を行うぞ!ということになり、AWS Control towerを検証したり、terraformコードでアカウントを作れるようにしたり(AWSがOSSで提供しているが名前は忘れた)してました。 それと同時にモノレポで管理されているterraform projectのリファクタリングタスクに取り組みました。 課題としては環境単位でterraform stateが分かれていないという問題がありました。そのterraform projectをいい感じにstateを分けるための設計を行いました。 理想的には環境とライトな粒度でstateをわけ、依存関係がはっきりしている構成であるべきだと思うのですが、ライトな粒度を提案することができず、環境単位でstateを分けることになりました。 今考えれば、妥協点を見つけてどのように移行していくかまで明確に各メンバーに提示しなければならなかったなと反省です。 この設計がひと段落したタイミングで現チームに移りました。
現チームに移って
現チームは開発チームがSREを実践できるを掲げるチームで開発チーム内でSRE的に困ったら一緒に解決していこうぜ!というチームでした。なので当時差し込みが結構多かったなと思います。 スプリントでタスクをこなしてましたが、差し込みが多くスプリントタスクが消化できないこともありました。 結構自分達のやりたいタスクに時間が避けていなかった部分は問題でした。問題は問い合わせ窓口が一元化していな状態だったのが不味かったのかなと思いました。 窓口が一元化できていなかったために、いろんなslack chでメンションされて対応するみたいな感じでした。 これもSRE全体で差し込み対応する流れとなり、対応窓口を設置することで一定の負荷は軽減できたかなと思います。(仕組み化してくれたマネージャに感謝です) これはチームトポロジ本でも記述されていた気がしますが、対応窓口は必ず作ったほうがいいです。必ずキャパオーバーになります。
現チームで活動していく中で、自分のモヤモヤ点としては自分はインフラの構築は受託会社や副業で行っていたものの運用という側面の経験が圧倒的に足りてなかったです。 そのため自分自身の武器をつけなければと言う思いで差し込みでもkubernetes周りのpodライトサイジングやHPAの調整などのタスクを積極的に取っていたのを思い出します。 そのおかげかkubernetesのPodのライトサイジングやHPA調整が自分自身でこなせるようになってきました。また開発組織でそのような相談にも助言や伴奏しながら調整ができるようになりました。
SREの姿勢的なところでいうと、マネージャーの存在は本当に大きかった。マネージャーをロールモデルにして成長に励んでいたように感じます。kubernetesとかdatadogとかその辺の力をつけた感じなのもマネージャーの追いかけたからこそかなと思います。
2年と4ヶ月くらい
現チームの方向性を固めようという方針になり自分達のdomain領域を固めようという方針となりました。朧げに自分達のチームはreliabilityに関係するチームだよねという意識はあったものの、色々手を出していたのでdaminを定めることは良い転換期だったと思います。 そんな中でもSLI/SLOとアラート対応の効率化という2つのテーマを掲げOKRを設定しました。自分はアラート対応効率化にオーナーを持つことになりました。実はこれまでkubernetes周りのタスクを取っていたので結構これらの項目はおろそかになっていました。 現状の課題は把握しつつ、アラート対応ってどうあるべきなのかとか通知先ってどうあるべきなのかとかが自分の中で言語化できなかったと思います。そんな中でテーマーメンバー(同じオーナー)は以前からアラート通知周りのタスクを取っており、色々背景やら、現状の方針の確認やら色々聞きまくったと記憶があります。本当に感謝です。 課題としては各マイクロサービスのアラート通知先が単一のchに流れていてアラート対応者の属人化や過去対応スピードの遅延による障害発生などがありました。これらに対処すべく適切なチャンネルにアラート通知が行えるようになるように活動しました。 具体的にdatadogのmonitorをterraformで管理しているのでいい感じしないといけなかったです。ここでmoduleにして各マイクロサービスに関係するディレクトリで管理すればええやんとなりますが、それではうまくいかなかったです。理由としては共通的に関しているmonitorの数が多くそれを1packで管理するmoduleを作成しようとするとparameter設計や再通知設定など考えることが多くmodule化できなかったです。ではmoduleのスコープを小分けにすればええやんとなりますがprivate、public moduleにせよ数が増えるのと、複雑性が増し保守しにくいと考えgo!とはならなかったです。そんなかマネージャーがdatadog workflow automationを提案してくれました。workflow automationを活用することでalert通知のハンドリング、理想の通知先や要件に応じた通知など、値とロジックを一箇所にまとめることができると感じ一気にmoduleからworkflow automationに舵を切りました。workflow automationはリリースされたばかりのサービスだったのでキャッチアップからやらないといけませんでした。その時、今Qがあと1ヶ月で終わる感じでした。これはやばい、未達は死、という思いから同じチームメンバーとworkflow automationの通知設計を書き上げ一気に実装しました。最終的には自分が死ぬ気でほぼ実装しました。我ながらいいものができたと思いました。(この後リファクタリングが始まる...) workflow automationを使うにあたって、ここがこうなら・・みたいなところがありdatadog に featureリクエスト投げまくっていたのを思い出します。workflow automationを育てたのは我々だと感じてます。(ただの奢り) またこの一件からなんでもサポート起票するようになり一皮剥けました。(いいのか悪いのかはさておき) ここら辺の経験もあり、担当テーマの長期的なロードマップにも関心が向き長期ロードマップの策定、タスクへの落とし込みなど長い視点で物事を考えないといけないと思いました。(AIの波のあるし)
2年と4ヶ月から現在
以前より自分は顧客の近いところでSRE practiceを実践したい思いがありました。このことから、効果的にSRE practiceを実践するにはどうしたら良いかそれを知るために、開発チームに留学に行くことになりました。 自分はPMがどんな感じで開発チームと関わっているかわかってなかったし、どんな感じでスプリントを回して開発アイテムを消化していくかみたいなところがイメージが湧いていなかったです。(リリースがどうたかも) 実際に開発チームに入って開発してみると色々学びは深かったです。特にSREに関することがかなり学びが深かったです。 今回の留学ではSRE practiceを実践するというよりは、開発を知り課題を洗い出すというのがメインテーマでした。留学先の開発チームはSRE practiceが全然浸透していないチームでした。チームのマネージャーも課題は認識しつつSRE practiceはどう実践したら良いかわからない状態でした。 もちろんSRE的に気になるポイントはチーム内で共有したり、改善タスクとしてチケット化などは行なっていました。 そんなか信頼性を維持するために必要な監視がほぼできていないことが判明し急遽SREグループを立ち上げることいなりました。 自分も 0 -> 1を経験したことがなかったので、最初戸惑いました。開発チームのマネージャーのサポートもあり進めていくことができました。 自分が着目したのはやはり、信頼性の階層でした。最下層で何ができて何ができていないかを洗い出しメンバーと一緒に対応することになりました。 ここで自分が徹していたのは、留学期間後自分がいなくなることを想定しポイントポイントで助言はするもののサポートに徹することを貫いてました。また自分が手を動かすのではなくメンバーに手を動かしてもらうようにしました。特にdataodogの技術移譲という文脈において、メンバーがドライバーになりダッシュボード作成、モニター作成などを一緒に行えたことはよかったです。一緒に手を動かす中で、なぜ監視するのか、SLI/SLOをなぜ設けるのかを伝えながら活動できたことは本当に良かったと思います。エンベデッドする上では、どのように組織にアプローチするか、どのように自分達が持っている技術を委譲するか、どのようにSRE practiceの価値を伝えるかが大切になると実感しました。特にどのように価値を伝えるかが一番大事なような気がします。 残念なことに、自分の留学期間が過ぎてしまい、ピックアップしたpracticeを全て行うことはできなかったですが、どのように進めべきかの方向性は伝えられたので、今のメンバーならやり切ってくれると思います。
これから
自分は顧客の近いところでSREをやっていきたい思いがあります。その為、これからはアプリ開発者としてキャリアチェンジすることになりました。 開発チームでSRE practiceはどうあるべきかを突き詰めて、開発チーム全体でSRE practiceを実践するために活動していきます。
hcl2パッケージでhclを書き換えてみた
こんにちは、完璧にblogを書くことをサボってました。 今回はgolangのhcl2パッケージを用いてaws security group id, subnet-idを直接記述されている部分をdata sourceへ書き直すツールをgolangで実装してみました。
背景
自分が所属している会社ではterraformを用いてaws infra resourceを管理しています。またマイクロサービスを展開しており、モノレポでterraform projectを管理しています。 そのリポジトリは歴史も古く、ところどころsecurity goup idやsubnet idが直接記述されているとこがありました。 これでは実態に依存している状態で良くないと考えています。 例えば、マルチアカウント戦略を取るときににはそのソースコードは元アカウントのリソースに依存している為、汎用性がないと言えるでしょう。 また自分はgolangを触ったことがなく、自己学習を兼ねてリファクタリングツールを作ってみようと思い書いてみました。(完全にはまだ実装できていない)
HCLについて
hclのデータ構造は以下のように分類ができます。
file,body, block, attribute,
file
hclファイルをparseするとfileというdata型に変換される。
fileの内部にはbodyというdataを保持しており、bodyの中にはblock, attributeを持つ。
イメージとしては下記のような感じになる。
マトリョーシカぽい感じだ...
File
└── body
├── attribute
└── block
└── body
├── attribute
└── block
body
file, blockの中身に相当する。
reource "aws_vpc" "main" { // body vpc_id = "" tags { // body } }
block
resouce {} など hoge {}で表す構造体。内部にbodyを持つ
実際のblockは下記のようになるかと思います。
resource "aws_vpc" "main" {} // block locals {} // block variable "hoge" {} //block reource "aws_vpc" "main" { // body tags {} // block } module "hoge" { hoge = {} // これはblockではない }
attribute
attributeは端的に言えば特定の名前が付けられた値である
key = value形式のものをいう
右辺に当たる部分をexpressionと呼びます
resource "aws_vpc" "main" { vpc_id = "" // attribute } // tfvars hoge = "hoge" //attribute module "hoge" { hoge = {} // これもattribute }
ここまでざっくりではありますがhclのデータ構造の説明でした。 hclはfileをrootに持ち、body -> block or attributeというふうにマトリョーシカのようなデータ構造になっている。
HCL2パッケージについて
golangではhclを扱うためにHCL2パッケージを提供しています。用途は主に読み込みと、書き込みであり。読み込みであれば, hclsyntax, gohclといったパッケージを使用することになり、書き込みを行う場合はhclwriteというパッケージを用いることになると思います。
今回はhclファイルのparse, 対象のresource idにマッチしたものを書き換え、書き換えたblock path(data.subnet_groups.hogeといったもの)にマッチしたdata source blockを生成するためhclwriteを用いました。
hclのファイル, 各種dataの読み込み
hclwriteでhclファイルをparseするには下記のように記述します。
file, err := os.ReadFile(path) if err != nil { log.Fatal(err) } hclFile, diags := hclwrite.ParseConfig(file, path, hcl.Pos{}) if diags != nil { log.Fatal(diags) }
上記でhclファイルをparseできたので、fileの中のblockを取得するには下記のようになります
for _, block := range hclFile.Body().Blocks() {}
さらにblockで定義されたattributeの一覧を取得するには下記のようになります。
for _, block := range hclFile.Body().Blocks() { attributes := block.Body().Attributes() }
次にattibutesのexpressionを取得するには下記のようになります
for _, block := range hclFile.Body().Blocks() { attributes := block.Body().Attributes() for _, attribute := range attributes { attibute..Expr() } }
愚直に各データにアクセスするには上記で対応できるかと思います。
特定のattributeにアクセスする、blockにアクセスするなどはhclwriteパッケージには用意されているのでdocを拝見していただければと思います。
subnet, sg idを書き換える
本題のsubnet-id, sg-idを書き換えなんですが, 一覧の流れとしてはresource idを定義したyamlを準備し、それをparseしaws-sdk用いてidに紐付いたreosurce情報を取得、必要dataをトリミングする。トリミング後そのデータを用いてsg-xxxxをdata.aws_security_group.xxx.ids[0]に書き換えを行い、それに相当するhcl構文を生成するという流れになります。
yaml parse後aws-sdkを用いてresource情報を取得
func fetchAwsResource(subnetIds SubnetIds, sgIds SgIds) map[string]string { ctx := context.TODO() cfg, err := config.LoadDefaultConfig(ctx) if err != nil { panic(err) } // clientの生成, aws profile情報を読み込む client := ec2.NewFromConfig(cfg) // sgの取得 groupInputs := ec2.DescribeSecurityGroupsInput{GroupIds: sgIds} //security groupの取得 sgOutput, err := client.DescribeSecurityGroups(ctx, &groupInputs) if err != nil { panic(err) } sgMaps := createSecurityGroups(sgOutput, client, ctx, sgIds) // subnetの取得 subnetOutput, err := client.DescribeSubnets(ctx, &ec2.DescribeSubnetsInput{ SubnetIds: subnetIds, }) if err != nil { panic(err) } subnetMaps := createSubnetGroups(subnetOutput, client, ctx, subnetIds) resourceMaps := mergeMap(sgMaps, subnetMaps) return resourceMaps }
変更対象を検出
変更対象をserchする。
変更対象が見つかったら、下記の戻り値をもとに、その変更対象を構造体として保持する。
// tokenとreplaceAwsResourcesのkeyを比較して一致したらmapに格納し返却する func appendMatchResourceId(attribute *hclwrite.Attribute, replaceAwsResources map[string]string) map[string]string { awsResourceIds := map[string]string{} tokens := attribute.Expr().BuildTokens(nil) for _, token := range tokens { str := string(token.Bytes) for key, resourceId := range replaceAwsResources { //aws resource idとattributeのtokenが一致するか if !strings.Contains(str, resourceId) { continue } awsResourceIds[key] = resourceId } } return awsResourceIds }
変更対象を書き換え
上記で変更対象を割り出して、変更対象のattribute.expressionを書き換えていく。
func (r *Rewrite) writeToken(attributes map[string]*hclwrite.Attribute) { //bodyのattributeを取得しloopで回す for attributeKey, attr := range attributes { // addressにかくのされているattribute名と一致するを確認 if attributeKey == r.Address.GetAttribute() { // attributeのtokenを取得しloopで回す tokens := attr.Expr().BuildTokens(nil) for tokenIndex, token := range tokens { // tokenの文字列を取得 hclToken := string(token.Bytes) // address("data.hoge": "sg-hogehoge" )のlistを取得しloopで回す for key, awsId := range r.Address.GetAwsIds() { // tokenの文字列にaddressの文字列が含まれているか確認 if hclToken == awsId { newLabel := createDataSourceSyntax(hclToken, key, awsId) //対象のaddressと一致するtokenを書き換える frontNodeString := string(tokens[tokenIndex-1].Bytes) backNodeString := string(tokens[tokenIndex+1].Bytes) tokens[tokenIndex].Bytes = []byte(strings.ReplaceAll(hclToken, awsId, newLabel)) tokens[tokenIndex-1].Bytes = []byte(strings.ReplaceAll(frontNodeString, frontNodeString, "")) tokens[tokenIndex+1].Bytes = []byte(strings.ReplaceAll(backNodeString, backNodeString, "")) } } } } } }
書き換え後、それに相当するblockを生成する
書き換えて、書き換えた内容に相当したdatasourceブロックを生成する
地味にhclTokens{}で定義される右辺の内容を理解するのに手こずってしまった。
hclはbuildTokenというdata型に変換でき、tokenに変換することで fileの中身をbyte列で取得することができる。
特定のattributeをtokenに変換できるし、expressionも変換可能である。
もちろん、下記のコード以外にhclパッケージにはattribute, expressionを生成してくれる関数も存在するので、詳しくはdocを参照してみてください。
// datasource blockを作成する func createBlock(hclBody *hclwrite.Body, newLabel, datasource, resourceTagName, vpcString string) { block := hclBody.AppendNewBlock("data", []string{datasource, newLabel}) body := block.Body() vpcFilterBlock := body.AppendNewBlock("filter", []string{}) vpcFilterBody := vpcFilterBlock.Body() vpcFilterBody.SetAttributeValue("name", cty.StringVal("vpc-id")) vpcTokens := hclwrite.Tokens{ { Type: hclsyntax.TokenOBrack, Bytes: []byte{'['}, }, { Type: hclsyntax.TokenIdent, Bytes: []byte(vpcString), }, { Type: hclsyntax.TokenCBrack, Bytes: []byte{']'}, }, } vpcFilterBody.SetAttributeRaw("values", vpcTokens) body.AppendNewline() filterResourceNameBlock := body.AppendNewBlock("filter", []string{}) filterResourceNameBody := filterResourceNameBlock.Body() var filterResourceName hclwrite.Tokens if datasource == aws_subnets { filterResourceNameBody.SetAttributeValue("name", cty.StringVal("tag:Name")) filterResourceName = hclwrite.Tokens{ { Type: hclsyntax.TokenOBrack, Bytes: []byte{'['}, }, { Type: hclsyntax.TokenOQuote, Bytes: []byte(`"`), }, { Type: hclsyntax.TokenIdent, Bytes: []byte(resourceTagName), }, { Type: hclsyntax.TokenCQuote, Bytes: []byte(`"`), }, { Type: hclsyntax.TokenCBrack, Bytes: []byte{']'}, }, } } if datasource == aws_security_groups { filterResourceNameBody.SetAttributeValue("name", cty.StringVal("group-name")) filterResourceName = hclwrite.Tokens{ { Type: hclsyntax.TokenOBrack, Bytes: []byte{'['}, }, { Type: hclsyntax.TokenOQuote, Bytes: []byte(`"`), }, { Type: hclsyntax.TokenIdent, Bytes: []byte(resourceTagName), }, { Type: hclsyntax.TokenCQuote, Bytes: []byte(`"`), }, { Type: hclsyntax.TokenCBrack, Bytes: []byte{']'}, }, } } filterResourceNameBody.SetAttributeRaw("values", filterResourceName) }
断片的ではありますが、以上でhclの特定のexpressionの書き換え、それに相当したdatasourceの生成を行いました。
もちろん上記コードは完全なものではありません。
実際は環境を判別し、それに相当したvpcのdatasouceを生成するコードも存在します。repositoryも社内codeに依存する部分があり公開することができないです。
不完全な内容で簡易的ではありますが、hclの操作例を記述してみました。
SRE本を読んでみた2
こんにちは長い間ブログをサボってました。 色々あってなかなか取り組むことができなかったです。 その話はまた別の機会にでもは書いてみます。
長い間SRE本を読むこともサボっていました。というのも、現在はSREとは少し遠いことをやっていたので、そちらの取り組みを主に行なっていました。(サボり)
また所属会社では来Qからproduct teamへSRE Practiceを注入するためのSREチームへ移動することが決まりまた読まなきゃなっていう気持ちで読み進めています。読んだことをまたアウトプット行きたいと思います
第四章
この章は前章のSLIを設定するがその目標値(SLO)を定め管理するのと、その目標値の測定と評価法を述べている。
SLI(サービスレベル指標)
サービスの信頼性の指標。特に重要にしているのがサービスSLIがリクエストのレイテンシである。もう1つ重要な指標としては可用性である。処理に成功したリクエスト数の比率をもとにすると説明があるが、サービスの特性を考えて、userが何を期待いているのかを加味した上でSLIを設定することが大切なのだと感じた。 サービス特性を考慮しメトリックスを収集するのが望ましいし。また、その値を収集していない場合はいったんそれを収集して観察すること。 ここでメトリクス取集として大切なことは平均値ではなく中央値で取集することらしい。 平均値は突発的な変化をマスクしてしまうので可視性の観点で向いていないためである。
実際のSLIの取り決め方はCUJを割り出して、そのエンドポイントに対してサービスの特性を加味した上で、レイテンシ、可用性、スループットなどを取り決める。あくまでサービスの特性を加味するので、必ずしもレイテンシ、可用性、スループットの指標を導入しない。サービスの特性を考えて取捨選択する。 これらの指標を取り決め、その値を取集する。
SLIはテンプレート化しておくこと、また設定メトリクスごとにテンプレート化しておいくこ方が良い
SLO(サービスレベル目標)
SLIで計測されるサービスレベルのターゲット値あるいはターゲット値の範囲。
SLIに対する目標値。下限 <= SLI <= 上限となる。
本書ではシェークスピア検索の検索リクエストに対する平均レイテンシを100ms以下にするというSLOを紹介されている。
設定したSLOは常に満たし続けることを求めるのは現実的ではない。それを追い求める代償として過剰な保守、リリースのペースが落ちて顧客へ価値提供が遅延されるなどが起こりうる。
大切なのはエラーバジェットを設けて、消費しつずけなければリリースを行い顧客へ価値を届けることが大切。
またSLOの未達比率を示すエラーバジェットを日ごと、週ごとなどに追跡をした方がよく、SLOに関しても同様に観察を行なっていくこと。
SLOは完璧なものでなくて良い。それよりもSLOを定期的に見直して育てていく活動の方が大切。
SRE本読み返して1
こんにちは、季節はもう秋ですね。急に気温が下がって体調不良には気をつけたいです。 データベース設計のことをブログとしてまとめていましたが、僕自身SREエンジニアなので、原点に立ち帰って(というか経験はかなり浅い)SRE本を再度少しづつ読んで自分用にまとめていきたいと思います。
第一章
元来企業にはシスアド(Ops)が存在しており、基本的なサーバーの運用業務などはシスアドが行なっていた。 従来型の企業では開発者と運用担当者で線引きが(ガードレールが引かれていた)行われていた。 開発者はビジネスサイクルを回すために、機能を開発をして変更をリリースしたいが、運用担当者はリリースによる不具合のリスクを下げたい(システムの安定化)を行いたい。こいったことからDev vs Opsの構図が出来上がってしまった。 SREとは運用の側面をソフトウェアの力で負荷を軽減することを目指し定量的判断をもとそのサービスの信頼性を向上めざす言わばプラクティス、動機付けである。
第三章
第二章はgoogleのシステムアーキテクトな話さのでスキップ。 リスクの受容という項目。サービスの100%の信頼性を提供するのは難しいし、現実的ではない。 どんなに優れたサービスアーキテクトで素晴らしいパフォーマンスでも、それ以前のネットワークレイヤーでパケロスをするかもしれないから100%のサービス稼働(信頼性)を行うことは不可能に近い。 それにシステムに100%の稼働といった信頼性を追い求めると、金銭的コストが増大する。 userにとってはネットワークレイヤーの不具合、提供するサービスでの不具合の原因内容の関心ごとは持っていない。それらはuserにとっては包括的にサービスの信頼性と考える。その為100%の信頼性の提供は現実ではない。 また100%の信頼性を追うことに集中すると新機能開発のなどのチャンスを失う可能性がある。よって信頼性とリスク許容はトレードoffなのだ。 信頼性の指標はどうやって表すのか、それはサービスの特性とuserが中心でなくてはならない。 サービスの特性、userが求めるものを加味した上で可用性やレイテンシに関する指標を作成する。 指標の定義は一旦は割愛する。 忘れてはいけないのはその指標を観察するにはuserやサービス特性を忘れてはいけない。なぜなら、userとしてはシステムのcpu使用率やメモリーの消費率は気にしていないというか関心ごとではないからだ。 第三章には明確には話が出てはないが、サービスの指標をSLI(service level indicator)という。そこから目標値(SLO)を定義し、現実のギャップをエラーバジェットとして管理し、信頼性向上の取り組み(パフォーマンス改善)や継続的リリースを推し進めていく。
終わりに
まだまだ続く。。
SLI /SLOの取り決めかた
こんにちは、季節はすっかり秋になってきましたね。 涼しくなり、非常にお酒が美味しい季節になってきました。のんべーにはたまりません。秋刀魚とビール最高です。
立ち話しはここまでにして、タイトル通りなんですが、自分自身SREエンジニアであるものの、経験が浅くSLI/SLOはどうやって取り決めるの??と考えていました。
サービースの信頼性の指標の為にSLI設定し、その指標をもとにSLOを定める。SLOの実際のギャップを埋める為に、エラーバジェットの概念がありますが、どうやってSLI/SLO決めたらいいのと考えてました。
答えは、SRE nextにありました!!!
動画は下記へ掲載しておきます。
さてさて、動画の内容を拝見してみると、前提にCUJが大切であると理解しました。
誰が信頼性があるサイトを決めるのか
システムのメトリクスがサイトの信頼性を取り決めるのか メトリクスではなく、そのサービスを利用するuserこそが信頼性があるサイトだと決めるのです。 なのでuserからすれば、そのサーバーのメトリクスなんて関心ごととして意識はないです。サクサク動いて使いやすいなーとかを抱くものです。 そいった観点から、userの行動を洗い出す必要があります。
どうやってCUJを洗い出す??
userがよく使う機能にフォーカスして、インフラコンポーネントレベルで洗い出すこと(関連性を考える)
コンポーネントが洗い出せたら、リクエストやapi単位でシーケンス図を書く。
これを行うことで、対処のコンポーネントを洗い出すことができると感じました。
SLIの取り決め方
CUJで割り出したえエンドポイントをもとにSLIを設定していく。
サービスの特性などにもよるが、今回は可用性とレイテンシーに関して考えていく。
SLIは良いイベントをもとに設定していく。
SLI:(良いイベント/有効なイベント) * 100% //あるイベントのHTTPリクエストレスポンスの全体の件数のうち、全体のリクエスト成功数 SLI = 成功リクエストレスポンス/全体のリクエストレスポンス * 100%
上記をかみしてSLIを考えると下記になる
// /hogeはCUJで割り出したエンドポイント ロードバランサーで測定したステータスが、 /hogeまたは /hgoe/profileに対する HTTP GETリクエストのうち、200番台、3xxまたは4xxを返す割合 // レイテンシー ロードバランサで測定した、/hogeに対するHTTP GETリクエスト のうちX msの範囲内にレスポンス全体を送信したものの割合
SLIが決まったらSLOを設定する
- SLIをもとにどうやってuserの満足度が測れる?
- ここで目標値を決めることは理解したが、やってはいけないことはエンジニアだけで取り決めてはだめ。プロダクトマネージャー、ビジネス側と一緒に決めること。
- 明確に目標値が決めれない時は過去の平均レイテンシーなどを考慮して取り決める
エラーバジェット
- 開発の舵取りを行える指標。SLOで作成した目標値から100%をもとに差し引きしたもの。例えば全体のリクエスト内、2xx台および3xx台, 4xx台の割合を99.99%に設定した際のエラーバジェットは0.01%になる。この0.01%の許容できる範囲を逸脱しなければ、開発を続けれるし、これを逸脱するばいいは改善作業をしていく取り組みをする。
終わりに
SLI/SLOの具体的な決め方などを知ることができました。SRE本を読んでいてわからなかったことが、この動画で補完できたと思います。
ディスカッションをする大切さ
こんにちは、季節もすっかり秋になってきました。と思ったら急に暑くなったりと、体調管理が難しい気候だなと感じます。 引き続きデータモデリングの勉強をしているのですが、議論する重要さにいろいろ気づきました。 きっかけは一緒に勉強しているメンバーの子に楽々ERDレッスンという本を読んで、疑問をなげかけた時です。 「商品コードは主キーになりえないとのことなんだけど、どう思う??自分は主キーになり得るかなと考えているだけど、なぜなら商品が同じでも新たな商品とみなして、insertを積み上げていけば良いと思っているだけど??」 という投げかけに対して、「~のユースケースがあるから、自分は〜だと思う」という具合に議論が活発になり、モデルが洗礼されていくのを感じていました。 そして、商品という概念から、他のユースケースを考え、おのずと他のデータモデルの設計ができてきました。 一人で学習することは、確かに大切です。ですが、ディスカッションをすることでより洗礼する感覚があります。
下記は商品から派生して作成したテーブルです。(あくまでディスカッションしながら作成しているので完璧なものではないです。)
create table 商品( 商品Id interger primay key, 商品コード varchar, 商品名 varchar, 金額 integer ... ) create table 商品履歴( 履歴Id 商品Id interger primay key, 商品コード varchar, 商品名 varchar, ... ) create table 税率( 税率Id PK 税率 ) create table 注文( 注文Id PK 利用者Id FK 合計金額 ) create table 注文詳細( 詳細Id 注文Id FK 商品Id FK 税率Id FK 商品価格 ) create table 利用者 ( 利用者Id FK 支払い方法Id FK profileId FK ) create table 支払い方法( 支払い方法Id ) create table 現金払い( 現金払いId PK 支払い方法Id FK ) create table カード払い( カード払いId PK 支払い方法Id FK ) create table カード詳細( カード詳細Id カード払いId FK カード番号 カードブランド 支払い形式 )
そして、slerの頃にどいうテーブル設計をしてたかというと、依頼主からの仕様をもとにエンジニアだけで作成していまいした。 確かに仕様書どうりに満たせるテーブルになっていたと思います。ですが大切なのは開発者とドメインエキスパートとの対話で生まれるドメインモデルの洗礼。 ここが重要なんじゃないかなと考えます。 モデルを洗礼することで、隠れている概念を抽出する作業をすることで、data storeレベルでの複雑さの軽減につながるのではないかなと考えた今日この頃でした〜 最後は長々となってしまいましたが、それではバイバイ〜
cloudflareにおけるmTLSの調査と検証
お久しぶりです。ながらく忙しくブログを書くことができませんでした。 実務ではEKSを触ったり、codepipeline周りを触りデプロイの仕組みを作成したりと触ったことのない領域を触る機会が出てきました。 本業では関係ないのですが、副業先で新規インフラ構築のタスクに当たっています。要件としてmTLSの要件がありました。 現行のシステムは現在root証明書をproxyで管理しているらしく、proxyでの管理を撤廃しどうにか awsのサービスでまかなえないかを模索していました。 調べたところ、 api gatewayを用いいるとmTLSの管理ができそうで、そちらを検討していました。検討の中、ググってみるとどうやらcloudflareでもmTLSの管理ができるということで検証してみることにしました。 実際に実装してみると簡単にmTLSの実装が出来ました。(ボタンをポチポチするだけ) 証明書の管理もcloudflare側で管理してくれるのでどうにかして、cloudflareでmTLSの管理を行いたいものです。