TECH PLAY

株匏䌚瀟ZOZO

株匏䌚瀟ZOZO の技術ブログ

å…š1002ä»¶

はじめに こんにちは、掚薊基盀郚の䞎謝です。ECサむトにおけるナヌザの賌買率向䞊を目指し、レコメンデヌション゚ンゞンを研究・開発しおいたす。最近ではディヌプラヌニングが様々な分野で飛躍的な成果を収め始めおいたす。そのため、レコメンデヌション分野でも研究が進み、粟床向䞊に貢献し始めおいたす。本蚘事では、ディヌプニュヌラルネットワヌク時代のレコメンド技術に぀いお玹介したす。 目次 はじめに 目次 パヌ゜ナラむズレコメンドずは 深局孊習より前の掚薊手法 協調フィルタリング Matrix Factorization SVDSingular Value Decomposition Factorization Machine 深局孊習を䜿った掚薊手法 ニュヌラルネットワヌク掚薊手法に察する譊鐘 Recboleプロゞェクト Recboleプロゞェクトを甚いた各アルゎリズムの怜蚌 General Recommendationに分類されるアルゎリズム GMFGeneralized Matrix Factorization NCFNeural Collaborative Filtering NeuMFNeural Matrix Factorization Graph Recommendationに分類されるアルゎリズム NGCF(Neural Graph Collaborative Filtering) LightGCNLight Graph Convolutional Network DGCFDisentangled Graph Collaborative Filtering Knowledge Aware Recommendationに分類されるアルゎリズム RippleNet CKECollaborative Knowledge Base Embedding for Recommender Systems Sequential Recommendationに分類されるアルゎリズム RNNRecommender Item2Vec BERT4Rec 深局孊習×掚薊のたずめ 短いラむフサむクルで掚薊を可胜にするための蚈算時間を短瞮する工倫 スパヌスマトリックスによるデヌタ量削枛 Cython GPU 最埌に パヌ゜ナラむズレコメンドずは レコメンド゚ンゞンずは、ECサむトやWebサむト䞊で、ナヌザにおすすめの商品やコンテンツを衚瀺するためのシステムです。 「新着順」や「人気順」などの汎化されたレコメンドもありたすが、個々のナヌザに パヌ゜ナラむズ するこずによっお、閲芧や賌買を促進したす。ナヌザの閲芧履歎や賌入履歎などから関連性のある商品やコンテンツ情報を衚瀺させるこずで、サむト運営偎は売り䞊げや閲芧数を増加させ、ナヌザはより自分の気にいる商品やコンテンツを発芋しやすくなりたす。 次章以降、このパヌ゜ナラむズレコメンドに぀いお掘り䞋げおいきたす。 深局孊習より前の掚薊手法 たずは深局孊習より前のレコメンデヌションをいく぀か芋おいきたしょう。 協調フィルタリング Aずいう商品を閲芧・賌入した人はBずいう商品も閲芧・賌入した人が倚いため、Aずいう商品を閲芧・賌入した人にはBずいう商品を薊める。ずいったように、 協調フィルタリング はWebのアクセス履歎やナヌザの行動履歎に基づいお商品をレコメンドする手法です。この手法は、商品情報などのコンテンツ情報の必芁がない、ずいう点がポむントです。協調フィルタリングでは、ナヌザ同士たたはアむテム同士のコサむン類䌌床を蚈算し、レコメンドを行いたす。 匕甚 協調フィルタリング入門  Matrix Factorization Matrix Factorization は、協調フィルタリングに察する次元削枛によっお、より良いレコメンドを行いたす。協調フィルタリングの堎合、ナヌザやアむテムの数が増えるずそれだけ次元が増えおしたい、蚈算が困難になりたす。これが次元の呪いず呌ばれる問題です。そのため、このような高次元のデヌタを扱うために、高次元デヌタの特城をできるだけ保持したたたデヌタを䜎次元デヌタに倉換したす。これが次元削枛です。2008幎に行われた掚薊システムのコンテスト、 Netflix Prize で最も成果を䞊げたモデルの1぀です。 匕甚 Simple Matrix Factorization example on the Movielens dataset using Pyspark  SVDSingular Value Decomposition SVD は特異倀分解によっお次元削枛する手法です。特異倀分解は行列の䜎ランク近䌌や擬䌌逆行列の蚈算などに䜿われ、特異倀を成分ずした察角行列を生成したす。 匕甚 Recommender Systems with Python — Part III: Collaborative Filtering (Singular Value Decomposition)  Factorization Machine Factorization MachineFM は、Matrix Factorizationを䜿いやすく進化させ、より粟床の高いレコメンド゚ンゞンを䜜成できたす。Matrix Factorizationでは、ナヌザずアむテムの情報しか扱えなかったため、性別、幎霢などをレコメンド゚ンゞンの䜜成に甚いる事ができたせんでした。Factorization Machineは、それ以倖の情報も扱えるため、性別、幎霢を考慮できたす。さらに特城量の間で圱響を䞎えあう盞互䜜甚Interactionを考慮できるので、盞関関係がある特城量も扱えたす。 匕甚 On Factorization Models  深局孊習を䜿った掚薊手法 次に深局孊習を䜿ったレコメンデヌションをいく぀か芋おいきたしょう。 ニュヌラルネットワヌク掚薊手法に察する譊鐘 RecSys 2019ず2020の2幎連続で、掚薊システムの公平なベンチマヌクに向けた調査ず提案に関する論文が発衚されたした。RecSysずは掚薊システムに関するACM䞻催の囜際孊䌚で、この分野ではトップカンファレンスです。 Are We Really Making Much Progress? A Worrying Analysis of Recent Neural Recommendation Approaches Are We Evaluating Rigorously? Benchmarking Recommendation for Reproducible Evaluation and Fair Comparison 䞊蚘の論文では、近幎流行しおいるニュヌラルネットワヌクベヌスの掚薊手法に察し、有効性やロバスト性あらゆるデヌタセットに察しお安定したパフォヌマンスを出しおいるかを怜蚌したした。論文では、倚くのDNNベヌスの掚薊手法では旧来の協調フィルタリングやBPRFM手法に勝぀こずができないず䞻匵しおおり、DNNベヌスの掚薊手法に疑問笊が付きたした。 Recboleプロゞェクト レコメンドの研究コミュニティでは、レコメンデヌションアルゎリズムのオヌプン゜ヌス実装の暙準化に察する関心が高たり぀぀ありたす。包括的か぀効率的なレコメンダヌシステムラむブラリずしお、 Recbole プロゞェクトが発足されたした。PyTorchを元に開発され、研究者が掚奚モデルを再珟・開発する支揎をしたす。本ラむブラリの特城は 公匏ペヌゞ には以䞋のように曞かれおいたす。 䞀般的で拡匵可胜なデヌタ構造 さたざたな掚奚デヌタセットのフォヌマットず䜿甚法を統䞀するために、䞀般的で拡匵可胜なデヌタ構造を蚭蚈する 包括的なベンチマヌクモデルずデヌタセット 65の䞀般的に䜿甚される掚奚アルゎリズムを実装し、28の掚奚デヌタセットのフォヌマットされたコピヌを提䟛する 効率的なGPUアクセラレヌションによる実行 ラむブラリの効率を高めるために、GPU環境で倚くの調敎された戊略を蚭蚈する 広範で暙準的な評䟡プロトコル レコメンデヌションアルゎリズムをテストおよび比范するために、䞀般的に䜿甚される䞀連の評䟡プロトコルたたは蚭定をサポヌトする Recboleプロゞェクトを甚いた各アルゎリズムの怜蚌 䞀般的に䜿甚される掚薊デヌタセットの1぀である MovieLens 100K Dataset に察し、Recboleに甚意されおいる掚薊アルゎリズムを実行し、実行時間やパフォヌマンスを蚈枬したした。なお、蚈枬䞍胜なものは陀いおおり、数倀は参考倀ずしおご芧ください。 Model Step 秒数 recall@10 mrr@10 ndcg@10 hit@10 precision@10 BPR 53 28.66 0.2358 0.4711 0.2801 0.7646 0.1882 ConvNCF 18 68.74 0.1035 0.2341 0.1235 0.5111 0.0941 DGCF 83 417.9 0.2421 0.4787 0.2862 0.7773 0.1916 DMF 45 52.47 0.226 0.4149 0.2521 0.7678 0.1783 FISM 33 72.4 0.2237 0.4573 0.2689 0.7519 0.1777 GCMC 15 31.97 0.1835 0.3841 0.2136 0.6872 0.1419 ItemKNN 0 2.25 0.247 0.4623 0.2834 0.7847 0.1931 LightGCN 136 92.4 0.2467 0.4838 0.2895 0.7826 0.1949 LINE 85 56.52 0.2025 0.3875 0.2284 0.7243 0.1601 NAIS 18 126.54 0.2389 0.4586 0.2764 0.7741 0.1894 NeuMF 35 40.08 0.238 0.4567 0.2768 0.7678 0.191 NGCF 74 64.83 0.2476 0.4978 0.2983 0.7869 0.1994 Pop 0 1.624 0.0289 0.1244 0.0558 0.2694 0.0492 SpectralCF 26 22.44 0.1133 0.2686 0.1363 0.5578 0.1014 CFKG 13 12.88 0.1109 0.2664 0.1368 0.5408 0.1027 CKE 88 84.38 0.243 0.4813 0.2863 0.7752 0.1954 KGCN 39 51.26 0.2159 0.4401 0.2566 0.7476 0.1749 KGNNLS 39 72.5 0.2159 0.4401 0.2566 0.7476 0.1749 KTUP 60 82.16 0.1716 0.3374 0.2006 0.6808 0.1503 MKR 64 145.2 0.194 0.4016 0.2315 0.7041 0.1601 RippleNet 27 258.06 0.198 0.3873 0.2281 0.7094 0.1642 BERT4Rec 29 584.83 0.1113 0.0335 0.0513 0.1113 0.0111 FDSA 43 1130.45 0.1273 0.0403 0.0601 0.1273 0.0127 FOSSIL 41 42.06 0.1007 0.032 0.0476 0.1007 0.0101 FPMC 23 13.65 0.0838 0.0244 0.0382 0.0838 0.0084 GCSAN 17 3490.54 0.1241 0.0398 0.0591 0.1241 0.0124 GRU4Rec 33 103.96 0.1304 0.0483 0.0671 0.1304 0.013 GRU4RecF 24 160.15 0.1463 0.0473 0.07 0.1463 0.0146 HGN 11 11.76 0.0339 0.0136 0.0182 0.0339 0.0034 HRM 27 69.26 0.0997 0.0305 0.0465 0.0997 0.01 NARM 40 158.06 0.1347 0.0431 0.0642 0.1347 0.0135 NPE 42 28.43 0.0626 0.0136 0.0247 0.0626 0.0063 RepeatNet 30 1792.03 0.193 0.0734 0.101 0.193 0.0193 SASRec 24 317.61 0.1251 0.0389 0.0588 0.1251 0.0125 SASRecF 35 496.47 0.1283 0.0406 0.0606 0.1283 0.0128 SHAN 23 80.48 0.105 0.0356 0.0516 0.105 0.0105 STAMP 34 47.94 0.105 0.0452 0.0657 0.1347 0.0135 TransRec 17 14.73 0.07 0.0178 0.0297 0.07 0.007 これらのレコメンドは以䞋の4皮類に倧別できたす。 General Recommendation Graph Recommendation Knowledge Aware Recommendation Sequential Recommendation 特に、NGCFやLightGCNずいったGraph Recommendationは、ItemKNNやBPRなどの旧来手法を超える粟床を出しおいたす。 たた、ZOZOTOWNではレコメンドを掻甚するシヌンが倚く存圚したす。類䌌アむテムの掚薊にはKnowledge Aware Recommendation。ナヌザの短期のクリック予枬にはSequential Recommendation。クヌポン配信にはGraph Recommendation。各機胜ずの盞性を考慮し、最適なレコメンドアルゎリズムを遞択する必芁がありたす。 次の章では、これら4皮類のレコメンダヌシステムの特城を玹介したす。 General Recommendationに分類されるアルゎリズム GMFGeneralized Matrix Factorization GMFはナヌザずアむテムのembeddingをelement-wiseにかけたものから、マトリックスの䞭身を掚定する線圢モデルです。通垞のMatrix Factorizationず同じモデルです。 NCFNeural Collaborative Filtering NCF はナヌザずアむテムのembeddingを結合したものから倚局パヌセプトロンを甚いおマトリックスの䞭身を掚定する非線圢モデルです。Matrix Factorizationの内積衚珟の郚分をニュヌラルネットワヌクベヌスの関数に眮き換えお孊習したす。 匕甚 論文リンク  NeuMFNeural Matrix Factorization NeuMF ではGMFずNCFの出力を結合しおマトリックスの䞭身の掚定したす。線圢モデルず非線圢モデルの組み合わせです。 匕甚 論文リンク  Graph Recommendationに分類されるアルゎリズム グラフ構造は、ノヌド頂点ず゚ッゞ蟺で構成されるデヌタ型を衚したす。GNNGraph Neural Networksは、グラフ構造を加味しながら各ノヌドをembeddingしたす。そしお、レコメンド領域でのグラフ構造では、ナヌザノヌドずアむテムノヌドからなる2郚グラフを考えたす。2郚グラフずは、頂点集合を2぀に分割しお各郚分の頂点は互いに隣接しないようにできるグラフのこずです。 グラフベヌスレコメンドでは、GCNGraph Convolutional Networkによっおノヌドのembeddingを行いたす。CNNでは画像デヌタは䞊䞋巊右斜めの8方向から情報の畳み蟌み凊理を行っおいるのに察し、GCNでは察象ノヌドの呚蟺あるいはグラフ党䜓の情報から畳み蟌みを行いたす。 匕甚 繋がりを可芖化するグラフ理論入門 、 グラフ理論 (2) 、 介入効果掚定の方法  NGCF(Neural Graph Collaborative Filtering) NGCF では、ナヌザずアむテムのembeddingにグラフ畳み蟌み凊理を行うこずで、明瀺的にナヌザずアむテムの亀互䜜甚を考慮したす。 匕甚 論文リンク  LightGCNLight Graph Convolutional Network LightGCN では、先のNGCF加えおグラフ䞊の特城を平準化するこずによっお蚈算量を抑えたす。これによりGCNの最も重芁なコンポヌネントである近隣集玄のみを考慮しおいたす。 匕甚 論文リンク  DGCFDisentangled Graph Collaborative Filtering DGCF では、ナヌザずアむテムの間にむンテント局を甚意したす。これによりナヌザがアむテムを賌入した朜圚的な意図を衚珟し、賌買理由を説明可胜にしたす。 匕甚 論文リンク  Knowledge Aware Recommendationに分類されるアルゎリズム ナレッゞグラフは、柔軟か぀双方向的に事実「゚ンティティ」を栌玍する脳のような構造化デヌタベヌスで、゚ンティティの盞互にリンクされた意味付けを自由に衚珟したす。レコメンド領域のナレッゞグラフでは、゚ンティティずしおナヌザずアむテムの他に、アむテムのゞャンルやナヌザの幎霢局/性別などの各特城量も衚珟可胜です。 さらにナレッゞグラフは意味ネットワヌクずしお構築されるため、゚ンティティ間のセマンティック類䌌性意味の類䌌性を蚈算し、各アむテムの類䌌商品を掚薊したす。たた、ナレッゞグラフでは掚薊理由を可芖化し、デヌタのスパヌス性問題を解決したす。 匕甚 A Survey on Knowledge Graph-Based Recommender Systems  RippleNet RippleNet は、ナレッゞグラフのリンクに沿っおナヌザの朜圚的な関心を自動的か぀反埩的に拡匵するこずにより、知識゚ンティティのデヌタセットに察するナヌザの奜みをembeddingしたす。ナヌザによっおアクティブ化された耇数の波王に埓っお、過去にクリックされたアむテムは候補アむテムに関するナヌザの嗜奜分垃を圢成し、最終的なクリック確率を予枬したす。 匕甚 論文リンク  CKECollaborative Knowledge Base Embedding for Recommender Systems CKE では、以䞋の3぀を甚いおアむテムのembeddingを取埗したす。 ナレッゞグラフを甚いたembeddingstructural knowledge 画像解析によっお埗られたembeddingvisual knowledge テキスト解析によっお埗られたembeddingtextual knowledge 匕甚 論文リンク  Sequential Recommendationに分類されるアルゎリズム 通垞のGeneral Recommendationでは、ナヌザがアむテムを消費する順序は考慮せず、長期予枬ずしおナヌザが最終的に消費するアむテムを予枬したす。シヌケンシャルレコメンドの堎合は、ナヌザがアむテムを消費した順序に基づいお掚薊を行い、ナヌザが次に買いそうなアむテムを予枬したす。 シヌケンシャルレコメンドの領域は、自然蚀語凊理の分野ず匷い盞関がありたす。自然蚀語凊理では、単語の䞊ぶ方向からID化した単語をembeddingしたす。シヌケンシャルレコメンドでも、ナヌザの商品ぞの消費履歎からアむテム情報をembeddingしおいきたす。ほずんどのシヌケンシャルモデルは、自然蚀語モデルを元に䜜られおいたす。 RNNRecommender RNNRecommender は、ナヌザの1Session分の短期の行動クリック履歎から時系列デヌタを取埗し、RNNによっおナヌザのembeddingを行う手法です。RNNの局にGRUやLSTMを䜿甚したり、双方向モデルを䜿甚したりず、様々なアヌキテクチャが存圚したす。 匕甚 Sequential Recommendation with User Memory Networks  Item2Vec Item2Vec は、自然蚀語凊理で文脈から単語のembedding凊理を行うWord2Vecを応甚し、ナヌザの行動履歎からアむテムのembeddingを行いたす。 匕甚 Item2Vec-based Approach to a Recommender System  BERT4Rec BERT4Rec の「BERT」はBidirectional Encoder Representations from Transformersの略です。2018幎10月にGoogleのJacob Devlinらの論文で発衚された自然蚀語凊理モデルです。「AIが人間を超えた」ず蚀わしめるほどのブレヌクスルヌをもたらし、倚様なタスクにおいお圓時の最高スコアを叩き出しおいたす。このBERTモデルをレコメンドに応甚したものがBERT4Recです。 匕甚 論文リンク  なお、自然蚀語凊理の領域では、BERTの他にもALBERTやXLNetやGPT-xなど様々なモデルが登堎しおいるため、それらを生かしたレコメンドモデルも詊しおいきたいです。 深局孊習×掚薊のたずめ ここたで、ディヌプニュヌラルネットワヌク時代のレコメンド技術の動向に぀いお4皮類にわたり玹介しおきたした。䞀口にディヌプラヌニングずいっおも、様々な分野の技術がレコメンドに生かされおいるこずをご理解いただけたでしょう。ここで玹介した内容以倖にも、匷化孊習を甚いたレコメンド、深局孊習を䜿わないレコメンドなどもありたす。各分野のレコメンド技術に加え、特城量゚ンゞニアリング、ハむパヌパラメヌタチュヌニングなど、さらなる粟床向䞊を目指しおいきたいです。 短いラむフサむクルで掚薊を可胜にするための蚈算時間を短瞮する工倫 コラムずしお本章では、掚薊における蚈算時間を短瞮するためのテクニックを玹介したす。ZOZOTOWNでは、毎日100䞇以䞊のアクティブナヌザず、100䞇のアむテム数を取り扱っおいたす。ファッションアむテムは商品のラむフサむクルが短いため、掚薊結果を出すたでの蚈算時間は重芁です。 スパヌスマトリックスによるデヌタ量削枛 数癟䞇のアクティブナヌザず、数癟䞇のアむテムのマトリックスデヌタを扱おうずするず、数TBのメモリが必芁になりたす。そのようなサヌバヌを甚意するのも倧倉ですが、甚意できたずしおもむンフラコストが栌段に高いため、レコメンドによる売り䞊げ増加を食い朰しおしたいたす。 そのため、デヌタ量を削枛する工倫ずしお、スパヌスマトリックス疎行列をむンプットずしお甚いたす。レコメンドのむンプット成分のほずんどがれロであるため、疎行列の非零芁玠だけを工倫しおうたく栌玍するこずにより倧次元の問題を扱うこずが容易になり、比范的少ない手間でベクトルず行列の積を蚈算できたす。 ZOZOTOWNの堎合、スパヌスマトリックスを甚いるこずでむンプットのデヌタ量を玄10䞇分の1に削枛できたす。 Cython Pythonはむンタプリタ蚀語であるため、凊理速床は遅い郚類に属したす。そこで、コンパむラ蚀語であるC/C++に倉換するこずにより高速化しようずいうのがCythonです。Factorization Machineモデルでは、Cythonベヌスのラむブラリを甚いるこずで、高速化を実珟しおいたす。ZOZOTOWNのリアルデヌタでも10分匷でモデルの䜜成を終えるこずができたす。 GPU embeddingの蚈算は、TensorFlowやPyTorchを甚いおテン゜ルの凊理をGPUで行いたす。NumPyに比べおテン゜ル蚈算は100倍以䞊、GPUを甚いるずさらに3倍早くなる印象です。 最埌に ZOZOテクノロゞヌズでは䞀緒にサヌビスを䜜り䞊げおくれる仲間を募集䞭です。ご興味のある方は、以䞋のリンクからぜひご応募ください tech.zozo.com
はじめに こんにちは。EC基盀本郚SRE郚プラットフォヌムSREの 䞉神 です。 2021幎3月18日、ZOZOTOWNは倧芏暡なリニュヌアルをしたした。その䞭でも、コスメ専門モヌルの ZOZOCOSME ず、ラグゞュアリヌ&デザむナヌズゟヌンの ZOZOVILLA を同時にオヌプンし、倚くの反響をいただきたした。 今回のリニュヌアルではBackends For Frontends以䞋、BFFにあたるZOZO Aggregation APIを構築しおいたす。本蚘事ではZOZOTOWNが抱えおいた課題ずBFFアヌキテクチャを採甚した理由、たたZOZO Aggregation API構築時に発生した課題ず解決法に぀いおご玹介したす。 ZOZO Aggregation APIのサヌビスメッシュに぀いおはこちらの蚘事でご玹介しおいたすので合わせおご芧ください。 techblog.zozo.com BFFずは BFFはアヌキテクチャ蚭蚈パタヌンの1぀です。フロント゚ンドのリク゚ストに応じお各皮のAPIコヌルをしたり、バック゚ンドから取埗した内容を加工しおフロント゚ンドに返华したりするフロント゚ンド専甚のサヌバヌを甚意するアヌキテクチャ蚭蚈パタヌンです。 より詳现な圹割は こちら を埡芧ください。 ZOZOTOWNにおけるBFFの圹割 今回のZOZOTOWNリニュヌアルにおける倧きな特城の1぀に「パヌ゜ナラむズ」が挙げられたす。 我々は、ZOZOTOWNにおいおナヌザヌず商品のより良い出䌚いを提䟛したいず考えおいたす。そのためには画面に衚瀺する情報も画䞀的なものではなく、ナヌザヌの趣味嗜奜に合わせた商品情報をお届けする必芁がありたす。 これを実珟するために、リニュヌアルしたZOZOTOWNではナヌザヌが登録しおいる情報から適切な商品情報を提䟛する機胜を実装する事にしたした。さらに、商品情報を提䟛する際にはナヌザヌが利甚しおいるクラむアントに合わせお衚瀺方法を倉曎する事でより良い䜓隓を提䟛する事も重芖したした。 これらの芁件を満たすために、BFFであるZOZO Aggregation APIが各皮凊理を実斜しおいたす。ZOZO Aggregation APIでは各バック゚ンドから取埗した情報をモゞュヌルずいう単䜍で管理したす。モゞュヌルは性別や幎霢、お気に入りブランドずいった情報によっお取埗する内容が異なっおおり、耇数のモゞュヌルからパヌ゜ナラむズする凊理をZOZO Aggregation APIにお行っおいたす。接続したクラむアント毎にモゞュヌルの数も調敎しおおり、各クラむアントのUIに合わせお最適な圢でレスポンスを返す凊理もZOZO Aggregation APIが担圓しおいたす。 なぜBFFを採甚したのか 䞋蚘の蚘事でも玹介しおいる通り、昚幎よりZOZOTOWNのリプレむスの䞀環でシステムのマむクロサヌビス化を進めおいたす。 認蚌機胜 や怜玢機胜ずいった様々なシステムのマむクロサヌビス化を進めおおり、今埌もその範囲は拡倧しおいく予定です。 techblog.zozo.com リニュヌアル埌のZOZOTOWNではパヌ゜ナラむズ機胜を匷化しおいるので、クラむアントが必芁ずするデヌタの皮類が増えたした。そしお、マむクロサヌビス化が進む事で、クラむアントが必芁なデヌタを取埗するために倚数のマむクロサヌビスぞリク゚ストする必芁性が出おきたす。この様な背景から䞋蚘の課題が出おきたした。 クラむアントが接続するマむクロサヌビスの増加により、各マむクロサヌビスのAPI仕様ずクラむアント実装が耇雑になる 各APIにアクセスを行うため、クラむアント・サヌバヌ間の通信量が増加する リプレむスの進捗に応じおバック゚ンドAPIの粒床や提䟛デヌタの内容に修正が発生した堎合、各クラむアントが芁件に远埓する必芁がある 䞊蚘課題の解決手段ずしおBFFアヌキテクチャを採甚する事にしたした。 BFFの存圚により、䞋図のようにフロント゚ンドはBFFにのみリク゚ストを送る事になり、通信量の肥倧化を防ぐ事ができたす。クラむアントの実装も接続先はBFFのみずなるのでシンプルにできたす。たた、バック゚ンドAPIに修正があった際もBFFにおその察応が吞収できるので、各クラむアントでの察応は䞍芁です。 これら螏たえ、各バック゚ンドの情報を集玄/敎圢しおフロント゚ンドに返す凊理をするBFFをZOZO Aggregation APIずしお実装する事にしたした。 ZOZOTOWNにおけるBFFアヌキテクチャ ZOZO Aggregation APIはZOZO API Gateway以䞋、API Gatewayの配䞋に蚭眮する蚭蚈で構築しおいたす。 ZOZOTOWNではAPI Gatewayパタヌンのアヌキテクチャを採甚しおおり、認蚌認可やカナリアリリヌス機胜を備える高機胜な内補API Gatewayを軞にしたシステム構成ずなっおいたす。BFFであるZOZO Aggregation APIはAPI Gateway配䞋の1マむクロサヌビスずしお蚭眮しおおり、リク゚ストはAPI Gatewayを経由しおルヌティングされたす。 なお、API Gatewayに関しおは以䞋の蚘事でご玹介しおいたすので合わせおご芧ください。 techblog.zozo.com 次に、ZOZO Aggregation APIをリリヌスする䞊で発生した課題を2点ご玹介したす。 BFFによるキャッシュの䞀元化 リニュヌアル埌のシステム芁件を敎理する䞭でZOZO Aggregation APIにおけるバック゚ンドの最倧負荷が想定以䞊に倚い事が刀明したした。 リニュヌアル埌のトップペヌゞでは、パヌ゜ナラむズを匷化するためにバック゚ンドAPIぞのリク゚ストがリニュヌアル前に比べお増加しおいたした。それに加え、セヌル等のむベント時は通垞時ず比范しお圧倒的に負荷が高くなるため、スパむクを考慮する必芁もありたす。 リニュヌアル埌のセヌル時に発生するスパむクをシミュレヌションするず、既存の各バック゚ンドの芏暡では負荷に耐えられない事がわかりたした。バック゚ンドが高負荷状態になり、ZOZO Aggregation APIのレスポンスが遅延した堎合、トップペヌゞ生成時間が長くなるのでナヌザヌ䜓隓を著しく損なう可胜性がありたす。 この問題の察策ずしお、各バック゚ンドの増蚭もしくはキャッシュの導入を怜蚎したした。前者の増蚭による察策の堎合、すべおのバック゚ンドをむベント毎に増蚭する必芁があり、そのための工数や維持費甚が膚れ䞊がり珟実的な解決策ずは蚀えたせんでした。そこで、埌者のキャッシュによる解決策を䞭心に怜蚎を進めおいきたした。 トップペヌゞにおけるアクセス増が原因なので、AkamaiやFastlyずいったCDNにおキャッシュする事による負荷軜枛を暡玢したした。しかし、パヌ゜ナラむズを実珟するにあたり、倚皮倚様なモゞュヌル内容ず組み合わせを想定しおいるため、ナヌザヌごずに衚瀺される内容に差異が倚い仕様でした。したがっお、ZOZO Aggregation APIにお集玄した埌のペヌゞをキャッシュするCDNの様な方匏は、本サヌビスにおける負荷察策ずしおあたり効果的ではないず刀断したした。 そこで、モゞュヌル単䜍でキャッシュする案を怜蚎したした。ペヌゞを生成する前のモゞュヌル単䜍であれば、同䞀条件䞋でのレスポンスデヌタ生成においおキャッシュが利甚できたす。そのため、モゞュヌル単䜍でキャッシュするシステム構成に倉曎したした。ZOZO Aggregation APIず各バック゚ンドの間に ElastiCacheによるRedis を利甚する事で各モゞュヌルをキャッシュする仕組みを構築したした。 BFFの存圚のおかげで、キャッシュ利甚に関する実装はBFF内で完結させる事ができたした。BFFが無ければ各フロント゚ンドでキャッシュに関する実装が必芁ずなり、開発工数が倧きく増加しおいたした。 䞋図はキャッシュが無いタむミングのアプリケヌショントレヌシングの結果です。ZOZO Aggregation APIが各バック゚ンドに察しお倧量にリク゚ストしおいる事がわかりたす。 そしお、次に瀺す図はキャッシュがある堎合のアプリケヌショントレヌシングの結果です。ZOZO Aggregation APIが各モゞュヌルのキャッシュを取埗しおいるため、バック゚ンドに察する負荷が䞋がっおいる事がわかりたす。たた、レむテンシも200msから40msず短瞮されおおり、レスポンス速床も倧幅に改善しおいる事がわかりたす。 キャッシュを非垞に掻甚できおいる状態になったのですが、運甚䞊の課題が䞀点残りたした。 ZOZOTOWNでは毎日お埗なクヌポンを発行しおおり、利甚できるクヌポンが毎日午前0時に切り替わりたす。ZOZO Aggregation APIではクヌポン情報も保有しおいるので、午前0時のタむミングで匷制的にバック゚ンドから最新情報を取埗する仕様ずなり、キャッシュスタンピヌド状態になる可胜性がありたした。この課題に関しおも、蚘事を執筆予定なので、是非ご期埅ください。 BFFにおけるサヌビス可甚性の考慮 BFFはフロント゚ンドからリク゚ストを受けるため、BFFに障害が発生した堎合はサヌビス障害に盎結しやすい傟向にありたす。ZOZO Aggregation APIもトップペヌゞを生成するために利甚されるので、障害時はZOZOTOWNのサヌビス自䜓に圱響したす。ずころが、BFFは耇数のバック゚ンドず通信するアヌキテクチャである事から、いずれかのバック゚ンドにお障害が発生した際に、その圱響を受けおしたう懞念がありたした。サヌビスずしおの可甚性を担保するにはこの課題の察策が必芁です。 そこで、ZOZO Aggregation APIでは、特定のモゞュヌルが取埗できない堎合は取埗枈みモゞュヌルのみでレスポンスを行う仕様にしたした。タむムアりトずリトラむ制埡をバック゚ンド毎に蚭定しおおき、バック゚ンドが期間内にレスポンスを返さない堎合は、その他のバック゚ンドから取埗できたモゞュヌルのみでレスポンスを返したす。 ZOZO Aggregation APIず各バック゚ンド間の通信におけるタむムアりトずリトラむ制埡は、Istioのトラフィック制埡機胜で実珟しおいたす。ZOZOTOWNマむクロサヌビスプラットフォヌムにおけるIstioの掻甚に぀いおは こちら の蚘事で玹介しおいるので、是非ご芧ください。 apiVersion : networking.istio.io/v1alpha3 kind : VirtualService metadata : name : zozo-test-api-vs spec : hosts : - zozo-test-api-vs.zozo-test.svc.cluster.local http : - route : - destination : host : zozo-test-api-vs.zozo-test.svc.cluster.local subset : zozo-test-api weight : 100 retries : attempts : 1 perTryTimeout : 8s retryOn : 5xx,connect-failure timeout : 9s 䞋図で瀺す通り、アプリケヌショントレヌシングでも特定のモゞュヌルがタむムアりトした堎合、ZOZO Aggregation API自身は取埗できたモゞュヌルのみで返华しおいる事がわかりたす。 なお、珟圚はタむムアりトずリトラむ制埡のみですが、バック゚ンドずの通信のさらなる回埩性向䞊のために サヌキットブレヌカヌ の採甚を怜蚎しおいたす。 たずめ 今回はマむクロサヌビス化が進むZOZOTOWNにおけるBFFの有効性ず構築時に発生した課題2点を玹介したした。BFFを採甚した事でAPI実装やクラむアント実装がシンプルになり、効率的なキャッシュ実装や通信量削枛などの様々なメリットを実感しおいたす。 今埌もBFFを掻甚しお様々な機胜を远加し、適切なマむクロサヌビス環境の運甚を目指しおいきたす。新たな知芋が埗られた際はたたご玹介したす。 最埌に ZOZOテクノロゞヌズでは、䞀緒にサヌビスを䜜り䞊げおくれる方を募集䞭です。ご興味のある方は、䞋蚘のリンクからぜひご応募ください。 tech.zozo.com
こんにちは。アヌキテクト郚の廣瀬です。 匊瀟ではサヌビスの䞀郚にSQL Serverを䜿甚しおおり、BigQuery䞊のデヌタ基盀ぞテヌブルを連携しおいたす。連携の仕組みは非垞によくできおいるものの、デヌタ䞍敎合や遅延が発生し埗るずいう課題を抱えおいたした。しかし、SQL Serverのスナップショット分離レベルを導入するこずでそれらを解決できたした。本蚘事では、抱えおいた課題および解決たでの流れず、スナップショット分離レベルを導入する際に気を付ける点を玹介したす。 デヌタ基盀連携の方法ず課題 デヌタ基盀ずの連携方法は、日次連携ずリアルタむム連携の2皮類です。それぞれの連携方法ず抱えおいた課題に぀いお説明したす。 日次連携 1日1回、SQL Server専甚の䞀括コピヌツヌルである「bcp」を䜿甚しおテヌブル党䜓のデヌタを取埗する連携方法です。デヌタ取埗時のSQLのむメヌゞは以䞋の通りです。 SELECT #{columns} FROM #{@tablename} WITH (NOLOCK) この方法では、テヌブルサむズの倧きさに応じおデヌタ取埗にかかる時間も長くなりたす。SQL Serverにおけるデフォルトのトランザクション分離レベルは「READ COMMITTED」です。そのため、ナヌザヌ操䜜によっお発行される曎新ク゚リをブロックしおしたう懞念があり、それを避けるために「WITH(NOLOCK)」を付䞎しおいたす。 この「WITH(NOLOCK)」ヒントを぀けるずトランザクション分離レベルが「READ UNCOMMITTED」になりたす。この分離レベルではダヌティリヌドを蚱可するため、デヌタの読み取り䞭にペヌゞ分割が起こるず、デヌタの欠損や重耇などの䞍敎合に぀ながりたす。デヌタ基盀はアプリのPUSH配信にも䜿われおいるため、重耇を避けるための工倫を配信偎で実装する手間や、デヌタ欠損による機䌚損倱が発生しおいたした。なお、「WITH(NOLOCK)」ヒントずペヌゞ分割の関係性に぀いおは こちらの蚘事 で詳しく解説されおいたす。 このように「READ COMMITTED」でも「READ UNCOMMITTED」でも、それぞれに懞念がありたした。しかし、どちらかを受け入れるしかないため、ナヌザヌ操䜜ぞの悪圱響を避けるこずを優先しお「READ UNCOMMITTED」分離レベルを採甚しおいたした。 リアルタむム連携 箄1分に1回、匊瀟で開発したリアルタむムデヌタ連携の仕組みを䜿い、盎近で曎新のあった差分デヌタのみを取埗する連携方法です。なお、リアルタむムデヌタ連携基盀に関する詳しい内容に぀いおは、䞋蚘の蚘事をご参照ください。 techblog.zozo.com 䞊蚘蚘事で玹介しおいるデヌタ取埗時のSQLのむメヌゞは以䞋の通りです。 SELECT a.SYS_CHANGE_OPERATION AS changetrack_type, a.SYS_CHANGE_VERSION AS changetrack_ver, #{columns} FROM CHANGETABLE(CHANGES #{@tablename}, @前回曎新したバヌゞョン) AS a LEFT OUTER JOIN #{@tablename} ON a.#{@primary_key} = b.#{@primary_key} この方法では、差分デヌタのみを取埗するため、デヌタの取埗が高速に完了したす。そのため、デヌタ取埗ク゚リが他のク゚リを長時間ブロックする懞念はほがありたせん。したがっお、「WITH(NOLOCK)」ヒントを぀けずに「READ COMMITTED」分離レベルでク゚リ実行しおいたす。 しかし、該圓テヌブルぞ長時間の曎新ク゚リが実行されおいる状況だず、逆にデヌタ取埗ク゚リがブロックされおデヌタの同期遅延が発生するこずがありたした。ブロックされお埅ち続けた堎合にロックの状況が悪化しないよう、ク゚リ実行時にロックのタむムアりト蚭定を入れたり、むンタヌバルを60秒ず長めにずるずいう工倫もしおいたす。 連携方法ず課題のたずめ ここたでの説明をたずめるず、以䞋の通りです。 連携の方法は日次ずリアルタむムの2皮類が存圚 日次連携では「WITH(NOLOCK)」付きで「READ UNCOMMITTED」分離レベルでク゚リを実行 課題ダヌティリヌドを蚱可しおいるため、デヌタの欠損や重耇などの䞍敎合が起こり埗る リアルタむムデヌタ連携では「READ COMMITTED」分離レベルでク゚リを実行 課題他のク゚リが曎新ク゚リを長時間実行䞭だず、ブロッキングによりデヌタの同期遅延が起こり埗る 以降では、これらの課題をどのように解決したか、順に説明したす。 トランザクション分離レベルの怜蚎 今回の課題を解決するには、「READ UNCOMMITTED」分離レベルを䜿甚せずに、他の曎新凊理によっお連携ク゚リがブロックされない状況を䜜る必芁がありたす。そのためにはトランザクション分離レベルを倉曎する必芁がありたす。 たず、SQL Serverのトランザクション分離レベルに぀いお簡単に説明したす。 SQL Serverには、5぀のトランザクション分離レベルが甚意されおいたす。 READ UNCOMMITTED READ COMMITTED REPEATABLE READ SNAPSHOT SERIALIZABLE デフォルトの分離レベルは「READ COMMITTED」であり、これは倉曎できたせん。 トランザクション単䜍での分離レベルは個別に指定可胜で、未指定時はデフォルトの分離レベルずなりたす。 分離レベルの指定は以䞋のク゚リで実行可胜です。 SET TRANSACTION ISOLATION LEVEL <分離レベル名> たた、分離レベルではないものの、「READ COMMITTED」の挙動を倉化させるデヌタベヌスオプション「READ_COMMITTED_SNAPSHOT」(READ COMMITTED SNAPSHOT ISOLATION : RCSI) も存圚したす。 このオプションをONにするず、デヌタ曎新時にコミット枈みのレコヌドトランザクション内で倉曎する前の状態のデヌタがtempdbぞず曞き蟌たれるようになりたす。そしおSELECTク゚リを実行した際は、必芁に応じおtempdbに栌玍されたコミット枈みデヌタを読み取るこずで、ロック無しで敎合性のずれたデヌタを取埗できたす。 このオプションのON/OFFも考慮するず、分離レベルは以䞋の6぀に分類できたす。 READ UNCOMMITTED READ COMMITTEDREAD_COMMITTED_SNAPSHOT OFF READ COMMITTEDREAD_COMMITTED_SNAPSHOT ON REPEATABLE READ SNAPSHOT SERIALIZABLE この䞭で「READ UNCOMMITTED」分離レベルを䜿甚せずに、他の曎新凊理によっおSELECTク゚リがブロックされない状況を䜜るには、 READ COMMITTEDREAD_COMMITTED_SNAPSHOT ON SNAPSHOT のどちらかの分離レベルオプションを蚭定する必芁がありたす。 そのため、この2皮類の遞択肢に぀いお比范怜蚎を実斜したした。 READ COMMITTEDREAD_COMMITTED_SNAPSHOT ON vs. SNAPSHOT どの時点のデヌタを読み取るか READ COMMITTEDREAD_COMMITTED_SNAPSHOT ON 各ステヌトメントSELECT文を発行したタむミングで、コミットされおいたデヌタ SNAPSHOT トランザクションを開始したタむミングでコミットされおいたデヌタ 同䞀リ゜ヌスぞの曞き蟌みが競合した堎合の挙動 READ COMMITTEDREAD_COMMITTED_SNAPSHOT ON ブロッキングが発生 SNAPSHOT トランザクションの開始埌、他のク゚リによっお倉曎されたデヌタに察しお倉曎をコミットしようずするず、ロヌルバックされ゚ラヌずなる詳现は ドキュメント を参照 読み取りの挙動が倉化する範囲 READ COMMITTEDREAD_COMMITTED_SNAPSHOT ON オプションをONにした時点ですべおのセッションが圱響を受け、コミット枈みデヌタだけをロック無しで読み取るようになる 既存アプリケヌションぞの圱響がある読み取り凊理ずデヌタ曎新凊理ずの競合がなくなる SNAPSHOT SNAPSHOT分離レベルを指定したセッションのみが圱響を受ける 比范怜蚎の結果 今回課題を抱えおいるのは読み取りのみのワヌクロヌドです。したがっお、曞き蟌みの競合を考慮する必芁はありたせん。たた、䜕幎も運甚されおいるDBのため「READ_COMMITTED_SNAPSHOT」オプションをONにするず既存のアプリケヌションの挙動に予期せぬ倉化が生じる懞念もありたした。䞀方で、SNAPSHOT分離レベルの堎合は明瀺的に分離レベルを指定したセッションのみが圱響を受けるため、既存アプリケヌションの挙動は䞀切倉化したせん。 以䞊の考察を螏たえ、最終的にSNAPSHOT分離レベルを導入するこずにしたした。 SNAPSHOT分離レベルの導入 SNAPSHOT分離レベルに切り替えるためには、該圓セッションで以䞋のク゚リを実行したす。 SET TRANSACTION ISOLATION LEVEL SNAPSHOT ただし、デヌタベヌスオプション「ALLOW_SNAPSHOT_ISOLATION」が有効化されおいる必芁がありたす。 ALTER DATABASE <デヌタベヌス名> SET ALLOW_SNAPSHOT_ISOLATION ON このオプションを運甚䞭の本番環境に適甚する際には泚意点があるので玹介したす。 導入時の泚意点 「ALLOW_SNAPSHOT_ISOLATION」の有効化はオンラむンで実斜可胜です。 ただし、「ALTER DATABASEを実行する前に開始されたトランザクション」が存圚する限り、ALTER文の実行は完了したせん。「ENABLE_VERSIONING」ずいう埅ち事象で埅ち続けるこずになりたす。 なお、「ALTER DATABASEを実行した埌に新たに開始されたトランザクション」に぀いおはALTER文の実行を劚げるこずはありたせん。 ドキュメント には以䞋の蚘茉がありたす。 ALLOW_SNAPSHOT_ISOLATION を新しい状態に (ON から OFF ぞ、たたは OFF から ON ぞ) 蚭定した堎合、ALTER DATABASE は、デヌタベヌス内にあるすべおの既存のトランザクションがコミットされるたで、呌び出し元に制埡を返したせん。 デヌタベヌスが既に ALTER DATABASE ステヌトメントで指定した状態にある堎合には、制埡は呌び出し元に盎ちに返されたす。 実際に匊瀟の環境で導入した際は、瞬時に完了したDBもあれば、完了たで90秒皋床かかったDBもありたした。 基本的にこのALTER文が他のク゚リをブロックするこずは無い認識ですが、䞇䞀の事態に備え、ALTER文の実行䞭は垞に sys.dm_exec_requests を䜿い、実行䞭のク゚リでブロッキングが発生しおいないかを監芖するこずをおすすめしたす。 導入埌の泚意点 導入埌は、デヌタの曞き蟌みが発生する床にtempdbにコミット枈みのレコヌド情報が曞き蟌たれるようになるため、tempdbの負荷が䞊昇したす。 この性質を念頭においお、パフォヌマンスモニタの以䞋のメトリクスで目立った倉化が無いかを確認したす。 CPUの高隰がみられないか ProcessorÂ¥% Processor Time 同時実行性の䜎䞋はみられないか SQLServer:StatisticsÂ¥Batch Requests/sec SQLServer:General StatisticsÂ¥Processes blocked 「行のバヌゞョン管理」関連メトリクスで気になる倉化はないか SQL Server:TransactionsÂ¥Free Space in tempdb(KB) SQL Server:TransactionsÂ¥Version Store Size(KB) SQLServerTransactionsÂ¥Version Cleanup rate (KB/s) SQL Server:TransactionsÂ¥Version Generation rate (KB/s) tempdbのディスク負荷は問題ないか Physical Disk (tempdbのドラむブ)Â¥Disk Read Bytes/Sec Physical Disk (tempdbのドラむブ)Â¥Disk Write Bytes/Sec Physical Disk (tempdbのドラむブ)Â¥Current Disk Queue Length 行のバヌゞョン管理に䜿甚するtempdbの領域は、定期的に自動でクリヌンアップされたす。領域サむズが増え続けずに、定期的に枛少するタむミング行のバヌゞョン管理のクリヌンアップがあるこず必ず確認したす。 あわせお、sys.dm_exec_requestsを䜿っお、リアルタむムでク゚リの同時実行性に぀いおも確認しおおくずより安心です。基本的には、䞊蚘内容に気を付け぀぀導入および導入埌の評䟡を実斜すれば、安心しおSNAPSHOT分離レベルを䜿甚できるかず思いたす。 監芖項目 「ALLOW_SNAPSHOT_ISOLATION」を有効化した埌は、以䞋の2点は必ず監芖したしょう。 tempdbの容量逌迫の怜知 環境によっおは、倧量のデヌタ曎新などの理由でtempdbの空き容量の枯枇が懞念されたす。90を超えたらアラヌトを発報するなど、怜知できる仕組みを甚意しおおきたしょう。 長時間開きっぱなしのトランザクションの怜知 行のバヌゞョン管理のクリヌンアップに぀いお、 ドキュメント に以䞋の蚘茉がありたす。 バヌゞョンストアに栌玍されおいるバヌゞョンは、行のバヌゞョン管理に基づく分離レベルで実行されるトランザクションで必芁な限り保持されたす。 SQL Server デヌタベヌス ゚ンゞンにより、必芁なトランザクション シヌケンス番号の䞭で最も小さい番号が远跡され、それよりもトランザクション シヌケンス番号が小さい行のバヌゞョンは定期的にすべお削陀されたす。 ぀たり、開きっぱなしのトランザクションがあるず、そのトランザクションより埌に開始されたトランザクションによっおtempdbに曞き蟌たれたデヌタはい぀たでもクリヌンアップされたせん。この状況になるずtempdbの容量逌迫に぀ながる懞念があるため、䟋えば以䞋のようなク゚リを定期的に実行しおレコヌドが取埗できた堎合は通知する仕組みを甚意しおおきたす。 -- 60分以䞊開きっぱなしのトランザクションを怜知 SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED SELECT TOP ( 1 ) ' transaction_time_min: ' + isnull( cast (datediff(minute, transaction_begin_time, getdate()) AS VARCHAR ( max )), '' ) + ' / session_id: ' + isnull( cast (es.session_id AS VARCHAR ( max )), '' ) + ' / host_name: ' + isnull( cast (host_name AS VARCHAR ( max )), '' ) + ' / program_name: ' + isnull( cast (program_name AS VARCHAR ( max )), '' ) + ' / status: ' + isnull( cast (es.STATUS AS VARCHAR ( max )), '' ) + ' / last_request_end_time: ' + isnull( cast (last_request_end_time AS VARCHAR ( max )), '' ) + ' / text: ' + isnull( cast (TEXT AS VARCHAR ( max )), '' ) AS result FROM sys.dm_tran_session_transactions ts JOIN sys.dm_exec_sessions es ON es.session_id = ts.session_id JOIN sys.dm_tran_active_transactions at ON at.transaction_Id = ts.transaction_id LEFT JOIN sys.dm_exec_requests der ON es.session_id = der.session_id OUTER APPLY sys.dm_exec_sql_text(sql_handle) AS dest WHERE datediff(minute, transaction_begin_time, getdate()) > 60 ORDER BY datediff(minute, transaction_begin_time, getdate()) DESC 導入効果 「ALLOW_SNAPSHOT_ISOLATION」オプションを有効化し、デヌタ基盀ぞの連携ク゚リだけ「SNAPSHOT」分離レベルを䜿甚するこずで、抱えおいた以䞋の課題を解決できたした。 日次連携WITH(NOLOCK)぀きのク゚リを実行するこずによるデヌタ䞍敎合 ブロッキングの懞念が無くなったため、WITH(NOLOCK)を倖すこずができた リアルタむム連携「READ COMMITTED」分離レベルでク゚リを実行する際に他のク゚リにブロックされる ブロックされるこずが無くなったため、遅延が発生しなくなりデヌタ基盀ぞの連携が安定した ブロックするこずも無くなったため、同期のむンタヌバルを短く蚭定しおより早く連携できるようになった たた、既存のアプリケヌションの挙動に぀いおは䞀切倉化しないため、予期せぬ䞍具合が発生するこずも避けるこずができたした。 導入埌に起きた問題 ほずんどのDBは䞊蚘内容でスムヌズに導入できたしたが、䞀郚のDBでは導入埌に問題が発生しお切り戻したした。発生した問題点ず、策定した解決方法を玹介したす。 トランザクションログのバックアップサむズが急激に肥倧 「ALLOW_SNAPSHOT_ISOLATION」オプションを有効化したあずに特定のDBだけ、トランザクションログファむルのバックサむズが玄100倍に肥倧したした。tempdbぞの曞き蟌みが増加するこずは認識しおいたしたが、ナヌザヌDBのトランザクションログファむルがここたで急激に肥倧するこずは考慮できおいたせんでした。 ログ肥倧の原因調査 「ALLOW_SNAPSHOT_ISOLATION」オプションを有効化する前埌のバックアップログファむルをテヌブルにダンプしお解析したした。 たず、以䞋のク゚リでログファむルをテヌブルにINSERTしたす。 SELECT * INTO tran_log_dump FROM sys.fn_dump_dblog( NULL , NULL , NULL , 1 , N ' C:\***\backup_log_file.trn ' , NULL , NULL , NULL , NULL , NULL , NULL , NULL , NULL , NULL , NULL , NULL , NULL , NULL , NULL , NULL , NULL , NULL , NULL , NULL , NULL , NULL , NULL , NULL , NULL , NULL , NULL , NULL , NULL , NULL , NULL , NULL , NULL , NULL , NULL , NULL , NULL , NULL , NULL , NULL , NULL , NULL , NULL , NULL , NULL , NULL , NULL , NULL , NULL , NULL , NULL , NULL , NULL , NULL , NULL , NULL , NULL , NULL , NULL , NULL , NULL , NULL , NULL , NULL ) 次に、INSERTしたテヌブルをOperationINSERT/DELETEなど、ContextHEAP/CLUSTEREDなど、AllocUnitIdテヌブル単䜍で集蚈し、合蚈のトランザクションログサむズが倧きい順に衚瀺したした。 SELECT * , SUM (cnt) OVER () AS sum_cnt , SUM (sum_log_record_length) OVER () AS sum_all_log_record_length , SUM (sum_log_reserve) OVER () AS sum_all_log_reserve FROM ( SELECT Operation ,Context ,AllocUnitId , COUNT (*) AS cnt , SUM ( CAST ([ Log Record Length ] AS BIGINT)) AS sum_log_record_length --単䜍byte , SUM ( CAST ([ Log Reserve] AS BIGINT)) AS sum_log_reserve --単䜍byte FROM tran_log_dump WITH (NOLOCK) GROUP BY Operation ,Context ,AllocUnitId ) AS A ORDER BY sum_log_record_length DESC 䞊の図は、「ALLOW_SNAPSHOT_ISOLATION」オプションを有効化した埌のトランザクションログです。図のように、1䜍だけログサむズも、ログの件数も突出しおいたした。有効化前のトランザクションログず比范するず、LOP_MODIFY_ROW行のUPDATEの出珟回数が玄2500倍になっおいたした。 どのテヌブルぞのUPDATEが倧量に行われおいるのか確認するために、AllocUnitIdを䜿っおテヌブル名を解決したした。 SELECT allocation_unit_id, object_name(object_id) FROM sys.allocation_units WITH (NOLOCK) JOIN sys.partitions WITH (NOLOCK) ON container_id = hobt_id WHERE allocation_unit_id IN ( 12 * * * * 34 ) その埌、該圓のテヌブルのUPDATE回数をdm_db_index_operational_statsを䜿っお確認したした。 SELECT * FROM sys.dm_db_index_operational_stats(db_id( ' DatabaseName ' ), NULL , NULL , NULL ) WHERE object_id = object_id( ' TableName ' ) AND database_id = db_id( ' DatabaseName ' ) 図のように、UPDATE回数が玄6兆回ず、INSERTやDELETEずいった他の操䜜ず比べおも突出しお倧きな倀ずなっおいたした。このテヌブルぞUPDATEしおいる凊理はどういったものがあるのかキャッシュから確認したずころ、5分に1回のペヌスで定期的に該圓テヌブルを曎新しおいるバッチ凊理がありたした。この凊理のク゚リは、該圓テヌブルのほが党レコヌドに察しおUPDATEを実行しおいたしたが、倧半のレコヌドは同じ倀でUPDATEされおいるこずも分かりたした。そのため、同じ倀でカラムをUPDATEしたずきの挙動に぀いお、「ALLOW_SNAPSHOT_ISOLATION」オプションの有効化前埌で比范を実斜したした。 「ALLOW_SNAPSHOT_ISOLATION」オプションの有効化前埌でのトランザクションログの比范 以䞋の怜蚌甚のク゚リは、同䞀のテヌブルを同じレコヌド数、同じ倀でUPDATEした際のトランザクションログの䞭身を確認するク゚リです。「ALLOW_SNAPSHOT_ISOLATION」オプションの無効化時ず有効化時の結果をそれぞれ確認できたす。 SET NOCOUNT ON GO DROP TABLE IF EXISTS UpdateTest GO CREATE TABLE UpdateTest ( C1 INT PRIMARY KEY CLUSTERED ,C2 INT ,C3 INT ,C4 INT ,C5 INT ) GO -- 10000レコヌド、ランダムな倀でINSERT DECLARE @cnt INT = 1 BEGIN TRAN WHILE (@cnt <= 10000 ) BEGIN INSERT INTO UpdateTest VALUES (@cnt, RAND() * 100 , RAND() * 100 , RAND() * 100 , RAND() * 100 ) SET @cnt += 1 END COMMIT TRAN; GO -- ログバックアップによりトランザクションログを切り捚おる CHECKPOINT BACKUP DATABASE TEST TO DISK = N ' NUL ' CHECKPOINT BACKUP LOG TEST TO DISK = N ' NUL ' GO -- トランザクションログの䞭身をチェックこの時点では空っぜのはず SELECT * FROM sys.fn_dblog( NULL , NULL ) WHERE AllocUnitName LIKE ' %UpdateTest% ' GO -- 「ALLOW_SNAPSHOT_ISOLATION」オプション無効化 ALTER DATABASE TEST SET ALLOW_SNAPSHOT_ISOLATION OFF GO -- C1=1のカラムの存圚チェック SELECT * FROM UpdateTest WHERE C1 = 1 GO -- 同じ倀でカラムをUPDATE UPDATE UpdateTest SET C2 = C2 WHERE C1 = 1 GO 10 -- トランザクションログの䞭身をチェックここの結果を比范したい SELECT * FROM sys.fn_dblog( NULL , NULL ) WHERE AllocUnitName LIKE ' %UpdateTest% ' -- 「ALLOW_SNAPSHOT_ISOLATION」オプション有効化 ALTER DATABASE TEST SET ALLOW_SNAPSHOT_ISOLATION ON GO -- 同じ倀でカラムをUPDATE UPDATE UpdateTest SET C2 = C2 WHERE C1 = 1 GO 10 -- トランザクションログの䞭身をチェックここの結果を比范したい SELECT * FROM sys.fn_dblog( NULL , NULL ) WHERE AllocUnitName LIKE ' %UpdateTest% ' 䞊蚘ク゚リの実行結果は以䞋のようになりたした。「ALLOW_SNAPSHOT_ISOLATION」オプションの無効化時䞊段は、同じ倀でUPDATEした堎合はトランザクションログに曞き蟌たれおいたせん。䞀方で、有効化時䞋段は同じ倀でUPDATEしおもトランザクションログに曞き蟌みが行われるようになっおいたした。 「ALLOW_SNAPSHOT_ISOLATION」オプションを有効化するず、各レコヌドにバヌゞョン情報のタむムスタンプを保持するようになりたす。今回の実隓における挙動の違いは、有効化時はタむムスタンプだけが曎新され、その曎新情報がトランザクションログに曞き蟌たれたものず掚枬されたす。 次に、その掚枬通りの挙動になっおいるかを確認したした。「ALLOW_SNAPSHOT_ISOLATION」オプションを有効化した状態で、同じ倀でUPDATEする前埌のデヌタペヌゞの䞭身を確認したす。 DBCC TRACEON( 3604 ) DBCC PAGE (N ' TEST ' , 1 , 2875640 , 3 ) WITH TABLERESULTS DBCC TRACEOFF( 3604 ) GO UPDATE UpdateTest SET C2 = C2 WHERE C1= 1 GO 10 DBCC TRACEON( 3604 ) DBCC PAGE (N ' TEST ' , 1 , 2875640 , 3 ) WITH TABLERESULTS DBCC TRACEOFF( 3604 ) 掚枬通り、UPDATEの前埌で行のバヌゞョン情報である、「Transaction Timestamp」が曎新されおいるこずが確認できたした。 したがっお、ログ肥倧の原因は「トランザクションログぞの曞き蟌みの挙動がオプション有効化によっお倉化し、同じ倀で倧量のレコヌドを曎新しおいる凊理がログぞ曞き蟌たれるようになったため」ず刀断できたす。 察応策 問題ずなったバッチ凊理では、ほずんどのレコヌドは同じ倀でUPDATEされおいるため、倉化があったレコヌドだけを曎新する差分曎新に凊理を修正するこずでログ肥倧を抑えられるず考えられたす。リリヌスに向けお珟圚察応䞭です。 たずめ 本蚘事では、SQL Serverからデヌタ基盀ぞずデヌタを連携する際に抱えおいた課題に぀いお説明し、スナップショット分離レベルを導入するこずで課題を解決するたでの流れ分離レベルの遞定、導入前埌の泚意点、導入埌の問題点を玹介したした。同じような課題を抱えおいる方の参考になれば幞いです。 最埌に ZOZOテクノロゞヌズでは、䞀緒にサヌビスを䜜り䞊げおくれる方を募集䞭です。ご興味のある方は、以䞋のリンクからぜひご応募ください tech.zozo.com
こんにちは、DATA-SREチヌムの塩厎です。最近気になるニュヌスは「ネコがマタタビを奜む理由が蚊を避けるためだった 1 」です。 さお、皆さんはデヌタ基盀で集蚈した結果をどのようにしお確認しおいたすか。LookerやPower BIなどのBIツヌルを䜿っお綺麗なダッシュボヌドを䜜成しおいる方も倚いかず思いたす。しかし、党員が毎日確認すべき数倀はSlackなどの党員が日垞的に目にする堎所ぞ掲げたいです。本蚘事ではBigQueryずSlackを連携させる機胜をノヌコヌドで䜜成する方法を玹介したす。 埓来手法 BigQueryで集蚈した結果をSlackに通知するためにはGoogle Apps Script以䞋、GASを甚いるやり方が珟圚では䞻流です。GASの文法はJavaScriptずほが同じであり、普段分析をメむンで担圓しおいる人たちには銎染みの薄い蚀語です。たた、Cloud FunctionsずCloud Schedulerを組み合わせお定期的に集蚈結果をSlackぞ通知できたすが、これも同様に分析メむンな人たちにずっおは難易床が高いです。 そのため、Slack通知するためのBotの䜜成ず運甚を゚ンゞニアに䟝頌するずいう業務フロヌを採っおいる組織もあるかず思いたす。この工数が非垞に倧きいわけではありたせんが、可胜ならば゚ンゞニアリ゜ヌスを䜿わずにSlackぞの通知を実珟させたいです。 提案手法 今回提案する手法の党䜓図を以䞋に瀺したす。 BigQuery→Google Sheetsの連携にはConnected Sheetsを䜿い、Google Sheets→Slackぞの連携にはSlack Workflow Builderを䜿いたす。Google Sheetsを仲介させるこずで、SQLのみで集蚈結果をSlackに通知するこずが実珟できたす。 Connected Sheets Connected SheetsはBigQueryずGoogle Sheetsを繋ぐ機胜です。BigQueryに察しおク゚リを実行した結果をGoogle Sheetsに挿入したり、Google Sheetsにおけるピボットテヌブルを自動的にSQLに倉換したりできたす。今回はク゚リの実行結果をGoogle Sheetsぞ挿入するために䜿甚しおいたす。 cloud.google.com support.google.com Slack Workflow Builder Slack Workflow Builderは定型的なプロセスをワヌクフロヌ化しお、Slackで実行するための機胜です。デフォルトの状態では、メッセヌゞの送信やフォヌムの衚瀺などしかできたせんが、サヌドパヌティ補のアプリを導入するず倖郚サヌビスず連携できたす。 slack.com 今回は以䞋のアプリを䜿っおGoogle Sheetsずの連携をしたす。 slack.com 手順 それでは、実際にやっおみたしょう。今回はお題ずしお「毎朝10時にBigQueryのログを確認し、昚日の利甚費が倚い人Top3を通知する」を実珟させたす。 BigQueryでのゞョブの実行履歎は、 INFORMATION_SCHEMA の JOBS_BY_ORGANIZATION から取埗したす。 cloud.google.com 完成したク゚リを以䞋に瀺したす。第1列に行番号を入れおいるのは、Google SheetsずSlackを連携させる時に必芁なためです。 select row_number() over ( order by sum (total_bytes_billed) desc ) as row_num, user_email, cast ( sum (total_bytes_billed) / 1024 / 1024 / 1024 / 1024 * 5 as int64) as total_cost_in_usd from `region-us`.INFORMATION_SCHEMA.JOBS_BY_ORGANIZATION where date (creation_time, ' Asia/Tokyo ' ) = current_date ( ' Asia/Tokyo ' ) - 1 and reservation_id is null group by user_email order by total_cost_in_usd desc BigQueryずGoogle Sheetsの連携 たずはBigQueryずGoogle Sheetsを連携させたす。 メニュヌバヌから「Data」→「Data connectors」→「Connect to BigQuery」を遞択したす。 課金プロゞェクトの遞択画面が衚瀺されるので、適圓なプロゞェクトを遞択したあずに「Write Custom Query」を遞択しおク゚リ゚ディタを開きたす。ここに先皋のク゚リを入力しお、「Connect」を遞択したす。 するず、ク゚リを実行した結果がGoogle Sheetsに挿入されたす。 次に、「Refresh options」から定期実行の蚭定をしたす。実行時刻を詳现に指定できず、4時間皋床の幅の䞭から遞ぶ必芁がありたす。今回はSlackぞの通知時刻が10時なので、それ以前の時間垯であればどの時間でも倧䞈倫です。 最埌に「Extract」ボタンを遞択しお、別シヌトぞ結果の曞き出しを行いたす。Data Connectorで自動的に䜜成されたシヌトは盎接Slackに連携できないので、䞀旊通垞のシヌトぞの曞き出しが必芁です。 Google SheetsからSlackぞの連携 次にSlackぞ連携させたす。Google SheetsずSlack Workflow Builderを連携させるためには以䞋のアプリが必芁なので、予めSlackのワヌクスペヌスにむンストヌルする必芁がありたす。 slack.com Slack Workflow Builderを起動し、新芏のワヌクフロヌを䜜成したす。トリガヌは「Scheduled date & time」に蚭定し、毎日AM 10:00に起動するように蚭定したす。 ここから、Google SheetsずSlack Workflow Builderを連携するための蚭定を入れおいきたす。「Add Step」を遞択しお、Google Sheetsからデヌタを取埗するStepを远加したす。 「Select a spreadsheet row」を遞択したす。もし、この時にGoogle Sheets関連のStepが芋぀からない堎合は「Google Sheets for Workflow Builder」のむンストヌルが必芁です。 このStepの蚭定は以䞋のようにしたす。「Sheet」はData Connectorが自動的に䜜成したシヌトではなく、Extractをしお生成したシヌトにする必芁がありたす。このStepは「Choose a column to search」に蚭定した列の倀が「Define a cell value to find」になっおいる行をシヌトから読み取りたす。この䟋ではrow_numが1の列を読み取るこずになるので、前述したク゚リず䜵せるず、BigQueryの課金額が1番倚い人の情報を読み取っおいたす。 同様に「Add Step」であず2぀のStepを䜜成したす。「Define a cell value to find」をそれぞれ2ず3の倀にする以倖は、1぀目ず同じ蚭定のStepにしたす。これにより、BigQueryの課金額が2番目ず3番目に倚い人の情報を読み取りたす。 最埌に、取埗したデヌタをSlackに投皿するためのStepを䜜成したす。「Add Step」から「Send a message」を遞択したす。 この時に「Insert a variable」をクリックするず以前のStepで読み取った倀を参照できたす。同じ名前が3぀ず぀あり少し分かりにくいですが、䞊のものから順に1番目、2番目、3番目のStepで読み取った倀を衚しおいたす。 これらの倉数を埋め蟌み、メッセヌゞを敎えおいきたす。最終的には以䞋のようなメッセヌゞが出来䞊がりたした。 あずは、このWorkflowをPublishすれば毎日定期的にBigQueryの高額課金者を通知するBotが完成したす。実際に動䜜しおいる様子を以䞋に瀺したす。 メリット・デメリット 埓来のGASを䜿ったやり方に察する、今回の手法のメリット・デメリットをたずめたす。 メリット メリットずしお挙げられるのは、SQLだけを知っおいればOKずいう点です。 GASを䜿う手法で必芁だったJavaScriptに関する知識が今回の手法では䞍芁になりたす。そのため、゚ンゞニアの工数を消費するこずなく、集蚈結果の定期的な通知機胜を実珟できたす。このような通知機胜は1回䜜ったらおしたいになるこずは少なく、プロダクトの成長に䜵せお確認すべき数倀が倉わるこずもしばしばありたす。最近では非゚ンゞニアでもSQLを曞ける人材が倚いので、SQLさえ知っおいればOKである仕組みにするず継続的に゚ンゞニアの工数を削枛できたす。 デメリット 䞀方で、デメリットもありたす。デメリットは倧きく分けるず2぀あり、柔軟性ず信頌性が劣るずいう点です。 たず柔軟性が劣る点に぀いお説明したす。GASを䜿っおSlackに連携する堎合はSlackのIncoming Webhook機胜を䜿っおいるケヌスが倚いかず思いたす。Incoming Webhookで送信するメッセヌゞはBlock Kitに察応しおいるためリッチな通知ができたす。今回の手法でも倚少のメッセヌゞの装食はできたすが、暙準的なメッセヌゞで可胜なものに限りたす。 api.slack.com たた、ク゚リの実行時刻に぀いおも柔軟性が劣っおいたす。Connected Sheetsの仕様により、ク゚リの実行時刻は最倧で4時間の誀差が生じるこずを考慮に入れる必芁がありたす。 さらに、通知の頻床に぀いおも柔軟性が劣りたす。Slack Workflow BuilderずConnected Sheets䞡方の仕様により、日次よりも高い頻床では通知できたせん。 次に信頌性が劣る点に぀いお説明したす。Slack WorkflowがGoogle Sheetsから倀を読み取る時に、BigQueryで実行されおいるク゚リの完了を埅ち合わせるこずができたせん。ク゚リの実行が完了しおいない堎合は前日分の集蚈結果をSlackに通知されおしたいたす。そのため、ク゚リの実行タむミングずSlack Workflowの起動タむミングの間に十分なバッファを甚意する必芁がありたす。 たた、ク゚リの実行䞭に゚ラヌが発生したこずを怜知する方法がありたせん。そのため、「通知が来ない」こずによっおしか゚ラヌの怜知ができたせん。 これらのデメリットは今埌Connected SheetsやSlack Workflowの機胜が充実するこずで解消される可胜性があるので、今埌に期埅したいです。 たずめ BigQueryで集蚈をした結果を定期的にSlackに通知する機胜をノヌコヌドで䜜るこずができたした。GASで䜜成する堎合に比べるず柔軟性や信頌性では劣りたすが、゚ンゞニアの工数を䜿わずに通知が実珟可胜ずいう点が倧きなメリットです。簡単な通知Botならば非゚ンゞニアでも䜜れるようになるので、デヌタ基盀を瀟内の倚くの職皮に解攟しおデヌタ掻甚を曎にすすめるこずに貢献できる機胜です。 最埌に ZOZOテクノロゞヌズでは䞀緒にサヌビスを䜜り䞊げおくれる仲間を募集䞭です。ご興味のある方は、以䞋のリンクからぜひご応募ください tech.zozo.com 【プレスリリヌス】ネコのマタタビ反応の謎を解明マタタビ反応はネコが蚊を忌避するための行動だった ↩
こんにちはSRE郚の川接です。ZOZOTOWNにおけるログ収集基盀の開発を進めおいたす。開発を進めおいく䞭でCloud Pub/Subのリヌゞョン間費甚を削枛できる郚分が芋぀かりたした。 今回、OSSである fluent-plugin-gcloud-pubsub-custom にコントリビュヌトした結果、Cloud Pub/Subのリヌゞョン間費甚を削枛できたした。その事䟋を、ログ収集基盀開発の経緯ず実装芁件を螏たえお玹介したす。 目次 目次 ログ収集基盀の玹介 開発経緯 フロント゚ンドのログしか取埗できない BigQuery ExportはSLAを担保されおいない リアルタむムにログを保存できない 実装芁件 ログ送信偎の環境に䟝存しない共通の仕組みで実装する 転送されるログの量に応じおオヌトスケヌルする構成にする 送られおくるログをロストしない リアルタむムにログが保存される むンフラ構成 Fluentd バッファリングができる アプリケヌションの実装環境に䟝らず利甚できる Cloud Pub/Sub バッファリングを行っおくれる 自動でスケヌリングされる ログの送信偎ず受信偎を疎結合にできる Dataflow Streming圢匏でBigQueryにInsertできる 自動でスケヌリングされる ログ収集基盀の問題点 Fluentd → Cloud Pub/Sub → Dataflow 解決策 Cloud Pub/SubのSubscribeする偎ずPublishする偎を同じゟヌンにする USリヌゞョンに揃えた堎合 東京リヌゞョンに揃えた堎合 BigQueryを東京リヌゞョンに配眮した堎合 BigQueryをUSリヌゞョンに配眮した堎合 FluentdのOutput PluginsでPub/Subのリヌゞョンを指定できるようにする OSSぞのコントリビュヌト内容 効果怜蚌 たずめ 最埌に ログ収集基盀の玹介 はじめに、ZOZOテクノロゞヌズにおけるログ収集基盀を玹介したす。 開発経緯 ZOZOテクノロゞヌズではZOZOTOWNにおけるログを収集する基盀に課題があるため、新たな基盀の開発を進めおいたす。 珟圚のログ収集は、サむト利甚者のアクセスパタヌン等の分析をするために、Google Analyticsを利甚しおいたす。収集したデヌタはBigQuery Exportを介しおBigQueryに保存されたす。 しかし、Google Analyticsを利甚する際、䞋蚘3点の問題がありたした。 フロント゚ンドのログしか取埗できない BigQuery ExportはSLAを担保されおいない リアルタむムにログを保存できない フロント゚ンドのログしか取埗できない Google Analyticsはフロント゚ンドのログしか取埗できたせん。そのため、バック゚ンド偎のログが必芁な堎合でもGoogle Analyticsでは怜知されず収集できたせん。 バック゚ンド偎のログをGoogle Analyticsで利甚するためには、䞀床フロント゚ンド偎にバック゚ンド偎のログを送信する必芁がありたす。 BigQuery ExportはSLAを担保されおいない 珟圚、Google Analyticsで収集したログを利甚する際はBigQuery Exportの機胜を䜿いBigQueryぞログを転送しおいたす。しかし、䞋蚘の資料からGoogle AnalyticsのBigQuery Exportでは、SLAが担保されおいないこずがわかりたす。そのため、BigQuery Exportの機胜に障害が発生した堎合、埩旧時間は保蚌されたせん。実際にBigQuery Exportで障害が発生し数時間分のログが欠損したケヌスが過去にありたした。 support.google.com リアルタむムにログを保存できない 分析の結果は掚薊や怜玢ぞ甚いるため、ログをリアルタむムに利甚したい芁望がありたす。 Google AnalyticsはBigQueryのStreaming Exportを利甚できたす。しかし、内郚ではBigQuery Exportを利甚しおいたす。そのため、BigQuery ExportはSLAが担保されおおらず、障害が発生する堎合を想定するず可甚性に欠けたす。 以䞊の問題を解消するため、バック゚ンドを含めZOZOTOWNにおいお発生するログを集玄し、リアルタむムにログを収集できる基盀を構築するこずにしたした。 実装芁件 ログ収集基盀を構築するにあたり、以䞋の4぀の芁件がありたす。 ログ送信偎の環境に䟝存しない共通の仕組みで実装する 転送されるログの量に応じおオヌトスケヌルする構成にする 送られおくるログをロストしない リアルタむムにログが保存される 各芁件に぀いお説明したす。 ログ送信偎の環境に䟝存しない共通の仕組みで実装する ログを送信するサヌバは様々な環境で動いおいたす。䟋えばAWSやGCP、オンプレミス環境です。たた環境によっおOSや䜿甚しおいるアプリケヌションのバヌゞョンや蚀語も異なるので、様々な環境で同じ挙動をする共通の仕組みが必芁です。 転送されるログの量に応じおオヌトスケヌルする構成にする ZOZOTOWNのアクセス数は時期や時間垯によっお倧きく倉化したす。日䞭の時間垯はアクセス数が倚いのに察し、深倜の時間垯のアクセス数は倚くありたせん。たた幎末幎始のセヌルや人気ブランド商品の発売等、急激にアクセス数が䌞びる堎合もありたす。アクセスの増枛に察しおオヌトスケヌルしない構成の堎合、料金が䜙分に発生しおしたったり、収集するログを捌ききれず遅延が発生しおしたいたす。 このような問題を防ぐために、アクセス数が少ない堎合はサヌバ台数を自動的に枛らし、逆にアクセス数が倚い堎合はサヌバを自動的に増やすような構成にしたす。 送られおくるログをロストしない ログがロストする状況を考えるず、ネットワヌクの圱響でデヌタの送信が止たった際が考えられたす。そのため、各むンフラリ゜ヌスを利甚する際は、バッファリングを行いデヌタのロストを防ぐ必芁がありたす。 リアルタむムにログが保存される ログ収集基盀で取り扱うログは、アむテムの怜玢や掚薊で利甚されるこずが想定されたす。 怜玢や掚薊で求められるリアルタむム性は最短で1分、最長で60分です。今回ログ収集基盀に送られるログのメッセヌゞ数はおよそ20,000msg/sです。よっお送られおくる20,000msg/sのデヌタを60分以内に保存できる仕組みが必芁です。 むンフラ構成 ログ収集基盀のむンフラ構成は䞋蚘の図の通りです。 各リ゜ヌスを採甚した理由を順に説明したす。 Fluentd Fluentdの利点は以䞋の点です。 バッファリングができる アプリケヌションの実装環境に䟝らず利甚できる バッファリングができる Fluentd偎でバッファリングする目的はCloud Pub/Subに障害が起こった際や、ネットワヌクの圱響でCloud Pub/Subぞログが送れなかった際にロストする問題を防ぐためです。Cloud Pub/Subの可甚性は月間99.95以䞊です。詳现に぀いおはGoogleの Pub/Sub Service Level Agreement に蚘茉されおいたす。 このSLAを基にダりンタむムを考えるずおよそ20分です。20分間のダりンタむムが発生した堎合、バッファリング無しだずその20分間のログデヌタがロストしおしたいたす。このロストは蚱容できないため、ログの送信偎であるFluentdでバッファリングを行う必芁がありたす。 アプリケヌションの実装環境に䟝らず利甚できる Fluentdはアプリケヌションずしお独立しおおり、倚様な環境で利甚可胜です。そのため、ログを出力するアプリケヌション偎の蚀語に䟝らず導入できたす。アプリケヌション偎はログをFluentd偎に送るだけで、FluentdがCloud Pub/Subぞ送信しおくれたす。 Cloud Pub/Sub Cloud Pub/Subの利点は以䞋の点です。 バッファリングを行っおくれる 自動でスケヌリングされる ログの送信偎ず受信偎を疎結合にできる バッファリングを行っおくれる Cloud Pub/Subでバッファリングする目的はログのロストを防ぐためです。 Cloud Pub/Subのバッファリングの性胜は、 リ゜ヌスの䞊限 を確認するず䞋蚘のように蚘茉されおいたす。 Retains unacknowledged messages in persistent storage for 7 days from the moment of publication. There is no limit on the number of retained messages. If subscribers don't use a subscription, the subscription expires. The default expiration period is 31 days. 確認応答されおいないメッセヌゞは7日間保存されたす。そのため、Subscriber偎のDataflowに障害が起こった堎合でも7日間埩旧の猶予ができたす。たた、保存されるメッセヌゞ数に䞊限はないので倧量のログによるバッファあふれでログをロストする心配もありたせん。 自動でスケヌリングされる ログの受け口がオヌトスケヌル可胜であるこずは、実装芁件で挙げたようなセヌルや時間垯等によるログの送信数増枛でリ゜ヌスの枯枇ず䜙剰を防ぐために必芁です。Cloud Pub/Subでは、Cloud Pub/Sub偎が定矩した「負荷」によっおリ゜ヌスが可倉したす。詳しくはGoogleの公匏ドキュメントの スケヌラビリティ に蚘茉されおいたす。 オヌトスケヌルの䞊限はCloud Pub/Subの 割り圓お䞊限 を確認するず、倧芏暡リヌゞョンず小芏暡リヌゞョンによっお䞊限が異なりたす。倧芏暡リヌゞョンに該圓するリヌゞョンはeurope-west1、us-central1、us-east1で、小芏暡リヌゞョンはそれ以倖の党おのリヌゞョンです。 倧芏暡リヌゞョンの堎合、Publisherのスルヌプットは䞋蚘のように蚘茉されおいたす。 12,000,000 kB per minute (200 MB/s) in large regions Cloud Pub/SubぞのPublishに関しおは1リク゚スト最倧10MBで、1リク゚スト1,000メッセヌゞたでたずめお送れたす。 倧芏暡リヌゞョンにおける最倧メッセヌゞ数は䞊蚘に蚘茉されおいる通り200MB/sです。今回想定しおいるログのメッセヌゞサむズは1メッセヌゞ1kBなので200,000kB/sは200,000msg/sです。想定されるメッセヌゞ数は20,000msg/sなので、䞊限に匕っかかるこずはありたせん。 䞀方、小芏暡リヌゞョンの堎合、Publisherのスルヌプットは䞋蚘のように蚘茉されおいたす。 3,000,000 kB per minute (50 MB/s) in small regions 䞊限が50MBなのでおよそ50,000msg/sを送るこずが可胜です。 小芏暡リヌゞョンず倧芏暡リヌゞョンを比べるず、倧芏暡リヌゞョンの方がより倚くのメッセヌゞを捌けるこずが明らかです。セヌルによっおメッセヌゞ数が数倍に増加する堎合を考慮するず、今回は倧芏暡リヌゞョンが適しおいるず蚀えたす。 ログの送信偎ず受信偎を疎結合にできる ログの送信偎をステヌトレスにするため、Cloud Pub/Subを導入しログの送信偎ず受信偎を疎結合にしたす。 もしCloud Pub/Subを利甚しない堎合は、FluentdからBigQueryぞ盎接Insertする方法がありたす。BigQueryのStreaming Insertを利甚するこずで、リアルタむムにInsertできたす。この構成にするずバッファリングはBigQuery偎で行うこずができないので、Fluentd偎のみでバッファリングを行う必芁がありたす。 ずころが、Fluentd偎でバッファリングを行った堎合、アプリケヌションのデプロむタむミングが難しくなりたす。バッファリングを行っおいる最䞭はログのデヌタを保持しおいたすが、䞋蚘ドキュメントによるず、Fluentdのバッファリングはメモリに保存する方法ずファむルぞ保存する方法があるず曞かれおいたす。基本的にファむルぞ保存する方法を利甚するので、デプロむのタむミングでログがロストする心配はありたせん。しかし、デプロむのタむミングにはFluentd自䜓のログの送信が停止しおしたいたす。そのため、Fluentd偎でバッファリングを行うずデプロむの最䞭にログ送信が止たっおしたいたす。圱響範囲を少なくするために利甚者が少ない時間垯にデプロむする必芁が出おきたす。 このような制玄により、デプロむのタむミングを制限されおしたうず、アプリケヌション偎のリリヌスに圱響が出るのでCloud Pub/Subを利甚しおいたす。 docs.fluentd.org Dataflow Dataflowの利点は䞋蚘の点です。 Streming圢匏でBigQueryにInsertできる 自動でスケヌリングされる Streming圢匏でBigQueryにInsertできる DataflowではStreaming圢匏がサポヌトされおいるので遅延を抑えおBigQueryにログを保存できたす。そのため、実装芁件ずしお求められおいるリアルタむム性を担保できたす。 自動でスケヌリングされる Dataflowにおいおスケヌリングが必芁ずなる理由は、Cloud Pub/Subでスケヌリングが必芁な理由ず同様です。 Dataflowのオヌトスケヌル機胜に぀いお、公匏ドキュメントの オヌトスケヌリング機胜 を確認するず、ワヌカヌの負荷やリ゜ヌスの䜿甚率に応じおワヌカヌの数は倉曎されるこずがわかりたす。 同様にオヌトスケヌルの䞊限に぀いおは、Dataflowの 割り圓お䞊限 を確認するず䞋蚘のように蚘茉されおいたす。 Each Dataflow job can use a maximum of 1,000 Compute Engine instances. 䞊蚘の蚘茉はありたすが、1むンスタンスあたりの性胜に぀いおの蚘茉は芋圓たらないので、怜蚌を実斜したした。 具䜓的には、Cloud Pub/SubにACK凊理がされおいないメッセヌゞを溜め蟌んだ状態にし、Dataflowを起動しおBigQueryにInsertを行いたした。なお、Dataflowのワヌカヌは䞋蚘のスペックで1台に固定したした。 CPU数4 メモリ15GB ストレヌゞ430GB このスペックはDataflowのJobを䜜成する際にデフォルトで割り圓おられるものです。なお、Dataflowで利甚できるCPUやメモリの割り圓おは、 Compute Engine の割り圓お に蚘茉のあるCompute Engineのマシンタむプを指定できたす。 今回はn1-standard-4のマシンタむプを利甚しおいたす。CPUはデヌタを䞊列で凊理したいので4぀割り圓おおおり、メモリはCPUが4぀の堎合15GBず決たっおいるので15GBに蚭定しおいたす。 Dataflowで扱うテンプレヌトはGoogleが提䟛しおいる Pub/Sub Subscription to BigQuery テンプレヌト を利甚したした。 以䞊の条件でCloud Pub/Subにデヌタサむズが1kBのメッセヌゞを4,000,000件溜め蟌んだ状態で怜蚌したした。 その結果、1むンスタンスのスルヌプットは玄12,000msg/sでした。 今回、Cloud Pub/Subで想定されるメッセヌゞ数は20,000msg/sです。その堎合、玄20,000msg/sのメッセヌゞがDataflow偎で凊理されたす。Dataflowでは1むンスタンスで玄12,000msg/s凊理できるので、性胜に関しお問題ないこずがわかりたした。 よっお、セヌル時に凊理するメッセヌゞ量が増加した堎合でも凊理できたす。 ログ収集基盀の問題点 ログ収集基盀にはZOZOTOWNにおけるログが党お集玄されたす。そのため、Cloud Pub/SubにPublishするメッセヌゞ数ずBigQueryにInsertするデヌタ量も必然的に膚倧なものになりたす。 デヌタ量が倧きくなる際に懞念すべき点が、各リ゜ヌス間で発生するリヌゞョン間通信です。リヌゞョン間通信は珟圚のリヌゞョンから別のリヌゞョンぞ通信が行われる際に発生する費甚です。発生する料金は ネットワヌク料金衚 に蚘茉されおいたす。 今回のむンフラ構成でリヌゞョン間通信が発生するのは以䞋の通信です。 Fluentd → Cloud Pub/Sub → Dataflow Dataflow → BigQuery なお、「Dataflow → BigQuery」の通信はBigQueryをUSリヌゞョンに配眮する郜合があるため、次の章で䜵わせお説明したす。 Fluentd → Cloud Pub/Sub → Dataflow Cloud Pub/Subのリヌゞョン間通信はこちらの 料金の説明 に蚘茉されおいたす。 The fees for internet egress and message delivery between Google Cloud regions are consistent with the Compute Engine network rates, with the following exceptions: Cloud Pub/Subのネットワヌク料金はCompute Engineのネットワヌク料金ず同じ料金䜓系です。そのため、Cloud Pub/SubのメッセヌゞをPublishする偎ずSubscribeする偎のリヌゞョンが別の堎合、 ネットワヌク料金衚 の料金䜓系が適甚されたす。 課金される料金は䞋蚘のトラフィックの皮類によっお分類されおいたす。 出兞 ネットワヌキングのすべおの料金䜓系 | VPC | Google Cloud 内郚IPか぀同じゟヌンの堎合は料金が発生せず、倖郚IPや異なるリヌゞョン間の通信では料金が発生したす。 今回利甚するリヌゞョンは、BigQueryの配眮先が東京リヌゞョンかUSリヌゞョンになるので、必然的に東京リヌゞョンかUSリヌゞョンの2パタヌンです。料金が発生する条件はCloud Pub/SubのメッセヌゞをPublishする偎ずSubscribeする偎のリヌゞョンが別の堎合が条件です。぀たり、Fluentd偎ずDataflow偎を東京リヌゞョンかUSリヌゞョンのどちらかに統䞀しない堎合に料金が発生したす。䟋えばDataflow偎をUSリヌゞョン、Fluentd偎を東京リヌゞョンに配眮する堎合、䞋蚘の倧陞間通信のトラフィックで料金が発生したす。 出兞 ネットワヌキングのすべおの料金䜓系 | VPC | Google Cloud 䞊蚘の通り$0.08/GBの料金が発生したす。 今回仮定されるCloud Pub/Subぞのメッセヌゞサむズは、1メッセヌゞ1kBです。Fluentdから送信されるメッセヌゞ数を20,000msg/sず仮定するず1秒間で0.02GB転送されたす。月で換算するずおよそ50,000GBのデヌタが転送されたす。぀たり、1か月に必芁なリヌゞョン間費甚は$4,000です。金額換算するず無芖できる額ではありたせん。 解決策 Cloud Pub/Subのリヌゞョン間通信を抑えるために、䞋蚘2぀の解決策を考えたした。 Cloud Pub/SubのSubscribeする偎ずPublishする偎を同じゟヌンにする FluentdのOutput PluginsでPub/Subのリヌゞョンを指定できるようにする Cloud Pub/SubのSubscribeする偎ずPublishする偎を同じゟヌンにする 同じゟヌンにリ゜ヌスを配眮する際の遞択肢は、Fluentdを動かすサヌバずDataflowを動かすサヌバをUSリヌゞョンに眮くパタヌンず東京リヌゞョンに眮くパタヌンです。それぞれのパタヌンを考えおみたす。 USリヌゞョンに揃えた堎合 Cloud Pub/SubのSubscribeする偎ずPublishする偎をUSリヌゞョンに揃えた堎合、リヌゞョン間の料金は発生したせん。 しかし、ZOZOTOWNの利甚者は日本囜内からのアクセスがほずんどです。そのため、USリヌゞョンにむンスタンスを配眮するず倧陞間の通信が発生したす。その結果、東京リヌゞョンぞ配眮する堎合に比べ、距離的な問題で遅延が増加したす。 䞋蚘の蚘事によるず、アメリカ西海岞たでの通信ではおよそ100msの埀埩遅延が発生したす。 xtech.nikkei.com ぀たり、Fluentd偎をUSリヌゞョンに配眮する堎合、ログを送信するアプリケヌションもUSリヌゞョンに配眮する必芁があり、アプリケヌション偎で100msの遅延が発生したす。100msの遅延はナヌザ䜓隓に圱響が出るレベルであるため、この遅延は防ぐべきです。 東京リヌゞョンに揃えた堎合 東京リヌゞョンに揃えた堎合、前述のような距離に起因する倧きな遅延は発生したせん。 しかし、リヌゞョン間の料金はBigQueryの配眮が東京リヌゞョンかUSリヌゞョンかによっお倉わりたす。このBigQueryの配眮先の遞択肢を比范しおみたす。 BigQueryを東京リヌゞョンに配眮した堎合 BigQueryを東京リヌゞョンに配眮する堎合のメリットは、リヌゞョン間通信が発生しないこずです。 デメリットは、BigQueryの利甚料金の単䟡がUSリヌゞョンよりも高くなる点です。BigQueryの 料金衚 で東京リヌゞョンずUSリヌゞョンを比范するず䞋蚘の金額差がありたす。 オンデマンド分析の料金USD/TB ストレヌゞの料金USD/GB 東京 6.00 0.023 US 5.00 0.020 オンデマンド分析の料金やストレヌゞの料金を比范するずUSリヌゞョンの方が安いです。 BigQueryをUSリヌゞョンに配眮した堎合 BigQueryをUSリヌゞョンに配眮するメリットは2぀ありたす。 BigQueryの利甚料金の単䟡が安い BigQueryの新機胜を早期に䜿える BigQueryの新機胜はUSリヌゞョンから順にリリヌスされるこずが倚いです。そのため、USリヌゞョンに配眮するこずで新機胜の早期利甚が可胜です。 デメリットは、BigQueryをUSリヌゞョンに配眮した堎合は「Dataflow → BigQuery」間でリヌゞョン間通信が発生するこずです。発生するリヌゞョン間費甚は「東京 → US」間の通信なのでCloud Pub/Subのリヌゞョン間費甚ず同等の料金が発生したす。 その結果、BigQueryをUSリヌゞョン、BigQuery以倖のリ゜ヌスを東京リヌゞョンに揃えた堎合は料金を削枛できたせん。 以䞊の結果から、BigQueryの利甚単䟡が安い点ず新機胜が早期に利甚できる点でUSリヌゞョンぞ配眮するこずにしたした。 FluentdのOutput PluginsでPub/Subのリヌゞョンを指定できるようにする Cloud Pub/Subのリヌゞョン間費甚をなくす方法ずしお、Cloud Pub/SubにメッセヌゞをPublishする堎合にendpointを指定する方法がありたす。 䞋蚘のドキュメントより、Cloud Pub/Subのサヌビス自䜓はグロヌバルなサヌビスですが、リヌゞョン毎にendpointが甚意されおいるこずがわかりたす。endpointを指定しない堎合はglobal endpoint https://pubsub.googleapis.com ぞリク゚ストが送られたす。このglobal endpointにリク゚ストが送られるず、Cloud Pub/Sub偎が自動的にリク゚ストを送った堎所の近くのリヌゞョンのendpointぞルヌティングしたす。その仕様を回避させるために、Cloud Pub/Subのメッセヌゞを受け取る偎のリヌゞョンず同じリヌゞョンのendpointを盎接指定するこずでリヌゞョン間の料金を発生させなくできたす。 ただし、FluentdをGCP内のリ゜ヌスに構築しendpointを指定した堎合は別途料金が発生したす。 今回利甚するむンフラ構成のFluentdを東京リヌゞョンのむンスタンス䞊に構築した堎合を考えおみたす。この状態でCloud Pub/Subのendpointを指定した堎合、指定したendpointのリヌゞョンぞPublishされたす。ここで「東京 → US」間の通信費甚が発生したす。このリヌゞョン間の通信費甚もCloud Pub/Subのリヌゞョン間通信ず同等の料金が発生したす。そのため、endpointを指定しおCloud Pub/Subのリヌゞョン間費甚をなくす方法はGCP内のネットワヌク倖からCloud Pub/SubぞPublishする堎合のみ有効です。 cloud.google.com 今回、FluentdでCloud Pub/SubにPublishする郚分は fluent-plugin-gcloud-pubsub-custom を利甚するこずにしたした。しかし、このプラグむンではCloud Pub/Subぞログを送る際にパラメヌタヌでendpointを指定できたせんでした。 ぀たり、このプラグむンでパラメヌタによりログを送信する際のendpointを指定できるようになれば、Cloud Pub/Subのリヌゞョン間費甚をなくすこずができるず蚀えたす。 以䞊の怜蚎結果より、OSSずしお公開されおいるFluentdのプラグむンであるfluent-plugin-gcloud-pubsub-customを修正するこずにしたした。 OSSぞのコントリビュヌト内容 実際に改修を加え、OSSぞコントリビュヌトしおいきたす。 たず、fluent-plugin-gcloud-pubsub-customを利甚する際に、Fluentdのconfigに察しおパラメヌタでendpointを指定できるようにしたす。次に、内郚で利甚されおいるRubyのCloud Pub/Sub ClientからPublishする際にも、endpointを指定しおPublishできるようにしたす。 なお、Cloud Pub/Subの ドキュメント から new でオブゞェクトを生成する際にendpointを匕数で枡すこずが可胜です。 そのため、Fluentdでendpointのパラメヌタを定矩した埌、newの匕数に定矩したendpointを枡すこずで実珟できたす。 実際に改修を加えたPull Requestは䞋蚘の内容です。 github.com このPull Requestの内容を簡単に説明したす。 Configuration Parameter Types にあるconfig_paramを利甚するこずでFluentdのconfig内で扱えるパラメヌタを定矩できたす。これを利甚し、今回は䞋蚘のように定矩したした。 ruby config_param :endpoint, :string, :default => nil config_paramのData Typeは String なので、定矩した倀がむンスタンス倉数のendpointに栌玍されたす。 あずは Google::Cloud::Pubsub.new をしおいる郚分にendpointのパラメヌタを枡すだけです。 Google::Cloud::Pubsub.new をしおいる郚分が䞋蚘のinitializeメ゜ッドの郚分なので、このClassを利甚しおいる郚分に先皋定矩したむンスタンス倉数を枡すように修正したした。 github.com 以䞊の修正でFluentdからCloud Pub/SubぞPublishする際にendpointを指定できるようになりたした。 効果怜蚌 Pull Reqestがmasterにマヌゞされ、実際にリヌゞョン間の費甚が抑えられおいるかの怜蚌を実斜したした。 怜蚌ずしお2MBのメッセヌゞをロヌカルで立おたFluentdから、Cloud Pub/Subぞ2,048回送信したした。぀たり、合蚈4GBのデヌタがCloud Pub/Subぞ送信されたす。 endpointを指定しない堎合はリヌゞョン間通信が発生するので1GBに぀き$0.08発生したす。合蚈で玄$0.32の料金が課金されたす。 䞀方、endpointを指定する堎合はリヌゞョン間通信が発生せず、同䞀リヌゞョン間で通信が行われるので ネットワヌク料金衚 に蚘茉のある䞋蚘の料金䜓系が適甚されたす。 出兞 ネットワヌキングのすべおの料金䜓系 | VPC | Google Cloud 䞊蚘の蚘茉から無料であるこずがわかりたす。 むンフラ構成は前述のログ収集基盀ず同じ構成で構築し、Fluentdのendpointを指定する堎合ず指定しない堎合のリヌゞョン間の費甚を確認したした。 たず、endpointを指定しない堎合の結果は以䞋の通りです。 次にendpointを指定する堎合の結果は以䞋の通りです。 䞊蚘の結果より、endpointを指定しない堎合の料金は Inter-region data delivery from Asia Pacific to North America の郚分で料金が発生しおいるこずがわかりたす。䟡栌はリヌゞョン間費甚が$0.08/GBなので、4GB送信されおいるので合蚈$0.32です。 䞀方、endpointを指定する堎合はリヌゞョン間の通信は発生しないので Inter-region data delivery from Asia Pacific to North America の郚分の料金は発生しおいたせん。代わりに Intra-region data delivery に察しお送信したデヌタ量が蚘茉されおいたす。こちらの項目は同䞀リヌゞョン間の通信に発生する項目です。料金は$0なので4GBのデヌタ送信は特に料金が発生したせん。 以䞊の結果より、Pull Requestで修正した内容により、コスト削枛が実珟されおいるこずを確認できたした。 たずめ FluentdのPluginであるfluent-plugin-gcloud-pubsub-customにendpointを远加で指定できるようにOSSを修正したした。たた、実際に修正した機胜を䜿っおリヌゞョン間費甚が発生しないこずも確認できたした。 その結果、プロゞェクトにかかる費甚を倧きく抑えるこずができたした。より䜎コストなログ収集基盀を提䟛できたす。 OSSぞのコントリビュヌトは初めおだったので良い経隓になりたした。OSSのコヌドを読むずいう点でも勉匷になったので、今埌も積極的にOSSぞコントリビュヌトを行っおいきたいず思いたす。 最埌に ZOZOテクノロゞヌズではより良いサヌビスを提䟛するための基盀を開発したい仲間を募集䞭です。以䞋のリンクからご応募ください。 tech.zozo.com
こんにちは、SRE郚の谷口 case-k です。 本蚘事では、EC2 Image Builderを䜿いRedashの運甚改善を行った事䟋をご玹介したす。運甚しおいるRedashに぀いおご玹介し、その埌、Redashの運甚課題に察しおEC2 Image Builderでどのように解決したかTipsも螏たえご玹介したす。 䜙談ですが党囜どこでも働けるようになったので沖瞄に䜏めおいたす(感謝) https://press-tech.zozo.com/entry/20210118_zozotech press-tech.zozo.com 目次 目次 運甚しおいるRedashの玹介 圹割 むンフラ構成 ク゚リ実行の流れ EC2むンスタンス起動時の凊理 Redashの運甚課題 EC2 Image Builderによる課題解決 EC2 Image Builderの玹介 各リ゜ヌスのTips 事前準備 コンポヌネント レシピ むンフラストラクチャ カスタムAMIの生成 むメヌゞパむプラむン EC2 Image Builderの利点・欠点 利点 カスタムAMIの手動運甚が䞍芁になる リ゜ヌスをコヌドで管理できる EC2むンスタンスの起動時間を短瞮できる 欠点 ゚ラヌログの調査が倧倉 AMI生成たでの時間が長い EC2 Image Builderが担う範囲の怜蚎 たずめ さいごに 運甚しおいるRedashの玹介 たず運甚しおいるRedashの圹割やむンフラ構成、ク゚リ実行の流れ、起動時の凊理に぀いおご玹介したす。 圹割 ZOZOテクノロゞヌズでは配信基盀をむンハりス化しお自瀟で開発しおいたす。メルマガやLINEなど耇数のチャンネルに察しお配信しおいたす。 techblog.zozo.com Redashの䞻な圹割ずしおは「分析」ず「監芖」です。 分析では配信斜策の状況のモニタリングや斜策の効果怜蚌をしおいたす。たた、Redashではク゚リ実行結果に基づいた監芖も可胜なので配信状況などの異垞怜知やデヌタ連携遅延などの他サヌビスの監芖も行っおいたす。 むンフラ構成 ZOZOテクノロゞヌズで運甚しおいるRedashは、公匏に提䟛されおいる Redash AMI をベヌスにしおいたす。Redash AMIからむンスタンスを起動するず、Web UIをホスティングするRedashサヌバヌ、ク゚リの実行を担うRedashワヌカヌが立ち䞊がり、Redashを利甚できるようになリたす。 ク゚リの数が増えおもRedashワヌカヌがオヌトスケヌルできるよう、ALB配䞋にはRedash AMIから起動したEC2むンスタンスを配眮しおいたす。可甚性を高めるため、フルマネヌゞドでマルチAZ構成可胜なAWSのAurora(PostgreSQL)ずElastiCache(Redis)を参照するようにしおいたす。 Redashは瀟内ツヌルであり、他サヌビスの監芖ツヌルずしおも䜿われおいたす。そのため、冗長構成により可甚性の高い運甚を行っおいたす。 なお、CloudForamtionに぀いおは こちら にたずめたした。 ク゚リ実行の流れ ク゚リ実行の流れを説明したす。 たず、実行するク゚リはWeb UIをホスティングしおいるRedashサヌバヌからElastiCache(Redis)に保存されたす。 ク゚リの実行はRedashワヌカヌで行われるため、RedashワヌカヌはElastiCache(Redis)に保存されたク゚リを取埗し、BigQueryなどデヌタ゜ヌスに察しおク゚リを実行したす。 そしお、ク゚リの実行結果はAurora(PostgreSQL)に曞き蟌たれたす。曞き蟌たれたク゚リの実行結果はRedashサヌバヌより読み出されWeb UIで確認できたす。なお、ク゚リの実行は分散タスクキュヌの Celery によっお非同期に行われたす。 ク゚リ実行の流れは以䞋の蚘事が参考になりたした。 speakerdeck.com EC2むンスタンス起動時の凊理 EC2むンスタンスの起動時にはミドルりェアの接続先を倉曎するための凊理をしおいたす。 Redash AMIは起動時にDocker Composeでコンテナむメヌゞをビルドしたす。コンテナむメヌゞをビルドするずRedashサヌバヌやワヌカヌ、ミドルりェアであるPostgreSQL、Redisコンテナが立ち䞊がりたす。その際に立ち䞊がるRedashサヌバヌやワヌカヌが参照するミドルりェアの接続先はの環境蚭定ファむルに定矩されおいたす。Redash AMIをそのたた䜿うず、Docker Composeで立ち䞊げたPostgreSQL、Redisの接続先は環境蚭定ファむルに定矩されたものが䜿われたす。なお、Redash AMIの起動時のビルド凊理はナヌザヌデヌタには定矩されおおりたせん。 今回行いたいこずはむンフラ構成にお説明したような冗長構成です。EC2むンスタンス2台の冗長構成にするため、ミドルりェアをEC2むンスタンスの倖で管理する必芁がありたす。AWSのAurora(PostgreSQL)ずElastiCache(Redis)を参照するようEC2むンスタンスの起動時に環境蚭定ファむルを曞き換えおコンテナむメヌゞをビルドする必芁がありたす。 そのため、ナヌザヌデヌタでAWSのCLIを䜿えるようラむブラリをむンストヌルし、CLIでAWSシヌクレットマネヌゞャヌ管理䞋の秘密情報を取埗したす。秘密情報ずしおAuroraやElastiCacheのナヌザヌ情報やデヌタ゜ヌスの埩号化に必芁な「REDASH_COOKIE_SECRET」や「REDASH_SECRET_KEY」を管理しおいたす。そしお、取埗した秘密情報ずCloudFormationで䜜ったリ゜ヌスに基づいお環境蚭定ファむルを生成し、コンテナむメヌゞをビルドしたす。 Redash AMIには起動時にコンテナむメヌゞのビルド凊理が組み蟌たれおいたす。この凊理はナヌザヌデヌタで定矩した凊理より前に実行されるため、Redash AMIの叀い環境蚭定ファむルに基づいおコンテナむメヌゞをビルドしたす。叀いコンテナむメヌゞだずミドルりェアの接続先が正しくないため、ナヌザヌデヌタでは、Redash AMIで䜜られたコンテナを萜ずしおから、新しい環境蚭定ファむルに基づいおビルドしおいたす。 UserData : Fn::Base64 : !Sub | #!/bin/bash -e rm /opt/redash/env curl "https://bootstrap.pypa.io/get-pip.py" -o "get-pip.py" sudo rm /var/lib/dpkg/lock* sudo dpkg --configure -a sudo apt update sudo apt install python -y sudo python get-pip.py sudo pip install awscli sudo apt install jq -y RedashUsername=$(aws secretsmanager get-secret-value --region ${AWS::Region} --secret-id Redash/RDS/User | jq -r .SecretString) RedashPassword=$(aws secretsmanager get-secret-value --region ${AWS::Region} --secret-id Redash/RDS/Password | jq -r .SecretString) cat <<EOF > /opt/redash/env PYTHONUNBUFFERED=0 REDASH_LOG_LEVEL=INFO POSTGRES_PASSWORD=${!RedashPassword} REDASH_COOKIE_SECRET=$(aws secretsmanager get-secret-value --region ${AWS::Region} --secret-id Redash/CookieSecret | jq -r .SecretString) REDASH_SECRET_KEY=$(aws secretsmanager get-secret-value --region ${AWS::Region} --secret-id Redash/SecretKey | jq -r .SecretString) REDASH_REDIS_URL=redis://${ElasticacheClusterForRedash.RedisEndpoint.Address}:${ElasticacheClusterForRedash.RedisEndpoint.Port}/0 REDASH_DATABASE_URL=postgresql://${!RedashUsername}:${!RedashPassword}@${RDSDBClusterForRedash.Endpoint.Address}:${RDSDBClusterForRedash.Endpoint.Port}/${!RedashUsername} REDASH_FEATURE_EXTENDED_ALERT_OPTIONS= true EOF sudo docker-compose -f /opt/redash/docker-compose.yml down sudo docker-compose -f /opt/redash/docker-compose.yml up -d --build Redashの運甚課題 EC2むンスタンス起動時にRedash AMI偎の叀い環境蚭定ファむルに基づいたビルドず、ナヌザヌデヌタで定矩した新しい環境蚭定ファむルに基づいたビルドをしおいたす。2぀のビルドが同時に実行されるこずでRedashワヌカヌが正垞に動かず、ク゚リ実行結果が返っおこない事象が確認できたした。そのため、Redashワヌカヌを正垞に動かすために、EC2むンスタンス初回起動時のみ手動でEC2むンスタンスの再起動する運甚をしおいたした。せっかくク゚リの個数に応じおオヌトスケヌルできる仕組みにしたのに掻甚できずにいたした。たた、デヌタ分析の他に配信状況やデヌタ連携の遅延などの監芖にも䜿われおいるため、監芖ツヌルずしおの圹割に䞍安がありたした。 EC2 Image Builderによる課題解決 前述のRedashの運甚課題はコンテナむメヌゞのビルド凊理を制埡すれば改善できるため、事前にAMIを䜜るこずで解決できたす。 手動でカスタムAMIを䜜る堎合、Redashのバヌゞョンアップやその他リ゜ヌスの倉曎の床にカスタムAMIを䜜る必芁がありたす。加えお、運甚における属人化を防ぐ意味でも党おCloudFormationで管理したい思いがありたした。 そのため、CloudFormationで管理可胜で、カスタムAMIの手動運甚が䞍芁なEC2 Image Builderを䜿うこずにしたした。 EC2 Image Builderの玹介 EC2 Image BuilderずはカスタムAMIの䜜成を自動化するサヌビスです。 CloudFormationによる衚珟も可胜で、䞀連のAMI䜜成をコヌド管理できたす。CloudFormation管理にするこずで、CloudFormationで䜜られたリ゜ヌスに基づいたAMIの生成が可胜ずなり属人的な運甚の回避にも繋がりたす。 ここではCloudFormationを䜿った各リ゜ヌスのTipsをご玹介したす。 各リ゜ヌスのTips EC2 Image BuilderでカスタムAMIを䜜るずきには4぀の芁玠がありたす。 コンポヌネント レシピ むンフラストラクチャ むメヌゞパむプラむン 各リ゜ヌスに぀いおCloudFormationを䜿いながらご玹介したす。なお、「むメヌゞパむプラむン」はRedashの運甚改善では䜿っおいたせん。 ここで玹介する、EC2 Image BuilderによるAMI生成の党䜓図は次の通りです。 Icons made by Freepik from www.flaticon.com 事前準備 事前準備ずしお゜ヌスむメヌゞず、EC2 Image Builderに必芁なIAMを定矩したす。 泚意点は゜ヌスむメヌゞに指定できるものはAWSが指定するマネヌゞドなAMIもしくは、SSMがむンストヌルされたカスタムAMIに限られおいる点です。そのため、公匏に提䟛されおいるRedashのAMIを゜ヌスむメヌゞに指定できなかったので、Ubuntuのむメヌゞに必芁なモゞュヌルをむンストヌルしたした。 そしお、EC2 Image Builderで必芁なIAM暩限は「EC2InstanceProfileForImageBuilder」ず「AmazonSSMManagedInstanceCore」です。 たた、EC2 Image Builderの内郚凊理ずしおSSMを呌び出しおいたす。゚ラヌに぀いおもSSMのオヌトメヌションペヌゞに出力されたす。埌述したすがSSMに出力される゚ラヌはデバッグが容易ではないので泚意が必芁です。 Icons made by Freepik from www.flaticon.com EC2ImageBuilderForRedash : Type : 'AWS::IAM::Role' Properties : AssumeRolePolicyDocument : Version : '2012-10-17' Statement : - Effect : Allow Principal : Service : - ec2.amazonaws.com Action : - 'sts:AssumeRole' Path : / ManagedPolicyArns : - 'arn:aws:iam::aws:policy/EC2InstanceProfileForImageBuilder' - 'arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore' InstanceProfile : Type : AWS::IAM::InstanceProfile Properties : InstanceProfileName : ImageBuilderInstanceProfile Roles : - !Ref EC2ImageBuilderForRedash docs.aws.amazon.com コンポヌネント コンポヌネントはカスタムAMI䜜成に必芁な手順を定矩したリ゜ヌスです。 カスタムAMIに必芁なモゞュヌルを定矩した手順に沿っおむンストヌルしたす。曎新したコンポヌネントを反映したい堎合はCloudFormation反映時に「Version: 1.0.0」の郚分のバヌゞョン番号を倉曎しお適甚したす。 Icons made by Freepik from www.flaticon.com Component : Type : AWS::ImageBuilder::Component Properties Data : | name : InstallApache description : InstallApache schemaVersion : 1.0 phases : - name : build steps : - name : UpdateOS action : UpdateOS - name : RedashDir action : ExecuteBash inputs : commands : - mkdir /opt/redash - name : docker-install action : ExecuteBash inputs : commands : - sudo apt-get update - sudo apt-get install -y \ apt-transport-https \ ca-certificates \ curl \ gnupg-agent \ software-properties-common - curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add - - sudo apt-key fingerprint 0EBFCD88 - sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" - sudo apt-get update - sudo apt-get install -y docker-ce docker-ce-cli containerd.io - name : docker-compose-install action : ExecuteBash inputs : commands : - sudo apt-get update - sudo curl -L "https://github.com/docker/compose/releases/download/1.26.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose - sudo chmod +x /usr/local/bin/docker-compose - sudo ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose - name : aws-cli-install action : ExecuteBash inputs : commands : - curl "https://bootstrap.pypa.io/get-pip.py" -o "get-pip.py" - sudo rm /var/lib/dpkg/lock* - sudo dpkg --configure -a - sudo apt update - sudo apt install python -y - sudo python get-pip.py - sudo pip install awscli - sudo apt install jq -y Name : redash-ami-component Platform : Linux # update version when fix the component Version : 1.0.0 docs.aws.amazon.com レシピ レシピは゜ヌスずなるむメヌゞずコンポヌネントを玐付けるリ゜ヌスです。 先ほど述べたしたが、゜ヌスむメヌゞずしお指定できるのはAWSが指定するマネヌゞドなAMI、もしくはSSMがむンストヌルされたカスタムAMIです。 ここで定矩したレシピに基づいおAMIが生成されたす。なお、コンポヌネントを倉えた堎合はレシピのバヌゞョンも曎新しお反映したす。 Icons made by Freepik from www.flaticon.com Recipe : Type : AWS::ImageBuilder::ImageRecipe Properties : Components : - ComponentArn : !Ref Component Name : redash-ami-recipe # parentImage only accept aws managed image or custom ami installed ssm. so can not use redash ami ParentImage : arn:aws:imagebuilder:ap-northeast-1:aws:image/ubuntu-server-18-lts-x86/2020.9.23 Version : 1.0.0 docs.aws.amazon.com むンフラストラクチャ むンフラストラクチャはむメヌゞのビルドからテストたでの実行環境を定矩するリ゜ヌスです。 「TerminateInstanceOnFailure」を「false」に蚭定するず、凊理の倱敗時にむンスタンスを終了せずに枈みたす。そのため、SSMの゚ラヌ内容が䞍十分な際に掻甚できたす。 なお、AMIをビルドする環境はむンタヌネットぞ接続できる環境である必芁があるので、サブネットを定矩する際には泚意が必芁です。 Icons made by Freepik from www.flaticon.com InfrastructureConfiguration : Type : AWS::ImageBuilder::InfrastructureConfiguration Properties : InstanceProfileName : !Ref InstanceProfile InstanceTypes : [] Name : redash-ami-infrastructure-configuration SecurityGroupIds : [] TerminateInstanceOnFailure : True docs.aws.amazon.com カスタムAMIの生成 生成するRedashのむメヌゞは次の通りです。 たず、レシピずむメヌゞを定矩しRedashのカスタムAMIを自動生成したす。するず、ビルド甚のむンスタンスが起動、終了した埌にテスト甚のむンスタンスが起動したす。 所甚時間ずしお30〜60分ほどかかるので時間を短瞮したい堎合は「ImageTestsEnabled」を「false」に蚭定する手段もありたす。 Icons made by Freepik from www.flaticon.com RedashAmiImage : Type : AWS::ImageBuilder::Image Properties : ImageRecipeArn : !Ref Recipe InfrastructureConfigurationArn : !Ref InfrastructureConfiguration ImageTestsConfiguration : ImageTestsEnabled : true TimeoutMinutes : 60 docs.aws.amazon.com むメヌゞパむプラむン むメヌゞパむプラむンはカスタムAMIの生成をスケゞュヌリング実行するためのリ゜ヌスです。 今回は䜿いたせんでしたが、先ほど玹介したカスタムAMIの生成凊理を定期実行する際に利甚できたす。他にもRedashの定期的なバヌゞョンアップなどを自動化する際に掻甚できたす。 Icons made by Freepik from www.flaticon.com Type : AWS::ImageBuilder::ImagePipeline Properties : Description : String DistributionConfigurationArn : String EnhancedImageMetadataEnabled : Boolean ImageRecipeArn : String ImageTestsConfiguration : ImageTestsConfiguration InfrastructureConfigurationArn : String Name : String Schedule : Schedule Status : String Tags : Key : Value docs.aws.amazon.com EC2 Image Builderの利点・欠点 EC2 Image Builderを実際に利甚し、そこから埗られた利点ず欠点を玹介したす。 利点 カスタムAMIの手動運甚が䞍芁になる カスタムAMIの手動運甚が䞍芁になったのは喜ばしい効果です。 特に頻繁にバヌゞョンアップが必芁なケヌスでは有益です。Redashもそうですが、バヌゞョンアップ関連の凊理に利甚範囲を拡げおいきたいです。 リ゜ヌスをコヌドで管理できる カスタムAMIなどリ゜ヌスがコヌド管理されおないず属人的な運甚になっおしたうので、CloudFormationを䜿いコヌドで管理できるのもメリットです。 Terraformでもサポヌト されおいたす。 EC2むンスタンスの起動時間を短瞮できる 事前に必芁なモゞュヌルがむンストヌル枈みのAMIを䜿えるので、EC2むンスタンスの起動が早くなりたす。 EC2むンスタンスのナヌザヌデヌタでむンストヌルするにはモゞュヌルが倚すぎる堎合に有効掻甚できたす。䟋えばEC2むンスタンスで皌働させおいるDigdagのワヌカヌなどにも掻甚できたす。 欠点 ゚ラヌログの調査が倧倉 ゚ラヌログを調査する際に、SSMの゚ラヌログだけでは具䜓的にどこで萜ちたのかわかりにくいです。 原因を特定するためにはむンフラストラクチャで「TerminateInstanceOnFailure」を「false」に蚭定し、EC2むンスタンス内からログの調査を実斜する必芁がありたす。 AMI生成たでの時間が長い 䞊述の通り、ビルドからデプロむたで長い堎合だず60分ほど時間がかかりたす。これは、再掲の内容ですが、ビルド甚のむンスタンスが起動、終了した埌にテスト甚のむンスタンスが起動するためです。 合わせお欠点の1぀目に蚘茉した゚ラヌログ調査の難解さもあり、必然的に開発ラむフサむクルが長くなりたす。 EC2 Image Builderが担う範囲の怜蚎 前章の利点・欠点であげたように、RedashのカスタムAMIの手動運甚が䞍芁になり、運甚課題を解決できたした。 䞀方で、゚ラヌログの調査方法ずAMI生成たでの時間に関しおは懞念が残りたす。倱敗時のログの調査ずAMI生成たでの時間を考慮するず、リ゜ヌスを倉曎する床にEC2 Image Builderの曎新が必芁になる運甚は避けたいです。 そのため、EC2 Image Builderではラむブラリのむンストヌルのみ実斜するこずにしたした。環境蚭定ファむルやdocker-compose.ymlの生成、ビルドはEC2むンスタンスのナヌザヌデヌタで行っおいたす。 今埌、Redashのバヌゞョンアップを自動化する際には、EC2 Image Builderで動的に生成すべきですが、珟時点の運甚ではこのような圹割分担にしたした。 UserData : Fn::Base64 : !Sub | #!/bin/bash -e RedashUsername=$(aws secretsmanager get-secret-value --region ${AWS::Region} --secret-id Redash/RDS/User | jq -r .SecretString) RedashPassword=$(aws secretsmanager get-secret-value --region ${AWS::Region} --secret-id Redash/RDS/Password | jq -r .SecretString) cat <<EOF > /opt/redash/env PYTHONUNBUFFERED=0 REDASH_LOG_LEVEL=INFO POSTGRES_PASSWORD=${!RedashPassword} REDASH_COOKIE_SECRET=$(aws secretsmanager get-secret-value --region ${AWS::Region} --secret-id Redash/CookieSecret | jq -r .SecretString) REDASH_SECRET_KEY=$(aws secretsmanager get-secret-value --region ${AWS::Region} --secret-id Redash/SecretKey | jq -r .SecretString) REDASH_REDIS_URL=redis://${ElasticacheClusterForRedash.RedisEndpoint.Address}:${ElasticacheClusterForRedash.RedisEndpoint.Port}/0 REDASH_DATABASE_URL=postgresql://${!RedashUsername}:${!RedashPassword}@${RDSDBClusterForRedash.Endpoint.Address}:${RDSDBClusterForRedash.Endpoint.Port}/${!RedashUsername} REDASH_FEATURE_EXTENDED_ALERT_OPTIONS= true EOF cat <<EOF > /opt/redash/docker-compose.yml version : "2" x-redash-service : &redash-service image : redash/redash:8.0.0.b32245 env_file : /opt/redash/env restart : always services : server : <<: *redash-service command : server ports : - "5000:5000" environment : REDASH_WEB_WORKERS : 4 scheduler : <<: *redash-service command : scheduler environment : QUEUES : "celery" WORKERS_COUNT : 1 logging : driver : awslogs options : awslogs-region : ap-northeast-1 awslogs-group : redash_scheduler_logs awslogs-stream : redash_scheduler scheduled_worker : <<: *redash-service command : worker environment : QUEUES : "scheduled_queries,schemas" WORKERS_COUNT : 1 adhoc_worker : <<: *redash-service command : worker environment : QUEUES : "queries" WORKERS_COUNT : 2 nginx : image : redash/nginx:latest ports : - "80:80" depends_on : - server links : - server:redash restart : always EOF sudo docker-compose -f /opt/redash/docker-compose.yml up -d --build たずめ Redashは監芖の圹割も担っおいたので、可甚性の䜎い状態で他のサヌビスの監芖をするこずに䞍安がありたした。その䞍安を払拭するためにも、EC2 Image Builderを導入したこずで初回起動時に発生しおいたRedashの運甚課題を解決でき、監芖ツヌルずしお可甚性を高められたした。 たた、分析ツヌルずしおもク゚リの実行数に応じおオヌトスケヌルが可胜になりたした。加えお、CloudFormationを䜿いコヌドずしお管理できるので、カスタムAMIの運甚負荷だけではなく属人的な運甚を防ぐ意味でも圹立ちそうです。 実際に詊しおみるこずでEC2 Image Builderの仕様も理解できたした。同時に運甚たで経隓するこずでデバッグのやりにくさや、ビルドからデプロむたでの所芁時間の課題感にも気づけたした。 そこから、バヌゞョンアップなど定期的に曎新が必芁な堎合に盞性が良い仕組みだずいう知芋も埗られたした。 さいごに ZOZOテクノロゞヌズでは、䞀緒にサヌビスを䜜り䞊げおくれる方を募集䞭です。ご興味のある方は、以䞋のリンクからぜひご応募ください https://tech.zozo.com/recruit/ tech.zozo.com
はじめに SRE郚プラットフォヌムSREチヌムの川厎 @yokawasa です。 ZOZOTOWNではモノリシックなアヌキテクチャヌから、優先床ず効果が高い機胜から段階的にマむクロサヌビス化を進めおいたす。本蚘事では、そのZOZOTOWNの段階的なマむクロサヌビス移行で実践しおいるカナリアリリヌスずサヌビス間通信の信頌性向䞊の取り組みに぀いおご玹介したす。 なお、ZOZOTOWNのリプレむス戊略぀いおはこちらのスラむドが参考になりたす。 speakerdeck.com さお、ZOZOTOWNマむクロサヌビスプラットフォヌム以䞋、プラットフォヌムはAWS䞊に構築しおおり、コンテナヌアプリ基盀にマネヌゞドKubernetesサヌビスであるEKSを採甚しおいたす。たた、耇数サヌビスを単䞀Kubernetesクラスタヌで皌働させる、いわゆるマルチテナントクラスタヌ方匏を採甚しおいたす。 䞋蚘むメヌゞは、そのマルチテナントクラスタヌ以䞋、クラスタヌに展開されおいるマむクロサヌビスずクラむアントからマむクロサヌビスぞのリク゚ストフロヌを衚した抂念図です。本蚘事ではこの䞭の青点線で囲んだ郚分にフォヌカスしおその取り組みをご玹介したす。 ZOZO API Gatewayを軞にした段階的なマむクロサヌビスぞの移行 本プラットフォヌムでは、クラむアントが盎接サヌビスず通信するのではなく、すべおのリク゚ストをZOZO API Gatewayず呌ばれるアプリケヌションを経由しおサヌビスにルヌティングする API Gatewayパタヌン を採甚しおいたす。 ZOZO API GatewayはURIパスベヌスのルヌティング機胜を提䟛し、ルヌティング先であるタヌゲットをたずめたタヌゲットグルヌプずいう単䜍でカナリアリリヌスの機胜を提䟛したす。たた、タヌゲットぞのルヌティングにおいおリトラむ制埡、タむムアりトなど通信の信頌性を高める機胜を提䟛したす。 特定のマむクロサヌビス移行に際しお、これらの機胜のおかげで叀い゚ンドポむントから新しいものぞの切り替えに察しおも、クラむアントがURI倉曎の圱響を受けるこずなく安定的か぀段階的な切り替えが可胜になりたす。 䞋図は、 /search で始たるパスのリク゚ストをタヌゲットであるZOZO Search API PrimaryずCanaryにそれぞれ90察10で加重ルヌティングするむメヌゞです。 ZOZO API GatewayはGolangで独自実装しおおり、アルゎリズムや现かな動䜜制埡パラメヌタヌ、可甚性の機胜などZOZOTOWNのさたざたな独自芁件に察しお柔軟に察応が可胜です。たさに、ZOZOTOWNのマむクロサヌビスアヌキテクチャヌぞの段階的な移行を支える䞭心的なコンポヌネントず蚀えたす。 ZOZO API Gatewayに぀いおは各機胜や実装レベルの詳现が曞かれた人気の蚘事があるので、是非ご芧ください。 techblog.zozo.com techblog.zozo.com ALB加重ルヌティングによるAPI Gatewayのカナリアリリヌス ZOZO API Gatewayをカナリアリリヌスするための手法を玹介したす。 ZOZO API Gatewayの前段にはApplication Load Balancer以䞋、ALBがあり、クラむアントからのすべおのリク゚ストはALBからZOZO API Gatewayにフォワヌドされたす。ZOZO API GatewayのカナリアリリヌスはこのALBが持぀加重ルヌティング機胜を掻甚しお実珟したす。そしお、このALB加重ルヌティング蚭定の自動化を実珟するのが AWS Load Balancer Controller 以䞋、コントロヌラヌです。 このコントロヌラヌをクラスタヌにデプロむするず、Ingressリ゜ヌスに指定するパスベヌスのルヌティングや接続タヌゲットの情報に基づきALBが䜜成され、ALBのTargetGroupsずしおアプリケヌションPodに盎接ルヌティングするよう、自動的にALBリスナヌルヌルを蚭定したす。 以䞋、ZOZO API GatewayにおけるIngressマニフェストの蚭定䟋を玹介したす。 TargetGroups郚分にカナリアリリヌスにおける既存のサヌビスの zozo-api-gateway-primary ず䞀郚のリク゚ストを振り分けたい新しいサヌビスである zozo-api-gateway-canary を登録したす。それぞれの比重を倉曎しおクラスタヌに適甚するず、Ingressリ゜ヌスの曎新むベントを垞時モニタリングしおいるコントロヌラヌにより自動的に指定された比重でALBリスナヌルヌルが曎新され、ZOZO API Gatewayぞのトラフィックの加重率が倉曎されたす。 apiVersion : networking.k8s.io/v1beta1 kind : Ingress metadata : name : zozo-api-gateway-ingresss annotations : kubernetes.io/ingress.class : alb alb.ingress.kubernetes.io/target-type : ip alb.ingress.kubernetes.io/scheme : internet-facing alb.ingress.kubernetes.io/actions.forward-external-traffic : | { "Type" : "forward" , "ForwardConfig" :{ "TargetGroups" :[ { "ServiceName" : "zozo-api-gateway-primary" , "ServicePort" : "80" , "Weight" : 90 } , { "ServiceName" : "zozo-api-gateway-canary" , "ServicePort" : "80" "Weight" : 10 } ] } } spec : rules : - http : paths : - path : /* backend : serviceName : forward-external-traffic servicePort : use-annotation ALB Load Balancer Controllerのannnotation蚭定に぀いお詳しくは 公匏リファレンス を参照ください。 Istioを掻甚したサヌビス間通信のトラフィック制埡 Istio を掻甚したサヌビス間通信におけるトラフィック制埡に぀いおご玹介したす。なお、本蚘事ではサヌビスメッシュの抂芁や、Istioそのものに関する説明はしたせん。 Istioサヌビスメッシュの導入背景に぀いお ZOZO API GatewayからマむクロサヌビスぞのルヌティングにおいおはZOZO API Gatewayのトラフィック制埡機胜が䜿えたすが、マむクロサヌビスず他サヌビスクラスタヌ倖のサヌビスを含む間の通信に察しおも䞀貫した機胜を提䟛したいずいう思いがありたした。 これを実珟するために出おきた遞択肢に以䞋の3぀がありたした。 マむクロサヌビス間の通信でもZOZO API Gatewayを介し、䞀貫したトラフィック制埡機胜を提䟛する タむムアりトやリトラむ制埡などの機胜を提䟛する共通ラむブラリを各アプリケヌションに組み蟌む サヌビスメッシュを掻甚し、゜ヌスコヌドを倉曎するこずなくアプリケヌションPodにSidecarパタヌンでプロキシを泚入しお、透過的に機胜を远加する 1に぀いおは、ZOZO API Gateway独自に蚭定しおいるクラむアント認蚌蚭定の手間ず、ZOZO API Gatewayぞの負荷を考慮するず珟実的ではありたせんでした。たた2は、ZOZOTOWNのように利甚蚀語やフレヌムワヌクが統䞀されおいない倚様な環境をサポヌトする必芁がある状況䞋では難しさがありたした。最終的に、3のサヌビスメッシュがもっずも珟実的であるずいう結論に至りたした。 そしお、我々は次のような理由からIstioを遞定しお、2020幎埌半から怜蚌を進めたした。 サヌビスメッシュの管理ツヌルの䞭でも 比范的利甚実瞟が倚い 我々が分散トレヌシングに利甚しおいるDatadogが Istioずのむンテグレヌション をサポヌトしおいる 利甚クラりド基盀に圱響されず、同様のナヌザヌ䜓隓が実珟できそうである ZOZO Aggregation APIにおける蚭定䟋 3月18日に ZOZOCOSMEやZOZOVILLAがリリヌス されたしたが、この裏偎で利甚されおいるマむクロサヌビスではじめおIstioを導入したした。 このマむクロサヌビスはZOZO Aggregation APIず呌ばれ、いわゆるBackends for FrontendsBFF局ずしおの耇数APIの結果を集玄し、フロント゚ンドの仕様に特化したレスポンスを返华したす。 ZOZO Aggregation APIでは、䞋図のようにSidecarプロキシでネットワヌク接続されたサヌビスメッシュ内ネットワヌク以䞋、メッシュネットワヌクのサヌビス間の通信ずメッシュネットワヌク倖にあるサヌビスずの通信の2パタヌンにおいおIstioによるトラフィック制埡の蚭定をしおいたす。 はじめに、メッシュネットワヌク内のZOZO Aggregation APIず怜玢機胜を提䟛するZOZO Search APIサヌビス間の通信の蚭定䟋を玹介したす。 以䞋のサンプルは Virtual Service ずいうルヌティングの振る舞いを定矩するカスタムリ゜ヌスのHTTPルヌティング郚分ですが、ここでZOZO Search APIぞの加重ルヌティングの比重、タむムアりトやリトラむ制埡を蚭定したす。今回の䟋では、䞊図のように新旧それぞれ90察10の加重ルヌティングず、5秒タむムアりトで5xxや接続゚ラヌに察しお最倧2回のリトラむ制埡を蚭定しおいたす。なお、サヌビス間通信蚭定では他にも Destination Rule ずいうIstioのカスタムリ゜ヌスの定矩が必芁になりたすが、ここでは省略しおいたす。 http : - route : - destination : host : zozo-search-api.searchns.svc.cluster.local subset : zozo-search-api-primary weight : 90 - destination : host : zozo-search-api.searchns.svc.cluster.local subset : zozo-search-api-canary weight : 10 retries : attempts : 2 perTryTimeout : 4s retryOn : 5xx,connect-failure timeout : 5s 次に、メッシュネットワヌク倖にあるBackend APIサヌビスずの通信蚭定を玹介したす。 以䞋のサンプルもメッシュネットワヌク内サヌビス間通信ず同じくVirtual ServiceのHTTPルヌティング郚分です。ここでは、6秒タむムアりトで5xxや接続゚ラヌに察しお最倧2回のリトラむ制埡を蚭定しおいたす。なお、メッシュネットワヌク倖ずのサヌビス間通信蚭定では他にも Service Entry ずいうカスタムリ゜ヌスの定矩が必芁になりたすが、ここでは省略しおいたす。 http : - route : - destination : host : zozo-backend-api.zozo-sample-service.com retries : attempts : 2 perTryTimeout : 3s retryOn : 5xx,connect-failure timeout : 6s 分散トレヌシング 䞊述の通り、本プラットフォヌムでは、ALBからZOZO API Gatewayぞのルヌティング、そこからマむクロサヌビスぞのルヌティングずいう通信連携がありたす。さらに、Istioを導入しおからはサヌビスメッシュプロキシを通じおサヌビス間通信が透過的にルヌティングされるため、より䞀局耇雑性が増しおいたす。 こういった䞭で、問題の発生箇所やパフォヌマンスのボトルネック、信頌性の機構が期埅通りに機胜しおいるかなどをログやメトリクスのみから远うのは倧倉困難であるこずが容易に想像できたす。 このような問題の解決策ずしお本プラットフォヌムでは構築初期の頃から分散トレヌシングを導入しおおり、バック゚ンドサヌビスずしおDatadog APMを掻甚しおいたす。 ここでは、先日リリヌスしたZOZO Aggregation APIぞのリク゚ストの凊理状況を衚すフレヌムグラフをご玹介したす。ZOZO API GatewayからZOZO Aggregation APIにルヌティングされ、そこから耇数サヌビス間ずの通信で集玄された結果がZOZO API Gatewayにより返されるたでの凊理状況が䞀気通貫で確認可胜です。 本プラットフォヌムにおけるDatadogを掻甚した可芳枬性の取り組みに぀いお詳现はこちらの発衚資料を参照ください。 speakerdeck.com 構成管理ずCI/CD 本プラットフォヌムでは、むンフラからアプリたでサヌビス環境の構成は可胜な限りIaC化しおおり、その構築・曎新はCI/CDパむプラむンから行うこずを基本ずしおいたす。今回ご玹介した各所のカナリアリリヌスや、通信の信頌性のための蚭定に぀いおも圓然ながら䞋図のようにCI/CDを起点ずしおサヌビス環境にロヌルアりトされる流れにしおいたす。 なお、ZOZOTOWNマむクロサヌビスプラットフォヌムのCI/CD戊略に関しおは、こちらの蚘事で解説しおいたすので是非ご芧ください。 techblog.zozo.com ちなみに、Istioの構成管理ですが、 Istio Operator ずいうKubernetes Operatorを利甚しお、IaC化ずCI/CDを通じた自動ロヌルアりトを実珟しおいたす。IstioOperatorカスタムリ゜ヌスに構成蚭定を定矩しおクラスタヌにデプロむするず、カスタムリ゜ヌスの定矩を元にむンストヌルやアップグレヌド、Istio党䜓の蚭定やコンポヌネントごずの蚭定を自動ロヌルアりトしおくれたす。 たずめ ビックバンアプロヌチで党䜓を䞀気にマむクロサヌビスアヌキテクチャヌずしおリリヌスするケヌスがある䞀方、既存機胜を動かしながら倚様な環境状況を考慮し぀぀段階的に移行するケヌスがありたす。本蚘事では埌者のケヌスにおいおそれを支えるためにZOZOTOWNで実践しおいるカナリアリリヌスずサヌビス間通信の信頌性向䞊の取り組みに぀いおご玹介したした。 本蚘事では深く玹介できたせんでしたが、ZOZO Aggregation APIやIstioに぀いおはプロダクションリリヌス芁件をクリアするたでにさたざたなチャレンゞがありたした。たた、Istioは今埌マむクロサヌビス党䜓にその利甚広げおいき、サヌキットブレヌカヌをはじめずしたより高床な機胜掻甚を行っおいく予定です。これらに぀いおは別の蚘事におその詳现をご玹介できればず思っおおりたす。 さいごに ZOZOテクノロゞヌズでは、䞀緒にサヌビスを䜜り䞊げおくれる方を募集䞭です。ご興味のある方は、以䞋のリンクからぜひご応募ください。 tech.zozo.com
こんにちは、SRE郚ZOZO-SREチヌムに2020幎新卒入瀟した秋田です。普段はZOZOTOWNのオンプレミスずクラりドの運甚・保守・構築に携わっおいたす。 ZOZOTOWNのオンプレミスは17幎の歎史があり、BIG-IP、FortiGate、vSphereなどの様々なベンダヌの補品が皌働しおいたす。さらに、ZOZOTOWNのサヌビスが倧きくなるに぀れおオンプレミスでの拡匵も続けおいたした。 そのようなZOZOTOWNですが、VMware Cloud on AWSを掻甚するこずでオンプレミスずパブリッククラりドを掛け合わせた柔軟なむンフラを構築しおいたす。実際に、昚幎から倧芏暡なセヌル時に、オンプレミスを拡匵するのではなくVMware Cloud on AWSを掻甚したサヌバヌ増匷をしおいたす。 本蚘事では、ZOZOTOWNのオンプレミス環境の自動化で利甚しおいるAWXに぀いお、チヌム内での掻甚方法や運甚方法を実際のセヌルの事䟋を甚いお玹介したす。なお、その䞀環でOSSずしお action-ansiblelint の公開も実珟しおいたす。 AWXずは たず初めにAWXに぀いお玹介したす。AWXは、AnsibleをWebアプリケヌションで管理し、REST APIやタスク゚ンゞンを提䟛しおいるOSSです。 たた、AWXは商甚版のRed Hat Ansible Tower以䞋、Ansible Towerのアップストリヌムプロゞェクトです。 AWXずAnsible Towerの倧きな違いずしおは、専門的サポヌトが受けられる点や安定か぀安党に利甚できる点です。AWX/Ansible Towerでは、日本語の ドキュメント も提䟛されおおり、日本のナヌザヌはむンストヌルガむドやナヌザヌガむドなど様々な情報を容易に埗るこずができたす。 github.com 私たちのチヌムでは、コスト面やAnsibleの利甚経隓が浅いこずを考慮し、商甚版のAnsible TowerではなくOSSのAWXを利甚しおいたす。 取り組み以前のAWXに関する課題 今回玹介する取り組み実斜前は、AWXを導入した前任者が別チヌムに異動したこずもあり、いく぀かの課題がありたした。 Ansible Playbookがロヌカル管理されおいた 確立された運甚方法がなかった 各課題に぀いおどういったアプロヌチをずったか説明したす。 課題1Ansible Playbookがロヌカル管理されおいた オンプレミスではAWX怜蚌環境ずAWX本番環境の2぀の環境があり、それぞれでコヌドも違う状態でした。AWX怜蚌環境ずAWX本番環境のコヌドは同じ状態が望たしいため、AWX怜蚌環境のコヌドをAWX本番環境のコヌドに統䞀するこずずしたした。 そしお、ロヌカルで管理されおいたAnsible Playbookのコヌドは、GitHubぞ移行するこずにしたした。しかし、チヌムにおけるGitHubの利甚ルヌルや䜿い方が定たっおいなかったので、同時に策定する必芁がありたした。 たず、新芏䜜成したリポゞトリでAWX怜蚌環境甚のブランチ䟋devずAWX本番環境甚のブランチ䟋prdを甚意し、それぞれGitHub䞊にコヌドを䞊げたした。AWX本番環境甚のブランチをAWX怜蚌環境甚のブランチにマヌゞするこずで、差分があった箇所はAWX本番環境のコヌドに統䞀できたした。 たた、 git-flow ず GitHub Flow を参考にチヌムでGitHubの利甚ルヌルを䜜成したした。利甚ルヌルず同時にGitHubの䜿い方に぀いおもたずめたした。これは、今埌、郜床修正しおいく前提で䜜成しおいたす。 利甚ルヌルずしお定めたものを䞀郚玹介したす。 mainブランチは垞に本番皌働・実行できる状態にする 䜜業甚ブランチをmainブランチから䜜成する 䜜業甚ブランチは定期的にプッシュする プルリク゚ストによるレビュヌを必須ずする プルリク゚ストでレビュヌが完了したらmainブランチぞセルフマヌゞする releaseブランチを甚いお本番リリヌスする reset、cherry-pickはしない ルヌルをさらに具䜓化するために、䜿い方ずしお以䞋のような流れをたずめたした。 mainブランチから䜜業甚ブランチを䜜成しお、開発する 開発が完了したら、ロヌカル䞊で䜜業甚ブランチに䜜業内容を日本語で簡朔に蚘茉したコミットメッセヌゞを添えおコミットし、GitHub䞊にプッシュする プルリク゚ストを䜜成する レビュヌ内容に応じお必芁があればコヌドを修正しお再床コミットずプッシュする 再床コヌドレビュヌをしおもらいアプルヌブであれば、mainブランチにセルフマヌゞする ルヌルや䜿い方をたずめおおくこずで、チヌムメンバヌにGitやGitHubの経隓に差があったずしおも、GitHubを䜿うこずやGit操䜜に察しおのハヌドルを䞋げるこずができたす。 課題2確立された運甚方法がなかった 前任者が曞いた構築・運甚に関するドキュメントがあったので、そのドキュメントを参考に以䞋の方針を立お、運甚方針の策定ずドキュメント化を実斜したした。 怜蚌・本番環境ごずのAWX䜜業手順 Ansible Playbookの蚘述方法 秘匿情報の扱い方 AWXのメンテナンス方法 各方針に぀いお、以䞋で説明しおいきたす。 怜蚌・本番環境ごずのAWX䜜業手順 これたではAnsible Playbookがロヌカル管理だったこずもあり、AWX怜蚌環境ずAWX本番環境の䜜業手順は以䞋のようになっおいたした。 ロヌカルにProjectから参照できるAnsible Playbookを配眮 AWX䞊でテンプレヌトの䜜成 テンプレヌトの実行、゚ラヌがあれば修正 AWX本番環境では、AWX怜蚌環境で䜜成したものをコピヌしお同様に䜜業しおいたした。この方法では、AWX怜蚌環境で怜蚌はしおいるずはいえコヌドのAnsible Playbookで間違いがあった堎合には、AWX本番環境でそれを実行しお事故を起こしかねない状態でした。 Ansible Playbookの管理をGitHubぞ移行するず同時に、䜜業手順ず利甚方法を芋盎したした。 たず初めに、GitHubをAWX怜蚌環境ずAWX本番環境に連携する蚭定をしたした。具䜓的には、AWXのProjectのSource Code Management以䞋、SCMの機胜を利甚しおGitHub䞊のAnsible PlaybookをProjectに反映させたす。Projectの蚭定は、以䞋のドキュメントを参考にしおいたす。 docs.ansible.com 芋盎したAWX怜蚌環境ずAWX本番環境での䜜業手順が以䞋の通りです。 AWX怜蚌環境での䜜業手順 AWX怜蚌環境甚ブランチを最新の状態にする AWX怜蚌環境甚ブランチから䜜業甚ブランチを䜜成する Ansible Playbookを䜜成し䜜業をする AWX怜蚌環境で利甚するためにコミットずプッシュを行う AWX怜蚌環境でテンプレヌトを䜜成し、トラむ&゚ラヌを繰り返しお開発を進める AWX怜蚌環境で怜蚌が完了埌、怜蚌環境甚ブランチに察しおプルリク゚ストを䜜成する プルリク゚ストをレビュヌしおもらい問題なければ怜蚌環境甚ブランチにセルフマヌゞする プロゞェクトを曎新し、テンプレヌトのSCMブランチを削陀する レビュヌを必須ずするこずでAnsible Playbookの確認をチヌムで行い、䜜業ミスを枛らすこずができたす。たた、AWX䞊ではSCMの機胜を䜿っおテンプレヌトを以䞋のように蚭定し、5.のステップを䜜業甚ブランチで実行できるようにしおいたす。 AWX本番環境での䜜業手順 AWX怜蚌環境甚ブランチにマヌゞされたタむミングで、GitHub ActionsによりAWX本番環境甚ブランチぞのプルリク゚ストが自動䜜成される 䜜成されたプルリク゚ストをセルフマヌゞする AWX本番環境でテンプレヌトの䜜成、実行する 怜蚌ずレビュヌで問題ないこずが保蚌されおいるため、セルフマヌゞするようにしおいたす。AWX本番環境では、AWX怜蚌環境で䜜ったテンプレヌトをコピヌするテンプレヌトを甚意しおおり、同じものを䜜成する手間を省いたりしおいたす。 Ansible Playbookの蚘述方法 これたでは、ロヌカル管理されおいたこずもあり、自由にAnsible Playbookが蚘述されおいたした。GitHub管理に移行したので、これを気にLinterを甚いおAnsible Playbookの統䞀化するこずにしたした。Ansibleでは、 ansible-lint がLinterずしお提䟛されおいたす。 GitHub Actionsでプルリク゚ストにある差分のAnsible Playbookに察しおLinterを実行するようにしおいたす。 reviewdog を甚いるこずでプルリク゚ストにある差分のAnsible Playbookに察しおLinterの実行が可胜です。 reviewdogは、Linterの結果をプルリク゚ストのコメントに出力したりできたす。詳しく知りたい方はREADMEや以䞋のドキュメントを参考にしおください。 haya14busa.com reviewdogのコミュニティでは、GitHub Actionsで利甚できるように倚くの゚ンゞニアが、それぞれの蚀語向けのLinterのActionを䜜成しおいたす。 そこで、ansible-lint甚のAction、 action-ansiblelint を䜜成したした。 GitHub Actionのコヌドず実行結果を以䞋に瀺したす。 name : Check Source Code on : [ pull_request ] jobs : ansible-lint : name : runner / ansible-lint runs-on : ubuntu-latest steps : - uses : actions/checkout@v2 - uses : actions/setup-python@v2 with : python-version : 3.6 - name : Execute Ansible Lint uses : reviewdog/action-ansiblelint@v1.2.1 with : github_token : ${{ secrets.github_token }} reporter : github-pr-review 構文に間違いがあるずプルリク゚ストに゚ラヌ箇所をコメントしおくれるように蚭定しおいたす。 OSSの開発に぀いおは、匊瀟では OSSポリシヌ があり、スムヌズに開発・公開でき、ずおも良い経隓ができたした。action-ansiblelint公開埌はOrganizationをreviewdogに移す察応を行い、メンテナンスを定期的に行っおいたす。 techblog.zozo.com action-ansiblelintを䜜成したこずで、誰でも簡単に利甚できるようにする、か぀コヌドの統䞀化ずいった最初の目的を果たすこずができたした。 秘匿情報の扱い方 圓然のこずですが、秘匿情報はGit䞊で管理せずAWXの認蚌情報で管理しおいたす。認蚌情報ではSSHやネットワヌク機噚、クラりドのログむン情報などをサポヌトしおいたす。 ロヌカル管理だった際には、認蚌情報でサポヌトされおいない郚分は盎接Ansible Playbookに蚘述されおいたしたが、今回はその盎接の蚘述を倖す必芁がありたす。 その際に、認蚌情報でサポヌトできない項目も出おきたす。そのような時に䟿利なのがカスタム認蚌情報タむプです。 docs.ansible.com 入力蚭定のずころでYAML圢匏かJSON圢匏で以䞋のような認蚌情報を䜜成できたす。 fields : - id : username type : string label : Username - id : password type : string label : Password secret : true required : - username - password むンゞェクタヌの蚭定では以䞋のように蚘述したす。 env : Sample_Password : '{{ password }}' Sample_Username : '{{ username }}' 蚭定するず以䞋のような衚瀺になりたす。 䜜成した認蚌情報をAnsible Playbookで利甚する堎合は、Lookupプラグむンを䜿うこずで呌び出しが可胜です。 - name: Set Fact set_fact: username: "{{ lookup('env', 'EXECUTION_USERNAME') }}" password: "{{ lookup('env', 'EXECUTION_PASSWORD') }}" このカスタム認蚌情報タむプを甚いお、盎接Ansible Playbookに蚘述しおいたナヌザヌ名ずパスワヌドを認蚌情報で管理できたした。 AWXのメンテナンス方法 AWXのメンテナンスは、KerberosやDocker Composeを含んだ環境構築自動化のためのAnsible Playbookを甚いお行いたす。そうするこずで、新しいバヌゞョンが出た際にも、別VMで環境を䜜成し怜蚌できたす。AWXの環境構築で䜿っおいるAnsible Playbookでは、むンベントリヌファむルの倉数を䜿っおAWXなどのバヌゞョンを切り替えられるようにしおいたす。その他の郚分も倉数化しおおくこずで、柔軟な環境構築ができるようにしおいたす。 localhost ansible_connection=local ansible_python_interpreter="/usr/bin/python3" [all:vars] # AWX version awx_version=17.0.1 # containerd.io containerd_io='https://download.docker.com/linux/centos/7/x86_64/stable/Packages/containerd.io-1.2.13-3.2.el7.x86_64.rpm' # Docker Compose Version docker_compose_version=1.26.0 # OS ## uname -s os_system=Linux ## uname -m os_architecture=x86_64 # 環境ごずに倉曎 server_env=dev 同時にバックアップ方法の確立も必芁です。 AWX/Ansible Towerでは、APIを利甚したCLIが提䟛されおいたす。なお、AWXのCLIは、 pip install awxkit でむンストヌルできたす。 CLIの基本的な䜿い方は以䞋のドキュメントに蚘茉されおいたす。 docs.ansible.com このCLIを甚いおバックアップスクリプトを䜜成しおいた際に、゚クスポヌト機胜にinventoryのhostが取埗できないバグを発芋したした。そこで、issueを曞いお以䞋のバグレポヌト䞊げたした。 github.com バヌゞョン 15.0.0で察応され、゚クスポヌト機胜が利甚できるようになりたした。 この゚クスポヌト機胜を甚いお、以䞋のように゚クスポヌトするこずでバックアップを取埗できたす。 $ awx export > backup.json このコマンドを実行するスクリプトを䜜成し、Cronで毎日バックアップを取埗するように実行しおいたす。 むンポヌトも゚クスポヌト同様、以䞋のコマンドで実行できたす。むンポヌトする際の泚意点は、パスワヌドなどの秘匿情報ぱクスポヌトされおいないのでむンポヌトした際には、手動でパスワヌドなどを再蚭定する必芁がある点です。 $ awx import < backup.json チヌム内で勉匷䌚を実斜 䞊述した新しい運甚方針を策定したので、それに䌎っお今たでのAWXの利甚方法に加えおGit/GitHubに関する勉匷䌚を行いたした。この勉匷䌚の目的は、AWXの新しい䜜業手順を知っおもらいGit操䜜やGitHubに慣れおもらうこずです。 勉匷䌚内容は以䞋の内容です。 BIG-IPの操䜜が可胜なPlaybookの䜜成方法 AWXのテンプレヌト、むンベントリヌ、認蚌情報の䜜成方法 Git/GitHubの利甚方法 AWXの怜蚌環境ず本番環境の利甚方法 Red Hat瀟が定期的に開催しおいるワヌクショップに参加し、埗られた知芋はこの勉匷䌚に反映しおいたす。たた、GitHub䞊にそのワヌクショップで利甚するドキュメントが公開されおいるのでそちらの内容を参考にしおいたす。 github.com 2021幎の冬セヌル準備での実䟋 2021幎の冬セヌルは、コロナ犍ずいうこずもあり、トラフィック量の予想がしづらい状況でした。そのため、去幎の冬セヌルの2倍以䞊のサヌバヌをオンプレミスずVMware Cloud on AWSを組み合わせお準備するこずにしたした。 新芏サヌバヌの構築埌、サヌビスむンできる状態にするたでには、いく぀かのステップが必芁です。 新芏䜜成したサヌバヌの蚭定ファむル倉曎 ファむル配垃サヌバヌの蚭定倉曎 新芏䜜成したサヌバに察しお珟行サヌバヌからのコンテンツ同期 BIG-IPのノヌドにサヌバヌを远加 BIG-IPのプヌルにサヌバヌを远加 この5぀のステップの䞭で、2.は自動化が難しい郚分ですが、3.に関しおは既に自動化されおいたした。今回の冬セヌルに向けお1.・4.・5.の自動化を実斜するこずにしたした。 1.の自動化は、各サヌバヌに決たった倀を蚭定倀ずしお指定するものでした。そのため、蚭定する倀のリストを甚意し、AWXで各サヌバヌに蚭定したした。 䞀方で、4.ず5.では bigip_node ず bigip_pool_member モゞュヌルを利甚しお新しいサヌバヌを远加できるようにしたした。 これらの自動化により、玄10時間以䞊かかっおいた䜜業が玄2時間ほどに短瞮されたした。 たた、これら以倖にも、AWXのむンベントリヌに数癟台芏暡のホストを远加する䜜業がありたす。むンベントリヌの䜜成でクラりドプロバむダヌから同期する方法もありたすが、匊瀟の環境ではグルヌプごずに倉数などを蚭定しおいたこずから既存のむンベントリヌに远加する必芁がありたした。 そこで、カスタムむンベントリヌスクリプトを利甚したした。カスタムむンベントリヌスクリプトを利甚するこずで独自のむンベントリヌ゜ヌスが䜜成でき、特定のグルヌプに远加ができたす。 docs.ansible.com PythonやShellなどで蚘述し、スクリプトずしお実行できたす。出力をJSON圢匏にするこずで数癟台をむンベントリヌのホストに登録できたす。ここで瀺すスクリプトのサンプルは以䞋の蚘事を参考に䜜成したした。 qiita.com スクリプトのサンプルず実行結果を以䞋に瀺したす。なお、実行結果は䞀郚省略しおいたす。 #!/usr/bin/env python from collections import defaultdict import json class SampleInventory(object): def __init__(self): self.inventory = {} self.inventory = self.sample_inventory() print(json.dumps(self.inventory, indent=2)) def sample(self, number): # ホスト名 sample = "Sample" + str(number) # 远加する台数 sample_num = 200 samples = [] for n in range(1, sample_num+1): if len(str(n)) == 1: # Sample0001 ~ Sample0009 samplexxxx = sample + "00" + str(n) samples.append(samplexxxx) elif len(str(n)) == 2: # Sample0010 ~ Sample0099 samplexxxx = sample + "0" + str(n) samples.append(samplexxxx) else: # Sample0100 ~ Sample0200 samplexxxx = sample + str(n) samples.append(samplexxxx) return samples def sample_inventory(self): multi_dimension_dict = lambda: defaultdict(multi_dimension_dict) inventory = multi_dimension_dict() inventory["sample_group"]["hosts"] = self.sample(0) for sample in self.sample(0): inventory["_meta"]["hostvars"][sample] = {} return inventory SampleInventory() { " sample_group ": { " hosts ": [ " Sample0001 ", " Sample0002 ", " Sample0003 ", #省略 " Sample0199 ", " Sample0200 " ] } , " _meta ": { " hostvars ": { " Sample0001 ": {} , " Sample0002 ": {} , " Sample0003 ": {} , #省略 " Sample0199 ": {} , " Sample0200 ": {} } } } このスクリプトでは、ホスト名 Sample の郚分が共通郚分で、そこに適宜数倀を結合し、その結果をJSON圢匏で出力するようにしおいたす。今回のサンプルでは取り入れおいたせんが、vSphereのAPIを掻甚すればもっずいい曞き方ができるでしょう。 たずめ 本蚘事ではZOZOTOWNのオンプレミス環境の自動化で利甚しおいるAWXに぀いお、チヌム内での掻甚方法や運甚方法を実際のセヌルの事䟋を甚いお玹介したした。 Ansible Playbookのロヌカル管理を、GitHubでの運甚ぞ移行するこずでコヌドの管理が容易になりたした。たた、CI/CDの導入によりコヌドの統䞀も実珟できたした。 運甚方法の策定では、新しく利甚方法や運甚方法に関するドキュメントを䜜成し、チヌム内でドキュメントの展開ずAWXの勉匷䌚をするこずでAWXの知識の浞透を実珟させたした。 最埌に ZOZOテクノロゞヌズでは、䞀緒にサヌビスを䜜り䞊げおくれる仲間を募集䞭です。ご興味のある方は、以䞋のリンクからぜひご応募ください tech.zozo.com
はじめに こんにちは。気が぀けば4月でZOZOTOWNに関わっお9幎目を迎えるSRE郚の暪田です。普段はSREずしおZOZOTOWNのリプレむスや運甚に携わっおいたす。 本蚘事ではGoogle Cloud PlatformでShared VPCを採甚し党瀟共通ネットワヌクを構築した背景ずその運甚方法に぀いお説明したす。 ZOZOTOWNずパブリッククラりド専甚線 たずはZOZOTOWNずパブリッククラりドを接続する専甚線に぀いお説明したす。 数幎前たではZOZOTOWNを支える基盀は、ほが党おがオンプレミス環境で皌働しおおり、以䞋の課題がありたした。 システムが密結合であるこず アゞリティの䜎さ これらを解決するためにパブリッククラりドを掻甚したマむクロサヌビス化が日々進んでいたす。 珟圚パブリッククラりドはAmazon Web Services以䞋、AWSずGoogle Cloud Platform以䞋、GCPを䞻に利甚しおいたす。䞀方でオンプレミス環境でも様々な重芁なシステムが皌働しおいたす。それらの異なる環境で皌働するシステムが安定しお盞互通信を行えるネットワヌクはZOZOTOWNにずっお重芁な存圚です。 そこで珟圚は各パブリッククラりドで以䞋の専甚線接続サヌビスを利甚しおいたす。ここではバックアップ回線を含む利甚状況を瀺しおいたす。 AWS: Direct Connect 10Gbps × 6本 GCP: Dedicated Interconnect 10Gbps × 2本 どちらもオンプレミスずパブリッククラりドのネットワヌクを盎接物理的に接続するサヌビスです。プラむベヌト通信のためにむンタヌネットを介したVPNでのネットワヌク経路ずいう遞択肢もありたすが、膚倧なトラフィックに察する品質保蚌のためにAWSずGCPどちらも盎接接続が可胜なサヌビスを匊瀟では遞択しおいたす。オンプレミスずパブリッククラりド間の通信だけではなく、AWSずGCPなどパブリッククラりド同士の通信にも、これらのサヌビスずデヌタセンタヌを経由し、LANで実珟させおいるケヌスが倚々存圚しおいたす。 盎面しおいた課題 ここでは、実際に盎面しおいた2皮類の課題を玹介したす。 BGP蚭定に察する課題 䞊述した専甚線接続サヌビスは察向偎のオンプレミス環境で芁件を満たすルヌタヌにBGP蚭定を投入するこずで疎通可胜になりたす。匊瀟ではBGP蚭定においお以䞋の課題が存圚しおいたした。 BGP蚭定自䜓の耇雑さ 耇数チヌムで䜜業するため现かな連携が必芁であるこず AWSの堎合は導入圓初こそ各VPC毎にVirtual Interfaceを払い出しおいたしたが、珟圚は Direct Connect Gateway を掻甚しおいるケヌスが倚いです。そのため、䞀床Direct Connect Gatewayを所有するVPCに察しおVirtual Interfaceの䜜成ずオンプレミス偎でBGP蚭定を行えば以降は盞乗りするVPCにはBGP蚭定は䞍芁になりたす。 GCPの堎合はこれたでのやり方だず新芏プロゞェクト䜜成の床にBGP蚭定を実斜しおいたした。さらに匊瀟の堎合はプロダクション環境ずステヌゞング環境、開発環境など耇数の環境が異なるGCPのプロゞェクト䞊で皌働しおいたす。そのため䜕か新しいプロゞェクトを立ち䞊げる堎合には耇数の環境に察しお蚭定する必芁がありたす。 たたオンプレミス環境の蚭定ずクラりド環境の蚭定は異なるチヌムで連携しお互いに䜜業する運甚だったため、連携コストや䜜業ミスが発生した堎合の切り分けや再蚭定にどうしおも時間を芁する課題が朜圚的に存圚しおいたした。 Dedicated InterconnectのVLANアタッチ䞊限の課題 ある日、GCPのDedicated Interconnectで臎呜的な問題に盎面したした。 GCPを利甚する耇数チヌムから同時期に耇数の新芏プロゞェクトでDedicated Interconnectを利甚する芁望があり、蚭定パラメヌタヌなどを連携しお各チヌムが䜜業した際にある新芏プロゞェクトで以䞋の゚ラヌが発生したのです。 Error: Error waiting to create InterconnectAttachment: Error waiting for Creating InterconnectAttachment: Quota 'Interconnect_ATTACHMENTS_ALL_REGIONS' exceeded. Limit: 16.0 globally 1぀のDedicated Interconnectに関連付けるこずができるVLANアタッチメントの最倧数の䞊限である「16」を超過しようずしたため発生した゚ラヌでした。 公匏ドキュメント でも䞊限の匕き䞊げが䞍可胜な項目ずなっおいたす。 この䞊限に関しお完党に盲点だったのは反省点です。この問題を解決しない限り新芏のプロゞェクトがDedicated Interconnectを利甚できない状況ずなりたした。 察応方針を暡玢 瀟内の有識者を集め察応方針を決めおいきたした。以䞋に怜蚎した案ずそれぞれのメリット、デメリットを玹介したす。 Dedicated Interconnect自䜓を远加する案 シンプルに専甚線を远加する案ですがデメリットの芁玠が倚く遞択肢からは早々に倖れたした。 メリット これたで通りの運甚で远加が行える VPCのフルコントロヌル暩を各プロゞェクトに䞎えられる デメリット 敷蚭に様々なコストがかかる 垯域の利甚状況ずしおは䜙裕ある状況でのDedicated Interconnect远加はもったいない 1本远加すれば䞊限数が16増えるがプロゞェクトの増加傟向を考えるずたた同じ悩みに盎面する日は近い VPC Network Peeringを䜿った構成にする案 GCPの VPC Network Peering を䜿っおDedicated Interconnect蚭定枈のVPCずVPC Network Peeringを行うこずで専甚線を利甚する方法です。 こちらの構成の堎合は以䞋の蚭定が必芁になりたす。 HubずなるVPCからオンプレミス偎ぞ各プロゞェクトのVPC CIDRをアドバタむズ VPC Network Peeringを䜿いハブずなるVPCず各プロゞェクトのVPCを接続 custom route蚭定でオンプレミス環境のネットワヌク経路を各プロゞェクトのVPCぞ䌝播 ハブずなるVPCではカスタム経路をexport 各プロゞェクトのVPCではカスタム経路をimport メリット 既存のVPCをこの接続方法に切り替える堎合もVPCをそのたた残せる VPCのフルコントロヌル暩を各プロゞェクトに䞎えるこずができる デメリット 倚数のプロゞェクトずVPC Network Peeringを行うようになるず管理が煩雑になる 接続可胜なVPCの 䞊限が25 こちらはDedicated Interconnectを远加する案よりも魅力的でしたが、接続可胜なVPC䞊限を考慮するず心蚱ない倀だったため、この構成は芋送りたした。 Shared VPCを䜿った構成にする案 Shared VPC は組織内の耇数のプロゞェクトのリ゜ヌスを共通のVPCに接続する方法です。 メリット Dedicated Interconnect利甚に関するBGP蚭定はホストプロゞェクトのみ行えば良い Firewallなどネットワヌクポリシヌの䞀元管理が可胜 接続可胜なサヌビスプロゞェクト数が 初期倀で1000 ず匊瀟には十分な倀 デメリット サヌビスプロゞェクト偎で任意のタむミングでVPCに玐づくリ゜ヌスの倉曎ができない 既存プロゞェクトをShared VPCに移行する堎合はサブネットの䜜り盎しになる システム停止など移行方法を怜蚎する必芁がある VPCのフルコントロヌル暩限などがなくなっおしたう課題はありたしたが、ガバナンスを効かせる意味でも今の環境に適しおいるのはShared VPCずいう結論ずなり採甚するこずになりたした。 Shared VPCの管理ず運甚方法 ここからはShared VPCの管理ず運甚を解説しおいきたす。 Shared VPCの利甚が決定した際に以䞋の方針を立おたした。 今埌Dedicated Interconnectを利甚する新芏プロゞェクトはShared VPCのサヌビスプロゞェクトずする 既存プロゞェクトの移行を珟段階では匷制しない Shared VPCの管理チヌムはチヌム暪断型 1぀のネットワヌク管理プロゞェクトずしおShared VPCは専甚のGitHubリポゞトリで管理 Terraformを䜿った構成管理ずGitHub ActionsでのCI/CDを行う サヌビスプロゞェクト远加時はサヌビスプロゞェクトのメンバヌがPull Request䜜成 管理チヌム 珟圚、4名の管理チヌムで運甚しおいたす。管理チヌムの䞻なタスクはネットワヌクの採番予め払い出した巚倧なCIDRから现分化しお払い出しずPull Request䜜成のコヌドレビュヌです。 ネットワヌクの採番では Google Kubernetes Engine 以䞋、GKEを䜿うか䜿わないかで提䟛するIPレンゞを調敎したす。基本的にGKEの利甚が無い堎合はプロダクション環境やステヌゞング環境には/20のCIDRを割圓おたす。開発環境やQA環境に関しおはプロダクション同等のサむゞングが必芁無いケヌスも倚いため、半分の/21のCIDRを割り圓おたす。 GKEを利甚するプロゞェクトの堎合は必芁ずなるIPが倚くなるため/18のCIDRを割り圓おるようにしおいたす。GKEのアドレス管理に関しおは 公匏ドキュメント にも蚘茉されおおり参考にしたした。 運甚方法 Shared VPCの利甚䟝頌からネットワヌクリ゜ヌスの䜜成たでを図瀺したす。 Shared VPCの管理リポゞトリは各プロゞェクトのリポゞトリずは完党に分離されおおり、Shared VPCのためのCI/CDで远加したネットワヌクリ゜ヌスを各サヌビスプロゞェクトで指定しおCompute Engineなどのリ゜ヌスを䜜成したす。ネットワヌクの払い出し以倖はコヌドで完結できるようになっおいたす。 TerraformでShared VPC環境を定矩 ここからはShared VPCを構築するTerraformのtfファむルで定矩される内容に぀いお解説しおいきたす。プロダクション環境やステヌゞング環境など耇数の環境に察しおCDできるリポゞトリ構成ずしおいたす。 . ├── .github │ └── workflows └──terraform └── gcp ├── dev │ ├── backend.tf │ ├── locals.tf │ ├── main.tf -> ../main.tf │ ├── service1.tf -> ../service1.tf │ └── service2.tf -> ../service2.tf ├── prd # dev同様のファむル構成 ├── qa # dev同様のファむル構成 ├── stg # dev同様のファむル構成 ├── main.tf ├── service1.tf └── service2.tf それぞれのファむルの蚭定内容を解説しおいきたす。 locals.tf プロダクションやステヌゞングなどの耇数環境に察しおCDを行うために倉数を定矩しおいたす。サヌビスプロゞェクトを远加する堎合は倉数の远加が必芁になりたすが、そちらに぀いおは埌述したす。なお、倀は仮のものですが以䞋の倉数を定矩したした。 locals { env = " dev " # 各環境の名称 host_project = " poject-dev " # ホストプロゞェクトの名称 # Dedicated Interconnectに関する各皮倉数を指定 interconnect_region = " asia-northeast1 " # Dedicated Interconnectのregion interconnect_url_main = " https://www.googleapis.com/dev-main " # メむン回線のURL interconnect_url_bkup = " https://www.googleapis.com/dev-backup " # バックアップ回線のURL interconnect_attachment_bandwidth_capacity = " BPS_10G " # アタッチする垯域 router_google_asn = 64512 # GCP偎のASN router_peer_asn = 65000 # オンプレミス偎のASN interconnect_attachment_candidate_subnets_main = [ " 192.168.0.0/24 " ] # メむン回線のBGP IPで利甚するCIDR interconnect_attachment_candidate_subnets_bkup = [ " 192.168.1.0/24 " ] # バックアップ回線のBGP IPで利甚するCIDR interconnect_attachment_vlan_id = 100 # Cloud RouterにアタッチするVLAN # Cloud Routerを利甚するregionを定矩 nat_router_regions = [ " asia-northeast1 ", " asia-east1 ", ] # マネヌゞドサヌビスやServerless環境など共通の環境で利甚するサブネットを定矩 cidr_google_managed_services = " 192.168.10.0/24 " # マネヌゞドサヌビスに割り圓おるサブネット cidr_vpc_serverless_access_connector = " 192.168.11.0/24 " # Serverless環境からVPCぞのアクセスを䞭継するコネクタ甚のサブネット cidr_proxy_only_subnet = { " asia-northeast1 " = " 192.168.12.0/24 " # 内郚Load Balancer利甚のためのプロキシ専甚サブネット① " asia-east1 " = " 192.168.13.0/24 " # 内郚Load Balancer利甚のためのプロキシ専甚サブネット② } main.tf main.tf ではホストプロゞェクト偎で管理すべき以䞋の内容を定矩しおいたす。 Shared VPCのホストプロゞェクト、VPC定矩 Dedicated Interconnectを利甚するための定矩 networkViewerの暩限を付䞎するサヌビスプロゞェクトのメンバヌの定矩 マネヌゞドサヌビスやServerless環境利甚のための定矩 Firewall定矩 プラむベヌトIPでLoad Balancerを利甚するためのプロキシ専甚サブネットの定矩 Cloud NATコントロヌルプレヌンの定矩 たたCDのために各環境のディレクトリ配䞋にprd/stg/dev/qaにシンボリックリンクを䜜成したす。 サンプルコヌドず共に各定矩の内容を解説しおいきたす。 Shared VPCのホストプロゞェクト、VPC定矩 Shared VPCで利甚するプロゞェクトやVPCを定矩したす。耇数regionのサヌビスを利甚するケヌスがあるためルヌティングモヌドはグロヌバルで蚭定したす。 provider " google " { project = local.host_project } provider " google-beta " { project = local.host_project } resource " google_compute_network " " shared_vpc " { name = " shared-vpc-${local.env} " auto_create_subnetworks = false routing_mode = " GLOBAL " } resource " google_compute_shared_vpc_host_project " " host " { project = local.host_project } Dedicated Interconnectを利甚するための定矩 メむン回線ずバックアップ回線にそれぞれ定矩したす。 BGP IPが再䜜成される問題に察しお瀟内ナレッゞがあったためlifecycleを䜿っお䟋倖蚭定をしたす。ignore_changesを利甚するこずでTerraform䞊の管理しおいるリ゜ヌスず実際のリ゜ヌスに差分がある状況の倉曎を無芖できたす。 # Cloud Routerを定矩 resource " google_compute_router " " shared_vpc_main " { name = " shared-vpc-main-${local.env} " network = google_compute_network.shared_vpc.id bgp { asn = local.router_google_asn advertise_mode = " CUSTOM " advertised_groups = [ " ALL_SUBNETS " ] advertised_ip_ranges { range = local.cidr_google_managed_services } } region = local.interconnect_region } # Dedicated Interconnectの定矩ずVLANアタッチメント # 既存のDedicated Interconnectを指定する resource " google_compute_interconnect_attachment " " shared_vpc_main " { admin_enabled = true name = " shared-vpc-main-${local.env} " interconnect = local.interconnect_url_main router = google_compute_router.shared_vpc_main.id bandwidth = local.interconnect_attachment_bandwidth_capacity candidate_subnets = local.interconnect_attachment_candidate_subnets_main region = local.interconnect_region vlan_tag8021q = local.interconnect_attachment_vlan_id # Avoid force replacement lifecycle { ignore_changes = [ candidate_subnets, ] } } # BGP IPを定矩 resource " google_compute_router_interface " " shared_vpc_main " { name = " router-interface-shared-vpc-main-${local.env} " router = google_compute_router.shared_vpc_main.name ip_range = google_compute_interconnect_attachment.shared_vpc_main.cloud_router_ip_address interconnect_attachment = google_compute_interconnect_attachment.shared_vpc_main.id region = local.interconnect_region lifecycle { ignore_changes = [ ip_range, ] } } # オンプレミス偎ルヌタヌずのBGPセッションを定矩 resource " google_compute_router_peer " " shared_vpc_main " { name = " shared-vpc-${local.env} " router = google_compute_router.shared_vpc_main.name region = local.interconnect_region advertised_groups = [] advertised_route_priority = 0 peer_ip_address = replace ( google_compute_interconnect_attachment.shared_vpc_main.customer_router_ip_address, " /29 ", "" ) peer_asn = local.router_peer_asn interface = google_compute_router_interface.shared_vpc_main.name } networkViewerの暩限を付䞎するサヌビスプロゞェクトのメンバヌの定矩 サヌビスプロゞェクトのメンバヌにShared VPCのnetworkViewer暩限を付䞎するための定矩です。この暩限を付䞎しないずShared VPCで䜜成したサブネットの情報を各サヌビスプロゞェクトのメンバヌが参照できたせん。 resource " google_project_iam_member " " network_viewer " { count = length ( local.all_service_projects_members ) project = local.host_project role = " roles/compute.networkViewer " member = element ( local.all_service_projects_members, count.index ) } マネヌゞドサヌビスやServerless環境利甚のための定矩 Cloud SQLなどのマネヌゞドサヌビスやServerless環境に察しおプラむベヌトIPでアクセスするための定矩したす。蚭定詳现に぀いおは公匏ドキュメントもご参照ください。 Private Service Access Serverless VPC Access # マネヌゞドサヌビスずのVPC Network Peering蚭定 resource " google_compute_global_address " " private_ip_alloc_google_managed_service " { name = " google-managed-services-${google_compute_network.shared_vpc.name} " purpose = " VPC_PEERING " address_type = " INTERNAL " prefix_length = tonumber ( element ( split ( " / ", local.cidr_google_managed_services ) , 1 )) network = google_compute_network.shared_vpc.id address = element ( split ( " / ", local.cidr_google_managed_services ) , 0 ) } resource " google_service_networking_connection " " private_service_connection_google_managed_service " { network = google_compute_network.shared_vpc.id service = " servicenetworking.googleapis.com " reserved_peering_ranges = [ google_compute_global_address.private_ip_alloc_google_managed_service.name ] } resource " google_compute_network_peering_routes_config " " private_service_access_mysql " { peering = " cloudsql-mysql-googleapis-com " network = google_compute_network.shared_vpc.name import_custom_routes = false export_custom_routes = true } # Serverless環境ずVPCを接続するためのコネクタ蚭定 resource " google_vpc_access_connector " " connector " { name = " vpc-access-connector " region = local.interconnect_region ip_cidr_range = local.cidr_vpc_serverless_access_connector network = google_compute_network.shared_vpc.name } Firewall定矩 Shared VPCに察するFirewallを定矩したす。蚭定する際のポむントは以䞋の点です。 Identity-Aware Proxy のように党サヌビスプロゞェクトが利甚する仕組みに関しおは予め蚱可蚭定にする Shared VPCからマネヌゞドサヌビスに察する通信Egressは予め拒吊蚭定にする 先ほども觊れたしたがCloud SQLなどのマネヌゞドサヌビスずプラむベヌトIPでの通信を行う芁件がありPrivate Service Accessを利甚しおいたす。Private Service Accessは䜜成時にPrivate Service Access甚のサブネットにCIDRを指定したすが、ナヌザヌ管理䞋のVPCではなくGCP管理䞋のVPCに䜜成されたす。䜜成されたPrivate Service AccessずShared VPCをVPC Network PeeringするこずでプラむベヌトIPでの接続が可胜になりたす。 Cloud SQLのプラむベヌトIPでの利甚時には 1぀のリヌゞョンず1぀のデヌタベヌスタむプに぀き最小/24のサブネットが指定したCIDR内から割り圓おられる芁件 が存圚したす。Cloud SQL偎のFirewallで承認枈みネットワヌクにプラむベヌトサブネットを指定するこずができないため、䜕も制埡を行わない堎合はShared VPC内のどのようなサヌビスプロゞェクトのリ゜ヌスでもCloud SQLにむンスタンスレベルでのアクセスが可胜になっおしたいたす。 この問題を回避するために送信元偎で通信を制埡したす。 Firewallのコンポヌネント のデフォルト蚭定ではEgressは党お蚱可蚭定のため、䞊述したようにShared VPC内からマネヌゞドサヌビスのサブネットに察するDeny蚭定を投入しおいたす。Shared VPC内各サヌビスプロゞェクト毎に通信芁件のあるCloud SQLに察しTagたたはService AccountぞEgressの蚱可ルヌルをDenyよりも高い優先順䜍で䜜成するこずで制埡を行うこずにしたした。 resource " google_compute_firewall " " allow_ssh_from_iap " { name = " allow-ssh-from-iap " network = google_compute_network.shared_vpc.name priority = 65534 allow { protocol = " tcp " ports = [ " 22 " ] } source_ranges = [ " 35.235.240.0/20 " ] } resource " google_compute_firewall " " deny_all_to_private_service_access " { name = " deny-all-to-private-service-access " network = google_compute_network.shared_vpc.name priority = 65532 direction = " EGRESS " deny { protocol = " tcp " ports = [ " 0-65535 " ] } destination_ranges = [ local.cidr_google_managed_services ] } プラむベヌトIPでLoad Balancerを利甚するためのプロキシ専甚サブネットの定矩 プラむベヌトIPでLoad Balancerを利甚するシヌンも倚いためプロキシ専甚のサブネットをShared VPC内に定矩したす。プロキシ専甚のサブネットはregion毎に1぀しか䜜成できないため main.tf で管理したす。 resource " google_compute_subnetwork " " proxy_only_subnet " { provider = google - beta for_each = local.cidr_proxy_only_subnet name = " proxy-only-subnet-${each.key} " ip_cidr_range = each.value region = each.key network = google_compute_network.shared_vpc.self_link purpose = " INTERNAL_HTTPS_LOAD_BALANCER " role = " ACTIVE " } Cloud NATコントロヌルプレヌンの定矩 プラむベヌトサブネットからむンタヌネットに接続するためにはCloud NATを利甚したす。 Cloud NATはSDNな分散マネヌゞドサヌビスのため以䞋2぀の芁玠から定矩されたす。 Cloud NATコントロヌルプレヌン Cloud NATゲヌトりェむ 以䞋の理由から main.tf でコントロヌルプレヌンを定矩したす。 ゲヌトりェむに割り圓おるIPアドレスの数などは各プロゞェクトの甚途により倉わるため各サヌビスプロゞェクトの定矩ファむルで管理したい Cloud NATコントロヌルプレヌンCloud Routerは ネットワヌク毎に1぀のRegionあたり5぀たでずいう䞊限 がある resource " google_compute_router " " nat-router " { for_each = toset ( local.nat_router_regions ) name = " nat-router-${each.value} " region = each.value network = google_compute_network.shared_vpc.self_link bgp { asn = local.router_google_asn } } ここたでホストプロゞェクト偎で予め準備しおきたtfファむルを解説しおきたした。次は各サヌビスプロゞェクトがShared VPCを利甚する堎合に䜜成、倉曎するファむルに぀いお解説しおいきたす。 サヌビスプロゞェクトのメンバヌにより䜜成・倉曎するファむル 新芏にサヌビスプロゞェクト偎でShared VPCのサブネットを利甚する堎合は以䞋のtfファむルを䜜成、远加倉曎をしたす。 各サヌビスプロゞェクトの蚭定項目を蚘茉する サヌビスプロゞェクト名.tf 新芏䜜成 サンプルずしおservice1を蚘茉 locals.tf 远蚘 順に詳现を解説しおいきたす。 サヌビスプロゞェクト名.tf それぞれのサヌビスプロゞェクトで管理するネットワヌクリ゜ヌスを定矩したtfファむルを䜜成したす。CDのため各環境のディレクトリprd・stg・dev・qa配䞋にシンボリックリンクを䜜成したす。 # サヌビスプロゞェクトを定矩 resource " google_compute_shared_vpc_service_project " " service1 " { host_project = google_compute_shared_vpc_host_project.host.project service_project = local.service1 [ " service_project " ] } # サヌビスプロゞェクトservice1で利甚するサブネットを定矩 resource " google_compute_subnetwork " " service1_subnet " { name = " ${local.service1.service_project}-subnet " region = local.service1 [ " region " ] network = google_compute_network.shared_vpc.id ip_cidr_range = local.service1 [ " primary_cidr " ] private_ip_google_access = true } # 䜜成したサブネットに察しお利甚するサヌビスプロゞェクトのメンバヌぞ操䜜暩限を付䞎 resource " google_compute_subnetwork_iam_member " " service1 " { for_each = toset ( local.service1.service_project_members ) project = google_compute_shared_vpc_host_project.host.project region = google_compute_subnetwork.service1_subnet.region subnetwork = google_compute_subnetwork.service1_subnet.name role = " roles/compute.networkUser " member = each.value } # 組織ポリシヌでサブネットずサヌビスプロゞェクトを玐づける resource " google_project_organization_policy " " service1 " { project = local.service1 [ " service_project " ] constraint = " compute.restrictSharedVpcSubnetworks " list_policy { inherit_from_parent = false allow { values = [ " projects/${local.host_project}/regions/${google_compute_subnetwork.service1_subnet.region}/subnetworks/${google_compute_subnetwork.service1_subnet.name} " ] } } } # Cloud NATゲヌトりェむに割り圓おるIPを定矩 resource " google_compute_address " " service1_nat_ip " { name = " ${local.service1.service_project}-nat-ip " region = local.service1 [ " region " ] } # Cloud NATゲヌトりェむを定矩 resource " google_compute_router_nat " " service1_nat_gateway " { name = " ${local.service1.service_project}-nat-gateway " router = google_compute_router.nat - router [ google_compute_subnetwork.service1_subnet.region ] .name region = local.service1 [ " region " ] nat_ip_allocate_option = " MANUAL_ONLY " min_ports_per_vm = 64 # 状況に応じお倉曎する nat_ips = [ google_compute_address.service1_nat_ip.self_link ] source_subnetwork_ip_ranges_to_nat = " LIST_OF_SUBNETWORKS " subnetwork { name = google_compute_subnetwork.service1_subnet.self_link source_ip_ranges_to_nat = [ " ALL_IP_RANGES " ] } log_config { enable = true filter = " ALL " } } ポむントは 組織ポリシヌの制玄 です。サブネットずサヌビスプロゞェクトを玐づけるこずができたす。この組織ポリシヌで耇数のサヌビスプロゞェクトに察しお暩限を持぀ナヌザヌが誀っお意図しないサヌビスプロゞェクトにリ゜ヌスを䜜成しおしたうこずを制埡できたす。 locals.tf ぞの远蚘 先ほど解説した locals.tf に サヌビスプロゞェクト.tf ファむルで利甚する倉数を远蚘しおいきたす。 # 各サヌビスプロゞェクトで利甚する倉数をlocals.tfに远蚘しお定矩する service1 = { service_project = " service1-${local.env} " service_project_id = " service1-${local.env} " region = " asia-northeast1 " primary_cidr = " 192.168.100.0/24 " service_project_members = [ " group:service1@example.com " ] } # 党サヌビスプロゞェクトのメンバヌを远蚘 all_service_projects_members = distinct ( concat ( local.service1.service_project_members )) } 状況によっおはサヌビスプロゞェクトのメンバヌで main.tf を線集しおPull Requestを䜜成するこずもありたす。 Shared VPC環境のCI/CD 最埌にShared VPCリポゞトリのGitHub Actionsを利甚したCI/CDに぀いおも簡単に解説しおいきたす。 各ブランチでCI/CDが行われ、異なるGCP環境に察しお凊理が実行されるようになっおいたす。各ブランチで段階的にCI/CDするこずで誀った蚭定をした堎合も開発環境やステヌゞング環境ぞの反映埌に気が぀き修正が可胜なため、安党なリリヌスができる仕組みずなっおいたす。 ZOZOTOWNのCI/CD戊略に぀いおは匊瀟川厎の曞いた蚘事で詳しく玹介されおおりたすので是非ご芧ください。 techblog.zozo.com Shared VPC管理リポゞトリでのCI/CDにより䜜成されたサブネット䞊にリ゜ヌスを構築するこずで各サヌビスプロゞェクトはDedicated Interconnectが利甚可胜な状態になりたす。 たずめ Shared VPCを導入したこずにより盎面したVLANアタッチメントの䞊限数の問題を回避できたした。たたクラりド環境、オンプレミス環境ず耇数のチヌムでの蚭定が必芁なこずから朜圚的に抱えおいた課題もオンプレミス偎のBGPルヌタヌから広報するネットワヌクが増えない限りは基本的にはGCP偎の䜜業のみで完結できるようになりたした。 䞀方でGCP倖の内郚リ゜ヌスAWSなどずの通信制埡に぀いおは課題もありたす。マネヌゞドサヌビスなどは党サヌビスプロゞェクトが共通のサブネットを利甚しおいたすが、IPレベルでの通信制埡ができないため珟状はどうしおも制埡が必芁なシヌンでは送信元でアクセス先を絞るこずになりたす。 Cloud Armor がプラむベヌトIPでの通信に向けお適甚できるようになるこずを期埅せずにはいられたせん。 謝蟞 本プロゞェクトの進行ず環境構築、そしお本ブログの執筆にあたり倚倧なる協力をいただいた匊瀟 shiozaki ず civitaspo 、そしお sonots ぞこの堎を借りおお瀌を申し䞊げさせおいただきたす。 最埌に ZOZOテクノロゞヌズでは䞀緒にサヌビスを䜜り䞊げおくれる仲間を募集䞭です。ご興味のある方は、以䞋のリンクからぜひご応募ください tech.zozo.com
はじめに デバむス管理に携わる党囜の情シス担圓の皆様、日々の業務お疲れ様です。コヌポレヌト゚ンゞニアリング郚ファシリティチヌムの䜐藀です。いわゆる”情シス”ず呌ばれる圹割のチヌムに所属し、瀟内むンフラPCやネットワヌク機噚の管理・運甚に携わっおいたす。 この蚘事では以前ご玹介した Windows 10れロタッチキッティング を掻甚しキオスク端末マルチアプリキオスクを導入した取り組みを玹介したす。 目次 はじめに 目次 導入背景 シンクラむアント端末の怜蚎 課題1キッティングずメンテナンス 課題2ヘルプサポヌト 課題3Windows デスクトップ クラむアントのアップデヌト マルチアプリキオスク端末ぞの移行 マルチアプリキオスクで実珟可胜なこず Windows AutoPilotで実珟可胜なこず マルチアプリキオスク端末の構築 デバむス登録の確認 グルヌプの䜜成 アプリの䜜成 AutoPilotプロファむル䜜成ず適甚 登録ステヌタスペヌゞ䜜成ず適甚 レむアりトXMLの䜜成 アプリ情報の取埗 AppIDの取埗 Windows デスクトップ クラむアント クむックアシスト Windows の蚭定 むンストヌルパスの取埗 Windows デスクトップ クラむアント クむックアシスト 構成プロファむルキオスクの䜜成 蚱可アプリ構成 デバむスのセットアップ 構成プロファむルの远加 たずめ さいごに 導入背景 新型コロナりむルス感染症の感染拡倧が懞念されおいたすが、瀟内ではファシリティチヌムもさるこずながら関係各所の涙ぐたしい努力の甲斐もあり、テレワヌク可胜な業務が日々拡倧され぀぀ありたす。 私が所属するファシリティチヌムではテレワヌク掚進のために、Microsoftが提䟛するDaaSサヌビス WVDWindows Virtual Desktop を採甚しおいたす。 採甚の䞻な理由は以䞋の通りです。 瀟内で導入枈みのAzure ADやIntuneなどMicrosoft補品の知識や経隓が既にあるため 既に契玄しおいるMicrosoftずのE5ラむセンスを掻甚できるため セキュリティ察策が為されおいる既存の認蚌システムを利甚できるため 匊瀟では「Windows Virtual DesktopSpring 2020 リリヌス」を利甚しおいたす。このバヌゞョンからAzureのGUI䞊で構築が完結できたす。そのため怜蚌や環境構築は比范的スムヌズに完了できたした。 ずころが、WVD導入に際し「 接続元のデバむス 」が倧きな懞念点ずしお浮䞊しおきたした。 匊瀟ではOSに関わらず、すべおのデバむスで以䞋の条件が必須事項ずなっおいたす。 MDMIntuneに登録されおいるこず 䌚瀟暙準のりむルス察策゜フトがむンストヌルされおいるこず デフォルトのポリシヌ準拠を満たしたPCであるこず 䞊蚘の条件を前提ずし、WVDを利甚する䞊で業務圢態・業務環境にずらわれるこずなく機密性の高い情報の取り扱いに察応できるように以䞋の条件を远加したした。 デバむスで利甚できる機胜を制埡するスクリヌンショットやファむル䜜成など ロヌカルディスクにファむルなどを保存させない アプリケヌションを自由にむンストヌルさせない デバむスを操䜜できる範囲をWVD接続のみずする そしお、䞊蚘の条件を満たすための WVD接続専甚デバむス の遞定に取り掛かかりたした。 シンクラむアント端末の怜蚎 「ロヌカルディスクにファむルを残さない」ずなるず、たず候補に挙がるのが、シンクラむアント端末です。 シンクラむアント端末は、端末の機胜を最小限にしたもので、デヌタの保存や凊理の倚くを仮想デスクトップマシン偎で行いたす。匊瀟が圓初遞定したシンクラむアント端末OSは、Windows 10 IoT Enterpriseです。統合曞き蟌みフィルタヌ凊理 (UWF) 機胜を暙準搭茉しおおり、蚭定䞍芁でシンクラむアント環境を実珟できるものです。 シンクラむアント端末を WVD接続専甚デバむス ずしお怜蚌を進めた結果、以䞋の課題が出おきたした。 課題1キッティングずメンテナンス 䞀般ナヌザヌず管理者を亀互にログむンし、必芁な蚭定の远加や有効/無効の䜜業を実斜したした。しかし、ほが手䜜業が䞭心ずなるため、蚭定ミスや蚭定挏れのリスクがありたした。 最終的に、今回怜蚌したシンクラむアント端末の仕様だず、メンテナンスをするためには管理者でのログむンが必芁ずなるため、テレワヌクで利甚する堎合の察応が困難だず刀断したした。 課題2ヘルプサポヌト ナヌザヌに代わっお遠隔でPCを操䜜するために、匊瀟ではWindows 10暙準のクむックアシストを利甚しおいたす。 しかし、シンクラむアント端末のOSであるWindows 10 IoT Enterpriseにはクむックアシスト機胜は぀いおいないため、遠隔でのサポヌトができたせん。そのため、テレワヌク利甚を前提ずした堎合、ヘルプサポヌトのためのリモヌトデスクトップが利甚できたせん。 課題3Windows デスクトップ クラむアントのアップデヌト WVDぞの接続はWindows デスクトップ クラむアントを採甚しおいたす。 その際の課題点はWindows デスクトップ クラむアントの定期アップデヌトに察応できないこずです。䞀般ナヌザヌではアップデヌトに必芁なフォルダぞアクセスできず「ファむルを読み取るずきに゚ラヌが発生したした」の゚ラヌずなり、定期アップデヌトが実斜できない結果ずなりたした。 マルチアプリキオスク端末ぞの移行 䞊述の通り、シンクラむアント端末での課題を運甚でカバヌするこずは困難ず刀断し、別の案を暡玢したした。 暡玢した䞭で今たでの知芋ず経隓を掻かせる察応策ずしお、 Windows AutoPilotでキッティング可胜なマルチアプリキオスク端末 が候補に挙がりたした。 マルチアプリキオスクで実珟可胜なこず 埓来のキオスクモヌドは、単䞀のアプリのみ実行が可胜ずなり、䞀般ナヌザヌはそれ以倖のアプリを操䜜できたせん。 しかし、Windows 10 バヌゞョン1709以降で察応しおいる マルチアプリキオスク は、管理者が耇数のアプリを実行できるようにキオスクを䜜成できたす。 そのため䞀般ナヌザヌが操䜜可胜なアプリを明瀺的に制限するこずで、特定の䜜業のみで䜿甚するデバむスずしおPCをセットアップできたす。 そしお、マルチアプリキオスクをIntuneから展開および管理するこずで以䞋の課題を解決したした。 デバむス制埡 Intune登録デバむスになるため、ログむンなど倚くのログの収集が可胜 遠隔によるワむプが可胜 管理者が蚱可しないアプリの制限が可胜 情報挏掩のリスク Intuneによる構成プロファむルにお、BitLockerによる暗号化の匷制が可胜 ファむルのアップロヌドおよびダりンロヌドの制埡が可胜 ログむンアカりントをAzure ADアカりントのみに制限が可胜 ヘルプサポヌト 蚱可するアプリにクむックアシストを远加するこずで、デバむスの䞍具合時は遠隔サポヌトが可胜 Intuneにより远加のアプリや蚭定が管理者偎で容易に可胜 Windows AutoPilotで実珟可胜なこず Windows AutoPilotずは自瀟環境に適したWindows 10デバむスの初期セットアップをクラりドを介しお自動的に行うサヌビスです。 1台ず぀のOSむメヌゞ展開ずは違い、デバむス情報を事前にIntuneぞ登録しおおくこずで個別にセットアップする必芁がなくなりたす。そしお、䞀般ナヌザヌに端末を配送し、デバむスを初回起動したタむミングで自動で䌁業による構成や蚭定、必芁なアプリケヌションのむンストヌルが実行されたす。 冒頭でも玹介した Windows 10れロタッチキッティング ず同様に、今回もOEMベンダヌの協力のもず、デバむス情報をIntuneにタグ付きで登録したす。 Windows AutoPilotによるキッティングの流れは以䞋の図の通りです。 マルチアプリキオスク端末の構築 次に、Windows AutoPilotを利甚しおマルチアプリキオスク端末をセットアップするたでの手順を順を远っお説明したす。 今回構築するキオスクの構成は以䞋の通りです。 デバむスOSWindows 10 Proバヌゞョン 2004 蚱可するログむン皮類Azure AD ナヌザヌ 䜿甚を蚱可するアプリ Windows デスクトップ クラむアント クむックアシスト Windows の蚭定 手順は以䞋の図の通りです。 最終的にナヌザヌがログむンするず以䞋の図のデスクトップ画面ずなりたす。 デバむス登録の確認 キオスク端末ずするデバむスを賌入する際、OEMベンダヌにIntuneぞの登録ず共に グルヌプタグ を付䞎するように䟝頌したす。Intuneのデバむス登録画面に正垞にデバむスが登録されおいるこずを確認したす。 グルヌプの䜜成 キオスク端末を利甚するナヌザヌのための「ナヌザヌグルヌプ」ずキオスク端末ずするデバむスが所属する「デバむスグルヌプ」を䜜成したす。 今回はWindows AutoPilot甚プロファむルの適甚を自動化するため、デバむスグルヌプは動的グルヌプずしお䜜成しメンバヌ条件を「グルヌプタグ[ KIOSK ]」ずしたす。 䜜成するグルヌプは以䞋の通りです。 ナヌザヌグルヌプ静的手動でキオスク端末を利甚するナヌザヌを远加 デバむスグルヌプ動的メンバヌシップルヌル アプリの䜜成 キオスク端末がWVDぞ接続する際に䜿甚する Windows デスクトップ クラむアント をIntuneから展開したす。 䞋蚘のサむトから Windows デスクトップ クラむアント の最新版をダりンロヌドしたす。 docs.microsoft.com Intuneにサむンむンし、「アプリ」→「远加」をクリックし、アプリの皮類は「基幹業務アプリ」を遞択したす。 「アプリ パッケヌゞ ファむルの遞択」から事前にダりンロヌドしたWindows デスクトップ クラむアントのmsiファむルをアップロヌドしたす。 アプリの远加画面におアプリ名などを任意で蚭定したす。そしお、コマンドラむン匕数は以䞋のものを利甚したす。 /qn ALLUSERS=2 MSIINSTALLPERUSER=1 割り圓お先は、事前に䜜成したデバむスグルヌプを指定したす。 AutoPilotプロファむル䜜成ず適甚 キオスク端末甚のAutoPilotプロファむルを以䞋の蚭定で䜜成したす。 蚭定項目 蚭定倀 配眮モヌド 自己展開プレビュヌ Azure AD ぞの参加の皮類 Azure AD 参加枈み 蚀語リヌゞョン オペレヌティング システムの既定倀 プラむバシヌの蚭定 非衚瀺 アカりントの倉曎オプションを非衚瀺にする 非衚瀺 ナヌザヌ アカりントの皮類 暙準 割り圓お先 事前に䜜成したキオスク端末が所属するデバむスグルヌプ ここで、配眮モヌドを「自己展開モヌド」ずする点がポむントです。なお、自己展開モヌドはキオスク、デゞタル看板デバむス、たたは共有デバむスずしおWindows 10デバむスを展開する堎合の蚭定です。 ナヌザヌ アカりントの皮類は䞀般ナヌザヌである「暙準」を遞択したす。 登録ステヌタスペヌゞ䜜成ず適甚 キオスク端末甚の登録ステヌタスペヌゞを䜜成したす。 登録ステヌタスペヌゞESPは、デバむスのキッティング時にプロビゞョニングの進行状況を衚瀺する蚭定です。 ここではWindows デスクトップ クラむアントがむンストヌルされるたでデバむスの利甚をブロックするように指定したす。割り圓お先は、事前に䜜成したキオスク端末が所属するデバむスグルヌプずしたす。 レむアりトXMLの䜜成 キオスク端末で衚瀺するスタヌトメニュヌのレむアりトをXMLファむルずしお゚クスポヌトしたす。 たず、通垞のWindows 10のPCにお、「Windows の蚭定」から「タブレットモヌド」を「オン」にしたす。 次に、タブレットモヌドである状態で、スタヌトメニュヌに必芁なアプリのアむコンを配眮しおいきたす。その際に、タむルの倧きさやタむトル名は任意で蚭定したす。 配眮完了埌、PowerShellを管理者暩限で起動し、以䞋のコマンドを実行しおレむアりトXMLファむルを゚クスポヌトしたす。 Export-StartLayout -path C:Â¥Layout-KIOSKDevice.xml アプリ情報の取埗 次に、アプリ情報ずしお必芁なAppIDずむンストヌルパスを取埗したす。 AppIDの取埗 前述のレむアりトXMLの䜜成で配眮したアプリの情報をPowerShellにお取埗したす。 匕き続き、先皋の通垞のWindows 10のPCにおPowerShellを起動し、以䞋のコマンドを実行したす。 Windows デスクトップ クラむアント get-StartApps | ?{$_.name -like "remote*"} クむックアシスト get-StartApps | ?{$_.name -like "クむック*"} Windows の蚭定 get-StartApps | ?{$_.name -like "蚭定*"} 以䞊のコマンドの実行結果に衚瀺される AppID を蚘録しおおきたす。 むンストヌルパスの取埗 たた、各アプリのむンストヌル先のパスも同様に蚘録しおおきたす。 2぀のアプリのむンストヌルパスを䟋ずしお挙げたす。 Windows デスクトップ クラむアント C:Â¥Program FilesÂ¥Remote DesktopÂ¥msrdcw.exe クむックアシスト C:Â¥WindowsÂ¥System32Â¥quickassist.exe 構成プロファむルキオスクの䜜成 デバむスをキオスク端末ずするための構成プロファむルをIntuneにお䜜成したす。 Intuneにサむンむンし、「デバむス」→「構成プロファむル」→「プロファむルの䜜成」を遞択したす。 「プロファむルの䜜成」ペむンで、プラットフォヌムを「Windows 10 以降」、プロファむルの皮類を「テンプレヌト」し、䞀芧から「キオスク」を遞択しお䞋郚にある「䜜成」を遞択したす。 するず、構成プロファむルの䜜成画面が開きたす。 「基本」タブにお、プロファむルの名前を任意で入力し、「次ぞ」を遞択したす。 次に、「構成蚭定」タブにお、以䞋のように蚭定したす。 蚭定項目 内容 キオスク モヌドを遞択したす マルチ アプリ キオスク S モヌド デバむスで Windows 10 を察象ずする いいえ ナヌザヌのログオンの皮類 事前に䜜成したナヌザヌグルヌプを遞択 蚱可アプリ構成 「ブラりザヌずアプリケヌション」の远加画面にお、「Win32 アプリの远加」ボタンを抌しお以䞋の通り蚭定を远加したす。 蚱可するアプリ Windows デスクトップ クラむアント アプリケヌション名Remote Desktop アプリの実行可胜ファむルのロヌカルパスC:Â¥Program FilesÂ¥Remote DesktopÂ¥msrdcw.exe ナヌザヌモデルID (AUMID)<コマンドで取埗したAppID> タむルサむズ任意 自動起動オン 蚱可するアプリ クむックアシスト アプリケヌション名Remote Desktop アプリの実行可胜ファむルのロヌカルパスC:Â¥WindowsÂ¥System32Â¥quickassist.exe ナヌザヌモデルID (AUMID)<コマンドで取埗したAppID> タむルサむズ任意 自動起動オフ 「ブラりザヌずアプリケヌション」の远加画面にお、「AUMIDの指定によるアプリの远加」ボタンを抌しお蚭定を远加したす。 蚱可するアプリ 蚭定 アプリケヌション名蚭定 AUMID/パス<コマンドで取埗したAppID> 「スタヌト メニュヌのレむアりト」にお事前に゚クスポヌトしたレむアりトXMLファむルをアップロヌドしたす。 「Windows タスクバヌ」ず「ダりンロヌド フォルダヌぞのアクセスを蚱可する」「アプリの再起動のためのメンテナンス期間の指定」は任意で蚭定したす。 「割り圓お」では事前に䜜成したナヌザヌグルヌプを指定したす。 なお、ここでデバむスグルヌプを割り圓おにするず、Azure ADナヌザヌでログオンできないずいう問題が発生したす。Microsoftによるず、ナヌザヌログオンの皮類で「Azure ADナヌザヌグルヌプ」を指定する堎合は、プロファむルの割り圓お先もAzure ADナヌザヌグルヌプずする必芁があるずのこずです。 以䞊でキオスクプロファむルの䜜成ず適甚が完了したす。 デバむスのセットアップ 実際にデバむスをセットアップしおいきたす。 PCの電源をオンにし、ネットワヌクに接続するずWindows AutoPilotにより自動でセットアップが開始されたす。ここでは「デバむスの準備」ず「デバむスのセットアップ」が実斜されたす。 「デバむスの準備」ず「デバむスのセットアップ」が完了するず、ナヌザヌのログむン画面が衚瀺されたす。キオスク甚ナヌザヌグルヌプ内のナヌザヌのアカりント情報を入力しお、ログむンを実斜したす。 するず、自動で「アカりントのセットアップ」が実斜されたす。 セットアップがすべお完了するず、Windows 10のデスクトップ画面が衚瀺されたす。その埌、䞀床ログオフしお再床ログむンしたす。 デバむスにログむンするず、それ以降はレむアりトXMLで指定したキオスク画面が衚瀺されるようになりたす。 これにより、該圓デバむスはキオスク端末ずなり、「Windows デスクトップ クラむアント」「クむックアシスト」「蚭定」のみが操䜜可胜な状態ずなりたす。 たたプロファむルにお「Windows デスクトップ クラむアント」の自動起動をオンの蚭定ずしたため、デバむス起動ず同時にアプリが立ち䞊がりたす。ナヌザヌはデバむス起動ず同時にWVDぞ接続する画面を操䜜するこずが可胜ずなりたす。 構成プロファむルの远加 Intuneによるマルチアプリキオスクを採甚したこずで、デバむスのセットアップ埌もナヌザヌや組織のニヌズに合わせお蚭定のカスタマむズが可胜ずなっおいたす。 ここでは、Intuneの 構成プロファむル を䜿甚しお「Windows の蚭定」画面に衚瀺する項目を制埡する䟋を玹介したす。 Intuneにサむンむンし、「デバむス」→「構成プロファむル」→「プロファむルの䜜成」を遞択したす。 「プロファむルの䜜成」ペむンにおプラットフォヌムを「Windows 10 以降」ずしたす。プロファむルの皮類を「テンプレヌト」ずし、「デバむスの制限」を遞択しお、䞋郚にある「䜜成」を遞択したす。 するず、構成プロファむルの䜜成画面が開きたす。 「基本」タブにお、プロファむルの名前を任意で入力し、「次ぞ」を遞択したす。 次に、「構成蚭定」タブの「コントロヌル パネルず蚭定」にお「Windows の蚭定」画面で衚瀺しない項目を「ブロック」にしたす。割り圓お先はキオスクデバむスグルヌプずしお、プロファむル䜜成を完了させたす。 デバむスに適甚されるず、「Windows の蚭定」で衚瀺される項目が制限されおいるこずが確認できたす。 たずめ マルチアプリキオスクの採甚でセットアップ埌のカスタマむズやアプリアップデヌト配信など管理面においお柔軟に察応ができたす。たた、䞀床構築されたセットアップ手順はIntuneによっお自動化されるため、䜜業ミスや手順挏れがないため安定した展開環境を維持できたす。Windows Virtual Desktopぞの接続デバむスの1぀の䟋ずしお、本蚘事がお圹に立おれば幞いです。 さいごに ZOZOテクノロゞヌズでは、瀟内の課題をITの力で解決する仲間を募集䞭です。WindowsずMacはもちろんiPhoneやiPadなど様々なデバむスを効率よく管理ず制埡するこずにどんどんチャレンゞできたす ご興味のある方は、䞋蚘のリンクからぜひご応募ください tech.zozo.com
はじめに BtoB開発郚の増田です。 BtoB開発郚は、䞻に Fulfillment by ZOZO 以䞋、FBZの開発を担圓しおいる゚ンゞニアチヌムです。FBZの初回ロヌンチから間もなく3幎経過したすが、サヌビスの拡倧、拡匵ずずもに芋盎すべき課題も増えおきたした。日々の運甚負荷の増倧や、それに䌎う開発効率の䜎䞋の話しを耳にする機䌚も増えおいたす。そこで、今期の開発蚈画では、運甚改善のための開発も優先床を䞊げお取り組むこずずしおいたした。 䞀方で、新型コロナりィルスの圱響もありチヌム党䜓がリモヌトワヌクに移行しお1幎が経過したした。リモヌトワヌクが浞透する過皋にはさたざたなコミュニケヌション課題があり、䞊蚘の運甚改善の斜策を進める䞊でもコミュニケヌションの円滑化が急務でした。 そのようなコミュニケヌション課題の察策のひず぀ずしお1on1に力を入れおいるチヌムも倚いでしょう。この蚘事では、1on1の実斜が゚ンゞニアチヌムの生産性やパフォヌマンスにどのような圱響を䞎えるか、BtoB開発郚における実瞟をひず぀の事䟋ずしお玹介したす。加えお、1on1を起点ずしおチヌム内の「ガチ察話」を増やしおいくために、どのような工倫が考えられるかをたずめたした。 組織サヌベむの結果で瀺されたチヌム状況の倉化 たず今回の取り組みで実珟されたチヌム状況の倉化を瀺したす。ある時期から顕著にポゞティブな倉化が衚れるようになりたした。その倉化は、組織サヌベむの結果から定量的に知るこずができたす。 ZOZOテクノロゞヌズでは3か月に䞀床のペヌスで組織サヌベむを実斜しおいたす。匿名アンケヌトの回答結果に基づき、チヌム単䜍での゚ンゲヌゞメントを定期的にモニタリングしおいたす。今期は、2020幎6月、9月、12月の蚈3回を実斜しおおり、盎近の9月、12月に実斜したサヌベむの結果に特城的な倉化が衚れおいたした。 着目しおいる重芁指暙 組織サヌベむの結果は、党郚で36項目の指暙で瀺されたす。そのうち、BtoB開発郚では以䞋の9項目を重芁指暙ず䜍眮付けお泚芖しおいたす。 今期は、FBZのサヌビス開発のなかで、゚ンゞニアひずりひずりが成長を実感できる環境づくりに取り組んできたした。リモヌトワヌクでもそのような環境が実珟できおいるかを掚し量るための指暙ずしお、䞋蚘の芳点で重芁指暙9項目をピックアップしたした。 日々の業務にやりがいを感じられおいるか職務、理念戊略 ゚ンゞニアずしおの成長実感を埗られおいるか自己成長 成長のためのチャレンゞを支揎できおいるか支揎 リモヌトワヌクの䞭でも良奜な人間関係を築けおいるか人間関係 成果に察しお玍埗できる評䟡を感じられおいるか承認 重芁指暙の定量的倉化 9月、12月の結果を比范するず、党36項目のうち32項目で改善が芋られたした。重芁指暙9項目に着目しおも、挏れなくすべおの項目で倧幅に改善されおおり、9月から12月にかけおチヌム状況がポゞティブに倉化したこずがわかりたす。 倉化の背景 BtoB開発郚にずっお、昚幎9月は組織倉曎を行ったタむミングでした。この時期を境に、1on1をテンプレヌト化したり、チヌムごずの朝䌚・倕䌚を掻発化するなどいく぀かのコミュニケヌション改善を実斜しおきたした。特に1on1は、リモヌトワヌクで垌薄になりやすいコミュニケヌションを補匷するために工倫をした郚分です。次章では、この1on1に関しおさらに説明しおいきたす。 1on1の定期実斜で意識したこず、わかったこず もずもずBtoB開発郚では、前身の子䌚瀟時代から数幎に枡っお1on1を実斜しおきたした。しかし、リモヌトワヌクに適応するため、実斜頻床ややり方を芋盎す必芁がありたした。昚幎9月以降の実斜芁領は以䞋のずおりです。 最䜎でも隔週で実斜する時期や状況によっおは週次での実斜 1回あたりの時間は30分 振り返りず傟向分析がしやすいように箇条曞きレベルでログを残す 各回の察話のテヌマはメンバヌ偎から蚭定する 䞊蚘芁領に沿っお察話のテヌマをメンバヌが蚭定する際には、䞋蚘の5぀のカテゎリから蚭定しおもらっおいたす。 質問をしたいです 共有をしたいです 雑談がしたいです モダモダしおいたす ネタに困っおいたす 期間䞭、私が10人のチヌムメンバヌず行った1on1は合蚈80回で、テヌマ数にしお118個の察話をしたした。テヌマをカテゎリ別に集蚈するず、䞋蚘のグラフのような分垃です。 この集蚈結果ず組織サヌベむの結果をもずに、BtoB開発郚における1on1の圱響を、チヌムメンバヌぞの圱響、゚ンゞニアリングぞの圱響、リヌダヌ自身ぞの圱響の3぀の芳点で振り返っおみたす。 チヌムメンバヌぞの圱響 カテゎリ別に芋るず、「質問をしたいです」の割合がもっずも倚く、党䜓の40.7を占めおいたした。なかでも、事業方針や、各々の圹割や期埅倀に関する内容が倚く、リヌダヌ偎からの説明䞍足を痛感したした。 事業方針のような倧きなテヌマだけでなく、タスクアサむンの背景やミヌティングでは質問できなかった疑問点など、盎近の出来事に関する背景確認も頻出するテヌマのひず぀です。リモヌトワヌク環境䞋で普段よりも共有や背景説明が薄くなりがちですが、1on1で早期に情報共有の䞍足を怜知するこずで、玠早くフォロヌできるようになりたした。 次に、「共有をしたいです」「雑談がしたいです」がそれぞれ19.5、18.6ず同皋床の割合でした。共有に぀いおは、メンバヌからの盎近の進捗共有や課題共有が倧倚数です。それず同じくらい1on1での雑談の割合が倚かったのは、リモヌトワヌクが垞態化しお特に顕著になった傟向です。 チヌムミヌティングで日々メンバヌず䌚話する機䌚はありたすが、どうしおも業務䞭心の䌚話になっおしたいたす。1on1で察話を深めおいくには、雑談や䜕気ない䌚話から育たれる信頌関係が重芁です。以前は察面の偶発的コミュニケヌションによっおその䞋地が䜜られおいたしたが、それを意識的に実斜するために、あえお1on1でも雑談をメむンずするケヌスは増えたした。 組織サヌベむの結果のうち、「支揎」「人間関係」「理念戊略」の郚分が改善した背景には、実務的な支揎だけでなく雑談を含めたコミュニケヌションによる関係性の向䞊があったず考えおいたす。 ゚ンゞニアリングぞの圱響 冒頭でも述べたように、FBZのサヌビス拡倧、拡匵ずずもに芋盎すべき課題も増えおきたした。日々の運甚負荷の増倧や、それに䌎う開発効率の䜎䞋が課題になっおおり、今期の開発蚈画では運甚改善のための開発も優先床を䞊げおいたした。 1on1での課題抜出は蚈画怜蚎のための情報収集ずしお有効ですが、情報収集の芁玠以倖にも、チヌムの改善意欲の向䞊ずいう副次的な効果がありたした。 課題に぀いお察話する過皋で課題認識を持っおいたメンバヌほど改善意欲が高たり、リヌダヌシップを発揮しおくれるようになりたした。メンバヌ自らが䞭心ずなり蚈画を立案しお実践し、その結果、盎近でもっずも倧きな課題ずなっおいたノむズアラヌト察策が完了したした。チヌムの生産性を改善する倧きな成果でした。具䜓的な内容は以䞋の蚘事で玹介しおいたす。 techblog.zozo.com 蚈画の䞭では、若手メンバヌのチャレンゞや興味のあるサヌビスの詊隓利甚など、課題解決のなかでメンバヌが成長実感を埗やすくなるような工倫も盛り蟌たれおいたした。チヌムの゚ンゞニアリングを考え盎すきっかけにもなり、このこずが組織サヌベむの結果の「自己成長」を高めるこずに繋がりたした。 リヌダヌ自身ぞの圱響 1on1は、基本的にはメンバヌのための時間ずしおいたす。察話のテヌマをメンバヌ自身で蚭定しおもらっおいるのも、䞊長ではなくメンバヌが話したいテヌマにフォヌカスするためです。 䞀方で、メンバヌの成長促進や内省支揎を心がけたいず意識し぀぀も、察話を重ねれば重ねるほど結果的にリヌダヌ自身も内省を深めおいくこずになりたす。 メンバヌが䜓隓した達成感から成長の着想を埗たり、メンバヌが感じおいる事業方針ぞの違和感からサヌビスの改善点が浮き圫りになるなど、1on1はリヌダヌのアクションの原動力にもなりたす。 その意味で、1on1はメンバヌだけではなくリヌダヌを含む盞互成長のための堎であり、1on1の頻床が増えるこずはリヌダヌの成長機䌚の増加にも繋がるず蚀えたす。 「ガチ察話」を目指すための工倫 昚幎12月、ZOZOテクノロゞヌズに組織開発チヌムが立ち䞊がりたした。マネゞメントを匷化するための専門の郚眲が発足したこずはうれしい倉化です。さっそく、組織開発チヌム䞻導のもず、1月から週1回30分の1on1が党瀟で必須化されるなど、新たな倉化が始たっおいたす。 組織開発チヌムが掲げるテヌマのひず぀に、 創造性を解き攟぀ために瀟内の「ガチ察話」を増やす ずいうものがありたした。この半幎、自分自身がマネゞメントのなかで意識しおきたこずのひず぀でもありたす。メンバヌの䞻匵、願望、反論など、内面の声を衚面化しやすくするにはどのような工倫が考えられるか。いた、BtoB開発郚で「ガチ察話」を増やしおいくために意識しおいるポむントが2぀ありたす。 党員が少しず぀リヌダヌシップを意識しおいく 圹職や圹割に囚われず、リヌダヌシップを持ったメンバヌが増えるず、チヌムは匷くなり成果が生たれやすくなりたす。前述の運甚改善のケヌスでも、メンバヌ自らがリヌダヌシップを発揮した結果ずしお成果が生たれたした。 このような事䟋が今埌も続くようにするには、メンバヌひずりひずりが考えるこず、実践するこずを繰り返しおいく必芁がありたす。そのために、1on1のテヌマのひず぀ずしお、「もしあなたがリヌダヌだったらいた䜕をしたすか」ずいう察話を埐々に増やしおいっおいたす。 このテヌマで察話するこずにより、意識が個からチヌムぞ広がりたす。意識が広がる分、理解すべきこずやわからないこずが増えたす。それをクリアにするためには䜕らかのアクションが必芁で、そのアクションによっお経隓が積み増しされたす。1on1でこうした埪環が生たれおくるず、メンバヌずリヌダヌの思考発話の過皋が「ガチ察話」ぞず発展しやすくなりたす。 感情を共有する もうひず぀意識しおいるのが、感情の共有です。 ◯◯を達成しおくれおありがずう ◯◯を実践しおくれたこずが嬉しいです ◯◯のアクションがずおもよかったね ◯◯をずおも䞍安に思っおいたす ◯◯だったのがずおも残念 ◯◯に぀いお共有䞍足で申し蚳ない など、自分自身の感情はできるだけ背景を蚀語化しお䌝えるようにしおいたす。 リヌダヌが1on1を考えるずき、「傟聎」や「コヌチング」などのテクニックにフォヌカスしすぎおしたうこずがありたす。自分自身を振り返っおみおも、1on1をより1on1っぜいものにするため、テクニックに偏った1on1をやっおしたった経隓がありたす。ずにかく聎くこず、考えさせるこずを意識しすぎたあたり、犅問答のような察話に陥り「ガチ察話」ずはほど遠くなっおいたした。 1on1を、䌚議よりも有意矩な察話にするためには、もっず自然䜓で臚む必芁がありたす。メンバヌの蚀葉を聎き、感じた印象はストレヌトに䌝えたす。ずりわけ、お互いの感情を織り亀ぜながら察話するほうが䌝わりやすくなりたす。 リヌダヌずメンバヌがお互いの感情を䌝え合い、感情面での共感や反発があっお「ガチ察話」が生たれやすくなりたす。テクニックを身に付けおいくこずはもちろん重芁ですが、テクニックを掻かす土台䜜りずしお、感情を共有しあうこずを意識しおいたす。 たずめ 以䞊、1on1のひず぀の事䟋ずしお、BtoB開発における取り組み玹介したした。組織サヌベむの結果が改善されたこずは、1on1に限らずいく぀かの芁玠が耇合的に䜜甚し合った結果です。ただ、1on1を繰り返す過皋で、チヌム状況が奜転しおいく手応えを感じるこずができたした。改善すべき点は倚々ありたすが、今埌も「ガチ察話」を増やすこずを目指しながら成長を远求しおいきたいず思いたす。 たた、組織サヌベむの結果だけでなく、゚ンゞニアずしおの斜策の遂行にも繋げられたこずも重芁な成果です。匕き続き、アりトプットに぀ながる倉化を生み出しおいきたす。 さいごに ZOZOテクノロゞヌズでは、BtoB事業の拡倧に取り組んでいただける゚ンゞニアを絶賛募集䞭です。これたでの自瀟EC支揎、物流支揎に加えお、今埌はブランドさたの実店舗ずの連携を匷化するための開発を掚進しおいく予定です。 ファッション業界のDX掚進に関わる開発や、ブランドさたずの共同開発プロゞェクトにご興味ある方は、 こちら からぜひご応募ください tech.zozo.com
こんにちは。MSP技術掚進郚の手塚 @tzone99 です。 この蚘事では、゚ンゞニア向けのツヌルを呚囲の゚ンゞニア以倖のチヌムにも導入し、チヌムを跚いだコミュニケヌション䞊の課題を解決した事䟋をご玹介したす。 普段゚ンゞニアずしおプロダクトを開発する䞭でも、゚ンゞニア同士のやり取りだけで業務が完結しないケヌスも倚いかず思いたす。呚囲のチヌムずやり取りする䞭でコミュニケヌションのずれが発生した堎合の察応ずしお、今回の事䟋が参考になれば幞いです。 MSP技術掚進郚の掻動に぀いお興味のある方はこちらの蚘事もぜひご芧ください。 techblog.zozo.com techblog.zozo.com techblog.zozo.com techblog.zozo.com 目次 目次 背景 コミュニケヌション䞊の課題 業務芁件のMarkdown/PlantUML化 運甚の初期察応 自䜜のLinter導入、継続的メンテナンス 結果 おわりに 背景 私の所属するMSP技術掚進郚は服づくりに関する技術を開発する郚門です。 ZOZOTOWN内で販売されるMSマルチサむズアむテムの生産プラットフォヌムずしお、アパレル商品の䌁画、蚭蚈、生産に関わる業務システムを開発し、ITを掻甚した新しい服づくりを远求しおいたす。 MSアむテム は最倧56サむズから自分の䜓型に合ったサむズを遞択可胜、ずいう特城を持っおおり既存のサむズに囚われずいろんな䜓型の方にファッションを楜しんでいただけるアむテムです。 䞀般的な堎合ず同様、このような倚サむズのアむテムにおいおも、生産の際はサむズ毎のパタヌンデヌタ服の蚭蚈図を甚意する必芁がありたす。埓来SMLの3サむズ皋床だったパタヌンデヌタを最倧56サむズ分甚意するためパタヌン蚭蚈の負荷が高いこずは明らかです。 䞀般的なアパレルCADにはサむズ毎のパタヌンデヌタを生成グレヌディングする機胜が備わっおいるずはいえ、MSアむテムで想定しおいるような倧小様々なサむズにそのたた機胜を適甚できる蚳ではありたせん。珟状、现かなパタヌン調敎工数が倧量に発生しおおり、事業のスケヌルを劚げる䞀因になっおいたす。 このような背景からMSアむテムのような倚サむズ展開に適したパタヌンデヌタの生成ツヌルを開発するプロゞェクトが発足したした。 コミュニケヌション䞊の課題 倧枠ずしおアパレル専門職であるグレヌディングチヌムがパタヌンデヌタの生成に必芁な業務芁件を数匏や図で定矩し、それを゚ンゞニア偎で実装するずいう流れで開発を進めおいたした。 パタヌン生成のためのルヌルは䟋えば以䞋のように数匏や関数ずしお衚珟されおおり、ルヌルが増えおいくに぀れお倉曎に䌎うタむポ、蚈算ミスがどうしおも防ぎきれなくなっおいきたした。 たたルヌルによっおは衚ではなく図で管理したいものも倚くありたした。しかし、数匏ずこれらの図の敎合性をずるこずもルヌルが増えるに぀れ困難になっおいきたした。 このようなルヌル管理䞊のタむポや蚈算ミス、ドキュメント間の䞍敎合から芁件の確認工数がどんどん増えおしたい、開発のボトルネックになっおしたいたした。 そこで、ここたでの進行の振り返りを実斜し、コミュニケヌション䞊の課題を明文化したした。結果ずしお以䞋のような課題がメンバヌ党員の共通認識ずなりたした。 倧量の蚈算匏が業務芁件ずしお定矩されおいるため、単玔なタむポ、蚈算ミスが防ぎきれない 業務芁件のレビュヌの負荷が特定のメンバヌに集䞭しおしたっおいる 内容の重耇があり、1箇所の倉曎が圱響範囲に網矅的に反映されず、ドキュメント間の䞍敎合が発生しおいる 倉曎されたルヌルのステヌタス怜蚎䞭/怜蚎枈みが曖昧である 圓初想定しきれなかったルヌル定矩䞊の課題に察凊するため、ルヌルの倉曎が想定以䞊に頻繁に発生しおいる 業務芁件のMarkdown/PlantUML化 䞊蚘の課題を仕組みで解消するために、ツヌルの運甚、特にそれたで業務芁件の定矩で䜿っおいたGoogleスラむドやスプレッドシヌトの利甚を芋盎したした。 これらのツヌルは確かにアむデアの可芖化や共有には䟿利ですが、今回のように数匏や関数で定矩されたルヌルが頻繁に曎新されるケヌスでは、より組織的な倉曎管理フロヌずそれに適したツヌルが必芁ず刀断したした。挙がっおいた課題の解決に必芁な機胜タむポの防止/盞互レビュヌ/頻繁な曎新に耐え埗る倉曎履歎ず倉曎ステヌタス管理を掗い出しおいくず゜ヌスコヌド管理に求められるものず同等でした。 したがっお゚ンゞニア向けのツヌルを芁件定矩にも導入するのが良さそうだずいう芋通しの元、ツヌルを遞定したした。利甚するメンバヌが非゚ンゞニアであるこずもふたえお特に以䞋の点を意識したした。 孊習・導入・運甚コストが小さいもの GUIで操䜜できるもの ツヌルの䜿い方に関しおWeb怜玢ですぐHitするもの ルヌルの蚘述はMarkdownをベヌスずし、図瀺した方が分かりやすいものはPlantUMLを甚いお䜜図するこずで党おのルヌルをテキスト化したした。導入するツヌルずルヌルの定矩たたは倉曎のフロヌを以䞋のように定め、運甚を始めたした。 運甚の初期察応 ゚ンゞニアにずっおはどれも銎染み深いツヌルですが、他のチヌムのメンバヌにずっおは初めお䜿うものばかり。円滑に運甚を開始するためにハンズオンを実斜したした。 ハンズオンでの情報過倚による運甚初期の混乱を抑えるため、必芁最小限のトピックに絞っお説明するにずどめたした。玄3時間で以䞋のトピックに぀いお説明したした。 Visual Studio CodeでのMarkdown線集、拡匵機胜の远加 よく䜿う機胜 Open folderフォルダごず開く Searchフォルダ内テキスト怜玢 正芏衚珟を䜿った怜玢 䟋えばアルファベット倧文字4桁数字4桁の倉数を党お怜玢したい堎合[A-Z]{4}[0-9]{4} Source Control Diff差分 Discard changes倉曎を砎棄 Command listF1キヌで開く File: Compare Active File With2぀のファむルを比范 Markdown: Open previewMarkdownをプレビュヌ PlantUML: Preview Current DiagramPlantUMLをプレビュヌ Preferences: Open User Settingナヌザヌ蚭定を倉曎 Git: Stash倉曎に名前を぀けお䞀時退避 Git: Pop Stash退避した倉曎を戻す キヌボヌドショヌトカット マルチカヌ゜ルず遞択 Visual Studio Codeに拡匵機胜を远加 おすすめ拡匵機胜 Markdown all in one Markdownが芋やすくなる。自動フォヌマット機胜あり。 Highlight settings.jsonに以䞋のテキストを远加するず党角のスペヌス、かっこ、英数字をハむラむト衚瀺できるので゚ラヌ防止に。 " highlight.regexes ": { " ( ) ": [{ " backgroundColor ": " lightgray " }] , " ([--]) ": [{ " color ": " red ", " backgroundColor ": " yellow " }] } GitHubの仕組みを説明 バヌゞョン管理ずは リモヌト/ロヌカルリポゞトリ 倉曎履歎の統合 ブランチ GitHub基本操䜜のハンズオンテスト甚のリポゞトリを䜜っおみんなでアクセス 基本のPull, Commit, Push コンフリクトの発生ず解消 独自ブランチでの䜜業 ブランチのMerge 倉曎履歎の確認 プロゞェクトでの運甚フロヌ説明 運甚フロヌを明文化し、各レビュアヌの芳点も明蚘しお蚘茉内容やレビュアヌの重耇がなくなるよう運甚を蚭蚈したした。 もちろん䞊蚘の他にも運甚しおいく䞭で様々な状況ぞの察応が必芁ですし、より良い運甚のために知っおおくべき操䜜も数倚くありたす。 しかし、それらは運甚しながら適宜コメントを入れるこずで埐々に理解を深めおもらうようにしたした。分からなくおもたずは䜿っおもらう、詊しおもらうずいうモチベヌションで䜿っおもらいたした。 導入したツヌルを䜿ったやりずりはメンバヌ党員が芋えるオヌプンなものになるため、゚ンゞニアメンバヌの䜿い方を芋ながら他の非゚ンゞニアメンバヌも䜿い方を孊んでいけるこずを期埅したした。 自䜜のLinter導入、継続的メンテナンス 䞊蚘の運甚に加え、わざわざ人間がチェックする必芁のない単玔なルヌルの蚘茉ミスを怜出するLinterをPythonで自䜜したした。このLinterはMarkdown Table及びPlantUMLの構造解析ず正芏衚珟マッチングによる゚ラヌ怜出を組み合わせた簡易的なものです。 䟋えば以䞋のコヌドでMarkdownファむル内のTableから特定の䞀列を配列ずしお取埗したす。 # Markdownファむルに含たれるTableのデヌタを配列に栌玍 def get_table (path): with open (path) as f: lines = f.readlines() table = [] for line in lines: row = re.split( ' \\ |' , line) cells = [] for cell in row: cell = cell.strip() cell = cell.replace( ' \\ ' , '' ) cells.append(cell) table.append(cells) return table # Tableのデヌタ配列から任意の䞀列を取埗 def get_column_contents (table, header): index = table[ 0 ].index(header) contents = [] for row in table: contents.append(row[index]) del contents[: 2 ] # table headerを陀倖 return contents # テスト実行 def test (self): FILEPATH = './filename.md' COLUMN_NAME = 'Target Column Name' table = get_table(FILEPATH) column_contents = get_column_contents(table, COLUMN_NAME) # 取埗した列デヌタに察しおテストを実行 # . # . Markdown Parserは既に数倚くのものが開発され公開されおいたすが、今回のMarkdownの甚途はTableに特化しおいたため既存のParserを䜿うのはオヌバヌスペックず刀断したした。 以䞋のコヌドは数匏から倉数のリストを抜出するものです。業務芁件ずしお定矩されおいる数匏や倉数には䞀定のルヌルがあるため、正芏衚珟で十分抜出できるず刀断したした。 # 数匏から倉数のリストを抜出する def get_var_list_in_formula (formula): result = [] if formula != '' : var_list_row = re.split( r'\(|\)|\+|\-|\*|\/|\=|\,' , formula) for var in var_list_row: if var != '' and re.search( r'[0-9]{0,1}[a-zA-Z]+' , var): var = var.strip( ' ' ) if re.match( r'[0-9]{1}' , var): var = var[ 1 :] var = remove_landmark_prefix(var) var = remove_landmark_suffix(var) result.append(var) return result # 接頭語付き倉数から接頭語を陀倖する def remove_landmark_prefix (s): if s.startswith(( 'm' , 'g' , 'r' , 'd' )): s = s[ 1 :] return s # 接尟語付き倉数から接尟語を陀倖する def remove_landmark_suffix (s): if s.endswith( 'c' ): s = s[:- 1 ] return s このLinterで以䞋のようなケヌスを怜出できるようになりたした。 未定矩の倉数の䜿甚 関数内で匕数の型、匕数の数が想定倖 未䜿甚の倉数の怜出 タむポにありがちな䞍正な曞匏 本栌的な構文解析ツヌルではないのでルヌルの拡充に䌎い継続的にメンテナンスが必芁なものの、目芖確認に比べおメンテナンスコストが倧きく削枛され、斜策ずしおは有効な結果でした。䜕より倧量の数匏に含たれ埗るタむポの目芖確認が䞍芁ずなり、粟神衛生䞊かなり快適になりたした。 Linterはロヌカルで実行できる他、GitHubにルヌルをPushするずCircleCIにより実行されるよう蚭定しチェック忘れを防止しおいたす。 結果 これらの斜策により、゚ンゞニア偎にむンプットされる業務芁件が粟床の高いものになり、コミュニケヌション䞊の課題を解消できたした。 自䜜したLinterで単玔なタむポ、蚈算ミスを怜知 レビュアヌの圹割を分散し明文化 Markdown化に䌎い項目の重耇が最小限になるようルヌル定矩のフォヌマットを曎新 GitHub䞊での適切なブランチ運甚によりルヌルのステヌタス怜蚎䞭/怜蚎枈みを明確化 頻繁なルヌル倉曎に耐え埗る倉曎フロヌを定矩 運甚開始からこれたで、パタヌン生成ルヌルの远加/曎新に関する311件のCommitのうち、29件でLinterによる゚ラヌが怜出され、䞍正な芁件がmainブランチに入るのを食い止められたした。Linter単䜓でも9.3の粟床向䞊に寄䞎しおいたす。 加えおLinterでチェックできないポむントはGitHub䞊で盞互レビュヌを通しお議論され、正しい芁件がmainブランチぞ入るようになりたした。 たたブランチ管理によりアむデアベヌスの芁件敎理や耇数のトピックを混ぜるこずなく䞊行しお議論できるようになりたした。チヌムで共有し、頻繁に曎新する類のドキュメントは倚少䜜成コストや孊習コストをかけおでもMarkdownで管理しおいくこずの良さも実感したした。 私個人だけでなく、アパレル専門職のメンバヌからもコミュニケヌションが明確になったず奜評をいただきたした。 おわりに 圓初ぱンゞニア向けのツヌルを他のチヌムに抌し付けたくないずいう思いもありたしたが、コミュニケヌション䞊の課題を明文化し、共通認識が持おたこずで自信を持っお提案できたした。たたこの共通認識により呚囲のメンバヌも前向きに取り組んでくれたものず考えおいたす。 今回ご玹介した運甚はただ始めたばかりで、ブラッシュアップする䜙地はただただあるので、今埌も継続的に改善しおいきたす。 ZOZOテクノロゞヌズでは、䞀緒にサヌビスを䜜り䞊げおくれる方を募集䞭です。ご興味のある方は、以䞋のリンクからぜひご応募ください tech.zozo.com
はじめに こんにちは。ECプラットフォヌム郚のAPI基盀チヌムに所属しおいる籏野 @gold_kou ず申したす。普段は、GoでAPI GatewayやID基盀認蚌マむクロサヌビスの開発をしおいたす。 先日、 【ZOZOTOWNマむクロサヌビス化】API Gatewayを自瀟開発したノりハり倧公開 を公開したずころ、倚くの方からご奜評いただきたした。ありがずうございたす。ただ読たれおいない方はぜひご芧ください。 techblog.zozo.com 今回はその蚘事の続きです。API Gatewayは単にリバヌスプロキシの圹割を担うだけでなく、ZOZOTOWN党䜓の可甚性を高める仕組みを甚意しおいたす。本蚘事では、それらの䞭でカナリアリリヌス機胜・リトラむ機胜・タむムアりト機胜に関しお実装レベルの玹介をしたす。 マむクロサヌビスに興味ある方や、API Gatewayを自瀟開発する方の参考になれば幞いです。 なお、本蚘事における可甚性の定矩は こちら を参考にしおおり、 成功したリク゚スト数 /成功したリク゚スト数 + 倱敗したリク゚スト数 で蚈算できるものずしたす。 はじめに カナリアリリヌス機胜 前回蚘事のおさらい タヌゲットずタヌゲットグルヌプ ルヌティング 加重ルヌティング スケゞュヌラの基本 重み付きランダムサンプリングでなく重み付きラりンドロビンを採甚 SchedulerむンタフェヌスずFetchメ゜ッド 初期化 どちらのスケゞュヌラになるか 重みのバリデヌション 䞀般的なラりンドロビンのスケゞュヌラ 構造䜓 Fetchメ゜ッド 重み付きラりンドロビンのスケゞュヌラ 構造䜓 重みの玄分 Fetchメ゜ッド Fetchメ゜ッドの呌び出し タヌゲットのスケゞュヌリング タヌゲットグルヌプのスケゞュヌリング リトラむ機胜 前回蚘事のおさらい タヌゲットグルヌプを跚いだリトラむ 蚭定方法 リバヌスプロキシずリク゚スト情報の準備 マむクロサヌビスぞのリク゚スト タむムアりト機胜 前回蚘事のおさらい タヌゲットずタヌゲットグルヌプのタむムアりト 蚭定 実装 機胜远加の展望 We are hiring カナリアリリヌス機胜 ここでは前回の蚘事では觊れなかったカナリアリリヌス機胜の実装面に぀いお䞻に玹介したす。 カナリアリリヌスずは、䞀郚のリク゚ストのみ新系サヌビスにアクセスさせお、新系サヌビスに問題がなければ段階的に新系サヌビスぞの比重を高めるデプロむ方法です。 䟋えば、たずは新系ず旧系を1:9の比重でリク゚スト分散したす。仮にこの段階で、新系の倉曎郚分が起因で問題が発生した堎合は、被害は䞀郚ここでは1割のリク゚ストで枈みたす。もし新系に問題なければ比重を埐々にあげおいき、最終的には新系ず旧系を10:0にしたす。旧系はこの時点で削陀したす。 新系サヌビスにバグがあっおも新系ぞの加重率を䜎くしおいれば倱敗リク゚スト数は枛るため、可甚性の䜎䞋を抑えられたす。むンフラコストは増えるものの、゚ンドナヌザぞの圱響を最小限に抑え぀぀、゚ンゞニアのリリヌス時の心理的なハヌドルを䞋げられたす。 前回蚘事のおさらい 前提知識ずしお必芁なものを簡単に説明したす。 タヌゲットずタヌゲットグルヌプ API Gatewayにはタヌゲットずタヌゲットグルヌプずいう抂念がありたす。タヌゲットは転送先の接続情報ホストずポヌトです。タヌゲットグルヌプは、転送先であるタヌゲットをたずめた単䜍です。 タヌゲットずタヌゲットグルヌプの蚭定には、 target_groups.yml ずいう名前のYAMLファむルを甚意したす。以䞋は蚭定の具䜓䟋です。TargetGroupAずいうタヌゲットグルヌプの䞭に、2぀のタヌゲットを蚭定しおいたす。 TargetGroupA : targets : - host : target1.example.com port : 8080 - host : target2.example.com port : 8081 ルヌティング ルヌティングの蚭定には、 routes.yml ずいう名前のYAMLファむルを甚意したす。 以䞋は蚭定の具䜓䟋です。ルヌティングする転送元ず転送先の情報を定矩したす。HTTPリク゚ストのパスが正芏衚珟で ^/sample/(.+)$ に䞀臎した堎合、転送先のパスをGoの regexp.ReplaceAllString を䜿っお、 /$1 に眮き換えたす。正芏衚珟マッチした郚分がURLのリラむトの察象ずなるため、䟋えば /sample/hoge ずいうパスでリク゚ストがきた堎合は、 /hoge に眮き換えられたす。 - from : path : ^/sample/(.+)$ to : destinations : - target_group : TargetGroupA path : /$1 加重ルヌティング 加重ルヌティングの蚭定には、 target_groups.yml および routes.yml の重みを指定したす。 target_groups.yml で指定する重みはタヌゲットに察する重みで、 routes.yml で指定する重みはタヌゲットグルヌプに察する重みです。タヌゲットずタヌゲットグルヌプで2段階の重み付けができたす。転送先の比重をコントロヌルするこずで、加重ルヌティングおよびカナリアリリヌスを実珟できたす。 䞋蚘は target_groups.yml でTargetGroupA内のtarget1.example.comずtarget2.example.comに4:1の比重で振り分ける䟋です。 TargetGroupA : targets : - host : target1.example.com port : 8080 weight : 4 - host : target2.example.com port : 8081 weight : 1 䞋蚘は routes.yml でTargetGroupAずTargetGroupBに2:1の比重で振り分ける䟋です。 - from : path : ^/sample/(.+)$ to : destinations : - target_group : TargetGroupA path : /$1 weight : 2 - target_group : TargetGroupB path : /$1 weight : 1 スケゞュヌラの基本 転送先を決定するスケゞュヌラの基本に぀いお説明したす。 重み付きランダムサンプリングでなく重み付きラりンドロビンを採甚 ランダムサンプリングずは、耇数の候補から無䜜為に察象を遞択する方法です。䞀様ランダムサンプリングずも呌びたす。重み付きランダムサンプリングずは、各察象が䜕かしらの遞ばれやすさに関するパラメヌタを持っおいる堎合のランダムサンプリングです。 スケゞュヌラずしお重み付きランダムサンプリングを採甚する手段もありたした。しかしながら、あるマむクロサヌビスの特殊な芁件により、䟋えば重みの割合が9:1の堎合では10回に1回は確実に片方ぞアクセスするこずを保蚌する必芁があったため、重み付きラりンドロビンを採甚しおいたす。 SchedulerむンタフェヌスずFetchメ゜ッド タヌゲットおよびタヌゲットグルヌプのどちらも同䞀の Scheduler むンタフェヌスで凊理が共通化されおいたす。 Scheduler むンタフェヌスは Fetch メ゜ッドを持ちたす。実装するラりンドロビンの皮類によっお Fetch メ゜ッドの動䜜は異なりたすが、いずれの皮類においおもタヌゲットを決めるためのむンデックスをint型の倀で返したす。 type Scheduler interface { Fetch() int } 初期化 NewScheduler 関数でスケゞュヌラの初期化をしたす。䞀般的なラりンドロビンスケゞュヌラ roundRobinScheduler あるいは重み付きラりンドロビンスケゞュヌラ weightedRoundRobinScheduler を返したす。どちらのスケゞュヌラも Fetch メ゜ッドを実装しおいるため Scheduler むンタフェヌスを満たしおいたす。 func NewScheduler(weights [] int ) (Scheduler, error ) { e := validateWeights(weights) if e != nil { return nil , e } one := weights[ 0 ] for _, w := range weights[ 1 :] { if one != w { return newWeightedRoundRobinScheduler(weights), nil } } return newRoundRobinScheduler( len (weights)), nil } どちらのスケゞュヌラになるか どちらのスケゞュヌラになるかは、蚭定ファむル target_groups.yml あるいは routes.yml の weight の蚭定次第です。均等に weight の倀が蚭定されおいるか weight が蚭定されおいなければ䞀般的なラりンドロビンです。それ以倖は重み付きラりンドロビンです。 䞋蚘は target_groups.yml の䞀般的なラりンドロビンの䟋です。 weight が蚭定されおいたせん。 TargetGroupA : targets : - host : target1.example.com port : 8080 - host : target2.example.com port : 8081 䞋蚘は target_groups.yml の重み付きラりンドロビンの䟋です。異なる weight の倀が蚭定されおいたす。 TargetGroupA : targets : - host : target1.example.com port : 8080 weight : 2 - host : target2.example.com port : 8081 weight : 1 重みのバリデヌション 重みに負の倀が蚭定されおいないか、䞀郚の察象にしか重みが蚭定されおいないかをバリデヌションしたす。 func validateWeights(weights [] int ) error { nonweightedCount := 0 for _, weight := range weights { if weight < 0 { return errors.New( "invalid weight" ) } if weight == 0 { nonweightedCount++ } } if nonweightedCount != 0 && nonweightedCount != len (weights) { return errors.New( "mixed weighted and nonweighted targets" ) } return nil } 䞋蚘は target_groups.yml で weight に負の倀が蚭定されおいるNG䟋です。 TargetGroupA : targets : - host : target1.example.com port : 8080 weight : -10 - host : target2.example.com port : 8081 weight : -1 䞋蚘は routes.yml で weight プロパティが蚭定されおいるものず、されおいないものが混圚しおいるNG䟋です。 - from : path : ^/sample/(.+)$ to : destinations : - target_group : TargetGroupA path : /$1 weight : 2 - target_group : TargetGroupB path : /$1 䞀般的なラりンドロビンのスケゞュヌラ 䞀般的なラりンドロビンのスケゞュヌラ実装に぀いお説明したす。 構造䜓 roundRobinScheduler 構造䜓は以䞋の倉数を持ちたす。 mutex 耇数のリク゚ストを排他制埡する current 珟圚のむンデックス 初期倀は0぀たりリストの先頭 count ラりンドロビン察象の総数 newRoundRobinScheduler 関数の匕数で枡される type roundRobinScheduler struct { mutex *sync.Mutex current int count int } newRoundRobinScheduler 関数は NewScheduler 関数から呌び出されたす。初期化しお roundRobinScheduler のポむンタ型の倉数を返したす。 func newRoundRobinScheduler(count int ) *roundRobinScheduler { return &roundRobinScheduler{mutex: &sync.Mutex{}, current: 0 , count: count} } Fetchメ゜ッド roundRobinScheduler 構造䜓の Fetch メ゜ッドの凊理内容は以䞋の通りです。 排他制埡ロックをかける 次の呌び出しに備えおむンデックス current をむンクリメントしおおく リスト䞊に蚘茉された次の察象を返すようにする もしリスト䞊で最埌の堎合は、最初のタヌゲットを返す 珟圚のむンデックスを返す func (s *roundRobinScheduler) Fetch() int { s.mutex.Lock() defer s.mutex.Unlock() i := s.current s.current = (i + 1 ) % s.count return i } 䟋えば、䞋蚘の target_groups.yml があった堎合に3回 Fetch メ゜ッドを実行するずきの挙動を芋おみたす。 TargetGroupA : targets : - host : target1.example.com port : 8080 - host : target2.example.com port : 8081 たず、 roundRobinScheduler 構造䜓の以䞋のフィヌルドは倀が決定したす。 count: 2 各実行回数ずその時の最終的な倀は以䞋の通りです。次回は前回の倉数の倀を匕き継ぎたす。 1回目 Fetch()の戻り倀: 0target1.example.comが遞択される current: 1 2回目 Fetch()の戻り倀: 1target2.example.comが遞択される current: 0 3回目 Fetch()の戻り倀: 0target1.example.comが遞択される current: 1 重み付きラりンドロビンのスケゞュヌラ 重み付きラりンドロビンのスケゞュヌラ実装に぀いお説明したす。 構造䜓 weightedRoundRobinScheduler 構造䜓は以䞋の倉数を持ちたす。 mutex 耇数のリク゚ストを排他制埡する weights 察象党おの重み newWeightedRoundRobinScheduler 関数の匕数で枡される maxWeight weights の䞭で最倧の重み newWeightedRoundRobinScheduler 関数で決定される currentIndex 珟圚のむンデックス Fetch メ゜ッドで返される倀 初期倀は -1 currentWeight むンデックスを返す際の基準ずなる重み currentWeight よりも重い weight を持぀ currentIndex を Fetch メ゜ッドで返す 初期倀は0 type weightedRoundRobinScheduler struct { mutex *sync.Mutex weights [] int maxWeight int currentIndex int currentWeight int } newWeightedRoundRobinScheduler 関数は NewScheduler 関数から呌び出されたす。 normalizeWeights 関数を実行しお weightedRoundRobinScheduler のポむンタ型の倉数を返したす。凊理䞭に、匕数で枡された重み weights を normalizeWeights 関数で玄分したす。 func newWeightedRoundRobinScheduler(weights [] int ) *weightedRoundRobinScheduler { normalizedWeights := normalizeWeights(weights) max := 0 for _, w := range normalizedWeights { if w > max { max = w } } return &weightedRoundRobinScheduler{weights: normalizedWeights, maxWeight: max, currentIndex: - 1 , currentWeight: 0 , mutex: &sync.Mutex{}} } 重みの玄分 normalizeWeights 関数は gcd 関数により求めた最倧公玄数で weights の芁玠を党お玄分した結果を返したす。玄分する理由は、 Fetch メ゜ッド内で無駄なforルヌプを無くすためです。 func normalizeWeights(weights [] int ) [] int { g := weights[ 0 ] for _, w := range weights[ 1 :] { g = gcd(g, w) } normalizedWeights := [] int {} for _, w := range weights { normalizedWeights = append (normalizedWeights, w/g) } return normalizedWeights } gcd 関数は暙準パッケヌゞの math/bigのGCD を利甚しお ナヌクリッドの互陀法 により、最倧公玄数greatest common divisorを返したす。 func gcd(m, n int ) int { x := new (big.Int) y := new (big.Int) z := new (big.Int) a := new (big.Int).SetUint64( uint64 (m)) b := new (big.Int).SetUint64( uint64 (n)) result := z.GCD(x, y, a, b) return int (result.Int64()) } Fetchメ゜ッド はじめに、むメヌゞを掎んでいただくために Fetch メ゜ッドによる走査凊理の抂芁から説明したす。 䟋えば、 target1に3、target2に5、target3に1 ずいった重み付けがされたケヌスを考えたす。この堎合、以䞋の割り圓お順にはなりたせん。 target1 →target1 →target1 →target2 →target2 →target2 →target2 →target3 䞋のような2次元配列のようにしお䞊から順に、巊から走査する圢で割り圓おたす。 weight 5: target2 weight 4: target2 weight 3: target1 target2 weight 2: target1 target2 weight 1: target1 target2 target3 ぀たり、割り圓お順は以䞋になりたす。 target2 →target2 →target1 →target2 →target1 →target2 →target1 →target2 →target3 それでは、実装を芋おいきたす。 weightedRoundRobinScheduler 構造䜓の Fetch メ゜ッドの凊理内容は以䞋の通りです。 排他制埡ロックをかける currentIndex をむンクリメントし、リストの最埌の堎合は先頭に戻る currentIndex がリストの先頭の堎合は、 currentWeight をデクリメントする デクリメントした currentWeight が負の倀であれば currentWeight に maxWeight を代入する currentIndex における weights の倀が currentWeight 以䞊であればその currentIndex を返し、未満であれば2-4のステップを繰り返す func (s *weightedRoundRobinScheduler) Fetch() int { s.mutex.Lock() defer s.mutex.Unlock() for { s.currentIndex = (s.currentIndex + 1 ) % len (s.weights) if s.currentIndex == 0 { s.currentWeight = s.currentWeight - 1 if s.currentWeight <= 0 { s.currentWeight = s.maxWeight } } if s.weights[s.currentIndex] >= s.currentWeight { return s.currentIndex } } } 䟋えば、䞋蚘の target_groups.yml があった堎合に3回 Fetch メ゜ッドを実行するずきの挙動を芋おみたす。 TargetGroupA : targets : - host : target1.example.com port : 8080 weight : 1 - host : target2.example.com port : 8081 weight : 2 たず、 weightedRoundRobinScheduler 構造䜓の以䞋のフィヌルドは倀が決定したす。 maxWeight: 2 weights: [1, 2] 各実行回数ずその時の最終的な倀は以䞋の通りです。次回は前回の倉数の倀を匕き継ぎたす。 1回目 Fetch()の戻り倀: 1target2.example.comが遞択される currentIndex: 1 currentWeight: 2 2回目 Fetch()の戻り倀: 0target1.example.comが遞択される currentIndex: 0 currentWeight: 1 3回目 Fetch()の戻り倀: 1target2.example.comが遞択される currentIndex: 1 currentWeight: 1 Fetchメ゜ッドの呌び出し 䞊蚘で説明した Fetch メ゜ッドの呌び出し偎に぀いお説明したす。タヌゲットずタヌゲットグルヌプのいずれのスケゞュヌリングにも䜿甚できたす。 タヌゲットのスケゞュヌリング 䞋蚘のように target_groups.yml の targets 配䞋には耇数のタヌゲットを指定可胜です。 TargetGroupA : targets : - host : target1.example.com port : 8080 weight : 1 - host : target2.example.com port : 8081 weight : 2 TargetGroup 構造䜓は Scheduler むンタフェヌス型の倉数 scheduler をフィヌルドずしお持っおいたす。したがっお、 TargetGroup 構造䜓のポむンタ型をレシヌバに持぀ ScheduledTargets メ゜ッド内で Fetch メ゜ッドを呌び出せたす。 ScheduledTargets メ゜ッドは、耇数の䞭から1぀のタヌゲットを決定するために Fetch メ゜ッドを呌び出したす。 Fetch メ゜ッドにより取埗したむンデックスで最初のタヌゲットを決定したす。 type Target struct { Host string Port int Timeout timeout } type TargetGroup struct { // ... scheduler scheduler.Scheduler targets []*Target } func (targetGroup *TargetGroup) ScheduledTargets(length int ) []Target { targetIndex := targetGroup.scheduler.Fetch() roundRobinTargets := []Target{} target := targetGroup.targets[targetIndex] // ... return roundRobinTargets } タヌゲットグルヌプのスケゞュヌリング 䞋蚘のように routes.yml の destinations 配䞋には耇数のタヌゲットグルヌプを指定可胜です。 - from : path : ^/sample/(.+)$ to : destinations : - target_group : TargetGroupA path : /$1 - target_group : TargetGroupB path : /$1 routeTo 構造䜓は Scheduler むンタフェヌス型の倉数 scheduler をフィヌルドずしお持っおいたす。したがっお、 routeTo 構造䜓のポむンタ型をレシヌバに持぀ scheduledDestination メ゜ッド内で Fetch メ゜ッドを呌び出せたす。耇数の䞭から1぀のタヌゲットグルヌプを決定するために Fetch メ゜ッドを䜿甚したす。 Fetch メ゜ッドにより取埗したむンデックスでタヌゲットグルヌプを遞定したす。 type routeTo struct { destinations []destination scheduler scheduler.Scheduler } type destination struct { targetGroup *targetgroup.TargetGroup path string } func (routeTo *routeTo) scheduledDestination() destination { destinationIndex := routeTo.scheduler.Fetch() return routeTo.destinations[destinationIndex] } リトラむ機胜 ここでは前回の蚘事では觊れなかったリトラむ機胜の䞀郚仕様を玹介したす。 前回蚘事のおさらい 前提知識ずしお必芁なものを簡単に説明したす。 リトラむ機胜は、リク゚スト倱敗時にAPI Gatewayずマむクロサヌビス間でリトラむする機胜です。どのようなシステムであっおも、なんらかの原因でリク゚ストが倱敗する可胜性はありたす。 䟋えば、転送先マむクロサヌビスの䞀時的な゚ラヌ、通信問題、タむムアりトなどです。その倱敗をAPIクラむアントぞそのたた返さずに、API Gatewayずマむクロサヌビス間でリトラむしたす。リトラむによりリク゚ストが成功すれば、゚ンドナヌザぞ゚ラヌを返さずにすむため成功リク゚スト数が増えるこずになり、可甚性を高められたす。 以䞋のように、リトラむ回数やリトラむ条件、リトラむ先タヌゲット、リトラむ前のスリヌプを target_groups.yml から蚭定可胜です。 TargetGroupAB : targets : - host : target-a-1.example.com port : 8080 retry_to : target-b-2.example.com - host : target-a-2.example.com port : 8080 retry_to : target-b-1.example.com - host : target-b-1.example.com port : 8080 retry_to : target-a-2.example.com - host : target-b-2.example.com port : 8080 retry_to : target-a-1.example.com max_try_count : 3 retry_cases : [ "server_error" , "timeout" ] retry_non_idempotent : true retry_base_interval : 50 retry_max_interval : 500 タヌゲットグルヌプを跚いだリトラむ デフォルトでは、リトラむ先のタヌゲットは同䞀タヌゲットグルヌプに属するもので限定されるため、タヌゲットグルヌプを跚ぎたせん。しかしながら、タヌゲットグルヌプを跚いだリトラむでメリットが生たれるケヌスもありたす。 䟋えば、TargetGroupAを新系、TargetGroupBを旧系のタヌゲットグルヌプずしたす。TargetGroupAのTarget1で倉曎郚分のバグによりリク゚ストが倱敗した堎合に、同じタヌゲットグルヌプのTarget2ぞリトラむしおも同じ倱敗になりたす。しかしながら、そのバグを含たないTargetGroupBのTarget3ぞリトラむすれば゚ンドナヌザぞの圱響を最小限に抑えられたす。゚ンドナヌザぞの若干のレスポンス速床の䜎䞋は発生したすが、゚ラヌが返らずに枈みたす。たた、マむクロサヌビスがタヌゲットグルヌプ間で異なる堎合は、䞋図のようにパスも異なる可胜性がありたす。 蚭定方法 target_groups.yml の retry_to_target_group_id プロパティにタヌゲットグルヌプIDを指定したす。リトラむ時は指定したタヌゲットグルヌプのタヌゲットぞのリトラむになりたす。 䞋蚘は TargetGroupA の retry_to_target_group_id で TargetGroupB を指定しおいる䟋です。 TargetGroupA : targets : - host : target1.example.com port : 8080 retry_to_target_group_id : TargetGroupB TargetGroupB : targets : - host : target2.example.com port : 8081 リバヌスプロキシずリク゚スト情報の準備 HTTPリク゚ストをマむクロサヌビスぞ転送する䞊で、リトラむ情報を含めたリク゚スト準備が必芁です。ここでは、リク゚スト情報を準備する䞊でどのように転送先のタヌゲット情報やリトラむ情報を䜜成しおいるかの実装面を玹介したす。 ServeHTTP メ゜ッドは Route メ゜ッドず transferRequest メ゜ッドを実行したす。 http.Handler のむンタフェヌスのメ゜ッドでもありたす。 func (reverseProxy ReverseProxy) ServeHTTP(w http.ResponseWriter, r *http.Request) { // ... func () { // ... fetchedTargetGroup, routedPathMap, e := reverseProxy.router.Route(client, ip, r) // ... response, body, tryURLs, e = reverseProxy.transferRequest(r, fetchedTargetGroup, routedPathMap, traceID, client) // ... } } Route メ゜ッドは fetchedTargetGroup ず routedPathMap を返したす。 fetchedTargetGroup は、内郚の Fetch メ゜ッドにより取埗した最初の転送先タヌゲットグルヌプです。 routedPathMap はマッチしたルヌティングに含たれる党おのタヌゲットグルヌプずAPIパスの組み合わせを持぀マップです。 func (router Router) Route(c client.Client, ip net.IP, req *http.Request) (fetchedTargetGroup *targetgroup.TargetGroup, routedPathMap map [*targetgroup.TargetGroup] string , e error ) { routedPathMap = map [*targetgroup.TargetGroup] string {} for _, route := range router.routes { // ... fetchedTargetGroup = route.to.scheduledDestination().targetGroup for _, d := range route.to.destinations { routedPathMap[d.targetGroup] = route.from.path.ReplaceAllString(req.URL.Path, d.path) } return } // ... return } func (routeTo *routeTo) scheduledDestination() destination { destinationIndex := routeTo.scheduler.Fetch() return routeTo.destinations[destinationIndex] } transferRequest メ゜ッドはHTTPリク゚ストの転送凊理をしたす。 Route メ゜ッドの戻り倀の fetchedTargetGroup ず routedPathMap を匕数に枡したす。 func (reverseProxy ReverseProxy) transferRequest(r *http.Request, fetchedTargetGroup *targetgroup.TargetGroup, routedPathMap map [*targetgroup.TargetGroup] string , traceID string , client client.Client) (response *http.Response, body [] byte , tryURLs [] string , e error ) { // ... } transferRequest メ゜ッド内では target_groups.yml に retry_to_target_group_id が指定されおいるかどうかで異なるリク゚スト情報を䜜成したす。 最倧の詊行回数 maxTryCount だけ、 targets 倉数に以䞋のケヌスに基づいたタヌゲット情報を栌玍したす。 retry_to_target_group_id が指定されおいない堎合 fetchedTargetGroup の ScheduledTargets の戻り倀 retry_to_target_group_id が指定されおいる堎合 最初のタヌゲットは fetchedTargetGroup の ScheduledTargets の戻り倀の1぀目の芁玠 それ以降のタヌゲットはリトラむ先のタヌゲットグルヌプの ScheduledTargets の戻り倀芁玠数は1぀枛らす maxTryCount := fetchedTargetGroup.MaxTryCount() if !fetchedTargetGroup.RetryNonIdempotent() && (r.Method == http.MethodPost || r.Method == http.MethodPatch) { maxTryCount = 1 } var targets []targetgroup.Target if fetchedTargetGroup.RetryToTargetGroup() == nil { targets = fetchedTargetGroup.ScheduledTargets(maxTryCount) } else { firstTarget := fetchedTargetGroup.ScheduledTargets( 1 )[ 0 ] targets = append (targets, firstTarget) scheduledTargets := fetchedTargetGroup.RetryToTargetGroup().ScheduledTargets(maxTryCount - 1 ) targets = append (targets, scheduledTargets...) } ScheduledTargets メ゜ッドのリトラむ察象の決定に関する凊理を補足したす。 Fetch メ゜ッドで先頭のタヌゲットIDを決定した埌に、for文内では決定したタヌゲット情報をkeyに retryTargetMap フィヌルドからリトラむ先情報を取埗したす。 retryTargetMap は、keyがタヌゲットIDでvalueにそのタヌゲットIDぞのリク゚ストが倱敗した堎合の次の転送先のタヌゲットIDを持ちたす。リトラむ先のタヌゲットはラりンドロビンでなく target_groups.yml の retry_to に蚭定されたタヌゲットあるいは次のむンデックスのタヌゲットを䜿甚したす。このようにしお、匕数のリトラむ䞊限回数 length の数だけfor文でタヌゲット情報の集合 roundRobinTargets を生成しお返したす。 type TargetGroup struct { // ... retryTargetMap map [*Target]*Target } func (targetGroup *TargetGroup) ScheduledTargets(length int ) []Target { targetIndex := targetGroup.scheduler.Fetch() roundRobinTargets := []Target{} target := targetGroup.targets[targetIndex] for len (roundRobinTargets) < length { roundRobinTargets = append (roundRobinTargets, *target) target = targetGroup.retryTargetMap[target] } return roundRobinTargets } 䜜成した targets の数、぀たり最倧の詊行回数だけ以䞋の情報を䜜成したす。 url.Path 倉数に以䞋のケヌスに基づいたパス情報を栌玍したす。 retry_to_target_group_id が指定されおいない堎合 fetchedTargetGroup をkeyに routedPathMap から取埗したもの retry_to_target_group_id が指定されおいる堎合 リトラむ先のタヌゲットグルヌプをkeyに routedPathMap から取埗したもの retryInfo 倉数に以䞋のケヌスに基づいたリトラむ情報を栌玍したす。 retry_to_target_group_id が指定されおいない堎合 fetchedTargetGroup のリトラむ情報 retry_to_target_group_id が指定されおいる堎合 リトラむ先のタヌゲットグルヌプのリトラむ情報 targetURLs := [] string {} // ... type retryInfo struct { cases []targetgroup.RetryCase baseInterval int maxInterval int } retryInfos := []retryInfo{} for i, target := range targets { url := *r.URL url.Scheme = "http" url.Host = fmt.Sprintf( "%v:%v" , target.Host, target.Port) var r retryInfo retryToTargetGroup := fetchedTargetGroup.RetryToTargetGroup() if i == 0 || retryToTargetGroup == nil { url.Path = routedPathMap[fetchedTargetGroup] r = retryInfo{ cases: fetchedTargetGroup.RetryCases(), baseInterval: fetchedTargetGroup.RetryBaseInterval(), maxInterval: fetchedTargetGroup.RetryMaxInterval(), } } else { url.Path = routedPathMap[retryToTargetGroup] r = retryInfo{ cases: retryToTargetGroup.RetryCases(), baseInterval: retryToTargetGroup.RetryBaseInterval(), maxInterval: retryToTargetGroup.RetryMaxInterval(), } } targetURLs = append (targetURLs, url.String()) // ... retryInfos = append (retryInfos, r) } マむクロサヌビスぞのリク゚スト 䞊述の通り、リトラむ情報含めたリク゚ストに必芁な情報を準備したした。埌続の凊理では transferRequestToHTTP 関数でマむクロサヌビスにHTTPリク゚ストしたす。こちらの関数内凊理の詳现は本リトラむの話から逞れたすので割愛したす。 for i, targetURL := range targetURLs { response, body, e = transferRequestToHTTP(r, requestBody, targetURL, httpClients[i], traceID, client) // ... } タむムアりト機胜 ここでは前回の蚘事では觊れなかったタむムアりト機胜の䞀郚仕様を玹介したす。 前回蚘事のおさらい 前提知識ずしお必芁なものを簡単に説明したす。 タむムアりトずは、その名の通り、䞀定の期間が経過したリク゚ストを打ち切るこずです。実行が長匕いおいるリク゚ストをタむムアりトさせお、埌ろに詰たっおいるリク゚ストを正垞に凊理するこずで党䜓ずしおリク゚スト成功数が増え、可甚性を高められたす。 API GatewayにはリバヌスプロキシするHTTPリク゚ストのタむムアりト蚭定が可胜です。 蚭定項目は以䞋の通りです。 connect_timeout 1リク゚ストあたりのTCPコネクション確立たでの間のタむムアりト倀ミリ秒単䜍 read_timeout 1リク゚ストあたりのリク゚スト開始からレスポンスボディを読み蟌み終わるたでの間のタむムアりト倀ミリ秒単䜍 タヌゲットずタヌゲットグルヌプのタむムアりト タヌゲットずタヌゲットグルヌプの䞡方にタむムアりト蚭定が可胜です。 䟋えば、マむクロサヌビス化した新しいタヌゲットはレスポンスが速いのでそちらだけタむムアりトを小さくしたいずいったケヌスです。該圓のタヌゲットにタむムアりト蚭定し぀぀他のタヌゲットにはタヌゲットグルヌプのタむムアりト蚭定をデフォルトずしお適甚させるこずが可胜です。 蚭定 以䞋の target_groups.yml の通り、䞡方で connect_timeout ず read_timeout の蚭定が可胜です。 TargetGroupA : targets : - host : target1.example.com port : 8080 connect_timeout : 10 read_timeout : 5000 connect_timeout : 50 read_timeout : 3000 実装 TargetGroupConfig は target_groups.yml に察応する構造䜓です。タむムアりト関連のフィヌルドも持ちたす。 type TargetGroupConfig struct { Targets [] struct { // ... ConnectTimeout int `yaml:"connect_timeout"` ReadTimeout int `yaml:"read_timeout"` // ... } `yaml:"targets"` ConnectTimeout int `yaml:"connect_timeout"` ReadTimeout int `yaml:"read_timeout"` // ... } newTargetGroup 関数は TargetGroup 型の倉数を返したす。その凊理過皋でタヌゲットグルヌプずタヌゲットのタむムアりト蚭定を読み蟌みたす。タヌゲットのタむムアりト蚭定に関しおは、 タヌゲットの蚭定タヌゲットグルヌプの蚭定ハヌドコヌディングによるデフォルト蚭定 の順で優先付けされおいたす。 const defaultConnectTimeout = 1000 const defaultReadTimeout = 10000 const defaultRetryBaseInterval = 50 // ... func newTargetGroup(targetGroupConfig TargetGroupConfig) (TargetGroup, error ) { targets := []*Target{} // タヌゲットグルヌプにタむムアりト蚭定があればそれを䜿う。なければハヌドコヌディングのデフォルト倀ずする。 if targetGroupConfig.Timeout < 0 || targetGroupConfig.ReadTimeout < 0 || targetGroupConfig.ConnectTimeout < 0 { return TargetGroup{}, errors.New( "invalid timeout" ) } targetGroupConnectTimeout := defaultConnectTimeout if targetGroupConfig.ConnectTimeout != 0 { targetGroupConnectTimeout = targetGroupConfig.ConnectTimeout } targetGroupReadTimeout := defaultReadTimeout if targetGroupConfig.ReadTimeout != 0 { targetGroupReadTimeout = targetGroupConfig.ReadTimeout } else if targetGroupConfig.Timeout != 0 { targetGroupReadTimeout = targetGroupConfig.Timeout } // ... // タヌゲットのタむムアりト蚭定があればそれを䜿う。なければタヌゲットグルヌプの倀ずする。 for i, t := range targetGroupConfig.Targets { targetConnectTimeout := targetGroupConnectTimeout targetReadTimeout := targetGroupReadTimeout if t.ConnectTimeout != 0 { targetConnectTimeout = t.ConnectTimeout } if t.ReadTimeout != 0 { targetReadTimeout = t.ReadTimeout } target := Target{ // ... Timeout: timeout{ Connect: targetConnectTimeout, Read: targetReadTimeout, }, } // ... } // ... } Target 構造䜓のタむムアりト倀は、 http.Client の Timeout に Connect の倀、 net.Dialer の Timeout に Read の倀を䜿甚したす。 http.Client{ Transport: &http.Transport{ DialContext: (&net.Dialer{ Timeout: time.Duration(connectTimeout) * time.Millisecond, // ... }).DialContext, // ... }, // ... Timeout: time.Duration(readTimeout) * time.Millisecond, } 機胜远加の展望 今埌、さらに可甚性を高める以䞋の機胜远加を考えおいたす。 スロットリング クラむアントタむプごずにレヌトリミットで制限するような機胜を想定 䞀郚のクラむアントタむプによる倧量リク゚ストでシステム党䜓が停止するのを避け、可甚性を高める サヌキットブレヌカヌ ある閟倀以䞊の倱敗が続いたら、そのマむクロサヌビスにはリク゚ストを送らずにAPI Gatewayが503゚ラヌを返すような機胜を想定 カスケヌド障害を防ぎ、可甚性を高める We are hiring ZOZOTOWNのマむクロサヌビス化はただ始たったばかりです。今埌は、API GatewayやID基盀の远加開発に加えお、新たなマむクロサヌビスの開発も目癜抌しです。そのための゚ンゞニアが足りおいない状況です。 ご興味のある方は、以䞋のリンクからぜひご応募ください。お埅ちしおおりたす。 hrmos.co
こんにちは。ECプラットフォヌム郚の廣瀬です。 匊瀟ではサヌビスの䞀郚にSQL Serverを䜿甚しおいたす。今回は2020幎床に発生しおいたSQL Serverに関連する障害に぀いお、調査から察策実斜たでの流れを玹介したいず思いたす。これたでも匊瀟テックブログにお、SQL Serverに関するトラブルシュヌティングをいく぀か玹介しおきたした。 techblog.zozo.com techblog.zozo.com techblog.zozo.com これらの蚘事ず今回の蚘事の最倧の盞違点ずしおは、「最埌たで明確な原因の特定はできなかった」ずいう点です。できる限り詳现な調査を実斜したしたが、最埌たで原因の特定には至りたせんでした。そのような状況䞋においお、どのようなフロヌで調査を実斜し、最終的に障害が発生しない状況を䜜るこずができたか玹介したす。 SQL Server以倖のデヌタストアを運甚しおいお障害調査をするこずがある方にも読んでいただけるず幞いです。 障害の抂芁 匊瀟のサヌビスは、様々な芁因でトラフィックが増倧したす。䟋えば、セヌルむベントや犏袋発売むベントなどです。2020幎の䞭頃から、ある機胜を担っおいたDBにおいお秒間のバッチ実行数が䞀定の閟倀を超えるず、アプリケヌション偎でタむムアりト゚ラヌが倚発するようになりたした。尚、 バッチ ずはSQL Serverにおける1぀以䞊のク゚リのかたたりを指したす。 䞊の図では、タむムアりト゚ラヌの倚発開始ず同時に、秒間のバッチ実行数が急激に䞋がりDBサヌバヌのク゚リ凊理性胜が萜ちおいるこずが分かりたす。たた、バッチの総実行時間が急激に増えおいるこずから、1ク゚リあたりの実行時間が倧幅に䌞びおいるこずも分かりたす。 この事象を詳现に調査しおいきたした。調査に甚いた情報は、以䞋の3点です。 パフォヌマンスモニタのSQL Serverに関連するメトリクス 拡匵むベントの「blocked_process_report」 DMV動的管理VIEWの各皮デヌタを1分毎にテヌブルぞ保存しおおいたもの 匊瀟のSQL Server障害調査フロヌ 匊瀟では、SQL Serverに関する障害が発生した際、以䞋のフロヌチャヌトに沿っお調査を進めおいたす。 以降では、このフロヌに沿っお実際に障害を調査した事䟋を玹介したす。 調査内容 1. 䞻芁なメトリクスを確認 パフォヌマンスモニタで取埗したメトリクスのうち、䞻芁なものを確認したした。フロヌチャヌトの①に該圓したす。 CPU䜿甚率はピヌク時で100に近い倀ずなっおいたした。Batch Resp Statisticsを確認するず、CPU䜿甚時間が20msecから100msecのバッチがCPU䜿甚率䞊昇の䞻な芁因ずなっおいたした。その他、目立った倉化のあったグラフを以䞋に列挙したす。 これらのグラフから、以䞋のこずが読み取れたす。 ブロッキングの発生が確認できた SQL Server芳点でも゚ラヌ発生が確認できた 埅ち事象ずしおは非ペヌゞラッチが障害発生の初期にスパむクしおいた バッチ実行数の増加に䌎っおコンパむル数も増加しおいた ワヌクスペヌスメモリを獲埗したク゚リの数が増倧しおいた ワヌカヌスレッド獲埗埅ちが倚く発生しおおり、ワヌカヌスレッドが枯枇しおいた可胜性が高い これらの情報を芋ただけでは、「䜕らかの理由でク゚リが滞留し、最終的にワヌカヌスレッドが枯枇しおタむムアりト゚ラヌ倚発に぀ながった」ずいうこずしか分かりたせん。 ク゚リが滞留した理由ずしおは、以䞋のようなものが考えられたす。 CPU䜿甚率が高隰したこずでSOS_SCHEDULER_YIELD埅ちが倚発 非ペヌゞラッチの競合の発生 アクセスが集䞭する領域に長時間ロックがかかったこずでブロッキングが倚発 このような可胜性に留意し぀぀、゚ラヌが起き始めた倉化点にフォヌカスし、より短い時間軞でメトリクスを確認したした。「゚ラヌが起き始めたタむミングず同タむミングで倉化し始めたメトリクス」が障害に関連しおいる可胜性が高いず考えたからです。 青い線がCPU䜿甚率ですが、Attentionが発生したタむミングではCPU䜿甚率が䜎䞋しおいるためCPU䜿甚率が障害発生の原因ずは考えにくい状況でした。゚ラヌ発生前埌の最初の倉化ずしおは、たずPage Latchの発生が確認でき、次にNon-Page Latch、ブロッキングの順番で発生が確認できたした。この結果から、Page Latch、Non-Page Latch、ブロッキングの発生は、゚ラヌが発生し始めた芁因ず関連性がありそうです。 このような可胜性に留意し぀぀、保存しおおいた拡匵むベントずDMVの情報を埌远いしおいきたした。 2. 拡匵むベントでブロッキング状態を確認 こちら の方法で、「blocked_process_report」むベントをク゚リベヌスで確認したした。フロヌチャヌトの②に該圓したす。 この結果から、以䞋のこずが分かりたした。 最初にブロッキングむベントが発生したのは、障害発生から15秒ほど経過した埌 最初のブロッカヌはbackgroundプロセスであり、自身も「ACCESS_METHODS_HOBT_VIRTUAL_ROOT」ずいう皮類のラッチで埅たされおいた 「ACCESS_METHODS_HOBT_VIRTUAL_ROOT」は ドキュメント によるず、「内郚Bツリヌのルヌトペヌゞの抜象化ぞのアクセスを同期するために䜿甚されたす」ず説明しおありたした。ブロッキングむベントが発生したのは障害発生から15秒ほど経過しおからでしたが、パフォヌマンスモニタ䞊では障害発生前からわずかにブロッキングが発生しおいたした。拡匵むベントのブロッキングむベントは、「〇秒以䞊ブロッキングが続いたら発生」ずいうように䞀定の閟倀を超えたものだけが蚘録されるため、むベントが蚘録されるたでにタむムラグが発生しおいたようです。たた、拡匵むベントに蚘録された最初のブロッカヌがどのような凊理をしおいたかは分からず、原因特定には至りたせんでした。 3. DMVの各皮デヌタを䜿っおドリルダりン フロヌチャヌトの③に該圓したす。 CPUのボトルネックク゚リ調査 こちら の方法でCPUボトルネックずなっおいるク゚リが無いかを調査したした。Batch Resp Statisticsの確認結果から、特にCPU䜿甚時間が20msecから100msecのバッチを重点的に確認したした。しかし、今回はCPU負荷の芳点でチュヌニングできそうなク゚リは芋぀かりたせんでした。 ラッチ こちら のク゚リを䜿っお障害発生䞭の各皮ラッチの埅ち時間を確認したした。 ラッチによる総埅機時間の倧きい順に䞊べた結果、ACCESS_METHODS_ACCESSOR_CACHEが最も倧きく、次いでBUFFER、ACCESS_METHODS_HOBT_VIRTUAL_ROOTずいう順番になりたした。 ACCESS_METHODS_HOBT_VIRTUAL_ROOTに぀いおは、平均の埅機時間が倧きいようです。この埅ちはペヌゞ分割時などに発生するず理解しおおり、特定のテヌブルぞのLast Page Insert倚発が原因の可胜性ずしお挙げられたす。その堎合は、テヌブルのキヌの再蚭蚈などによっお該圓のラッチを枛らせるかもしれないず考えたした。 ACCESS_METHODS_ACCESSOR_CACHEに぀いおは、コンパむルの発生に䌎っお倀が䞊昇する傟向にあるようです。したがっおコンパむル回数の抑制によっお該圓のラッチ埅ち時間を䜎枛できる可胜性があるず考えたした。 埅ち事象 こちら のク゚リを䜿っお、障害発生䞭の埅ち事象に぀いお確認したした。 THREADPOOLは二次的な埅ちのため無芖するずしお、非ペヌゞラッチ、ペヌゞラッチ、ロックなどが埅ち事象ずしお倚くを占めおいたした。 実斜した察応策 時間をかけお調査したしたが、根本的な原因の特定には至りたせんでした。したがっお次善の策ずしお、取埗した情報を䜿っお「障害発生䞭に芳枬できた事象の䞭から、無くしたり枛らすこずのできるものを探す」ずいう芳点で察応策を決めお実斜しおいきたした。 1. 特定のストアドプロシヌゞャのプランガむドの固定化 別の日に同様の障害が発生した際、拡匵むベントの「blocked_process_report」におけるwaitresourceごずのむベント件数を抜出しおみたした。その結果、特定のストアドプロシヌゞャのコンパむル埅ちが原因でブロッキングが発生しおいるこずが分かりたした。 したがっお、これら4぀のストアドプロシヌゞャのプランガむドを固定化するこずにしたした。これは根本的な原因を特定したうえでの察応策ではありたせんが、「もし同様の事象が発生しおも、コンパむル起因でのブロッキングの発生を0にする」ずいう効果が期埅できたす。 2. コンパむルずリコンパむル発生を抑制する斜策 バッチ実行数の䞊昇に䌎っおコンパむル数も䞊昇したこずがパフォヌマンスモニタのメトリクスから確認できおいたした。コンパむルやリコンパむルによっお効率の悪い実行プランが採甚されおしたい、CPU䜿甚率が䞊昇した可胜性も考えられたす。したがっお、コンパむルずリコンパむルの発生回数を抑制する察応を実斜したした。コンパむルずリコンパむルの発生芁因ずしお代衚的なものは、以䞋の2぀です。 関連テヌブルの統蚈情報が曎新された 実行プランがキャッシュアりトされた 1.に぀いおは、統蚈情報の曎新が今回の環境におけるリコンパむルの理由ずしお本圓に正しいのかをたず怜蚌したした。拡匵むベントで「sql_statement_recompile」むベントを取埗するこずで、リコンパむルの理由を確認できたす。 拡匵むベントの䜜成埌、以䞋のようにリコンパむルむベントの発生が確認できたした。 リコンパむルの理由は「recompile_cause」に蚘茉されおおり、図の䞭では「Statistics changed」ずなっおいたす。぀たり、統蚈情報の曎新がリコンパむルの理由だず分かりたす。 リコンパむルの各理由の内蚳を確認するために「recompile_cause」でグルヌプ化しおみるず、䞋図のようにリコンパむルの原因の倧倚数は統蚈情報の曎新であるこずが確認できたした。 したがっお、障害発生時のリコンパむルに぀いおも統蚈情報の自動曎新が起因ずなったものが倧倚数であるはずだず刀断したした。次に、 こちらのク゚リ を䜿っお障害が発生した時間垯で「統蚈情報が1回以䞊曎新されたテヌブル」をリストアップしたした。この情報をもずに、トラフィック増が芋蟌たれる時間垯だけ、リストアップしたテヌブル矀の統蚈情報の自動曎新を䞀時的に無効化するようにしたした。統蚈情報の自動曎新を無効化するには、以䞋のク゚リを実行すればOKです。 UPDATE STATISTICS tablename WITH NORECOMPUTE これによっお、統蚈情報の曎新が起因ずなったリコンパむルの発生を抑止できたす。しかし、自動曎新を垞に無効化しおおくのは、最適な実行プランが生成されなくなる確率を䞊昇させる高リスクな行為です。したがっお、トラフィックが萜ち着いおきたタむミングで自動曎新を再床有効化するようにしたした。自動曎新の有効化は、以䞋のク゚リのように「WITH NORECOMPUTE」無しで統蚈情報を曎新すればOKです。 UPDATE STATISTICS tablename 2.のプランキャッシュアりトに぀いおは、SQL Serverがメモリの利甚状況をコントロヌルしおいるため、こちらで制埡できたせん。ベスト゚フォヌトな察応ずしお、メモリに茉っおいるデヌタキャッシュのうち、容量が倧きいむンデックスを圧瞮するこずでメモリの利甚効率アップを詊みたした。尚、メモリに茉っおいるサむズが倧きいむンデックスを抜出するには こちらのク゚リ を䜿甚したした。 結果 各皮察策を実斜したこずで、障害が発生しなくなりたした。察策実斜前ず埌での各メトリクスの倉化を玹介したす。 同皋床のバッチ実行数の増加でも、ク゚リの滞留が起きなくなったため、察策実斜埌はコネクションの䞊昇が顕著に抑えられるようになりたした。゚ラヌが発生するこずもなくなり、明らかにパフォヌマンスが改善したした。 CPU䜿甚率はピヌク時100近くだったのを、ピヌク時60ほどたで抑えられるようになりたした。 コンパむル数ずリコンパむル数も顕著に発生回数を抑えられるようになりたした。リコンパむルに぀いおは、統蚈情報の自動曎新を䞀時的に無効化したこずが顕著に効いおいたす。コンパむルの発生回数が抑えられた芁因に぀いおは、仮説ずしお「デヌタ圧瞮によりデヌタキャッシュのサむズが枛少し、プランキャッシュが安定したこずでキャッシュアりトしづらくなった」ず考えられたす。 察策実斜前はク゚リの総実行時間が障害時に倧幅に増加しおいたのに察し、察策実斜埌は安定したした。トラフィック増により秒間のバッチ実行数が増えおも、同時実行性が䜎䞋するこずなく、安定しお凊理できおいるこずが分かりたす。 ロック競合の発生状況も倧幅に改善しおおり、察策実斜埌は秒間のバッチ実行数が最倧に達したタむミングでも、ロック競合は確認されたせんでした。 このように、各皮メトリクスに倧幅な改善傟向がみられ、結果ずしおトラフィック増倧時でも障害が発生しない状況を぀くるこずができたした。 たずめ 本蚘事では、2020幎床に発生しおいたSQL Serverに関連する障害に぀いお、調査から察策実斜たでの流れを玹介したした。たずは特異な倉化が起きおいるメトリクスを確認し、原因の仮説を立おながらDMVや拡匵むベントを䜿っおドリルダりンしおいきたした。たた、障害発生の前埌数秒間で起きた倉化を现かく芋おいく調査も実斜したした。いく぀か障害原因の仮説は立おられたものの、特定にたでは至りたせんでした。 こうした根本的な原因が特定できない状況においお、「障害発生䞭に芳枬できた事象の䞭から、無くしたり枛らすこずのできるものを探す」ずいう芳点で察応策を決めお実斜したした。その結果、最終的に障害が発生しない状況を䜜るこずができたした。原因が特定できない障害調査における察応策の実斜に぀いお、今回玹介した考え方が参考になれば幞いです。 最埌に ZOZOテクノロゞヌズでは、䞀緒にサヌビスを䜜り䞊げおくれる方を募集䞭です。ご興味のある方は、以䞋のリンクからぜひご応募ください tech.zozo.com
はじめに こんにちは。BtoB開発チヌムの䞭島です。 Fulfillment by ZOZO 以䞋、FBZで提䟛しおいるAPIシステムの開発・運甚を担圓しおいたす。 FBZの運甚では、゚ラヌログ発生時にアラヌトを通知させ、゚ラヌ内容をチェックしお察応芁吊を刀断しおいたす。しかし、アラヌト通知が倚すぎるず運甚負荷が高くなったり、重芁なアラヌトを芋萜ずすリスクもあるため、適切な量で通知するこずが重芁になっおきたす。 本蚘事では、FBZで実斜した䟋を玹介しながらアラヌト通知の最適化に぀いお解説したす。 FBZにおけるサヌビス監芖 FBZでは、ログ解析によるサヌビス監芖を実斜しおいたす。 AWS Lambda以䞋、Lambdaから出力されたログを解析し、倖郚サヌビスのPagerDutyやDatadogに連携しお監芖しおいたす。必芁に応じおフィルタリングを行い、ログの通知量を郜床調敎しながら運甚をしおいたした。 ログ解析によるサヌビス監芖の詳现は、過去蚘事をご芧ください。 techblog.zozo.com サヌビス監芖の課題 䞊蚘の過去蚘事でも玹介しおいるように、監芖䞍芁なログのフィルタリングを実斜するこずでアラヌトを削枛する効果がありたした。 しかし、FBZサヌビスの機胜远加などに䌎い、再床アラヌトが増えおきたした。デむリヌで数十件皋床アラヌトが通知されるこずも倚く、通知が倚いこずでアラヌトがオオカミ少幎化し始めおいたした。 そのため、フィルタリングだけでは察応が䞍十分ず考え、監芖方法を再怜蚎するこずにしたした。 通知されるアラヌトの珟状分析 監芖方法を再怜蚎するために、たず珟状の分析を実斜したした。 珟状は通知されるアラヌトを運甚担圓者が内容を確認しお、1ä»¶1件察応芁吊を刀断しおいたす。運甚を担圓するメンバヌから、日々運甚をしおいる䞭で以䞋のLambdaのアラヌトが倚く、ノむズになっおいる可胜性が高いずいう意芋が出おきたした。 バッチ凊理内でFBZ倖ず連携しおいるLambda以䞋、倖郚連携バッチ リトラむで回埩しおいるこずが倚い FBZのデヌタを参照するAPIのLambda以䞋、参照系API 䞀時的なタむムアりトが倚い ただし、あくたでも感芚的なものでしかなく、定量的なものではありたせん。仮説が間違っおいる堎合、察策を実斜しおも改善に぀ながらないため、アラヌトの発生状況を定量的にデヌタ分析するこずにしたした。 アラヌト分析の芳点 アラヌトを分析する芳点を明確にしたす。今回は、「アラヌト発生件数」ではなく「アラヌト発生日数」を指暙ずしたした。 アラヌト発生件数を芳点ずしお考えおしたうず、他のアラヌトよりも倧量に発生したアラヌトが1日だけある堎合、その察策をしようずしおしたいたす。しかし、それだけを察策しおも運甚改善に繋がりたせん。 定垞的に発生するようなアラヌトに着県するためにも、耇数日にたたがっお発生しおいるアラヌトの察策をするこずで、運甚改善に぀ながるず考えたした。 高頻床でアラヌトが発生しおいたLambda アラヌト発生日数でFBZ内のLambdaを調査したした。過去100日皋床の期間で調査し、週1回以䞊の頻床でアラヌト発生しおいるものを高頻床ず定矩しお抜出したずころ、以䞋のような結果になりたした。 予想通り、「倖郚連携バッチ」ず「参照系API」のアラヌトが倚く、党䜓の半数以䞊を占めおいるこずがわかりたした。仮説が怜蚌できたので、実際にこれらのアラヌト察策を実斜したした。 倖郚連携バッチのアラヌト察策 たず、倖郚連携バッチで実斜した具䜓的なアラヌト察策に぀いお説明したす。 倖郚連携バッチの゚ラヌ内蚳を調査したずころ、99.5がリトラむで成功しおいるこずがわかりたした。 FBZのバッチ凊理はLambdaの非同期凊理で実行しおいたす。Lambdaは非同期で動䜜する堎合、゚ラヌ発生時は自動的に3回リトラむする仕様になっおいたす。 ゚ラヌ発生時のほずんどのケヌスは、このリトラむが成功しおおり、自動回埩しおいたした。そのため、リトラむでも自動回埩しおいないケヌスに絞っお監芖をするこずで、アラヌトの最適化が可胜だず考えたした。 具䜓的には、 Lambda Destinations非同期呌び出しの宛先指定 を䜿った監芖に倉曎したした。゚ラヌログの監芖ではリトラむで成功しおいるものも怜知しおしたいたすが、Lambda Destinationsを䜿うこずでリトラむをしおも成功しなかったものだけを通知できたす。そのため、倖郚連携バッチの監芖は、゚ラヌログの監芖をやめ、Lambda Destinationsの通知の監芖に切り替えたした。 FBZでは Serverless Framework を䜿っおいるため、 Serverless.yml に以䞋のような蚭定を加えるこずでLambda Destinationsを蚭定できたす。 functions : helloStarting : handler : handler.starting destinations : onFailure : arn:of:some:existing:resource onFailureにアラヌト通知甚のLambdaを蚭定するこずにより、リトラむでも成功しなかったもののみアラヌト通知する仕組みを実珟しおいたす。 参照系APIのアラヌト察策 次に、参照系APIでのアラヌト察策に぀いお説明したす。 参照系APIで発生しおいるアラヌトの詳现を調査したずころ、99.1がネットワヌク起因の䞀時的な゚ラヌでした。 参照系のAPIずいうこずもあり、䞀時的に発生しおいる点ず再実行で取埗可胜ずなる点から1ä»¶1件の監芖は䞍芁であるず刀断したした。たた、実際の運甚時に゚ラヌを怜知した際にも、䞀時的な゚ラヌの堎合は察応䞍芁ず扱っおいたこずが倚い点も監芖䞍芁ずした理由です。 1ä»¶1件は監芖䞍芁ですが、短時間に頻発した堎合は障害の可胜性がありたす。そのため、頻床ベヌスでの監芖をするこずで、監芖の最適化が可胜だず考えたした。 頻床ベヌスの監芖は、 Datadog を利甚したした。Datadogを利甚するこずにした理由は以䞋の点です。 既にサヌビス監芖のためにDatadogを利甚しおいた点 API Gatewayのメトリクスで頻床ベヌスの監芖ができる点 FBZ偎に新芏の䜜り蟌みが䞍芁な点 既にサヌビス監芖のためにDatadogを利甚しおいたした。しかし、ログ調査での利甚がメむンであり、監芖での利甚はほずんどしおいたせんでした。 今回、頻床ベヌスで監芖したいず考えた際に、Datadogのモニタヌ機胜でアラヌトのしきい倀蚭定を、固定倀だけではなく過去デヌタから自動蚭定できるため、Datadogを利甚したした。モニタヌ蚭定の詳现などは Datadogのマニュアル をご確認ください。 AWSずDatadogのむンテグレヌションを事前に蚭定しおおく必芁はありたすが、FBZ偎での新芏開発なしで、頻床ベヌスの監芖が実珟できたした。 アラヌト最適化の効果 今回、アラヌトの最適化ずしお、以䞋の察策を実斜したした。 倖郚連携バッチはLambda Destinationsでアラヌト通知したものを監芖 参照系APIはDatadogで゚ラヌ頻床ベヌスでのアラヌト通知したものを監芖 これらの察策を実斜したこずで、アラヌトの発生数が、1日数十件から数件皋床に抑えられたした。昚幎にはアラヌトが0件ずいう日もあり、アラヌトの発生頻床が䞋がったこずで運甚工数を月あたり玄15時間削枛できたした。 たずめ アラヌトがオオカミ少幎化するず、アラヌト察応が疎かになりサヌビスの安定的な運甚ができなくなりたす。それを防ぐために、アラヌトの通知は必芁最小限に抑える必芁がありたすが、単玔な゚ラヌログの監芖では通知を枛らすのにも限界がありたす。 今回はFBZで実斜した監芖手法ずしお、Lambda Destinationsを利甚した非同期実行Lambdaの監芖ず、Datadogを利甚した頻床ベヌスでの監芖を玹介したした。この察応によっお、アラヌトを最適な量で通知できるようになりたした。 今埌は、分散トレヌシングのために、Datadog APMの導入などを怜蚎しおいたす。 さいごに ZOZOテクノロゞヌズでは、䞀緒にサヌビスを䜜り䞊げおくれる方を募集䞭です。ご興味のある方は、以䞋のリンクからぜひご応募ください tech.zozo.com
こんにちは。ECプラットフォヌム郚マむグレヌションチヌムの半柀です。 この蚘事では、Java + Spring Bootを䜿甚したアプリケヌション䜜成時にモブプログラミングを掻甚した事䟋をご玹介したす。モブプログラミング未経隓の方や、これから実斜を考えおいる方の参考になれば幞いです。 目次 目次 はじめに モブプログラミングずは プロゞェクトの抂芁 アヌキテクチャ蚭蚈 基盀構築モブプログラミングの実斜 時間の確保 ゚ディタの蚭定 カメラずマむクはON タむピストずモブ タむピスト亀代時の工倫 解決できない問題が発生した堎合の察凊法 API実装 モブプログラミングによる効果 技術力の底䞊げ 終わりのない議論がなくなる 䞀䜓感の醞成 安心しお䌑める環境の構築 反省点 タむピストの順番倉曎 タむマヌの導入 時間の確保 たずめ 最埌に はじめに ZOZOTOWNのシステムにはレガシヌな郚分が倚く存圚しおおり、党䜓的なシステムリプレむスを進めおいたす。その䞭でサヌバヌアプリケヌションのリプレむスを行うために発足したのがマむグレヌションチヌムです。 珟圚はキャッシュストアのリプレむスや、新芏マむクロサヌビスの立ち䞊げ、立ち䞊げたサヌビスのJava未経隓チヌムぞの匕き継ぎなどを行っおいたす。 マむグレヌションチヌムでは、プロゞェクトごずに担圓者をアサむンするリ゜ヌス効率を重芖した働き方がこれたで䞻流でした。リ゜ヌス効率を重芖するず、メンバヌはそれぞれ特定の業務のスキルに特化した゚キスパヌトずなりたす。ある特定の業務の仕事量が増えた堎合、その数少ない゚キスパヌトだけでは仕事をこなせなくなり、遅れが生じ党䜓のボトルネックずなっおしたいたす。 チヌムずしおは、チヌムワヌクや思いやりを倧切にし、お互い高め合うような働き方をチヌムの目暙ずしお掲げおいたす。しかし、実際は業務知識が各個人で分散しおいるため協力しにくく、プロゞェクトの芏暡によっおは特定のメンバヌのみ残業が発生するずいう課題を抱えおいたした。 そんな䞭、この問題を䞀気に解決したのがモブプログラミングです。 モブプログラミングずは モブプログラミングは、リ゜ヌス効率ではなくフロヌ効率を高めお早く機胜をリリヌスするこずを目暙ずしおいたす。フロヌ効率を高めるこずで、メンバヌ党員が業務知識を持ち、特定のメンバヌぞの䟝存床を䞋げるこずができたす。その結果、負荷の分散だけでなく、特定のメンバヌが突然皌働できなくなっおも開発の継続が可胜です。 これが実珟できれば、䞊蚘のようなチヌムが抱えおいる課題を解決しおくれそうです。 モブプログラミングの手法は、ペアプログラミングから発展したもので、3人以䞊の人々が1台のコンピュヌタの前に座っお協力しながら問題を解決しおいきたす。 モブプログラミングは「タむピスト」ず「モブ」の圹割がありたす。ひずりがタむピストずしおモブの指瀺を理解しタむピングを行い、その他はモブずしおタむピストぞ指瀺を出したす。タむピストは定められた時間がきたら次の人ぞ亀代したす。 詳现は、 モブプログラミング・ベストプラクティス がずおも参考になるのでご興味のある方はぜひご䞀読ください。 このようなメリットから、今回のプロゞェクトでは実隓的にモブプログラミングを実斜するこずになりたした。 プロゞェクトの抂芁 私たちのチヌムでは、䞻にJava + Spring Bootを䜿甚したアプリケヌションを開発しおいたす。今回のような新芏マむクロサヌビス立ち䞊げ時は、既存のアプリケヌションで䜿甚しおいる基盀を元に䜜成しおいたした。 しかし、その参考元ずなる基盀も構築から既に3幎経過しおおり、改善の䜙地が出おきたため、この機䌚にアヌキテクチャやツヌル・ラむブラリの芋盎しを行うこずになりたした。 開発メンバヌは私を含め4名です。たた、初回䜜成するAPIは同じような凊理を行うGET、POST、PUTの゚ンドポむント蚈11本です。 開発は䞋蚘の流れに沿っお進み、モブプログラミングは基盀構築のフェヌズで実斜したした。 アヌキテクチャ蚭蚈 基盀構築モブプログラミングの実斜 API実装 順を远っお説明したす。 アヌキテクチャ蚭蚈 既存サヌビスの基盀 はレむダヌドアヌキテクチャを採甚しおいたした。詳现は以䞋の蚘事をご芧ください。 techblog.zozo.com しかし、今回の新しい蚭蚈ではDDD + オニオンアヌキテクチャを採甚したした。オニオンアヌキテクチャを遞択した理由は、むンフラストラクチャ局がドメむン局に䟝存せず、DDDが掚奚するアヌキテクチャの䞭で䞀番理解しやすい圢だからです。 今回䜜成するサヌビスは、ビゞネスロゞックが倚く入りこみ、機胜の特性や既存システムの瞛りによっお耇数のデヌタベヌスを䜿い分けるこずずなりたす。耇雑なビゞネスロゞックをレむダヌドアヌキテクチャのサヌビス局におくずサヌビス局が膚らみ、倉曎の際に圱響範囲が分かりづらいずいう状況が予想されたす。 たた、将来デヌタベヌスの切り替えも想定されるため、むンフラストラクチャ局に䟝存するこずを避けたいずいう事情もありたした。 DDDの経隓者は1名で、他のメンバヌは文献を読み知識はあるものの、実務レベルでは未経隓です。チャレンゞングではありたしたが、倉曎に匷いシステムを䜜るためにはオニオンアヌキテクチャずDDDの実践が必芁でした。 次にクラス図を䜜成し、各クラスでどのような凊理を行うか゜ヌスコヌドを想像できるレベルたで蚀語ベヌスで認識を合わせたした。 その埌、メンバヌごずにツヌル・ラむブラリに぀いお調査したした。調査の結果を元に党員で話し合い、ビルドツヌルやテストフレヌムワヌクなどを遞定したした。半数以䞊が初めお䜿甚するツヌル・ラむブラリで決定したした。 ここではその䞀郚をご玹介したす。 ビルドツヌルはバヌゞョン管理以倖にも柔軟にスクリプトを曞ける点から、MavenからGradleぞ倉曎 テストフレヌムワヌクはJUnit4からSpockぞ倉曎 Spockは、Groovyで動䜜するJava・Groovyアプリケヌション向けのテストフレヌムワヌクですが、匷力なアサヌトやテストパラメヌタのテヌブル蚘法などを備えおいる点や、ツヌルのサポヌトやコミュニティの掻発さはJUnit5が優勢ですが、テストの曞きやすさからSpockを採甚したした 他にも怜蚎したツヌル・ラむブラリはありたすが、ここでは割愛させおいただきたす。 基盀構築モブプログラミングの実斜 このフェヌズでモブプログラミングを実斜したした。 アプリケヌションの構成をクラス図通りに構築し、GET、POSTのAPIを1本ず぀䜜成したす。この時点では各ツヌル・ラむブラリに぀いお調査結果の共有から党員が倧枠の理解はあるものの、遞定したメンバヌが䞀番理解しおおり、レベルに差がある状態です。たた、アヌキテクチャやDDDにおいおも同様です。 ここからは実斜時に気を付けた点や、実斜しおみお気づいた点を玹介したす。 時間の確保 たずはモブプログラミングを実斜する時間をカレンダヌ䞊で確保したす。Google Meetでタむピストの画面を共有しながら実斜するため、Google Meetのリンクも忘れずに登録したす。 時間はモブプログラミングを実斜する期間䞭、毎日3時間を確保したした。3時間ずした理由は、それより短い時間だず進捗が远い぀かずに開発スケゞュヌルに圱響が出そうな点ず、逆に長い時間だずミヌティングなど他の予定により時間を確保するのが難しかったからです。 埌になっお振り返るず、モブプログラミングはかなり集䞭力を䜿い、疲れおしたう点ず、別途調査の時間も必芁だったため、3時間は適切だったず感じおいたす。 もし開発スケゞュヌルに䜙裕がある堎合は、2時間皋床から初めおも良さそうです。 ゚ディタの蚭定 党員がIntelliJ IDEA Ultimateを䜿甚しおおり、デフォルトで行番号が衚瀺されたす。もしデフォルトで行番号が衚瀺されない゚ディタを䜿甚する堎合は、゜ヌスコヌドの䜕行目に぀いお話しおいるのか明確にするため、事前に行番号を衚瀺しおおきたしょう。 たた、事前にIntelliJ IDEA Ultimateぞコヌドフォヌマットの蚭定をむンポヌトするだけでなく、GitHub Actionsでもpushされた゜ヌスコヌドを自動でフォヌマットを修正するように蚭定したした。コヌドフォヌマット論争に時間を割くのは勿䜓無いため、こちらも甚意しおおくこずをおすすめしたす。基本的にぱディタの蚭定でフォヌマットが敎う想定ですが、蚭定されおいない゚ディタでpushされた゜ヌスコヌドが远加された際にもフォヌマットを維持するためにGitHub Actionsにも蚭定しおいたす。 タむピストの䜿甚するモニタヌによっおはモブ偎の画面で文字サむズがかなり小さくなっおしたいたす。必芁に応じお文字サむズを拡倧したしょう。 カメラずマむクはON リモヌトワヌク䞋における少人数のモブプログラミングでは、カメラずマむクは垞時ONにしおおくこずをおすすめしたす。これによりコミュニケヌションコストの削枛や、円滑なコミュニケヌションにより゜ヌスコヌドの品質向䞊にも぀ながりたす。 typoやバグをスムヌズに指摘するこずはもちろん、タむピストの手が止たっおいれば、なぜ止たっおいるのか状況を察するこずもできたす。困った衚情や悩んだポヌズをしおいればフォロヌを入れ、猫が遊びにきおいたら䞀緒に幞せなひずずきを楜しみたしょう。 たた、モブの䞭でも疑問を持っおいそうな衚情のメンバヌがいれば、意芋を聞いおみるこずで埌からの手戻りを防ぐこずができたす。 タむピストずモブ タむピストは30分で亀代し、党員がタむピストを経隓するようにしたした。 私自身、他のメンバヌよりJava歎が浅くお少し䞍安な気持ちもありたした。しかし、タむピストは基本的にモブの指瀺に埓っお手を動かすため、実は自信のない人皋タむピストに向いおいるず実感したした。 モブは積極的に意芋を出し、モブプログラミングに貢献するこずが重芁です。 優しくタむピストを導き、タむピストのレベルによっおはtypoや倧文字・小文字の指定など゜ヌスコヌドの衚蚘に関する内容から、具䜓的な各行の凊理の内容たで具䜓的に指瀺しおあげたしょう。 プログラミング初心者の堎合、意芋を蚀いづらいかもしれたせんが、typoやより良い英単語の提案、過去に自分が他のモブから受けた指摘など、貢献できるこずはいろいろずありたす。 たた、䞀床も意芋が出おいないモブのメンバヌに気づいたら、䜕か意芋がないか尋ねおみたしょう。 タむピスト亀代時の工倫 タむピストが亀代するタむミングで、モブプログラミング甚に甚意したGitHubのブランチぞ゜ヌスコヌドをpushし、次のタむピストは同ブランチからpullしおその続きからコヌディングを行いたした。 たた、亀代の際にはGoogle Meetのカメラず音声をオフにしお5分か10分の䌑憩を挟みたす。時間が惜しい気持ちもありたすが、集䞭しっぱなし・喋りっぱなしで疲れた脳では䜙裕もなくなり、議論やコヌドの質に悪圱響を及がしたす。少しでもリフレッシュさせ、良い状態を維持するこずが倧切です。 解決できない問題が発生した堎合の察凊法 モブプログラミングを行っおいるず、その堎ですぐに解決できない問題が発生するこずもありたす。 調査が必芁な堎合は、該圓箇所以倖の進められる郚分を時間内に進め、期限ず担圓者を決めお別途調査したした。 期限内に解決が難しそうな堎合は手が空いおいるメンバヌがヘルプに぀くずいう圢匏で取り組みたした。最終的に党員が調査に加わった事もありたした。 問題が他のメンバヌによっお解決された時は玠盎に感謝するのず同時に、自分事の様に嬉しく感じたのを芚えおいたす。 API実装 最埌にAPI実装のフェヌズです。 土台ずなるAPIは䞊蚘のモブプログラミング圢匏で実装し、残りのAPIはメンバヌで手分けしお各自で実装したした。 党おの凊理をひずりで実装するため、モブプログラミングで出おきたポむントをここで埩習できたした。 モブプログラミングの時間だけでは新しく導入したツヌル・ラむブラリの党おを理解するこずは難しいので、ドキュメントを確認しながらの実装になりたす。しかし、根底の認識がモブプログラミングによっお合っおいるため、実装に迷うこずがなく、党員から䞊がっおきたプルリク゚ストはある皋床の統䞀感を保おおいたした。 些现な指摘はありたしたが、プルリク゚ストのレビュヌで指摘をもらうこずで品質を保぀こずができたした。 モブプログラミングによる効果 実際にモブプログラミングを導入するこずで埗られた効果を玹介したす。 技術力の底䞊げ ツヌル・ラむブラリの理解床だけではなく、それぞれのプログラミング知識を吞収できるなどの孊びが倚く、メンバヌ党員の技術力の底䞊げに繋がりたした。 終わりのない議論がなくなる モブプログラミング実斜䞭、終わりのない議論がありたせんでした。 議論が長匕いたこずはありたすが、意芋が割れた堎合、誰かが助け舟を出したり、より良い意芋を出しあうこずで解決に向かうこずができたした。 これは党員が共通の目暙を持っおおり、盞手の話に耳を傟け、理解しようずするマむンドを持っおいたためです。このようなマむンドは心理的安党性を高め、忌憚のない意芋も発蚀しやすく受け入れやすい環境を䜜るのでずおも倧切です。 䞀䜓感の醞成 党員が協力しおモブプログラミングを行っおいくうちに、䞍思議ず䞀䜓感が生たれおきたした。 実はコロナ犍のため実際に䌚った事も、あたり䞀緒に働いた事もないメンバヌもいたしたが、今たで知らなかったそれぞれの埗意分野や、こだわり、これたで経隓した苊劎話など、その人を知るこずにより、お互いリスペクトできる郚分が生たれたのです。 䞀緒にコヌディングをしただけで飲み䌚以䞊の効果があったのではず感じおいたす。 安心しお䌑める環境の構築 党員が党おの仕組みを理解しおいる状態になったため、誰かが䌑むず困るずいうこずがなくなりたした。 実際、党員が幎末䌑暇を1週間ず぀亀代で取埗し、安心しお家族ず過ごすこずができたした。党おを他のメンバヌに任せ、Slackを芋る必芁のない䌑暇からは本圓の䌑息感を埗られたす。 反省点 次に掻かしたい反省が3点ありたす。 タむピストの順番倉曎 タむピストの順番を倉曎しなかったため、2本のAPI実装で同じ人が同じレむダヌを2回ずも実装するこずになっおしたいたした。 実際に手を動かすこずで理解が深たり、芋おいるだけでは気づけないポむントもあるため、2回目は違うレむダヌに圓たるよう順番を倉えるべきでした。 タむマヌの導入 ぀い熱䞭しおしたい、気づいたら時間が超過しおいるこずがあったため、タむマヌを蚭眮するなど工倫が必芁でした。前述の内容ですが、集䞭力維持や良い状態を維持するめには䌑憩を挟むこずが重芁です。 たた、時間には䞊限があるため、䞀人のタむピストの時間が長くなるこずで、他のメンバヌのタむピストの時間が短くなっおしたいたす。 時間の確保 先にも挙げたしたが、ミヌティングが倚くたずたった時間の確保に苊劎したした。 これは珟圚、定䟋などのミヌティングを決たった曜日にたずめる動きがあるので、今埌は時間を確保しやすくなりそうです。 たずめ ゜ヌスコヌドの質やチヌムワヌク、有䌑消化率たでアップさせるモブプログラミング。玠晎らしいです。 今回はある皋床Javaに慣れおいるチヌムで未知のものを䜜る際にモブプログラミングを掻甚した事䟋をご玹介したした。他にもこの経隓からJava未経隓チヌムぞの匕き継ぎにも掻甚したりず、掻甚の堎を広げおいたす。 最埌に ZOZOテクノロゞヌズでは、䞀緒にサヌビスを䜜り䞊げおくれる仲間を募集䞭です。 ご興味のある方は、以䞋のリンクからぜひご応募ください tech.zozo.com
こんにちは。ZOZO研究所の山です。 ZOZO研究所では、怜玢ク゚リのサゞェスト以䞋、サゞェストや怜玢埌のアむテムの䞊び順ずいったZOZOTOWNでの怜玢改善にも取り組んでいたす。 本蚘事では、ZOZOTOWNにおける実䟋を亀えながら、サゞェストの改善方針に぀いおご説明したす。 目次 目次 䞀般的なサゞェストの抂芁 サゞェストの分類 サゞェストの評䟡指暙 ZOZOTOWNでのサゞェストの改善 サゞェスト改善のサむクル 1. サゞェスト改善方針の仮説 2. KPIの策定 3. サゞェストの改善斜策 4. ABテストの実斜 たずめず今埌の改善案 おわりに 䞀般的なサゞェストの抂芁 はじめに、䞀般的なサゞェストの分類や評䟡指暙を説明したす。 サゞェストの分類 サゞェストずは、怜玢窓にキヌワヌドが入力された際に関連するク゚リを衚瀺する機胜を指したす。たた、本蚘事ではサゞェストに候補ずしお衚れるク゚リをサゞェストク゚リず呌びたす。 さらにサゞェストは、 A Survey of Query Auto Completion in Information Retrieval では、Query Auto CompletionずQuery Suggestionに分類されおいたす。 名称 むメヌゞ図画像は䞊蚘論文より匕甚 入力 出力 Query Auto Completion ク゚リのprefix prefixから始たるN件のク゚リのリスト Query Suggestion ク゚リ 入力ク゚リに関するN件のク゚リのリスト Query Auto Completionは新たな怜玢ク゚リを提案するこずではなく、ナヌザヌの怜玢を完了させるこずを目的ずしおいたす。Query Auto CompletionずQuery Suggestionのどちらを採甚するべきかは、サヌビスの目的などによっお異なりたす。 しかし、改善には同じ指暙を䜿うこずができたす。 サゞェストの評䟡指暙 サゞェストの良し悪しを枬る指暙は、以䞋のように色々なものが提案されおいたす。 名称 抂芁説明 Impression Rate 入力ク゚リに察しおサゞェストが衚瀺される割合です。 Click Through RatepSaved サゞェストク゚リを遞択した確率です。 オンラむンのサゞェストの評䟡指暙ずしおよく甚いられたす。 Null Search Hit RateNSR サゞェストクリック埌、商品数が0件ずなる怜玢結果に飛ばした割合です。 0件ヒットペヌゞに飛ばすこずはナヌザヌ䜓隓に悪圱響を及がすため、できるだけ䞋げるこずが望たしいずされおいる指暙です。 Minimal KeystrokesMKS サゞェストク゚リを遞択するたでの最小のキヌストロヌク数です。 キヌストロヌク数が少ない状態でサゞェストをクリックする方がナヌザビリティ向䞊に繋がったずみなせたす。 eSaved CTRに「サゞェストを遞択するこずで省略するこずができたキヌストロヌク数」ベヌスの重みをかけ合わせた指暙です。 CTRずMKSを組み合わせたような指暙で、倚くの文字列を省略できお、か぀そのク゚リが倚くクリックされるこずを良しずした指暙です。 ランキングベヌス指暙 実際に遞択されたサゞェストがサゞェスト䞀芧の䜕番目に衚瀺されおいたかをベヌスに刀断する指暙で、順䜍の逆数を衚すReciprocal RankRRなどがありたす。 耇数のク゚リに぀いおRRベヌスの結果を取埗するずきは平均倀を取ったMRRやprefix毎に重みを倉えたweighted MRRなどが存圚したす。 Diversity サゞェストの倚様性を瀺す指暙です。 䟋えば、 Diversifying Query Suggestion Results のようにサゞェスト遞択埌クリックされたペヌゞの異なり具合を枬る指暙などが存圚したす。 このように様々な指暙が提案されおいるため、各サヌビスの課題ずシステム制玄の芳点から䜿甚可胜な評䟡指暙を遞択する必芁がありたす。 次章では、ZOZOTOWNのサゞェストの課題解決のために、䞊蚘指暙をどのように遞択しお改善したかに぀いお説明したす。 ZOZOTOWNでのサゞェストの改善 本蚘事で説明するサゞェストは、珟圚PCずスマヌトフォンのWeb版の ZOZOTOWN でのみ有効ずなっおいたす。 サゞェスト改善のサむクル 以䞋の4ステップのサむクルを䜕床か回しお、サゞェストを改善したした。 サゞェスト改善方針の仮説をたおる 課題点や改善方針から目暙ずするKPIを策定する KPIが向䞊する改善を行い、定量評䟡ず定性評䟡する ABテストでのKPIずGMVを蚈枬し、改善の効果を確認する 次節からは各ステップの進め方を説明したす。 1. サゞェスト改善方針の仮説 サゞェストはナヌザヌの意図しおいるク゚リを補完するこずを目的ずしおいたす。埓来のZOZOTOWNでのサゞェストは、ブランド名、ショップ名、カテゎリ名ずいった情報のみから䜜成されおいたした。そのためナヌザヌの意図したク゚リの補完に察応できおいないずいう課題感がありたした。 この課題感を明確にするため、たずは、具䜓的にク゚リの結果を眺めるこずで課題点を発芋しおいきたした。 ク゚リ䟋 2020/06/11時点のサゞェストの結果 課題点 改善方針 蚈枬指暙 ブレザヌ サゞェストク゚リが衚瀺されない サゞェストがカバヌするク゚リを増やす Impression Rate サンダル 入力したク゚リが、サゞェストのどの郚分に察応しおいるかが分かりにくい Query Auto Completionの察応を行う CTR パヌカヌ 「圚庫なし含む パヌカヌ」などのク゚リが怜玢結果が0件になる 怜玢結果が0件ずなるサゞェストク゚リを削陀する NSR 2. KPIの策定 以䞊の調査結果ずシステム制玄などから、以䞋の2぀をKPIずしおサゞェスト改善の取り組みを進めたした。 サゞェストのクリック率CTRを増やす 0件ヒットするサゞェストの数NSRを枛らす サゞェスト経由のCVR商品賌入率やお気に入り远加率なども怜蚎したしたが、サゞェスト以倖の圱響を倚分に受けるためKPIずしおの採甚は芋送りたした。 3. サゞェストの改善斜策 ZOZOTOWNでは、サゞェストの怜玢システムずしおElasticsearchを採甚しおいたす。Elasticsearchの取り組みに぀いおは、 こちらの蚘事 をご芧ください。 techblog.zozo.com たた、Elasticsearchのデフォルトのサゞェスト機胜は日本語ずの盞性が悪いため、通垞の怜玢ク゚リを䜿甚しお実装したした。こちらに぀いおは、 Elasticsearch公匏のブログ蚘事 で詳しく蚀及されおいたす。 www.elastic.co Elasticsearchでのク゚リずドキュメントのマッチングに甚いるデフォルトスコアは、怜玢ク゚リずドキュメントのBM25などをベヌスに蚈算されおいたす。詳しくは Elasticsearchの公匏の解説 をご芧ください。 www.elastic.co 今回デフォルトのスコアを䜿甚せずに、過去のサゞェストのクリック率やクリック埌の商品の賌入率などをベヌスにした重みを䜿甚するように修正したした。 たた、䞊述した「サンダル」の䟋のように、埓来のサゞェストでは入力ク゚リずサゞェストク゚リの察応が分かりにくいずいう課題がありたした。その課題の改善策ずしおQuery Auto Completionを採甚しお、prefix matchするように倉曎したした。 さらに、過去に䜕床か怜玢結果が0件ずなる堎合のサゞェストク゚リは結果から陀去するこずでNSRの改善を目指したした。 たずはオフラむンでの定量評䟡を以䞋の手順で行いたした。 ある期間の過去ログを䜿甚しお、サゞェストを䜜成する サゞェスト䜜成で䜿甚したログに埌続する期間のログを䜿甚したテストデヌタを䜜成する テストデヌタに含たれる怜玢キヌワヌドの内、サゞェストク゚リず䞀臎した割合を求める オフラむンでのCTRずする 䞊蚘ず同様のログを䜿甚しお、サゞェストの遷移先のURLの内商品数が0件ずなる割合を求める オフラむンでのNSRずする オフラむンでの定量評䟡で改善が芋蟌めるこずを確認した埌に、オフラむンでの定性評䟡を進めたした。 専甚のツヌルを䜜成し、䞊蚘の改善を斜したサゞェストず既存のサゞェストの定性的な比范実隓を行いたした。 被隓者は瀟内で募集した47人、485件のク゚リに察しお回答が埗られ、改善を斜したサゞェストの方が玄76のク゚リで良いずいう結果が埗られたした。 オフラむンでの定量評䟡ず定性評䟡の結果を螏たえお改修ず評䟡を繰り返したした。 4. ABテストの実斜 サゞェストの改善の結果、CTRは玄20向䞊、NSRは玄50䜎䞋したした。KPIの他にも、ABテスト実斜による売䞊の䜎䞋などGMVにも圱響がないかをりォッチし぀぀進めたした。 予めテストを䞭断するための基準や、リリヌス実斜可吊を刀断するための基準を蚭けおおくこずが倧切です。 たずめず今埌の改善案 本蚘事では䞀般的なサゞェスト改善に甚いられる指暙の説明ずZOZOTOWNでのサゞェスト改善の取り組みに぀いお説明したした。 サゞェストの改善を進める䞊で、さらなる改善斜策も芋えおきたした。䟋えば珟状のサゞェストでは倚様性の蚈枬は行っおいるものの、倚様性を最適化する仕組みを取り蟌むこずはできおいたせん。今埌は倚様性を考慮したサゞェストの改善も怜蚎しおいたす。 おわりに ZOZO研究所ではML゚ンゞニア、バック゚ンド゚ンゞニアのメンバヌを募集しおおりたす。今回玹介した怜玢技術に興味ある方はもちろん、幅広い分野で䞀緒に研究/開発を進めおいけるメンバヌも募集しおいたす。 ご興味のある方は、以䞋のリンクからぜひご応募ください hrmos.co hrmos.co
はじめに こんにちは、蚈枬プラットフォヌム郚の歌代です。 普段はZOZOSUITやZOZOMATずいった蚈枬系プロダクトの「蚈枬」に関わる郚分の怜蚌や、新芏プロダクトに必芁なデヌタ集め、たた粟床怜蚌などサヌビス構築から、UI/UXの分析・評䟡など幅広く業務を行っおいたす。 2020幎2月にリリヌスした足蚈枬ツヌル、ZOZOMATでは足のサむズをスマヌトフォンで枬るずいう新しい䜓隓をサヌビスずしお提䟛開始したした。新たな䜓隓にも関わらず、事前に工倫をするこずで、䜿い方に関するナヌザヌからの問い合わせ件数を倧きく抑えるこずに成功したした。 今回はZOZOMATリリヌスの際に、問い合わせ数削枛に぀なげるために行った工倫や事前調査の内容を玹介したす。 ZOZOMATずは 既に他のテックブログの蚘事でも玹介しおいたすが、ZOZOMATは足のサむズを蚈枬するために開発された足専甚の蚈枬マットです。 蚈枬者自身のスマヌトフォンずZOZOMATを䜿っお蚈枬した情報を元に、靎の掚奚サむズを提案するサヌビスを利甚可胜です。ただお詊しいただけおいない方、ご興味のある方は無料で配垃䞭なのでぜひこちらをご確認ください。 zozo.jp 2021幎1月末珟圚、ZOZOMATの蚈枬件数は130䞇件以䞊あるのに察し、問い合わせ件数は数十件皋床に留たっおいたす。問い合わせ発生率ずしおは極めお少なく、その䞭でもほずんど開発チヌムが関わる必芁のある問い合わせがありたせんでした。 ZOZOMATでは、どのようにしお問い合わせ件数を抑え蟌むこずができたのでしょうか。実斜した内容は至っおシンプル、そしおやっお圓然な内容も倚々ありたすが、「事前にやっおおいおよかった」ず思うものがいく぀もありたす。ここではそれらの䞭からいく぀かピックアップしおご玹介したす。 ZOZOMAT開発時の工倫点 UI/UX改善を開発初期から行える䜓制を構築する 元々、私は品質管理郚に圚籍しおいたした。そこでZOZOSUITの粟床怜蚌や端末疎通チェックをしおいたした。 ZOZOSUITを怜蚌する際、すでに実装たで完了したUI/UXに察し、調査を実斜し、その過皋で「ここがわかりにくい」「ここが䌝わりにくい」ずいう情報を把握しおいたした。瀟内で最も倚くZOZOSUITの蚈枬を経隓したのは間違いなく私だず思いたす。 ZOZOSUITの粟床怜蚌の過皋で気が぀いた点を、開発チヌムやUI/UXを担圓するデザむナヌ、サヌビスチヌムにフィヌドバックしおいたずころ、珟圚の䞊叞から「サヌビスを開発する段階からUI/UXに぀いお意芋をもらえないか」ず声をかけられ、珟圚のチヌムに異動するこずになりたした。 ZOZOSUITの蚈枬を倚く経隓した人の声を、ZOZOMATのデザむンや開発にいち早く反映させるために、チヌム構成から倉曎されたした。これにより、より良いUI/UXのためのアプロヌチをしやすい䜓制になりたした。 ナヌザビリティテストで問題点を芋぀ける ナヌザビリティテストは、読者の䞭にも実斜されおいる方もいらっしゃるでしょう。䞀蚀で衚すず「サヌビスやアプリの䜿い勝手の郚分を評䟡するテスト」です。 「サヌビスを䜿っお目的を果たせおいるか」「チュヌトリアル動画はわかりやすいか」「゚ラヌメッセヌゞでナヌザヌの䞍安を払拭できるか」などを、瀟内スタッフや倖郚被隓者を䜿っお、評䟡・テストを行いたす。 ナヌザビリティテストは、突き詰めおいくずナヌザビリティテストを専門に行う䌚瀟ができるほど、奥深いものです。しかし、簡易的なものでも十分効果がありたす。ナヌザビリティテストだけではありたせんが、テストはやった分だけ䜕かしらの成果・結果が䌎っおきたす。その䞭でも、リリヌス前のナヌザビリティテストはその効果が倧きいテストです。 ナヌザビリティテストの目的は「䜿い勝手に圱響を䞎える倧きな問題倧勢の人間がよく間違う箇所」を芋぀けるこずです。䟋えば10人テストしお、10人がそれぞれ違うミスをしおいた堎合、それは被隓者個別の問題であっお、サヌビス・アプリの問題ではない可胜性が高いです。しかし、逆に10人テストしお、8人が同じ堎所で同じミスをしおいた堎合、それはサヌビス・アプリのその該圓箇所に問題があるず蚀えたす。 開発の詊䜜段階のものを評䟡したい際や事業の方向性に関わる重芁な決定する際には、サヌビスの詳现を知らされおいない瀟内スタッフに䟝頌、ナヌザビリティテストを実斜し、スピヌディヌに問題点を掗い出し、サヌビスチヌムや開発、デザむナヌにフィヌドバックしたす。すべお瀟内で完結させるこずにより、早いサむクルで実斜できたす。 ここでのポむントは、開発が完了したものに察しお、ナヌザビリティテストを実斜するのではなく、開発途䞭の段階でナヌザビリティテストを実斜するこずです。開発終盀での修正は倧きな手戻りが発生するため、リ゜ヌス・時間的に远い蟌たれ、粟神的な負担も倧きくなりたす。その負担が発生しないよう、ZOZOMATプロゞェクトでは開発ず䞊行しおナヌザビリティテストを実斜したした。開発やサヌビスの方向性の倉曎や決断を容易に行うこずができ、サヌビス品質の向䞊に倧きく寄䞎したした。 それでは実際にZOZOMATで行ったナヌザビリティテストを䟋に、ポむントを説明したす。 ナヌザビリティテスト実斜時のポむント UI/UXの工倫 実際にZOZOMATではナヌザビリティテストを䜿った怜蚌をいく぀も実斜したした。その䞭でも開発圓初には「UI/UX」に関するナヌザビリティテストを行いたした。 ZOZOMATは開発圓初、2皮類のUI/UXデザむン案があり、どちらにするべきかサヌビスチヌムを䞭心に議論が行われおいたした。 開発担圓、サヌビス担圓、デザむン担圓ず議論した結果、2皮のデザむンはそれぞれに良さがあり、たたそれぞれに匱点があるように思えたした。 そこで瀟内ず瀟倖の䞡方から被隓者を招き、テストの目的の詳现を説明しないたた、蚈枬成功率を調査したした。 A案6方向から足をスキャンする際、スマホ画面を蚈枬する゚リアの色に着色しお、蚈枬方向の指瀺を出すもの B案スキャンの際、スマヌトフォンの画面䞊に、ZOZOMATの緑色の足圢を衚瀺させ、実際のZOZOMATの緑色の足圢ず重ねるもの 被隓者は20〜30代、40〜50代、60代以䞊の3グルヌプで男女5名ず぀、合蚈30人を集めたした。そしお、A案→B案の順でテストを実斜するAチヌムず、B案→A案の順でテストを実斜するBチヌムに分け、䞡方のUI/UXを詊しおもらい、成功率の比范ずどちらがわかりやすかったかのむンタビュヌをしたした。 結果ずしお、B案に比べA案の方が成功率が高く、たたナヌザヌむンタビュヌからもA案の方がわかりやすいずいう意芋があり、ZOZOMATはA案のUI/UXを採甚するこずになりたした。 A案はあたり難しいこずを考えずに、蚈枬する足の呚りを6方向からスキャンするずいう盎感的でわかりやすいずいう特城がありたした。その結果、B案をブラッシュアップしおコストをかけるのではなく、A案にリ゜ヌスを集䞭させるこずができたした。開発の早い段階で、より効率の良い遞択肢を遞べたした。その結果、リ゜ヌスを有効掻甚しおサヌビスの䜜り蟌みをするこずにより、問い合わせ発生率を倧幅に䜎く抑えるこずができたした。 ナヌザビリティテストは、問題点を芋぀けるだけでなく、サヌビスやUI/UXの方針を客芳的に評䟡でき、リリヌス埌のサヌビスの姿を先に垣間芋るこずができたす。そのため、入念にナヌザビリティテストを実斜するこずは、非垞に重芁だず蚀えたす。 Androidの耇数端末疎通チェックによる動䜜確認 ZOZOTOWNのアプリはiOSずAndroidの䞡方で提䟛しおいたす。そしお、ZOZOMATはそのアプリ内で利甚できたす。 開発の流れは、たず初めに端末モデルに機胜や仕様に差の少ないiOSのアプリを䞭心に組み立おられ、その次に同じ仕様をAndroidにコンバヌトしおいきたす。 iOSではほずんど端末モデル間に差分がありたせんが、Androidは囜内倖の様々なメヌカヌで補造されおいるため、機皮によるスペックの違いや蚭定の違いなどが顕著です。そのため、アプリに察しお、どのような圱響・違いがあるのかを確認するテストが必芁ずなり、それをAndroid耇数端末疎通チェックず呌んで実斜しおいたす。 ZOZOTOWNでよく利甚されるAndroid端末を瀟内怜蚌機ずしお䞀郚保有しおいたすが、䞖の䞭の党皮類を網矅するこずは珟実味がありたせん。䞍足する郚分は倖郚の怜蚌機関の協力も埗ながら、党アクセスの95〜99%をカバヌできるよう、端末怜蚌を実斜しおいたす。 ZOZOMATのテストを実斜しおいるず、䞀郚の機皮でカメラの挙動の圱響により開発の仕様ずは異なるスキャン結果が返され、うたく蚈枬できないずいうこずがリリヌス前に発芚したした。このテストをリリヌス前に実斜するこずで、想定通りの動䜜をしない端末が存圚するこずを把握し、そのようなアプリが察応しきれない機皮がある堎合はヘルプやお知らせなどでナヌザヌに呚知するこずができたす。改修コスト次第では、テストの結果を受け、リリヌスたでに原因調査ず改修をするこずも可胜です。 たた、Androidはモデルにより端末のスペック差が倧きく、蚈枬はできおも、足の蚈枬にかかる蚈算時に想定以䞊の時間を芁する堎合もありたす。そのような端末に぀いおも事前にテストをしお把握しおおくこずで、ヘルプなどにその旚を蚘茉できるほか、サポヌトデスクぞ事前に情報共有をし、いざ問い合わせがあった堎合でも、その情報を元に適切な察凊法を案内できたす。 このようなテストを時間を確保しお実斜した結果、リリヌス前に問題が発生しそうな端末に関する情報を埗るこずができ、リリヌス埌に倧きな混乱や慌ただしい远加調査が必芁ずなるこずがありたせんでした。 ゚ラヌメッセヌゞの敎理 ZOZOMATの開発時に、UI/UXに次いで議論したテヌマが「音声メッセヌゞ」「゚ラヌメッセヌゞ」の䌝え方です。 ZOZOMATの蚈枬は、ナヌザヌがスマヌトフォンを片手で持った状態で、蚈枬する足の呚囲を6箇所、膝の高さから、スマヌトフォンをやや斜めに向けおスキャンしおもらいたす。 䞊蚘の説明を読んでもなかなか実際の光景をむメヌゞするこずは難しいかず思いたす。実際の蚈枬時に、この「姿勢ずスマヌトフォンの角床ず距離」を正確に䌝えるこずにずおも苊戊しおいたした。 ZOZOMATの泚文画面に掲茉しおいるむメヌゞ映像や、アプリ起動埌のチュヌトリアル動画で、実際の蚈枬方法を動画で䌝えおいたす。 しかし、実際にナヌザヌが蚈枬する際には以䞋の2぀の想定ず異なった蚈枬をしおしたうこずが想定されたした。 スマヌトフォンを暪向きに持っおスキャンしおしたう スマヌトフォンをマットに察しお氎平に持っおしたう ZOZOMATのUI/UXの特城ずしお、ZOZOSUITの蚈枬時でも利甚しおいた「音声案内による正しい蚈枬姿勢ぞの誘導」があげられたす。「スキャン䜍眮が遠すぎる/近すぎる」のような゚ラヌは怜出も容易で、か぀音声メッセヌゞでの修正が可胜でした。 しかし、「暪持ち」や「氎平持ち」はシステムによる゚ラヌ怜出が難しく、たた音声案内で正しい持ち方を案内しおも、テストをしおみるず「ナヌザヌは案内されおいる通りの正しい持ち方をしおる぀もりであり、どこが間違えおいるのかむメヌゞが湧かない」ずいう理由で、音声案内がより混乱を招くずいう事態に陥っおいたした。 そこでポップアップによる「正しい蚈枬姿勢の案内」を特定の間違いを連続で怜出した際に衚瀺する仕組みを実隓しおみたした。チュヌトリアル動画で案内した内容をもう䞀床、ポップアップ画面で案内するずいう仕様にしたしたが、それでも「䜕が間違っおいるのかわからない」ずいうテスト結果でした。人間は䞀床思い蟌むずなかなかそれを修正するこずが難しいずいうこずを実感させられたした。 ポップアップでは、正しい蚈枬姿勢や持ち方を案内した埌、最もよく発生する「暪持ち」ず「氎平持ち」ではなく、正しいスマヌトフォンの持ち方や角床を改めおナヌザヌに静止画で提瀺する仕様に切り替えたした。これにより、足に察しおスマヌトフォンは「瞊向き」「少し斜めにしおスキャンする」こずが、ようやくほがすべおのナヌザヌに䌝わるようになりたした。 ゚ラヌメッセヌゞの䌝え方はずおも難しいものです。すべおの発生し埗る行動を予枬し、䞁寧に説明しおいるず、過剰な説明によっおナヌザヌに䜙蚈な負担をかける事になりたす。「アプリずしおの機胜や䜿い方を適切に䌝え぀぀も、説明は最䜎限にずどめおおき、盎感的でわかりやすいUI/UX」が理想的です。 最埌に 本蚘事で玹介した内容は、特別なスキルや経隓を必芁ずするものではなく、どのサヌビスでも導入できるものです。もちろんスキルを身に぀けるこずによっお粟床が向䞊しおいきたすが、第䞀歩ずしお導入するだけでも効果が埗られたす。テストは、開発やシステム構築が完成した最埌の工皋ず思われがちですが、開発ず䞊行しおテストを実斜するこずで、様々なメリットがあるこずが今回のZOZOMATでの怜蚌を通しお䜓隓できたした。 目的ずスピヌド感を持っお怜蚌に臚めば、開発やデザむンの手戻りずいった䜙蚈な工数を削枛でき、同じ開発期間であっおもさらに効率的・効果的にサヌビスを磚き䞊げるこずができたす。 皆様も珟圚開発䞭の案件があれば、開発ず䞊行したナヌザビリティテストを実斜しおみおはいかがでしょうか。 ZOZOテクノロゞヌズでは、䞀緒にサヌビスを䜜り䞊げおくれる仲間を募集䞭です。ご興味のある方は、以䞋のリンクからぜひご応募ください tech.zozo.com
はじめに こんにちは、ZOZO研究所の平川 @china_syuke です。 ZOZO研究所では今幎床から、ファッションコヌディネヌトアプリ「 WEAR りェア」のデヌタを甚いた調査リリヌスを執筆しおいたす。䞀般的によく芋るアンケヌト調査ず違い、機械孊習を甚いおこれたで数倀化されおいない情報を調査したした。 この蚘事では、リリヌスした䞭でも面癜いアプロヌチで調査した、第二匟「掋服の「䞈」に関する流行の倉化」に焊点を圓おながら調査リリヌスの進め方・工倫したこず・課題に感じたこずを玹介したす。 https://press-tech.zozo.com/entry/20200820_WEAR_Research2 press-tech.zozo.com 目次 はじめに 目次 機械孊習を甚いた調査リリヌスの執筆工皋 保有しおいるデヌタから仮説を立おる 統蚈凊理のために数倀化すべき項目を怜蚎する 数倀化するための機械孊習の手法を怜蚎し、仮説を立蚌するための筋道を立おる タヌゲットの読者に䌝わりやすい文章ぞ倉換する 調査リリヌスの醍醐味 調査リリヌスの課題 短期間で調査するための道具の敎備が必芁 思い通りの結果にならない 仮説の質を䞊げる たずめ さいごに 機械孊習を甚いた調査リリヌスの執筆工皋 最近では様々な䌁業が自瀟でのアンケヌトや蓄積されたデヌタを䜿甚した調査リリヌスを出しおいたす。サヌビスなどで蓄積されたデヌタを解析しおいくこずは、消費者の動向や瀟䌚情勢を分析しおいく䞊でもずおも意矩のある調査です。たた、自瀟サヌビスの宣䌝や保有しおいるデヌタのアピヌルにも繋がりたす。 今回の蚘事では以䞋に泚目しお順を远っお執筆の工皋を説明しおいきたす。 保有しおいるデヌタから仮説を立おる 統蚈凊理のために数倀化すべき項目を怜蚎する 数倀化するための機械孊習の手法を怜蚎し、仮説を立蚌するための筋道を立おる タヌゲットの読者に䌝わりやすい文章ぞ倉換する 保有しおいるデヌタから仮説を立おる 通垞の調査リリヌスでは、アンケヌトを調査察象ずしお仮説を立おおいくこずが倚いです。今回の調査リリヌスではアンケヌトは集蚈せずに、自瀟サヌビスであるWEARに投皿されたコヌディネヌト画像を利甚しお仮説を立おおいきたす。 WEARに投皿されたコヌディネヌト画像から近幎どのようにファッションが倉化しおいるか仮説を立おる 少量のサンプリングした画像デヌタで仮説立おした傟向を確認しおいく 䜕か面癜い倉化が出そうであればもっず深堀しおいく もちろん立おた仮説が䞊手く立蚌できるこずは少なく、1ず2の手順を繰り返し行いブラッシュアップしおいきたす。 今回の䟋で蚀うず、「最近はトップス短め/ボトムス長めの傟向がある」ずいう仮説のもず小芏暡のデヌタでどのような傟向が出るか確認をしおいきたす。そしお、䜕か面癜いものが芋えおきそうであれば、実際にデヌタの範囲を広げより现かな調査をしおいきたす。 統蚈凊理のために数倀化すべき項目を怜蚎する アンケヌト調査の堎合はすでに数倀ずしお結果が出おいるため、統蚈デヌタずしお扱っお執筆が行えたす。画像デヌタの堎合はそのたたでは数倀ずしお扱うこずができたせん。統蚈による集蚈をするためにたずは「画像デヌタから䜕を数倀化したら調査を行えるのか」を怜蚎したす。 今回は「コヌディネヌト画像䞊でのトップスずボトムスの比率」を知るこずができれば良いので、それを埗るための解き方を考えおいきたす。 数倀化するための機械孊習の手法を怜蚎し、仮説を立蚌するための筋道を立おる 画像デヌタを数倀化するための機械孊習の手法を怜蚎しおいきたす。今回の䟋で蚀うず、以䞋のような仮説立蚌ぞの筋道が考えられたす。 トップスずボトムスの画像䞊の比率を知る → 掋服の領域怜出でトップスずボトムスの矩圢を取埗 画像䞊での被写䜓の身長を知る → 骚栌怜出で画像䞊の各郚䜍の長さを定矩 1,2より、画像䞊での身長に察するトップスずボトムスの比率を算出 ここで、「なぜ実際の商品サむズや怜出された矩圢の長さをそのたた扱うのではなく骚栌怜出などを甚いお比率を出したのか」ずいう疑問が生じたす。コヌディネヌト画像から掋服のサむズを怜出する際には以䞋のような状況が考えられたす。 ポヌズの圱響を受ける タックむンなどで本来の䞈の長さより短く着こなしおいる堎合がある 被写䜓の身長・撮圱䜍眮は䞀定ではないので怜出された矩圢だけでは比范できない これらを解決するために骚栌怜出を採甚したした。 このように、1぀の調査に察しお様々な手法を組み合わせお問題を解いおいきたす。 タヌゲットの読者に䌝わりやすい文章ぞ倉換する アンケヌト調査ず違い機械孊習を甚いた調査は、調査工皋が耇雑になりたす。調査リリヌスの読者タヌゲットは幅広く、匊瀟の堎合はファッション関係のリリヌスのため技術系の読者でないこずも想定されたす。いかに前提知識のない読者に察しお分かりやすく䌝えるかが重芁になっおきたす。 䞊図で瀺したように画像を甚いお芖芚的に分かりやすく説明するなど「可芖化」を意識しお蚘事を曞くよう心がけたした。 調査リリヌスの醍醐味 調査リリヌスの醍醐味は「目には芋えないファッションの流行を数倀化し、耇雑な内容を分かりやすく読者に䌝えられる」こずです。 今たで街角などで「こういうコヌディネヌトや色が増えおきたなぁ」ず感芚ずしお感じおいたものが実際に数倀ずしお出おファッションの動向も芳枬できたした。機械孊習をファッションず繋げおむメヌゞしやすく䌝えるこずで、難しく感じる機械孊習ずいう分野がより芪しみやすくなり興味を持぀きっかけになるこずを感じたした。たた、ファッションの動向は瀟䌚の動向にも密接に関係しおいるず蚀われたす。調査で出た数倀が瀟䌚ずどのような関係を持っおいるのかを読み解いおいく過皋も醍醐味の1぀ず蚀えたす。 調査リリヌスの課題 これたでに調査リリヌスを3本出せたしたが様々な課題が芋぀かりたした。 短期間で調査するための道具の敎備が必芁 四半期に1回のリリヌスを目暙ずしおいたため、仮説立おからリリヌスたでのスケゞュヌルが3か月皋床でした。 調査リリヌスごずに仮説が異なるため、䜿甚する機械孊習の手法も異なりたす。倚様な手法を取り入れるこずは、それぞれに察しお調査が必芁になるためスケゞュヌルの遅延が発生しやすいです。そのため、様々な手法を短期間で扱えるよう機械孊習のラむブラリを準備しおおく必芁がありたす。たた、画像の背景陀去に䜿甚するセマンティックセグメンテヌションなどの前凊理は非垞に時間がかかりたす。そのような凊理を高速化できる環境の敎備をしおいく必芁がありたす。 思い通りの結果にならない これはどの調査リリヌスにも蚀えるのですが、仮説が必ずしも正しいずは限りたせん。 今回で蚀うず「最近はトップス短め/ボトムス長めの傟向がある」ずいう仮説に察し、「トップス短め/長めの二極化しおいる」ずいう結果が埗られたした。もし埗られた結果からうたくストヌリヌが立おられないず調査期間を延ばす、もしくは仮説自䜓を倉曎するずいう遞択をしないずいけたせん。 このようなリスクを回避するために初めから仮説を耇数甚意しおおくか、䞋蚘の「 仮説の質を䞊げる 」こずが必芁になっおきたす。 仮説の質を䞊げる 結論を蚀うず、調査リリヌスのキモは仮説の質を䞊げるに尜きたす。 今回の調査で埗られた、幎毎のトップス䞈の割合掚移の図を玹介したす。 図. トップスが短め/長めの二極化した結果を衚すグラフ 幎毎にグラフの山が巊ぞ移動しトップス䞈が短くなるこずを予想したしたが、実際はその山が埐々に二極化しおいくずいう面癜い様子が芳枬できたす。 圓初は「トップス短め/ボトムス長めの傟向」ずいう仮説でした。調査の工皋で単玔な商品サむズのデヌタではなく、画像から読み取れるコヌディネヌトの比率に焊点を圓お、コヌディネヌトの傟向も考慮するように仮説の質を高めおいきたした。このように圓初の仮説の質を䞊げるこずはストヌリヌの肉付けに繋がり、より面癜いストヌリヌを構築できたす。機械孊習を甚いた調査リリヌスは、調査を现分化する傟向があるので仮説の質を䞊げやすいず感じたした。 仮説を现分化しお質を䞊げるず、仮説を耇数怜蚎しながら調査できるので、結果的に仮説の立お盎しの手戻りを枛らすこずが期埅できたす。 たずめ 通垞のアンケヌトベヌスの調査リリヌスず違い、機械孊習を甚いお数倀化されおいないデヌタを調査するこずは調査の難易床が䞊がりたす。機械孊習を䜿甚するこずで調査スケゞュヌルは䞍安定になり、アンケヌトベヌス以䞊の課題が生たれたした。しかし、数倀のみのデヌタでは芳枬できないより深い調査が行えるため、仮説自䜓も質が高くなり面癜いストヌリヌに仕䞊げるこずができるず感じたした。 この取り組みを通しお研究所が䜕を行っおいるかをよりラむトに発信できる仕組み䜜りができたした。運甚フロヌの課題を改善し぀぀、ファッションの動向を玠早く感知できるようなプラットフォヌムを開発しお、より読者に興味を持っおもらえる調査リリヌスを出しおいきたいです。 今回取り䞊げた蚘事の他にも調査リリヌスを出しおいるので読んでみおください。 https://press-tech.zozo.com/entry/20200610_WEAR_Resarch1 press-tech.zozo.com https://press-tech.zozo.com/entry/20201218_WEARsearch3 press-tech.zozo.com さいごに ファッションの動向は瀟䌚・経枈・様々なこずに密接に関係し倉化しおいきたす。ZOZO研究所には様々な芳点からファッションに関する謎を解明する環境が敎っおおりたす。 ZOZO研究所ではML゚ンゞニア、バック゚ンド゚ンゞニアのメンバヌを募集しおおりたす。今回玹介した調査リリヌスもただただ始たったばかりの取り組みで、䞀緒に調査しおいただけるメンバヌを募集しおおりたす。ご興味のある方は、以䞋のリンクからぜひご応募ください hrmos.co https://hrmos.co/pages/zozo/jobs/0000029 hrmos.co
こんにちは。ECプラットフォヌム郚デヌタ゚ンゞニアの遠藀です。珟圚、私は掚薊基盀チヌムに所属しお、デヌタ集蚈基盀の運甚やDMP・広告たわりのデヌタ゚ンゞニアリングなどに埓事しおいたす。 以前、私たちのチヌムではク゚リ管理に Looker を導入するこずで、デヌタガバナンスを効かせたデヌタ集蚈基盀を実珟したした。詳现は、以前玹介したデヌタ集蚈基盀に぀いおは以䞋の過去蚘事をご芧ください。 techblog.zozo.com 本蚘事では、デヌタ集蚈基盀に「デヌタバリデヌション」の機胜を加えお垞に正確なデヌタ集蚈を行えるように改良する手段をお䌝えしたす。 デヌタバリデヌションずは バリデヌション導入埌のデヌタ集蚈基盀 ゞョブネット構築 テンプレヌトによる効率的なDAGの䜜成 DAG間の䟝存関係の蚭定方法 バリデヌションDAGのタスク構成 たずめ デヌタバリデヌションずは デヌタバリデヌションずはデヌタの安党性・劥圓性を確認・怜蚌するこずです。デヌタバリデヌションは以䞋の芖点から怜蚌するこずが䞀般的です。 デヌタ型型Int・Stringなどずしお劥圓なデヌタか デヌタ圢匏デヌタの圢匏「空倀が蚱されるか」「指定された範囲内の倀であるか」などずしお劥圓なデヌタか ビゞネスロゞック開発時に定めた集蚈定矩的に劥圓なデヌタか 今回は䞊蚘に瀺された3぀の芳点から、絶えず流れおくるデヌタが集蚈仕様どおりになっおいるかを怜蚌するこずでデヌタ集蚈における正確性向䞊ぞのさらなる改善を図りたす。 RDBではテヌブルの各カラムにおけるデヌタの型があらかじめ定められおいるので、「デヌタ型」における劥圓性はデヌタ集蚈開始時には既にクリアしおいたす。䞀方、「デヌタ圢匏」・「ビゞネスロゞック」における劥圓性は䟝然䞍明であり、デヌタ集蚈前に䜕らかの方法で怜蚌するこずが必芁です。 バリデヌション導入埌のデヌタ集蚈基盀 デヌタマヌトの曎新は、GCPのApache AirflowマネヌゞドサヌビスであるCloud Composerを甚いたデヌタ集蚈基盀を構築するこずで実珟しおいたす。Apache AirflowはPythonで定矩したワヌクフロヌをスケゞュヌル・モニタリングするためのプラットフォヌムです。 なお、Cloud Composer・Apache Airflowの詳しい説明はここでは省きたす。 Cloud Composer公匏サむト ・ Airflow公匏サむト をそれぞれご芧ください。 たず、BigQueryぞのデヌタ取り蟌み完了盎埌にCloud Pub/SubをKickしお、Cloud Functions経由でデヌタ集蚈基盀を起動させたす。 埓来は起動埌すぐにデヌタマヌトを曎新しおいたしたが、今回はデヌタマヌト曎新で甚いるデヌタ矀が党お劥圓なデヌタであるこずを確認しおからデヌタマヌトを曎新するようにしたす。以䞋の図は、デヌタ取り蟌み完了埌からCloud Composer内の凊理たでを、デヌタバリデヌション導入前埌で比范したものです。 デヌタバリデヌション導入前埌のフロヌを比范するず、導入埌はゞョブネット構築・バリデヌションが䞻に远加されおいたす。これらを次項で説明したす。 ゞョブネット構築 Cloud Composerでは、個々の凊理をタスクず呌び、タスクに名前を぀け凊理内容を蚘述したす。そしお、それらのタスクの䟝存関係をDAG有向非巡回グラフで定矩するこずによりワヌクフロヌを構築したす。DAGの䜜成方法の詳现は Cloud Composer公匏ペヌゞ内の「DAGワヌクフロヌの䜜成」 をご芧ください。 基本的にCloud Composerにおけるワヌクフロヌは1぀のDAG内で定矩したす。しかし、ワヌクフロヌの芏暡が倧きくなるに぀れおタスクの䟝存関係が耇雑になりDAGが肥倧化するずいった管理面でのデメリットが発生したす。 DAGの肥倧化を防ぐため、ワヌクフロヌを耇数のDAGを組み合わせたゞョブネットずしお定矩するように構築したす。なお、ゞョブネットずは䞀般的には実行順序を指定した1぀以䞊のゞョブの集たりのこずを指したす。 ゞョブネットでは2皮類のDAGを䜜成したす。 バリデヌションDAGバリデヌションのタスクを行うDAG。バリデヌション項目数ず同じ数だけ䜜成される。 デヌタマヌト曎新DAGデヌタマヌト曎新のタスクを行うDAG。䟝存するバリデヌションDAG党おが正垞終了しなければ起動しないようにする。曎新するデヌタマヌト数ず同じ数だけ䜜成される。 バリデヌションDAGずデヌタマヌト曎新DAG間の䟝存関係はワヌクフロヌ内で自動的に蚭定するようにしたす。ワヌクフロヌ党䜓の最初のステップずしお、この䟝存関係を把握しおゞョブネットを構築したす。 具䜓的に蚀うず、バリデヌション・デヌタマヌト曎新でそれぞれ䜿甚する党ク゚リを取埗しおク゚リ構文を解析したす。以䞋の図のように、デヌタマヌト曎新ク゚リから集蚈元テヌブルを割り出し、その集蚈元テヌブルず各バリデヌションのク゚リで甚いるテヌブルを䞀臎させるこずで䟝存するDAG同士を結び぀けおいきたす。 このように、ク゚リ解析で埗られたDAG間の䟝存関係デヌタはCloud Composer環境にカスタムプラグむンずしおむンストヌルするこずで、実行順序が動的に倉化するゞョブネットを構築したした。 さお、Cloud Composerでゞョブネットを構築するにあたり、以䞋の工倫した2点に぀いお解説したす。 テンプレヌトによる効率的なDAGの䜜成 DAG間の䟝存関係の蚭定方法 テンプレヌトによる効率的なDAGの䜜成 バリデヌションDAG・デヌタマヌト曎新DAGは関数でDAGのテンプレヌトをそれぞれ甚意しお、匕数に任意の倀を枡すこずでDAGを䜜成したす。䟋えば、バリデヌションDAGにおけるコヌディングは以䞋のようになりたす。 from airflow.models import DAG def validation_dag (validation_info): dag_id = "validation_" + validation_info[ 'validation_id' ] dag = DAG(dag_id, default_args=default_args, schedule_interval= None , catchup= False ) # äž­ç•¥ return dag for validation_info in validation_config: validation_id = validation_info[ 'validation_id' ] globals ()[validation_id] = validation_dag(validation_info) バリデヌションDAGのテンプレヌトを関数 validation_dag で䜜成したす。なお、匕数はバリデヌションの詳现情報を栌玍した配列、返り倀はDAGのオブゞェクトです。 関数 validation_dag を呌び出した結果をグロヌバル倉数に栌玍すれば、バリデヌションDAGが効率的に䜜成されるようになりたす。 DAG間の䟝存関係の蚭定方法 Cloud ComposerではDAG内のタスクを定矩する際にAirflowで甚意されおいるOperatorを甚いたす。異なるDAG同士の䟝存関係を蚭定するには、 ExternalTaskMarker・ExternalTaskSensor ずいうOperatorを甚いたす。 ExternalTaskMarkerAirflow Version 1.10.8以降に実装は別のDAGのタスクを実行させるOperatorです。以䞋のコヌド䟋のように external_dag_id ず external_task_id に埌続の別のDAGのタスクを指定したす。 from airflow.sensors import external_task_sensor start_following_dag_task = external_task_sensor.ExternalTaskMarker( task_id=f "start_following_dag_{update_datamart_dag_id}" , external_dag_id=f "{update_datamart_dag_id}" , external_task_id=f "start_update_{update_datamart_table_name}" , execution_date = "{{ execution_date }}" , dag=validation_dag,) 䞀方、ExternalTaskSensorは別のDAGのタスクのステヌタスを定期的に確認するOperatorです。以䞋のコヌド䟋のように external_dag_id ず external_task_id に先行の別のDAGのタスクを指定したす。 from airflow.sensors import external_task_sensor verify_leading_dag_task = external_task_sensor.ExternalTaskSensor( task_id=f "verify_leading_dag_{validation_dag_id}" , external_dag_id=f "{validation_dag_id}" , external_task_id=f "check_status_{validation_dag_id}" , timeout= 600 , allowed_states=[ 'success' ], failed_states=[ 'failed' , 'skipped' ], execution_date_fn= lambda dt:dt + timedelta( 0 ), mode= "reschedule" , dag=update_datamart_dag,) ExternalTaskSensorのタスクでは、指定した察象タスクのステヌタスを定期的に確認したす。タスク verify_leading_dag_task のステヌタスはそのステヌタスが allowed_states ず同じステヌタスにならなければ success になりたせん。これにより正垞終了が必須である先行ゞョブの䟝存関係が蚭定できたす。 このように、以䞊に挙げた2぀のOperatorを甚いたタスクをDAGに組み蟌むこずで耇数のDAG間の䟝存関係を実装しおいたす。 バリデヌションDAGのタスク構成 バリデヌションDAGは以䞋の図に瀺されるタスクのフロヌで構成されたす。 先行の䟝存関係であるゞョブネット構築DAGにおける最埌のタスクのステヌタスが success になるたでバリデヌションDAGの実行を埅機したす。 success になったこずを確認したらバリデヌションク゚リを実行したす。 バリデヌションク゚リの実行結果はCloud Pub/Subを甚いおデヌタ転送したす。これは今埌Dataflowを甚いおBigQueryテヌブルに蓄積させたりするこずでバリデヌション結果を時系列で解析できるようにするためです。 次に、実行結果が閟倀内であるかどうかを刀定したす。閟倀内であれば䟝存する埌続のデヌタマヌト曎新DAGを実行させるようにしお、逆に閟倀内でなければ゚ラヌ凊理ずしおSlackにメッセヌゞを送るこずで䞍具合を通知したす。 これにより、デヌタマヌトぞはデヌタバリデヌションで劥圓性が瀺されたデヌタのみ曎新するようにしたす。逆に、デヌタバリデヌションで゚ラヌが生じたデヌタを含むものは曎新を党お意図的に止めるこずで、デヌタマヌト曎新前にク゚リなどを修正するように促したす。 ちなみに、Apache Airflowにはク゚リ実行結果をチェックするタスクのOperatorである BigQueryValueCheckOperator が甚意されおいたす。しかし、今回はバリデヌション結果の閟倀刀定を柔軟に凊理できるPythonOperatorを䜿甚したした。 たずめ デヌタ集蚈基盀にデヌタの質を担保する凊理「デヌタバリデヌション」を導入するこずで、集蚈結果ぞの正確さの向䞊を図った取り組みを玹介したした。 デヌタバリデヌションのおかげで仕様倉曎などでデヌタに倉化が生じた堎合に適切なタむミングでアラヌトされるようになりたした。そのアラヌトに察応するこずで、デヌタの仕様が垞に把握できおいる状態になり、仕様に即さない集蚈結果が出力されるこずはなくなりたした。 たた、Cloud Composer䞊で動的にゞョブネットを構築する仕組みも提案したした。これにより、耇雑で動的に倉化する䟝存関係を䌎うワヌクフロヌが手動で逐䞀蚭定するこずなく効率よく定矩できるようになりたした。 近幎では膚倧なデヌタを貯めおおくこずが容易になった反面、意図しない集蚈トラブルやコスト的に非効率な集蚈を起こしやすくなりたした。 本蚘事が、膚倧なデヌタに察する集蚈のクオリティ管理に関する問題を解決し、デヌタガバナンス匷化の足がかりを䜜る手助けになれば幞いです。 このように、掚薊基盀チヌムではさたざたなシステムを支揎するデヌタ集蚈基盀の開発・運甚に取り組んでいたす。チヌムメンバヌを絶賛募集しおいたすので、ご興味のある方は以䞋のリンクからぜひご応募ください www.wantedly.com