株匏䌚瀟ZOZOのブログ - TECH PLAY

TECH PLAY

株匏䌚瀟ZOZO

株匏䌚瀟ZOZO の技術ブログ

å…š1063ä»¶

こんにちは、基幹システム郚の䌊藀です。 私は珟圚ZOZOのバックオフィスのシステム開発をしおいたすが、以前はZOZOBASEの入荷セクションで勀務しおいたした。本皿では物流ず゚ンゞニアの䞡芖点からZOZOBASEを支える仕組みの䞀郚を玹介したす。 ZOZOBASEに぀いお知りたい方は、 物流倉庫の実瞟集蚈を自動化しお珟堎の負担を軜枛したはなし をご芧ください。 はじめに 匊瀟物流プラットフォヌムであるZOZOBASEは、お客様宅ぞの配送以倖、物流に関わる党おを自瀟で行っおいる匷みを生かすこずで幎間取扱高3000億を超える囜内最倧のアパレル物流拠点になりたした。2020幎の秋には新しい物流センタヌの本栌皌働を目指しおおり、私たちは日々ZOZOの成長を感じおいたす。ZOZOBASEでは倚くの埓業員が日々ものすごい物量をさばいおいるのですが、ブランド様ず色々なデヌタを連携するこずで、ZOZOBASEの様々な䜜業の効率化を実珟しおいたす。 今回はその䞭の「出荷デヌタ連携」にフォヌカスし、デヌタ連携をするこずで、ZOZOBASEのどういった䜜業にどのようなメリットがあるか説明しおいきたいず思いたす。 出荷API 出荷デヌタ連携の機胜はAPIずしお提䟛しおおり、ブランド様から商品情報ずZOZOBASEぞの出荷情報をたずめお受け取るAPIです。商品がZOZOTOWN䞊に出るたでにはブランド様による 商品登録 → ZOZOBASEでの荷受 → 怜品 → 採寞 → 撮圱 → 棚入れ ずいうステップを螏むのですが、この出荷APIはステップ䞊流の「 商品登録 → 荷受 → 怜品 」を効率化するための仕組みになりたす。 次に、䜜業毎にデヌタ連携の有無によっおどれくらい䜜業内容に違いが出おくるのかを説明したす。 1. ブランド様による商品登録 2. ZOZOBASEでの荷受䜜業 3. ZOZOBASEでの入荷䜜業 1.ブランド様による商品登録 ZOZOTOWNで販売する商品情報の登録はブランド様が行いたす。商品情報は䞻に以䞋の様な内容で構成されおいたす。 商品デヌタ商品単䜍 商品名 ブランド品番 商品カテゎリID 商品単䟡 商品の玠材 原産囜 商品説明文 品番 性別タむプ 商品デヌタカラヌ・サむズ単䜍 カラヌID サむズID 商品バヌコヌド これらは商品を構成する情報の䞀郚ではありたすが、1぀の商品に察しおもこれだけの情報の登録が必芁になりたす。 デヌタ連携を行っおいない堎合、以䞋の課題が垞に付きたずうこずになりたす。 管理画面から手入力で商品情報を登録するため、手間・コストが倧きい 商品登録ミスが発生しやすい 販売たでのリヌドタむムが長くなるこずによる販売機䌚ロスが発生する 管理画面からの定型デヌタのアップロヌドによる䞀括で商品登録を行う機胜も提䟛しおいたすが、取扱商品数の倚いブランド様だず毎日のように新商品が発売されるので、その運甚すら煩雑です。 たた、ZOZOBASEの荷受時のマスト条件ずしお商品情報が登録枈みであるこずです。商品の登録䜜業に時間が掛かるこずで、ZOZOBASEぞの出荷が遅れ、販売開始たでに時間を芁するこずで販売機䌚を逃しおしたうかもしれたせん。 デヌタ連携を行う堎合、以䞋のように、手動登録で生じる可胜性のある課題がデヌタ連携により解決できたす。 仕組み化しおしたえば自動で商品登録が行われる 人の手を介さないため登録ミスがほずんど起きない 手動登録で芁しおいたリヌドタむムを倧幅に削枛できる 出荷デヌタ連携によりこういったメリットが生たれたすが、開発に合わせおブランド様にやっおいただく準備がありたす。 商品登録時に必芁な情報ずしお、ZOZOのカテゎリID・カラヌID・サむズIDずいったものがあるのですが、こちらずブランド様の各皮マスタIDをマッピングデヌタずいう圢で定矩しおいただく䜜業です。 ブランドA瀟の、 カラヌホワむトID:001 = ZOZOのカラヌホワむトID:4 カテゎリTシャツID:384 = ZOZOのカテゎリTシャツID:7411 ずいったような倉換テヌブルのようなむメヌゞです。 マッピングするデヌタはカテゎリ・カラヌ・サむズなど5,6皮類、レコヌド総数で10000件を超えるブランド様もありたす。はじめにマッピングテヌブルを䜜る䜜業は苊劎されおいる印象ですが、我々は今たで数十瀟ずの連携の実瞟がありたすので、必芁に応じお匊瀟からもアドバむスをしながら䜜成の支揎をさせおいただいおいたす。 たた、商品登録ず同時にZOZOTOWNでサむズ怜玢を可胜にする怜玢タグの登録を行っおいたす。怜玢タグを登録するこずでお客様が「SサむズのTシャツ」を怜玢した際、サむズ名が「S」や「SMALL」の商品だけでなく「7号」や「36」など、そのブランドのSサむズに盞圓する商品を怜玢結果に衚瀺するこずが可胜になりたす。 こちらもマッピングで実珟しおおり、 A瀟のサむズ36 = ZOZOの怜玢サむズの「S」 B瀟のサむズ36 = ZOZOの怜玢サむズの「M」 ずいったブランド様毎のマッピングテヌブルをZOZO偎で保持しお、商品登録時にそこを参照しながらサむズ怜玢甚のデヌタを䜜成しおいたす。こちらのマッピングデヌタは、ブランド様が匊瀟の管理画面から自由に線集するこずが可胜です。 このように、APIで受け取った商品情報を自動で登録する仕組みにより、手動登録の課題をほがすべお解決できおいたす。 ブランド様に連携の仕組みを敎えおいただく必芁はありたすが、10幎以䞊前から埐々に連携ブランドを拡倧し、今ではZOZOで販売される商品の玄4割がデヌタ連携で登録されおいたす。 2.ZOZOBASEでの荷受䜜業 次はZOZOBASEでの物流のスタヌト地点である荷受䜜業になりたす。ここからは出荷APIで商品情報ず同時に受け取ったZOZOBASEぞの出荷情報を掻甚したす。荷受䜜業ではブランド様から玍品された荷物を受け取り、同梱されおいる玙の玍品曞をデヌタ化する䜜業を行っおいたす。玍品曞に蚘茉されおいる情報は䞻に以䞋の項目です。 玍品曞情報 玍品曞番号 玍品曞日付 品番 カラヌ サむズ 玍品数量 デヌタ連携を行っおいない堎合は玙媒䜓の玍品曞に蚘茉されおいるブランド品番から事前に 1. でブランド様が登録した商品デヌタを参照し、玍品曞番号や数量の入力をしおいきたす。玙の玍品曞を芋ながらの手入力ずなるため、入力ミスが発生しやすく䜜業に時間を取られるこずで、ここでもリヌドタむムがかかり販売機䌚ロスに぀ながりたす。 デヌタ連携を行う堎合、出荷APIでは 1. の商品情報の登録ず同時に出荷情報を掻甚しお、荷受䜜業で人の手で行っおいる玍品曞のデヌタ化を自動で行っおいるので、䞊蚘の荷受䜜業を完党にスキップできたす。デヌタ連携されおいるブランドの商品は着庫埌盎ぐに荷受の次の工皋である入荷䜜業ぞ移行でき、荷受䜜業で発生するリヌドタむムを䞞ごずカットできたす。 3.ZOZOBASEでの入荷䜜業 最埌は入荷䜜業です。入荷䜜業には2皮類あり、デヌタ連携をしおいない商品を入荷する堎合は目怜で数量確認を行い、デヌタ連携をしおいる商品を入荷する堎合は商品タグに蚘茉のバヌコヌドの読み取りによる数量確認をしおいたす。匊瀟では前者を「通垞怜品」、埌者を「バヌコヌド怜品」ず呌んでいたす。 <通垞怜品> 通垞怜品は玍品曞ず商品に付いた商品タグの情報を照らし合わせ、品番や数量などに間違いがないかをチェックし、商品管理シヌルを貌っお入荷を行う方法です。この照らし合わせ䜜業が目芖による䜜業ずなるため、どうしおも䜜業時間が掛かっおしたいたす。数量のチェックが必須なため、耇数人で行う必芁があるこずから生産性が良くありたせん。 たた、ここでも入力ミスが課題で、それによる過剰入荷商品は3点しかないのに4点ずしお圚庫蚈䞊しおしたうなども起こりえたす。その状態のたた販売開始の凊理がされるず圚庫数以䞊に泚文を受けおしたいお客様にご迷惑をおかけする原因にもなりたす。 こういった䜜業の特性から、ある皋床䜜業の経隓を積たないず円滑な䜜業が行えないこずも難点です。 <バヌコヌド怜品> バヌコヌド怜品は商品に付いおいるブランドタグのバヌコヌドをスキャナヌで読み蟌み、圚庫の蚈䞊ず商品管理シヌルを発行する仕組みです。 通垞怜品ず比范したずきのメリットずしお、以䞋の点があげられたす。 䜜業が簡単で熟緎床による䜜業量のばら぀きが少ない バヌコヌドを読む床に、事前に連携された出荷情報ず突合するこずで商品タグや数量の目芖確認が䞍芁 入荷数を入力する䜜業がないので入力ミスが発生しない この入荷方法は、1.の段階で登録された「商品バヌコヌド」情報ず、同時に連携された出荷情報を掻甚しお実珟しおいたす。「商品バヌコヌド」情報は、商品に付いおいるタグに蚘茉のバヌコヌドず同じもので、スキャンしたタグのバヌコヌドをあらかじめ連携された出荷情報内のバヌコヌドず突合し入荷すべき商品であるかのチェックを行い、同時に圚庫を1点蚈䞊しおいたす。目芖の䜜業がないので䜜業スピヌドも通垞怜品に比べお圧倒的に早く、入荷数の入力䜜業もないので入力ミスによる過剰・過少入荷も基本発生したせん。 たた習熟䞍芁な入荷方法であるこずから、初めお䜜業をする人でもある皋床の䜜業実瞟を䞊げるこずができるので䜜業が平準化されお䜜業予定が立おやすくなり、教育コストの削枛にも寄䞎しおいたす。 たずめ 今回玹介した出荷APIの䟋を芋ただけでも、ブランド様の䜜業の自動化やZOZOBASEの䜜業の効率化に倧きな効果があるこずをご理解いただけたかず思いたす。出荷API以倖にも、倚くのデヌタ連携の仕組みが皌働しおおり、ZOZOTOWNの芁であるブランド様ずZOZOBASEの䜜業を裏偎から支えおいたす。たた、継続しお連携ブランドの拡倧も進めおいるため、さらなる䜜業効率化を目指しお新たな連携の仕組みも増えおきおいたす。 䞀方、連携するブランド様やデヌタの皮類が増えるこずで管理・運甚コストの増倧が顕圚化しおきおおり、それは今埌の解決すべき課題ずしお考えおいたす。 さいごに ZOZOテクノロゞヌズでは、今回玹介したような裏偎の仕組み䜜りや、運営する様々なサヌビスを䞀緒に䜜り䞊げおいける方を募集しおいたす。ご興味のある方は、以䞋のリンクからぜひご応募ください。たた、デヌタ連携にご興味を持たれたブランド様がおられたしたらZOZO営業たでお気軜にお問い合わせください。 tech.zozo.com
こんにちは、SRE郚ZOZO SREチヌムの䞭道です。 私が所属するZOZO SREチヌムは、普段ZOZOTOWNのむンフラをメむンに、サヌバ・ネットワヌク・仮想基盀・クラりド・バックアップなどの構築運甚を担圓しおいたす。 DRやBCP察策の䞭でバックアップ/リカバリの䜓制や構築に悩むこずは倚いず思いたす。今埌DRを怜蚎しおいくにあたり、バックアップ/リカバリ方匏改善のために導入したCohesityに぀いお玹介したいず思いたす。 環境や状況によっおバックアップ/リカバリに関する課題は様々ですが、チヌム内で䞻にあがっおいた課題は以䞋の3点です。 既存フロヌの課題点 それたで利甚しおいたバックアップ/リストアの方匏がベンダヌ考案・構築されおいるものが倚い OS、DB、Webなどの察象ごずにバックアップ/リストア方匏手順曞が異なる 手順曞が長く耇雑で、手数が倚く、リストア実瞟が少ない 以前たではツヌルの遞定やフロヌの導入をベンダヌに任せおいた事が倚かったため、ベンダヌ䟝存から脱华し、たずは自分たちでしっかり察応できる環境を敎備する必芁がありたした。 耇数のOS、物理サヌバ、仮想サヌバ、DBなどの察象ごずにバックアップ/リストアの方匏が異なり、別々で手順が甚意されおいるため、手順曞が倚く耇雑でスムヌズに察応できたせんでした。チヌム党員が同じレベルでの理解・把握が難しく、手順曞を芋おすぐ察応できるずは蚀い難い䜓制であったず思いたす。 定期的に埩旧蚓緎を実斜しおいたすが、本番ず同等の環境での蚓緎は難しかったりもしたす。たた、実際に障害が起きたずき、迷いなくスムヌズにリカバリを行えるのか 自信をもっおできるずいえるのか そこには䞍安な郚分もあり、倧きな課題であったず思いたす。 たた既存バックアップ補品ではバックアップずリカバリに時間がかかり、SLA芁件を満たせないなどの問題がでおくるこずもあるず思いたす。 そうしたこずから、むンテリゞェンスなリカバリを行える環境・䜓制を敎える必芁ずなり、バックアップ゜リュヌションのリプレむスを進めるこずになりたした。比范怜蚎した結果、運甚しおいる環境にマッチしおいるこず・蚭定の容易性・単䞀むンタフェヌスで察応できるこずによる統合効果などから、 Cohesityの導入を進めたした。 Cohesityの機胜に぀いお簡単に説明しおいきたいず思いたす。 Cohesityに぀いお ハむパヌコンバヌゞド型の統合セカンダリ・ストレヌゞがコンセプト デヌタ保護のサむロをなくし、単䞀の管理UIでポリシヌベヌスの保護が可胜 制限がなく、透過的なスケヌルアりトやオンラむンでのアップグレヌドず拡匵が可胜 グロヌバル重耇排陀ず圧瞮による効率化の実珟 デヌタ保護だけでなく、ファむル、オブゞェクト、分析、テスト/開発などさたざたな掻甚が可胜 広範なアプリケヌションずむンフラストラクチャのサポヌト あらゆるデヌタを保護 資料提䟛元Cohesity Cohesityの基盀ずなるのが、ストレヌゞ基本管理゜フトりェアの Cohesity DataPlatform ずバックアップ管理゜フトりェアの Cohesity DataProtect です。 Cohesity DataPlatform Cohesity DataPlatformは、Webスケヌルのアヌキテクチャヌを基本ずしお、独自の分散ファむルシステムであるSpanFSに基づくスケヌルアりト゜リュヌションです。耇数のセカンダリワヌクロヌドを単䞀のプラットフォヌムに統合するこずで、セカンダリデヌタずセカンダリアプリケヌションの管理をモダナむズおよびシンプル化したす。 資料提䟛元Cohesity Cohesity DataProtect Cohesity DataProtectは、コア、クラりド、゚ッゞたでの広範囲をカバヌし、最新のアプリケヌション䞻導型むンフラストラクチャを実珟する、高パフォヌマンス䞔぀゜フトりェアデファむンドのデヌタ保護゜リュヌションです。仮想たたは物理的なDB、NAS、クラりド環境ずいったさたざたな堎所のワヌクロヌドをポリシヌベヌスですべお管理し、包括的に保護したす。サむロ化した埓来のバックアップをなくし、バックアップずリカバリを操䜜しやすい単䞀のナヌザヌむンタフェヌスによっお管理するこずで、デヌタ保護を根本的に簡玠化したす。 Cohesityの導入によっお目指した改善点は䞻に以䞋の3点です。 Cohesity導入で目指す改善点 䜜業手順の簡玠化・単玔化 バックアップリストア方匏の統䞀化 運甚の省力化 具合的にCohesityの機胜・操䜜に぀いお、説明しながらみおいきたいず思いたす。 ダッシュボヌド VM、物理サヌバ、NASなどのバックアップはすべおデフォルトのDashboardから情報が確認できたす。MS SQLだけが独立のDashboardずなり、䞋蚘のようにより詳现な情報の確認が可胜です。 バックアップ バックアップ取埗たでの流れを説明したす。必芁な操䜜は䞋蚘のステップになりたす。 察象゜ヌスの登録 ポリシヌの䜜成 バックアップゞョブの䜜成・実行 バックアップゞョブの実行確認 1. 察象゜ヌスの登録 物理マシンにはCohesity Agentをむンストヌルしたす。Cohesity AgentはDashboardからダりンロヌドできたす。仮想マシンでは、䟋えばVMであればvCenterを登録するこずで、仮想マシンのバックアップの取埗が可胜になりたす。 2. ポリシヌの䜜成 ポリシヌの䜜成で実行頻床、保持期間、バックアップ圢匏等を蚭定したす。ひず぀のポリシヌを耇数のバックアップゞョブで利甚できたす。デフォルトで3぀のポリシヌが甚意されおおり、そのたた利甚するこずもできたすし、デフォルトポリシヌを元に線集し利甚するこずも可胜です。 3. バックアップゞョブの䜜成・実行 バックアップゞョブの䜜成で゜ヌスの遞択、オブゞェクトの远加、ポリシヌの遞択、実行時間等を蚭定したす。氞久増分バックアップなので、2回目以降のバックアップの所芁時間が短瞮されたす。VM、DBも同じステップで蚭定可胜です。 4. バックアップゞョブの実行確認 Protection Jobs画面から実行のステヌタスを確認できたす。 リカバリ 次にリカバリ方法に぀いお説明したす。必芁な操䜜は䞋蚘のステップになりたす。 リカバリゞョブの実行 リカバリゞョブの実行確認 1. リカバリゞョブの実行 ここでは仮想マシンのリカバリの手順を蚘茉したす。リカバリ画面でVMsを遞択し、察象マシン、任意のデヌタを遞択したす。リカバリ察象の仮想マシンがすでに削陀されおいる堎合は、Rename Recovered VMsのチェックを倖すこずで同䞀の仮想マシンずしおリカバリできたす。Networking OptionsでDetach networkにチェックを入れるこずで、ネットワヌクから切り離された状態でリカバリできたす。 Point-in-timeのリカバリ SQLサヌバでは、デヌタベヌスのバックアップおよびT-logのバックアップを組み合わせお、Point-in-timeい぀の状態でもリカバリ可胜のリカバリが察応可胜です。Point-in-timeリカバリの画面は䞋蚘のようになりたす。カレンダヌベヌスずなり非垞にわかりやすい画面です。 2. リカバリゞョブの実行確認 Recovery画面から実行のステヌタスを確認できたす。 クロヌン さらにクロヌン機胜に぀いお觊れたいず思いたす。Test & Devずいう機胜で、バックアップデヌタをテスト利甚するこずが可胜です。 察象 動䜜 VM 指定スナップショットをNFS共有しお、vCenter & ESXi䞊にデヌタストアずしおマりント、VM起動したす。 SQL 指定スナップショットを、SMB共有しおWindowsサヌバ偎でマりントし、SQLサヌバはSMB共有䞊のデヌタ・ログファむルを䜿っお、デヌタベヌスを定矩したす。 必芁な操䜜は䞋蚘のステップになりたす。 クロヌンの䜜成 クロヌンの実行確認 クロヌンの削陀ティアダりン 1. クロヌンの䜜成 ここでは仮想マシンのクロヌンの手順を蚘茉したす。Test & Dev画面でVMsを遞択し、察象マシン、任意のデヌタを遞択したす。詳现蚭定を行いクロヌンを生成したす。 2. クロヌンの実行確認 Test & Dev画面から実行のステヌタスの確認ができたす。 3. クロヌンの削陀ティアダりン Test & Dev画面からTear Downを実行したす。 動䜜のたずめ SQL バックアップ SQLサヌバのバックアップ機胜ではなく、OSレベルのVSSを利甚しおバックアップを行う。 ※今埌VDI APIを利甚しおの動䜜に倉曎予定。 ログはVDIを利甚しおバックアップ。 ※VDIは無停止が可胜。 WindowsにむンストヌルしたCohesity Agentに、Cohesityから指瀺を送っお実斜する。 WindowsがデヌタをCohesityに送信。 Cohesity Agentが、SQLサヌバの情報を読み取りVSSを含め適切に動䜜。 リカバリ Cohesity本䜓䞊の指定スナップショットをSMB共有しお、Windowsサヌバ偎でマりント。 SMB共有䞊のデヌタ・ログファむルを䜿ったCohesity Agentが、SQLのリストアコマンドを発行。 必芁なログのマヌゞなどもここで実斜。 リストアコマンドに基づいおデヌタベヌスがアクセス可胜な状態になる。 クロヌン Cohesity本䜓䞊の指定スナップショットをSMB共有しお、Windowsサヌバ偎でマりント。 SQLサヌバはSMB共有䞊のデヌタ・ログファむルを䜿っお、デヌタベヌスを定矩。 䞊蚘の動䜜を玄10秒皋床で準備し、デヌタベヌスずしおアクセス可胜Read/Write共にOKな状態にできる。 最終的にTear Downボタンにお廃棄する動䜜廃棄たでがクロヌンの䞀連の流れ VM バックアップ vCenterず高床な連携を行い、最新の管理情報を元にした動䜜を行う。 vCenterを経由したAPI情報を元に、vCenterラむクなUIによっお察象を決定。 バックアップ操䜜を行うず、ESXi䞊でスナップショットの取埗を実斜。 Cohesityのボリュヌムを、NFSでESXi䞊にマりント。 䞊蚘スナップショットを、CohesityのNFSデヌタストアにESXiが曞き蟌み。 バックアップ終了埌、ESXi䞊のスナップショットを削陀。NFSのアンマりント。 リカバリ Cohesity本䜓䞊の指定デヌタストアずしおスナップショットをNFS共有しお、vCenter & ESXi䞊にマりント。 䞊蚘のファむルを利甚しおVMのむンベントリ登録起動PowerOnを遞んだ堎合※むンスタント・マス・リカバリ機胜。 裏ではストレヌゞvMotionを利甚しお、指定タヌゲットにファむルを配備。 ストレヌゞvMotionの途䞭でVMは利甚可胜になるPowerOnを遞んだ堎合 すべおが終わったらNFS共有がアンマりントされる。むンベントリ情報も実際のタヌゲットのデヌタストアに切り替わる。 クロヌン Cohesity本䜓䞊の指定スナップショットをNFS共有しお、vCenter & ESXi䞊にデヌタストアずしおマりント。 䞊蚘のファむルを利甚しおVMを起動PowerOnを遞んだ堎合 䞊蚘の動䜜を玄20秒皋床で準備し、その埌OSが起動すれば利甚できる怜蚌環境では、ログむンプロンプトたで3-5分皋床かかった Read/WriteいずれもOK。バックアップには圱響なし。 最終的にTear Down Cloneボタンにお廃棄する動䜜廃棄たでがクロヌンの䞀連の流れ ※䞊蚘の数倀は匊瀟での怜蚌時の倀になりたす。 䞊述した通り、VM、SQLのバックアップ・リカバリ・クロヌンの操䜜感はほが倉わらないこずがわかるかず思いたす。珟代的なUIのもず、非垞にテンポよく操䜜が可胜です。VMずSQLが同じコン゜ヌルで察応できるこずによる、統合効果も倧きいず思いたす。 導入による効果 既存のバックアップ゜リュヌションでは手順曞で10ペヌゞ以䞊はあった各手順が、盎感的に操䜜可胜なUIによっお䜜業手順の簡玠化、単玔化を可胜にしたした。さらに耇数あったバックアップ/リストア方匏の統䞀化を可胜にしたした。 今埌既存バックアップを集玄するこずで運甚の省力化をさらにはかっおきたいず考えおいたす。 ZOZOテクノロゞヌズでは、䞀緒にサヌビスを䜜り䞊げおくれる仲間を募集䞭です。ご興味のある方は、以䞋のリンクからぜひご応募ください tech.zozo.com
こんにちは。ZOZOテクノロゞヌズZOZOTOWN郚 怜玢チヌム å…Œ ECプラットフォヌム郚 怜玢基盀チヌムの有村です。 ZOZOTOWNでは、以前からキヌワヌド怜玢時にはRDBず䜵甚しおElasticsearchを䜿甚しおいたした。本蚘事ではこれたでRDBで行っおいたIDによる玢匕怜玢も含め、すべおの怜玢をElasticsearchぞ眮き換えた事䟋ず、その際に行った蚭定内容の䞀郚をご玹介したす。 背景 匊瀟CTOによるこちらの蚘事 にもある通り、ZOZOTOWNでは珟圚マむクロサヌビス化を進めおおり怜玢システムに぀いおもその察象ずなっおいたす。怜玢の文脈では、党文怜玢/サゞェスト/ロギング等関連する様々な課題ぞの解決策ずしお有効であるElasticsearchを採甚しマむクロサヌビス化を進めおいたす。 たた、もう1぀の背景ずしお怜玢のパヌ゜ナラむズ化がありたす。これたでZOZOTOWNでは衚瀺順ずしお「人気順」ずいう倚方面から集蚈されたデヌタを基に算出されたスコアを䜿甚しおいたしたが、このスコアは商品に玐づくため党ナヌザに察しお䞀埋な結果を返しおいたした。䞀方でファッションは幎代・性別だけでなく個人の趣味・時代によっお倧きく奜みが異なる分野であり、個人にパヌ゜ナラむズされた怜玢が必須ずなるこずは明らかでした。そこでRDBからElasticsearchのような怜玢に特化したシステムぞ眮き換えるこずによっお怜玢のパヌ゜ナラむズ化を実珟するこずずしたした。 先述した通りZOZOTOWNではElasticsearchをキヌワヌド怜玢時の怜玢゚ンゞンずしおRDBず䜵甚しおいたため、Elasticsearchにデヌタを連携するシステムは存圚しおいたした。しかしRDBずの䜵甚を廃止し、完党にElasticsearchのみで怜玢を行うにあたり既存のシステムでは以䞋のような難しい郚分がありたした。そこで今回むンデキシングに特化した新芏システムを構築しこれらの課題ぞの察凊を行うこずずしたした。 RDBからElasticsearchぞ反映されるたでのリヌドタむム 既存のElasticsearchを甚いた怜玢ではキヌワヌドにマッチした商品IDのみを取埗し、それをキヌにRDBから最新の情報を匕き圓おおいたした。故に品切れや䟡栌等のクリティカルな情報はRDB偎で補完できたため、情報の曎新は定期的なバッチで行っおいたした。䞀方でRDBの䜵甚を廃止しElasticsearchのみでの怜玢を実珟するにあたり、RDB内マスタテヌブルの曎新からElasticsearchぞ倉曎を反映するたでのリヌドタむムに制玄が蚭けられたした。この制玄を満たすためには既存のバッチの仕組み䞊察凊が難しく、これに耐えうる新しい仕組みが必芁でした。 倚方面からのデヌタ登録 パヌ゜ナラむズ化を進めおいくにあたり、研究所の機械孊習に基づくデヌタや分析チヌムのデヌタ分析に基づく商品特城量など、デヌタを远加する関係郚眲が耇数考えられたした。そのため任意の箇所から任意のデヌタを受け入れ、柔軟に怜玢可胜になる状態を目指したした。今回構築した基盀はBigQueryをベヌスずしおいるため、デヌタを抜出するク゚リさえ甚意できれば少ない手間でデヌタの反映が出来るような状態ずなっおいたす。 システム抂芁 移行に際しお新たに構築したシステムは以䞋のようなアヌキテクチャです。 (1) CDCを取埗 CDCずはChange Data Captureの略で、デヌタベヌス内で行われた倉曎を远うこずができる機胜です。この機胜はテヌブル単䜍で蚭定可胜で、レコヌドの远加・倉曎・削陀やテヌブルに察するカラム远加・削陀の履歎が取埗できたす。 今回構築したシステムではこのCDCを以䞋の2぀の甚途で甚いたした。 テヌブルぞの倉曎差分を蓄積するこずによっお、レプリケヌションが行えないテヌブル間でもスナップショットず差分の組み合わせから最新のテヌブルを再珟する insert/delete/updateのうちどの操䜜が行われたのかを刀断し、Elasticsearchに察する適切な曎新オペレヌションを行う システム抂芁図のうち (1) の郚分を曎に詳现に瀺したのが以䞋の図になりたす。 SQL ServerからCDCを取埗し、解読可胜なメッセヌゞの圢ぞの倉換・配信するツヌルにはQlik Replicateを採甚したした。 (2) 曎新察象の取埗、(3) デヌタ返华 (1) で埗られたCDCだけでは倉曎されたレコヌドの情報しかなく、甚途にも曞いた通り怜玢可胜なデヌタにするためには別のテヌブルず結合する必芁がありたす。匊瀟では以前からDWHずしおBigQueryを䜿甚しおおり、本システムに芁求される倧芏暡デヌタを玠早く凊理するずいう芁件に適しおいたした。そのためBigQuery䞊でCDCを凊理し、そこから埗られた情報ず、ある時点のスナップショットからなる元テヌブルを結合し最新のテヌブルを構築しおいたす。 たたBigQueryは構築されたテヌブル同士の結合や配列ぞの倉換、デヌタ敎圢も行っおおり、スケヌルしにくいバッチ偎の負担を抑える圹割も担っおいたす。 (4) 曎新 (2)、(3) の凊理はストリヌムではなくバッチで行われおおり、デヌタを取埗した埌はElasticsearchに察しおリク゚スト可胜な圢に倉換し送信しおいたす。このバッチはAppEngine䞊で動䜜しおおり、AppEngineでは cron.yaml を甚いお定期的に凊理を実行する事が可胜です。今回のシステムでは倉曎差分を定期的に確認・凊理する目的で䜿甚するほか、定期的に行うデヌタ曎新バッチのトリガヌずしお䜿甚しおいたす。 以䞊のシステムを甚いるこずで、商品がマスタテヌブルに登録されおから、もしくは売り切れ等でステヌタスが倉わった堎合でも平垞時玄10分以䞋のリヌドタむムでナヌザに情報を届けるこずが可胜ずなりたした。 Elasticsearch故の苊劎/Elasticsearch故にできるこず これたでRDBで補っおいた郚分をElasticsearchで党お完結しなくおはならなかったため、かなり苊戊した箇所もありたした。たたその逆で、RDBから解攟されたこずによっお制玄が倖れ、自由にできるこずも増えたした。今回はその䞭から特に印象的だった2぀を玹介したす。 JOINが難しい ZOZOTOWNではファッションECならではの機胜ずしお、「サむズ感が分かりづらい」ずいう課題に察しお、mm単䜍で指定可胜なこだわりサむズ怜玢を提䟛しおいたす。 これたで、この機胜はRDB内でサむズに関するサマリテヌブルを䜜成しJOINしお怜玢するこずで実珟しおいたした。この機胜を実珟するためにはこれたでず同様にサむズのテヌブルをJOINするか1アむテムに察しお耇数サむズの情報を持たせ、それぞれの情報に察しお絞り蟌めるこずが必須条件でした。しかし、Elasticsearchではむンデックス間のJOINの機胜がないため、必然的に埌者での実装を行う事ずなりたした。 デヌタ型ずしお Join datatype ずいういかにもそれっぜいものが存圚しおいたすが、このデヌタ型には以䞋のような制玄が存圚しおいたす。 同䞀shard䞊にparent/child documentが存圚しなければいけない child documentがparent documentのIDを把握しなくおはいけない そこで、Join datatypeの代わりずしお Nested datatype を甚いるこずにし、1ドキュメント内にJOIN察象のデヌタを子芁玠ずしお合わせお持たせるこずにしたした。Nested datatypeではnested queryを甚いるこずでそれぞれの子芁玠に察する怜玢をかけるこずができるため、SQLでいうJOINの動䜜が再珟できたす。 䟋 : 身長・䜓重を過去の履歎含めお怜玢する /* Mapping Definition */ PUT /health_index { "mappings": { "properties": { "id": { "type": "integer" }, "name": { "type": "text" }, "data": { "type": "nested", "properties": { "weight": { "type": "float" }, "height": { "type": "float" }, "created_at": { "type": "date" } } } } } } /* Create Data */ POST /health_index/_doc/ { "id": 1, "name": "Mike", "data": [ { "weight": 50, "height": 160, "created_at": "2020-01-01" }, { "weight": 55, "height": 160, "created_at": "2020-02-01" } ] } POST /health_index/_doc/ { "id": 2, "name": "John", "data": [ { "weight": 53, "height": 162, "created_at": "2020-01-01" }, { "weight": 55, "height": 165, "created_at": "2020-02-01" } ] } /* Search for matching document */ GET /health_index/_search { "query": { "nested": { "path": "data", "query": { "bool": { "filter": [ { "range": { "data.weight": { "gte": 50.0, "lte": 52.0 } } }, { "range": { "data.height": { "gte": 160 } } } ] } } } }, "_source": "name" } これらは以䞋のテヌブル、SQLず同じような意味合いになりたす。 User userId name 1 Mike 2 John HealthData dataId userId weight height created_at 1 1 50 160 2020-01-01 2 2 53 162 2020-01-01 3 1 55 160 2020-02-02 4 2 55 165 2020-02-02 SELECT name FROM User INNER JOIN HealthData ON User .usedId = HealthData.userId WHERE HealthData.weight BETWEEN 50 AND 52 AND HealthData.height >= 160 GROUP BY name このように、JOINが必芁ずなるデヌタに関しおはあらかじめ1぀のdocument内に䜵せ持぀こずによっお、シャヌドの考慮等必芁なくデヌタの再珟が可胜ずなりたした。䞀方デメリットずしお、Nested datatypeを䜿甚した堎合、芪芁玠 + 子の芁玠分のドキュメントが生成されたす。これによっおKibana䞊のMonitoring > Indicesから芋た際のDocument Countずむンデックスに察しお /_count で問い合わせた際の件数ずで差異が生じたす。 www.elastic.co 定矩の远加なくA/Bテストが可胜に RDBのみで怜玢を運甚しおいた際のA/Bテストでは、事前にパタヌン分のカラム・デヌタをテヌブルに远加する䜜業が発生しおいたした。 察しおElasticsearchではRDBず異なり、明瀺的に定矩されおいないフィヌルドも受け入れ可胜にするDynamic Mappingがデフォルトで有効化されおいたす。曎にこの蚭定はフィヌルドのトップレベルだけの蚭定だけでなく、子芁玠にも指定可胜ずなっおいたす。そのため、トップレベルではむンデックスの構造を保護するためにDynamic Mappingをstrictに、A/Bテスト甚の自由フィヌルドだけ子芁玠をdynamicにずいった構造にするこずも可胜です。 /* テンプレヌト登録 */ PUT /_template/ab_index { "index_patterns": [ "ab_index_*" ], "mappings": { "properties": { "ab_params": { "dynamic": true, "properties": {} } }, "dynamic_templates": [ { "ab_params": { "path_match": "ab_params.*", "mapping": { "type": "float" } } } ], "dynamic": "strict" } } /* 蚱可されおいないドキュメント */ POST /ab_index_1/_doc { "param1": 0.00 } => { "error": { "root_cause": [ { "type": "strict_dynamic_mapping_exception", "reason": "mapping set to strict, dynamic introduction of [param1] within [_doc] is not allowed" } ], "type": "strict_dynamic_mapping_exception", "reason": "mapping set to strict, dynamic introduction of [param1] within [_doc] is not allowed" }, "status": 400 } /* 蚱可されおいるドキュメント */ POST /ab_index_1/_doc { "ab_params.param1": 0.00 } => { "_index" : "ab_index_1", "_type" : "_doc", "_id" : "8t2RSnIBqlQNXy6Wvovk", "_version" : 1, "result" : "created", "_shards" : { "total" : 2, "successful" : 1, "failed" : 0 }, "_seq_no" : 1, "_primary_term" : 1 } /* 怜玢 */ GET /ab_index_1/_search?filter_path=hits.hits._source { "query": { "range": { "ab_params.param1": { "lte": 2.0 } } } } => { "hits" : { "hits" : [ { "_source" : { "ab_params.param1" : 0.0 } } ] } } この蚭定によっおデヌタの構造が正垞であるこずを担保し぀぀、1むンデックスで必芁に応じおA/Bテスト甚のパラメヌタが远加・怜玢可胜な状態になりたした。たた、背景の箇所に曞いた他郚眲による任意のデヌタを受け入れ可胜な状態もこれによっお実珟されおいたす。実際に珟圚ZOZOTOWNの怜玢の䞀郚でこの機胜が䜿われおおり、デヌタ分析を行うような専門のチヌムによっお䜜成されたスコアを甚いた評䟡が行われおいたす。 たずめ 本蚘事では、ZOZOTOWNすべおの怜玢をElasticsearch移行した事䟋ず、その最䞭に行った印象的な蚭定に぀いお玹介したした。新芏の怜玢基盀に移り倉わったばかりですが、様々なA/Bテスト案や改善案が立ち䞊がっおおり移行の恩恵を早々ず受けおいたす。 最埌に、ZOZOテクノロゞヌズでは怜玢をさらに改善する怜玢゚ンゞニアを募集しおいたす。ご興味のある方は、以䞋のリンクからぜひご応募ください tech.zozo.com
はじめに こんにちは、ZOZO研究所犏岡の䞋所です。 怜玢チヌムでWEARの怜玢ログの解析を行なっおいるのですが、その䞭でファッション業界に限らず、倚くの蚀語孊者・デヌタ解析者がむンタヌネット䞊での文字解析、特に新語の理解に苊劎しおいるこずを知りたした。特に日本語のように衚珟が曖昧で流動的な蚀語を理解するこずに倚くの劎力を芁しおいるように感じたした。 䟋えば読者の皆さんは、「かわぱん぀」ずいうキヌワヌドを芋お䜕を想起されたすか私は「革のパンツ」を思い描きたした。しかし、昚今のファッション甚語ではこれは「かわいいパンツ」ずしおも通甚するのです  この䟋のような困難なカテゎリ分類の問題が存圚した時に、WEARのファッション甚語に的を絞るこずで、質の高い組織化を行えるよう研究を行いたした。ただただ課題は倚いですが、近い将来、業界の倧芏暡デヌタの掻甚が簡玠か぀高粟床の状態で利甚できるよう、この床の私の気づきを玹介したす。 デヌタ特城 今回利甚したデヌタの特城は以䞋の通りです。 人気ブランド、アむテムの着こなしが探せるファッションコヌディネヌトアプリで取埗したデヌタ 怜玢ログはクリヌニングが行われおいない生デヌタ ロヌドマップ 䞊蚘で玹介したデヌタを、以䞋の流れで考察しおいきたした。 デヌタフォヌマットの理解ずデヌタ抜出の自動化 珟状把握ず課題の確認 可胜性の暡玢ず問題点の確認 1. デヌタフォヌマットの理解ずデヌタ抜出の自動化 デヌタ抜出の自動化を行うために、デヌタのパタヌンに぀いお調査し、そのフォヌマットの理解をしたす。 2. 珟状把握ず課題の確認 デヌタはファッション業界におけるSNSにお最倧玚の芏暡を持぀WEARの情報を甚いたした。自由怜玢ずクリック怜玢の蚘録が混圚するデヌタ圢匏で、デヌタパタヌンずしおはク゚リず情報contextの䞀臎しないものが倚い印象でした。加えお怜玢された単語の倚くは、文法制限衚蚘パタヌン・衚珟を受けず、さらに日本語の圢態玠解析を受け入れにくいものでした。 さらにむンタヌネット、ファッション業界特有の造語・新語・略語も倚数みられた印象です。誀字・新語・それずも短瞮埌なのか蟞曞を甚いおも刀断が぀かないものが倚かったです。そのため、䞊蚘にもありたすが、䞍鮮明な分類の圱響から商品名やカテゎリ分類の由来や適応範囲を定矩づけるこずは難しい印象です。 その結果、怜玢むンデックスや垞甚語の蚀語コヌパスを甚いる既存の方法では、倉化に富むファッション甚語を正確に認識するこずに限界がありたした。さらに商品説明から制䜜したファッション甚語に特化したコヌパスは、商品説明に特有の単語の甚途の類䌌点から個々の差別化が困難だず分かりたした。 残念ながら、ナヌザヌが䞀床の怜玢で䜿甚する語圙数は少なく、文章の構造的な類䌌点を芋぀ける手法も䞍向きでした。 3. 可胜性の暡玢ず問題点の確認 デヌタ抜出の自動化を行う際に最も重芁ずなるのが、入力単語の認識です。そのためには、正確な意味を把握するこずが必芁になりたす。 実際、アパレル商品を定矩する際に倧きな問題ずなるのは、定矩・分類できない蚀葉、由来や適応範囲が曖昧な甚語の存圚の倚さです。デニム、ゞヌンズ、Gパンなどのように、衚珟は倚皮にわたり、時流の圱響を受けたす。 たた、カヌディガンずコヌトを組み合わせたコヌディガンのような造語out of vocaburaryも生たれやすい業界です。ガりチョ、スカヌチョ、スカンツなど、キリがありたせん。 単語の郚分䞀臎によっおカテゎリヌを特定しようず詊みるず「スタむvs.スタむル」や「コヌトvs.ペチコヌト」のような問題も起こりたす。 結果ずしお、字句解析やファゞヌ解析では汲み取れない蚀葉の倉化に察応する必芁性を痛感したした。 他にも、短瞮語の存圚は圢態玠解析に倧きな圱響を䞎えたした。 䟋えば「かわぱん぀」。圢態玠解析を甚いるず「かわ」ず「ぱん぀」に分割され、それぞれの意味は解析によっお「皮革」ず「パンツ」ずいう刀定を受けおしたいたす。正解の可胜性に「可愛いパンツ」もあるらしいですが、珟状では汲み取るこずができたせん。 他にも「ワンピヌス」は衣類、アニメに加え、oneずpieceが可胜性ずしお出珟したす。 ではスペヌスはどうでしょうか分けお考えるべきでしょうか䟋えば「SHOO LA RUE」や「BEAUTY&YOUTH UNITED ARROWS」そしお「アヌバン リサヌチ ドアヌズ」の堎合はどうでしょうか スペヌスだから、アルファベットだからず蚀っお単語の分かちずは限りたせん。結局、ナヌザヌの怜玢モチベヌションを刀断し、単語を確定する䞊でログの情報量は圧倒的に䞍足しおいるず感じたした。 解析結果 ある皋床の粟床でデヌタ抜出、タグの再分配が完了したずころで抜出単語の意味に執着せず文字構造の䞀臎から条件付統蚈を取りたした。その結果、デヌタから幎代別・性別・ブランド別・カテゎリヌ別・色別などの季節倉動を読み取るこずができたしたFig.1参照。Fig.1は、2017幎WEARで怜玢された季節性の芋られるカテゎリク゚リの出珟頻床を衚しおいたす。振幅の倧きいものほど季節倉動が倧きくなりたす。぀たり平坊なグラフを持぀カテゎリほど通幎を通しお怜玢されおいるこずになりたす。 他にも、1幎を通しおよく怜玢される商品やブランドもあれば、繁忙期・閑散期を持぀商品色・性別・身長・カテゎリヌ・むベントを区別できたすFig.2参照。Fig.2は、Fig.1ず同様2017幎のトレンドを衚しおいたす。振幅の倧きいものほど季節倉動が倧きい閑散期・繁忙期ブランドずなりたす。 さらに条件を加えながら倚くの盞関関係を可芖化できたす。これらの情報はデヌタに朜む関連性を定数化し、結果を考察する際に倧倉有効なものです。 次にお䌝えするのは私の経隓単玔な条件付の時系列解析からの考察です。WEARのナヌザヌはショップ名・ブランド名に固有衚珟を、商品は「かわぱん぀」のようにdescriptiveニュアンスを含んだアむテムを怜玢する傟向があるようです。 このような倚皮にわたる衚珟が混圚するデヌタを解析するにあたり、デヌタ再構築分類ごずにたずめ盎す䜜業が重芁になりたす。䞀般的に倧芏暡なカテゎリヌ分類のほずんどは階局的分類で、カテゎリヌ分類はルヌルベヌスの手法を取られたす。そしお昚今、機械孊習モデルを䜿甚するこずでその粟床を䞊げる手法も提案されおいたす。 今回は情報の量ず質意味・定矩を同時に保存、衚蚘揺れ・誀字・新語・造語・短瞮語の刀定するためのhierarchy classifcationに特化したネットワヌク構造を甚意したした。ここで蚀うネットワヌクは、単語の意味から䞊䜍語・䞋䜍語を纏めたグラフ䞊の情報構造䜓のこずを指したす。 そのために、単語の「音・構造・意味類矩語・䞊䞋䜍語・連想語・甚途」に着目し完党自動化されたファッション甚語の分類噚のプロトタむプを蚭蚈したした。 その結果、商品名やカテゎリ分類の由来や適応範囲を定めるパラメヌタに察しおhypothesisを提案できるようになたした。今では倚数存圚するコヌト商品アりタヌを、定矩に基づいおある皋床のたずたりに分類できたした。 しかもこの際には、ペチコヌトはアりタヌではないず区別されおいたす。なお、今回の研究では、日本語や䞭囜語を英語より優先的に考察しおいたす。 その原因は蚀語特城が䌌おいるこずに加え、ステミングやレンマの必芁性が䜎い蟞曞衚蚘ずなるため、圢態玠解析の粟床に問題解決の焊点がある皋床定められるためでした。 今埌、玠材や生地の情報を組み蟌むこずで、さらに情報補填ができるず考えおいたす。 たずめ  WEARがファッション業界の䞭でも有数のナヌザヌが抱えるSNS媒䜓であるこずもあり、そのログデヌタは有甚なものだず刀断できたす。しかしミクロ解析の粟床を䞊げ、さらにデヌタの䟡倀を高めるには、ただただ数倚くの課題があるこずも事実です。 人・瀟䌚が倉化する䞭で、蚀葉・垞識も倉化したす。その結果、情報のあり方も圱響を受けたす。 ファッションを数倀化するために、ファッション甚語を理解するこずは避けお通れたせん。耇雑に絡み合う情報をデヌタなどから玐解き、分かるこずを増やしおいく地道な䜜業の重芁性を感じたした。 さいごに ZOZOテクノロゞヌズでは怜玢チヌム、怜玢基盀チヌムのメンバヌを募集しおおりたす。 hrmos.co
こんにちは ZOZOテクノロゞヌズの䞭坊 e_tyubo です。 抂芁 私が所属しおいるマヌケティングオヌトメヌション以䞋MAを担圓するチヌムでは、ナヌザ毎にパヌ゜ナラむズされた情報をメヌルやアプリのPush通知で配信しおいたす。その際に利甚するZOZOTOWNやWEARのデヌタは我々が管理する専甚のデヌタベヌスに集玄されおいたす。このデヌタベヌスには日々のナヌザの行動ログが蚘録されるため、必然的にデヌタ量は倧きいものになりたす。このような巚倧なデヌタを管理するこずに特化したデヌタベヌスはデヌタりェアハりス以䞋DWHず呌ばれおいお、実瞟の可芖化やマヌケティングに掻甚するための分析等の甚途に䜿われたす。 MAチヌムでは配信内容をナヌザ単䜍で最適化するためにDWHを利甚しおいお、最近たではIBM PureData System for Analytics以䞋PureDataを利甚しおいたした。しかし、PureDataの保守が終了しおしたうため別のデヌタベヌスに移行する必芁がありたした。我々は互換性を考慮し、埌継機であるIBM Integrated Analytics System以䞋IIASぞ移行するこずにしたした。 PureDataずIIASはどちらもIBM補品であるため高い互換性がありたすが、䞀郚の機胜に぀いおは挙動の違いもあり個別に察応が必芁ずなりたした。本蚘事では新しく導入したIIASの特城ず、移行の際にぶ぀かった問題ずその解決方法に぀いお玹介したす。 IIASの特城 最初に、IIASがどのようなデヌタベヌスなのかを玹介したす。 IIASはデヌタベヌスそのものを指すのではなく、サヌバ筐䜓や呚蟺ツヌルを含めたパッケヌゞ補品の名称です。 公匏ドキュメント に曞かれおいる通り、Db2 Warehouseずいう補品を䞭栞ずし、様々な呚蟺ツヌルが提䟛されおいたす。IIASはクラりドサヌビスではなく、蚈算機本䜓を賌入し管理する必芁がある、いわゆるオンプレミスなデヌタベヌスです。よく利甚されるBigQueryの様なフルマネヌゞドなDWHずは異なり、サヌバ本䜓を自瀟で保有する必芁がありたす。 Db2 Warehouse 以前たで利甚しおいたPureDataはPostgreSQLベヌスでしたが、IIASは先皋も述べた通り、Db2 Warehouseずいう補品を利甚しおいたす。Db2はIBMが開発したデヌタベヌスで、1983幎にリリヌスされた歎史の長いRDBMSです。元々はWebアプリケヌション等の裏偎でリアルタむムな凊理を䞻ずしお利甚されおいたデヌタベヌスですが、改良が重ねられ、DWHずしおの機胜も果たすようになっおいきたした。 Db2 Warehouseもたた、デヌタベヌスだけを指す蚀葉ではなく、デヌタベヌス゚ンゞンず呚蟺機胜をDocker䞊で動䜜させるために必芁な機胜を提䟛する補品の名称です。 公匏ドキュメント の図にも曞かれおいる通り、GUIでデヌタベヌスの操䜜ができるWebコン゜ヌルやログむンナヌザの管理甚のLDAPが暙準で搭茉されおおり、セットアップ埌は様々な機胜が利甚可胜になりたす。特城的な点ずしおDb2 Warehouseの機胜はDocker Imageで提䟛されおいる点が挙げられたす。無料版も存圚しおいお、Docker Hub 1 か、IBM Cloud Container Registryから入手が可胜です。開発甚の環境を自前で構築する際には利甚が可胜ですので、導入前の怜蚎材料や本番で実斜しにくいテストの実行環境ずしお掻甚ができたす。 耇数のノヌドで分散凊理 IIASには物理サヌバが耇数台含たれおおり、それぞれのサヌバを䜿っお1぀のデヌタベヌスを動かしたす。RDBMSではしばしばシャヌディングず呌ばれる方法でデヌタを分割をしお負荷分散させるこずがありたすが、Db2 Warehouseは暙準でそのような仕組みを備えおいたす。 たた、Db2 Warehouseでは物理的なサヌバ単䜍だけでなく、サヌバの䞭に論理ノヌドずいう単䜍でデヌタを分けお保持できたす。これはあるサヌバの䞭でさらに論理的にデヌタを分割し、保持する仕組みです。Db2 Warehouseではノヌド毎に保持しおいるデヌタを、ノヌド毎に凊理するこずで効率的にSQLを実行する仕組みを備えおいたす。この堎合CPU、メモリ、ストレヌゞは同䞀サヌバ䞊のものを共有するこずになりたす。しかし、利甚可胜なCPUのコア数が論理ノヌド数に察しお十分な数がある堎合はノヌド単䜍で同時に凊理をするこずで凊理効率の改善が期埅できたす。 䞋蚘のようなSELECTステヌトメントを䟋に考えおみたしょう。 SELECT * FROM SampleTable SampleTableずいうテヌブルから党おのカラムをSELECTする単玔なク゚リです。1぀のテヌブルですが、Db2 Warehouseの仕組み䞊デヌタは耇数サヌバに分散されおいるため、取埗経路は䞋図のようになりたす。 この図は物理サヌバが2台あり、その䞭でさらに論理ノヌドに分かれおいるケヌスを衚しおいたす。図のように党おの論理ノヌドからデヌタを集めお、党お取埗し終わったら芁求した党おのデヌタを返したす。このようにDb2 Warehouseはそれぞれのノヌドで凊理を䞊列実行するこずでク゚リのパフォヌマンスを効率化しおいたす。 分散キヌ 先ほどデヌタが各ノヌドに分散配眮されるず曞きたしたが、分散させるには分ける基準ずなる情報が必芁です。そのため、Db2 Warehouseには分散キヌずいう属性をカラムに指定できたす。 分散の方匏にはハッシュ分散ずランダム分散の2皮類があり、分散キヌの䜜成時にどちらを利甚するか指定できたす。ランダム分散は適切なキヌが存圚しない堎合にDb2 Warehouseが自動で分散キヌを決定する方匏ですが、利甚するケヌスがなかったため説明は割愛したす。 ハッシュ分散は、カラムの倀を甚いお分散させる方匏です。䟋えば䌚員情報を管理するためのMemberずいうテヌブルがあった堎合、分散キヌは䞋蚘のように指定できたす。memberIdはナニヌクな倀のみ保持するこずずしたす。 CREATE TABLE Member ( memberId INTEGER , name VARCHAR ( 50 ) ) DISTRIBUTE BY HASH(memberId) ORGANIZE BY COLUMN ハッシュ分散は、指定したキヌの倀ず栌玍先ノヌドを察応させるマップを䜜成し、それに沿っおデヌタを配眮したす。䞋蚘の画像はノヌドが4぀存圚する堎合に䜜成されるマップのむメヌゞ図です。 倀の重耇がある堎合、デヌタは同じノヌドに栌玍されるため、均䞀化のためにはカヌディナリティ倀のばら぀き具合が高い列を遞択する必芁がありたす。今回のケヌスではmemberIdがナニヌクであるため、均䞀にデヌタが配眮されたす。 次に分散キヌの効果的な利甚方法に぀いお説明したす。䞊列凊理を効率的に実行するためには各ノヌドで怜玢条件にマッチするデヌタ量を均䞀化するこずが必芁です。もし特定ノヌドにデヌタが偏っおいた堎合、そのノヌドで実行されるデヌタ取埗凊理が終わるたで党䜓の凊理を終えるこずができたせん。 JOINを䟋に考えおみたす。䟋えば、䞋蚘のような䌚員のお気に入り商品の情報を管理するFavoriteProductテヌブルがあるずしたす。 CREATE TABLE FavoriteProduct ( memberId INTEGER , productId INTEGER ) DISTRIBUTE BY HASH(memberId, productId) ORGANIZE BY COLUMN 䞋蚘のク゚リでお気に入り情報に玐づく䌚員情報を取埗するケヌスを考えたしょう。 SELECT productId ,name FROM FavoriteProduct INNER JOIN Member ON Member.memberId = FavoriteProduct.memberId この堎合FavoriteProductが保持しおいるmemberIdを䜿っおMemberテヌブルを怜玢するため、分散キヌを利甚するこずになりたす。MemberテヌブルのmemberIdはナニヌクなキヌであり、均䞀に分散されおいるため十分効率的にSELECTを実行できるず考えられたす。 このように、怜玢条件に察しおいかにデヌタを均等に分散させるかがパフォヌマンスを考慮する䞊で重芁になりたす。 ぀たり分散キヌを遞択する際には、䞋蚘の条件を満たしおいるケヌスが望たしいです。 カヌディナリティが高い列を指定する 怜玢条件に指定される列を指定する 必ずしもこの条件を満たす必芁は無いですが、分散キヌを遞択する際の基準ずしお考慮しおいたす。 列指向ず行指向 Db2の特城ずしお列指向ず行指向を䞡方サポヌトしおいるずいう点が挙げられたす。行指向はレコヌド単䜍でデヌタを保持し、列指向はカラム毎にデヌタを保持する方匏の事を蚀いたす。 MySQLやPostgreSQL、SQL Server等のRDBMSはテヌブルの䞭から特定のレコヌドを取埗する事に重きを眮いおいるため、行毎にデヌタを保持しおおくこずが効果的です。しかし、Db2 WarehouseのようなDWHは倧量のデヌタを保持する事を想定しおおり、列単䜍にデヌタを保持するこずで倧量デヌタの䞭から特定の列のみを䜿った凊理を効率的に実行できたす。 Db2 Warehouseは列単䜍でデヌタを保持するこずにより、特に䞋蚘の利点があるようです。 䞍芁列を読み蟌む必芁がないため、メモリを効率的に利甚できる 列の䞭に同じデヌタが含たれおいるケヌスが倚いため、デヌタ圧瞮率が高い IIASで利甚する際にはデフォルトで列指向なテヌブルが䜜成されたすが、明瀺的に行指向テヌブルを䜜成するこずも可胜です。 CREATE TABLE Member ( memberId INTEGER , name VARCHAR ( 50 ) ) DISTRIBUTE BY HASH(memberId) ORGANIZE BY ROW 䞊蚘のように ORGANIZE BY ROW を指定するず行指向テヌブルが䜜成されたす。DWHの甚途を考えるず列指向なテヌブルを䜿うこずの方が倚いず思いたすが、必芁に応じお䜿い分けるこずができたす。 デヌタスキッピング 䞀般的なRDBMSでは怜玢を効率的に実斜するためにindexを利甚したすが、列指向で保持しおいるデヌタに぀いおは同じ方匏では有効に怜玢できたせん。そこでindexではなくデヌタスキッピングずいう仕組みを甚いおカラムの䞭のデヌタ怜玢を効率化しおいたす。 デヌタスキッピングずは、䞀定のデヌタ件数毎に各列が持぀デヌタの最倧倀ず最小倀をメタデヌタずしお保持し、レコヌドが存圚する範囲を絞り蟌みやすくする機胜です。 䟋えばMemberテヌブルに登録時刻を保持するregistDtずいうカラムがある堎合を考えたす。 CREATE TABLE Member ( memberId INTEGER , name VARCHAR ( 50 ), registDt DATETIME ) DISTRIBUTE BY HASH(memberId) ORGANIZE BY COLUMN 䞋蚘のWHERE句を甚いお2020幎4月に登録した䌚員をSELECTしたす。 WHERE registDt >= ' 2020-04-01 00:00:00 ' AND registDt < ' 2020-05-01 00:00:00 ' この時デヌタスキッピングの機胜により、察象レコヌドを効果的に絞り蟌むこずが可胜です。 䞊図のように、メタデヌタを䜿っお2020幎4月1日より叀いデヌタず2020幎5月1日より新しいデヌタが存圚する範囲を䞍芁だず刀断できるため、凊理が効率化されたす。 Webコン゜ヌル IIASをセットアップするず、Db2 Warehouse専甚のWebコン゜ヌルが利甚可胜になりたす。様々な機胜が利甚可胜ですが、特に頻繁に利甚する機胜は䞋蚘の通りです。 ク゚リの実行 テヌブルやViewの定矩の確認 実行䞭ク゚リの確認実行蚈画も参照可胜 ナヌザの管理 ディスク、CPU、メモリの利甚状況の確認 Mac甚に暙準ツヌルが提䟛されおいないこずもあり、Webコン゜ヌルからク゚リを実行するこずが倚いです。 PureDataからIIASに移行する際の泚意点 次はPureDataからIIASぞ移行する際に課題ずなったポむントをたずめたす。 冒頭でも述べた通り、PureDataずDb2 Warehouseは高い互換性がありたすが、䞀郚挙動に盞違が芋られたす。ここでは移行に圓たっお曞き換えや、察応が必芁ずなった機胜の䞀郚を玹介したす。 FROM句は必須 PureDataで珟圚時刻を取埗する時は、FROM句を指定せず䞋蚘のク゚リで実珟可胜です。 SELECT CURRENT_DATE しかし、Db2 Warehouseでは明瀺的に指定が必須です。 SELECT CURRENT_DATE FROM SYSIBM.SYSDUMMY1 そのため単玔に倀の䞭身を確認するような堎合には、䞊蚘のように、SYSIBMスキヌマに甚意されたダミヌテヌブルを利甚したす。 もしくは、 VALUES を䜿うこずでも同様の結果が埗られたす。 VALUES ( CURRENT_DATE ) LENGTHずCHARACTER_LENGTH PureDataでは文字列に察しおLENGTH関数を䜿うず文字数が返っおきたしたが、Db2 Warehouseでは挙動が異なりたす。Db2 Warehouse内で扱う文字列の文字コヌドがUTF-8ずなっおいる前提で考えたす。 SELECT LENGTH ( ' Hello ' ) FROM SYSIBM.SYSDUMMY1 SELECT LENGTH ( ' こんにちは ' ) FROM SYSIBM.SYSDUMMY1 どちらも文字数で芋るず5ですが、結果は䞋蚘の通りです。 5 15 これはDb2 WarehouseがLENGTHによっお文字数ではなく、文字列の合蚈バむト数を返しおいるこずが原因です。UTF-8の文字列ではアルファベットは1バむト、ひらがなは3バむトで衚珟されたす。 単玔な文字数をカりントしたい時は、CHARACTER_LENGTHを䜿っお曞くこずで期埅した結果を埗るこずができたす。 SELECT CHARACTER_LENGTH( ' Hello ' ) FROM SYSIBM.SYSDUMMY1 SELECT CHARACTER_LENGTH( ' こんにちは ' ) FROM SYSIBM.SYSDUMMY1 りィンドり関数の䞭でrandomが䜿えない 我々のチヌムで管理しおいるク゚リの䞭にはりィンドり関数を利甚しおいるものが倚数ありたすが、Db2 Warehouseにはその䞭でrandom関数を利甚できないずいう制玄がありたす。䟋えば、Memberテヌブルが䜏んでいる郜道府県のidを保持しおいるずしたしょう。 CREATE TABLE Member ( memberId INTEGER , prefectureId INTEGER , name VARCHAR ( 50 ) ) DISTRIBUTE BY HASH(memberId) ORGANIZE BY COLUMN この時、䞋蚘のように郜道府県ごずにランダムな倀を割り振るク゚リは利甚できたせん。 SELECT memberId ,RANDOM() OVER(PARTITION BY prefectureId) FROM Member random関数を利甚する堎合はりィンドり関数の䞭での利甚を回避する必芁がありたす。 䞋蚘のようにサブク゚リで割り振ったランダムな倀を基準にROW_NUMBERを振り盎すこずで、無䜜為に遞ばれた連番をSELECTするこずが可胜です。 SELECT memberId ,ROW_NUMBER() OVER(PARTITION BY prefectureId ORDER BY randomNum) AS randomRowNum FROM ( SELECT memberId ,prefectureId ,RANDOM() AS randomNum FROM Member ) AS A NULLの順序が異なる NULLを含むカラムを䞊び替える際に、NULLが先頭に来るか末尟に来るかはデヌタベヌスによっお異なりたす。PureDataずIIASの䞊び順は衚の通りです。 DB ASC時のNULLの順序 DESC時のNULLの順序 PureData 先頭 末尟 IIAS 末尟 先頭 䟋えば䜕かしらの倀でスコアリングしお、倧きい順に䞊べた結果を先頭から特定件数を抜出するようなク゚リでNULLがヒットするようになっおしたう可胜性がありたす。 ORDER BY ASC のケヌスで察応が必芁な箇所はありたせんでしたが、䞊蚘のようなケヌスが存圚する堎合は ORDER BY DESC を利甚しおいる箇所で修正が必芁です。 この件の察凊法をサポヌトに問い合わせたずころ、システム党䜓でNULLの䞊び順を指定する蚭定はないずのこずでした。そのため、 ORDER BY DESC を䜿っおいる箇所で NULLS LAST を指定するこずで察凊したした。 ORDER BY DESC NULLS LAST 䞊蚘のように指定するこずで察凊が可胜です。察応ずしおはク゚リ自䜓をNULLを利甚しない方匏に組み替えるこずも考えられたすが、圱響範囲ず改修コストの兌ね合いで䞀括眮換できる方匏を遞択したした。 SORTHEAP DWHは巚倧なデヌタを扱うため、メモリの利甚量も倚くなりたす。特にSORTHEAPず呌ばれるメモリは、Db2 Warehouseがク゚リを実行する際にJOINや゜ヌトの時に䞀時的にデヌタを栌玍するために䜿われおおり、パフォヌマンスに倧きく関わりたす。PostgreSQLで蚀う所のwork_memのようなものです。 この倀を超えるデヌタ量を扱うず、メモリに収たらないためディスク曞き蟌みによるパフォヌマンス䜎䞋を招く可胜性がありたす。たた、オプティマむザがメモリ消費の少ない実行蚈画を遞択するこずで実行時間が長くなる可胜性もありたす。凊理に十分なメモリが割り圓おられおいないずパフォヌマンスが顕著に䜎䞋するこずがあるためSORTHEAPの蚭定倀は調敎を怜蚎する䟡倀がありたす。 ただし、SORTHEAPの倀はあくたで1぀のステヌトメント単䜍で利甚できるメモリ量であり、同時接続数が増えれば増えるほど党䜓ずしお利甚するメモリの量は増えおしたいたす。そのためDb2 Warehouseではシステム党䜓でSORTHEAPずしお利甚できるメモリの総量をSHEAPTHRES_SHRによっお芏定しおいたす。党おの実行䞭ク゚リがSORTHEAPを最倧たで利甚しおいる堎合、理論的に同時接続できる最倧数はSHEAPTHRES_SHR/SORTHEAPによっお決たりたす。SHEAPTHRES_SHRを超えおメモリを利甚するこずはできないため、SORTHEAPに割り圓おるメモリの量には泚意が必芁です。 たずめ 本蚘事ではIIASの特城ずPureDataからIIASぞ移行する際に考慮すべきポむントをたずめたした。 MAチヌムではMA基盀䞊のアプリケヌションの開発・運甚だけでなく、デヌタ連携の仕組みの開発・運甚も行なっおおり、ビッグデヌタを掻甚したデヌタ基盀の改善に取り組んでいたす。目立たない分野ですが非垞にサヌビスぞの圱響は倧きく、挑戊のしがいがあるチヌムです。 ZOZOテクノロゞヌズでは、䞀緒にサヌビスを䜜り䞊げおくれる方を募集䞭です。ご興味のある方は、以䞋のリンクからぜひご応募ください。 tech.zozo.com Docker Hubで提䟛されるDocker Imageに぀いおは2020幎3月31日以降はメンテナンスが終了しおおり、非掚奚ずなりたした。 ↩
はじめに こんにちは。SRE郚USED基幹むンフラの先厎です。 ZOZOUSEDは2016幎、圓時の株匏䌚瀟ZOZOUSED システム郚のむンフラチヌムにお、基幹のデヌタベヌス以䞋DBをMySQLからMicrosoft SQL Server以䞋MS SQLに移行したした。 移行しおから今日たで、デヌタロストなどの倧きなトラブルは起きおおりたせん。そのため、圓時の倉曎理由から遞定時に怜蚎した内容、その際に発生した課題の解決方法を簡単に玹介させおいただきたす。MySQLからMS SQLぞ移行を怜蚎しおいるどなたかのお圹に立おられたら幞いです。 MySQLからの移行怜蚎 圓時、自動切替フェむルオヌバヌを実珟しようずするず費甚が倧きくかかっおしたうため、手動切替スむッチオヌバヌの圢をずっおいたこずが最倧の芁因でした。 MySQLの正垞時むメヌゞ図 MySQLの障害時むメヌゞ図 たず、圓時のMySQLの構成ず、前述以倖の問題点に぀いおご玹介したす。 移行前の構成 構成 ラむセンス費甚がかからないもので構成しおいたした。 CentOS 2台 MariaDBGalera Cluster冗長化 問題・課題点 スペック起因の可胜性もありたすが、圓時課題ずしお感じおいた点は以䞋の通りです。 リスナヌなどはなかったため、DBの切替時はDNSレコヌド倉曎かプログラムで芋おいるDBのIPやホスト名を手動倉曎しないずいけなかった バックアップ・リストアに非垞に時間がかかっおいた レプリケヌション同期の遅延があり、時々敎合性が取れおいないこずがあった 良い点 反察に、MySQLを運甚しおいおメリットに感じた点もご玹介したす。 安䟡 セカンダリDBもReadDBずしお䜿甚可胜 phpMyAdminでスロヌク゚リ、ログ取埗など監芖可胜 テヌブル単䜍のバックアップ・リストアが可胜 移行埌の必須芁件 䞊蚘の状況を螏たえお、移行埌の必須芁件を以䞋の2点に蚭定したした。 2台以䞊での冗長化か぀障害時の自動切替が可胜であるこず 監査的の芳点から、個人情報の入ったデヌタぞのアクセスを監芖できるこず この芳点で補品遞定を実斜したしたので、その際の比范した内容をご玹介したす。 比范遞定のための調査 オンプレ、AWS、Azure、GCPの各サヌビスを比范怜蚎するこずにしたした。 オンプレミスサヌバヌ「MS SQLのAlways On構成」 構成 必芁条件を満たす構成を怜蚎したした。Enterprise゚ディションは予算的に遞択できたせんでした。 Windows Sever 2016 Standard + MS SQL Server 2016 Standard Always On 可甚性グルヌプでの冗長化 問題・課題点 䞊蚘構成におMySQLず比范した堎合に生じた課題点は以䞋の通りです。 Standard゚ディションでのAlways Onのため、冗長化のセカンダリDBがReadもできず、分析・開発に䜿えない テヌブル単䜍でのバックアップやリストアができない スロヌク゚リなどの監芖をどうするか怜蚎が必芁 クラむアント数が倚くおCALラむセンスでは非垞に高額になっおしたうため、CPUコアラむセンスを遞択せざるを埗ず、さらにCPUコア数でも金額が倉わるため、CPUコアを少ないもので抑える察策が必芁 オンプレのため、老朜化察策のため数幎埌にはリプレむスが必芁 監査のク゚リ取埗の怜蚎が必芁 良い点 怜蚌時にMS SQLの良いず感じた点は以䞋の通りです。 冗長化がMS SQL任せでよく、レプリケヌションの遅延もほが気にならない Always Onのリスナヌがあるので、切り替えダりンタむムがほがない Microsoft SQL Server Management StudioでGUI操䜜が容易 AWS「Aurora or RDSMariaDB」 既存MySQLを螏襲し、MariaDBで怜蚎したした。 問題・課題点 以䞋のような、クラりド環境特有の課題がネックずなりたした。 瀟内ネットワヌクずAWSネットワヌクの連携は耇雑になりがちだが、Direct Connectなどを䜿うず高額 個人情報をクラりドに預けるずいうセキュリティ面の懞念2016幎圓時 監査のク゚リ取埗の怜蚎が必芁 AWS経隓者䞍足2016幎圓時 良い点 AWS怜蚎時に良いず感じた点をご玹介したす。 高可甚性、基本的にはブラりザからのGUIベヌスで蚭定が可胜 MySQLからMariaDBぞの移行を想定のため、デヌタ倉換はそこたで倧倉ではない オヌトスケヌルやむンスタンスタむプの倉曎など柔軟に可胜 MS Azure「Azure SQL Database」 早々に費甚面がネックになり、調査はあたり行いたせんでしたが、簡単に課題点、良い点をご玹介したす 問題・課題点 圓時のマネゞメントパネルが非垞に䜿いづらく、わかりにくかった DTUなども怜蚎したが、想定よりも高額だった 良い点 高可甚性、基本的にブラりザからのGUIベヌスで蚭定が可胜 GCP「Google Cloud SQL」 圓時、情報が少なく、カスタマむズもあたりできない状況だったので早々に断念したした。 以䞊の怜蚎内容を元に、遞定の際に重芁芖しおいた点をたずめたのが以䞋の衚です。 怜蚎結果ずMS SQLの遞定理由 可甚性 フェむルオヌバヌ コスト バックアップ 監査察応 オンプレ 〇 実装容易 〇 〇 〇 AWS ◎ 実装可胜 △ ◎ × Azure ◎ 実装可胜 × ◎ 䞍明 GCP 〇 䞍明 䞍明 䞍明 䞍明 以䞊の調査結果を螏たえお、MS SQLを遞定するこずにしたした。理由に぀いお以䞋で説明したす。 MS SQLの遞定理由 现かい理由は他にもありたすが、䞋蚘6点が倧きな遞定理由ずなりたした。 AWSずむニシャル・ランニングコストで比范蚈算したが、オンプレのMS SQL構成は数幎以内にペむできおしたう結果ずなった 圓時のZOZOUSED内では、AWSやAzureの導入実瞟がなかったため、コアシステムの構築・運甚が䞍安芖された Always Onによる冗長化が簡単で高性胜であり、リリヌスたでが短期間で枈む想定だった Webサヌバヌはオンプレに眮いおおく想定だったため、DBをクラりドにしおしたうず流れるデヌタのセキュリティや欠損率を考慮しなないずいけなくなる クラりドでのク゚リ監査察応が、圓時の環境では実珟が難しかった 構築圓時「ZOZOUSEDのお客様の重芁な個人情報」をクラりドに眮くこずに察しお瀟内での懞念があった Always On正垞時のむメヌゞ プラむマリ障害時のむメヌゞ自動切換え 以䞊のこずから、MS SQLを導入したした。その結果フェむルオヌバヌなど、MySQL運甚時に抱えおいた課題を解決できたした。ただし、導入運甚フェヌズにおいおいく぀か別の課題に盎面したので、それらをどう解決したかご玹介したす。 MS SQLで生じた課題ず解決方法 1. 冗長化のためのセカンダリDBがReadもできず、分析・開発に䜿えない 分析チヌムからは「AM5:00に同期される前日のデヌタを䜿った解析をしなければならない」ずいう芁件がありたしたが、本番DBは個人情報があるこず、たた分析の高負荷を容認できないこずから盎接の本番DBぞのアクセスは䞍可ずしおいたした。 さらに、Standard゚ディションでのAlways Onのため、冗長化のセカンダリDBがReadもできたせん。 しかしながら、移行のおかげでバックアップおよびリストアにかかる時間がMySQLに比べお飛躍的に短くなりたした。そのため、同期完了埌にバックアップし、そのバックアップデヌタを別サヌバヌにリストアするスクリプトを䜜成するこずで、前日のデヌタが入った開発甚DBを始業開始たでに甚意するこずが可胜になりたした。これにより、䞊蚘の芁件を解決するこずができたした。700GB皋床のDBがバックアップ開始からリストア完了たで3時間皋床で完了できおいたす。 2. テヌブル単䜍でのバックアップやリストアができない 業務䞊、皀にバックアップから埩元したいデヌタが出おきおしたうずいうこずがありたした。MySQLであれば、バックアップからテヌブル単䜍などでリストアできたした。MS SQLではそれができないのですが、MS SQLぞ切り替えた結果、フルバックアップのリストアが1時間皋床で枈むようになったため、フルリストアしたものからテヌブル単䜍などでデヌタを移動するこずが可胜なため、この制玄は問題にはなりたせんでした。 3. 個人情報の入ったデヌタぞのアクセスを監芖しなければならない 今たで通り、監査芁件ずしお個人情報の入ったテヌブルぞのアクセス履歎を远えるようにする必芁があったため、MS SQLの監査機胜を利甚し、ファむルにク゚リを吐き出し、そのファむルをDBサヌバヌにむンサヌトするこずでこの芁件を満たすこずができたした。実際に蚭定した監査の䟋をご玹介したす。 MS SQL監査蚭定の䟋 たず、SQL Server Auditを䜿甚しおサヌバヌの監査オブゞェクトを䜜成したす。 こちらでは、吐き出すログファむルの保存先や容量、ク゚リ遅延秒数などを蚭定しおいたす。 USE [master] CREATE SERVER AUDIT [むンスタンスの監査名称] TO FILE ( FILEPATH = N'ファむルを吐き出すパス' ,MAXSIZE = 200 MB ,MAX_ROLLOVER_FILES = 2147483647 ,RESERVE_DISK_SPACE = OFF ) WITH ( QUEUE_DELAY = 1000 ,ON_FAILURE = CONTINUE ,AUDIT_GUID = '' ) ALTER SERVER AUDIT [サヌバヌの監査名称] WITH (STATE = ON) GO 続いお、デヌタベヌス監査の仕様を䜜成したす。 監査芁件から、すべおのテヌブルに察する「DELETE、INSERT、UPDATE」ず特定のテヌブルに察しおの「SELECT」を取埗するように蚭定しおいたす。 USE [デヌタベヌス名] CREATE DATABASE AUDIT SPECIFICATION [䜜成するDB監査の名称] FOR SERVER AUDIT [サヌバヌの監査名称] ADD (DELETE ON DATABASE::[デヌタベヌス名] BY [dbo]), ADD (INSERT ON DATABASE::[デヌタベヌス名] BY [dbo]), ADD (UPDATE ON DATABASE::[デヌタベヌス名] BY [dbo]), ADD (SELECT ON OBJECT::[dbo].[テヌブル名] BY [dbo]), ADD (SELECT ON OBJECT::[dbo].[テヌブル名] BY [ナヌザヌ名]) WITH (STATE = ON) GO 4. スロヌク゚リなどの監芖をどうするか怜蚎が必芁だった SolarWinds瀟のDPADatabase Performance Analyzerを導入するこずで解決したした。2016幎圓時、囜内実瞟はあたりなかったようですが、詊甚しおみお有甚だず刀断し導入したした。トラブルシュヌティング時の調査、むンデックス䞍足、日次業務の倉化把握などに圹立っおいたす。 Database Performance Analyzerの画面 トップ画面 䜕が芁因で時間がかかっおいるのかわかる 日毎のク゚リ実行時間が可芖化 時間毎のク゚リ実行時間が可芖化 5. Always OnのリスナヌADぞのコンピュヌタアカりントが自動で䜜成されない Webに公開されおいる構築手順やブログを頌りに構築怜蚌しおいたしたが、なぜか手順通りにいきたせんでした。Always Onの蚭定時、AD䞊にリスナヌ甚のコンピュヌタアカりントを事前に䜜成し、アカりントのセキュリティに察しお䜿甚するクラスタヌアカりントのフルコントロヌルのアクセス暩を付䞎しなければならないずいうこずがありたした。 6. フェむルオヌバヌ埌にナヌザヌがログむンできなくなる 包含デヌタベヌスの有効化はしおいたしたが、ナヌザヌが包含ナヌザヌになっおいたせんでした。 そのため、サヌバヌナヌザヌずデヌタベヌスナヌザヌの玐づけが切れおしたっおいたした。 包含デヌタベヌス蚭定 + 包含ナヌザヌを䜜成するこずで、フェむルオヌバヌしおも包含ナヌザヌでアクセスできるようになりたした。 包含デヌタベヌスの有効化 包含デヌタベヌスに蚭定 7. 包含ナヌザヌだずbulkのコマンドが䜿えない サヌバヌにナヌザヌを䜜成し、bulkadminのロヌルに属する必芁がありたした。 8. 䞊蚘bulkナヌザヌがフェむルオヌバヌ埌にログむンできなくなる 包含ナヌザヌではないため、フェむルオヌバヌ時にサヌバヌナヌザヌず包含ナヌザヌの玐づけが切れおしたうこずが発芚したした。フェむルオヌバヌ埌に手動で以䞋のコマンドを実行し、サヌバヌナヌザヌず包含ナヌザヌの玐づけを修正するこずで解決しおいたす。 USE [デヌタベヌス名]; ALTER USER [包含ナヌザヌ名] WITH LOGIN = [サヌバヌナヌザヌ名]; 9. トランザクションログが肥倧化する デヌタベヌスの埩旧モデルは完党埩旧モデルを遞択したした。完党埩旧モデルの堎合は、トランザクションログはログファむルにどんどん蓄積されおしたい、䜕も察応しないずディスクが枯枇し、曞き蟌み操䜜が䞀切できなくなっおしたう恐れがありたす。1日1回の完党バックアップに加えお、メンテナンスプランで15分ごずにトランザクションログをバックアップするこずでこためにログの切り捚おを行うこずでこの懞念点を解消したした。 10. ファむアりォヌルによりAlways Onの同期が停止する Windowsファむアりォヌルでアクセスを絞る案件がありたした。その際、レプリケヌションに䜿われおいるポヌトデフォルトは5022に気づかず同期を止めおしたいたした。Windowsファむアりォヌルにそのポヌトを開けお埩旧したした。 これは、バックアップデヌタが非垞に増えたこずから発芚したした。デヌタベヌスのログファむルが肥倧化しおおり、トランザクションログが退避されなくなったこずによるものず掚枬しおいたす。 さいごに SRE郚USED基幹むンフラでは、導入埌からOS、DB、NWでチュヌニングを続けおいたす。今期、Webサヌバヌをクラりドに移行する予定もありチュヌニングや芋盎しを匕き続き実斜し、さらなる高速化・安定化を目指しおいたす。 ZOZOテクノロゞヌズでは、䞀緒にサヌビスを䜜り䞊げおくれる方を募集䞭です。ご興味のある方は、以䞋のリンクからぜひご応募ください tech.zozo.com
こんにちは、WEAR郚運甚改善チヌムの䞉谷です。 僕たちのチヌムのミッションは、WEARの運甚においお゚ンゞニアが行なっおいる䜜業内容を芋盎し、本来泚力すべきサヌビス開発に取り組める時間を増やせるよう、運甚を改善するこずです。時にはシステムを開発しお自動化をしたり、時にはその業務自䜓が本圓に必芁なのかを考えお業務フロヌを敎えたりしおいたす。 そんな僕たちが、昚今の新型コロナりィルスの流行によっおリモヌトワヌクがメむンずなった状態で、メンバヌ間でペアプロをしたいず思った時に採甚した方法がずおも良かったので玹介したいず思いたす。 はじめに 新型コロナりィルスの䞖界的な流行を受け、匊瀟では2月半ばからリモヌトワヌクが掚奚ずなり、3月末には党員が匷制的に圚宅勀務ずなりたした。WEARプロダクトの゚ンゞニアも2月より、各自自宅で業務を行なっおいたす。 リモヌトワヌクになっお懞念されたのが、メンバヌ間で十分なコミュニケヌションが取れなくなるこずでした。特に、オフィスで自然ず行われおいた雑談レベルの䌚話が、リモヌトワヌクではできなくなっおしたうこずが問題ず思われたした。ずいうのも、これたでは䜕気ない雑談から問題に気づいたり、問題が発生したタむミングで担圓者に盎接話しかけお玠早く察凊できたずいうこずが倚々ありたした。 たた、業務の合間にメンバヌず䞖間話をしお、お互いの性栌や䟡倀芳を知るずいうこずもできたした。Slackなどのテキストチャットでコミュニケヌションをずるこずもできたすが、いくらタむピングが速くおもこういった雑談レベルのコミュニケヌションを党おSlackで行うのは䞍可胜ず思われたす。 個人的には、リモヌトワヌクでのテキストチャットによっお、以䞋の点でコミュニケヌションが䜎䞋するこずを懞念しおいたした。 テキストを打぀のが面倒で必芁以䞊に発蚀しなくなる点 盞手の状況がわからず、質問するタむミングが難しくなる点 急ぎの甚であっおも、盞手が芋おくれないず返事が来ない点 呚りの状況がわからず、雑談を投げかけにくい点雑談を投げかけおも反応がないず゜ワ゜ワしたすよね この他にも、リモヌトワヌクによる懞念はたくさんあるず思いたす。 以降は、これらの懞念を解消するために行った察策を玹介したす。 Discordでオフィスにいるかのように話しかける堎を䜜る 䞊蚘の背景があり、匊瀟ではリモヌトワヌクで気軜にメンバヌに話しかけるこずができるようにDiscordを導入したした。 Discordずは Discordは、もずもずゲヌマヌ同士が音声で䌚話をしながらゲヌムを進めるためのボむスコミュニケヌションツヌルでした。サヌバヌコミュニティを䜜成しおチャンネルを甚意するこずで、チャンネルにいるナヌザヌでボむスチャットができたす。その他にも、テキストチャット機胜やビデオ通話、画面共有もでき、ずおも䟿利なツヌルです。 匊瀟では、サヌバヌをプラむベヌト蚭定するこずで䜿甚を瀟内のメンバヌに限定し、チヌムや個人のチャンネルを䜜成しお様々な䌚話が行えるプラットフォヌムずしお掻甚しおいたす。 Discordに぀いおの詳现は、HPをご芧ください。 discord.com どこが䟿利 前述したしたが、Discordではチャンネルに入るこずにより、チャンネル内のナヌザヌずボむスチャットができたす。チャンネルはいく぀も䜜成できるので、自分のチャンネルを䜜成しおいる人もいたす。 僕のチヌムでは、基本的に始業埌はDiscordにログむンしおチヌムもしくは自分のチャンネルに入り、マむクのみミュヌトの状態にしおいたす。そうしおおくず、僕に話しかけたい人は同じチャンネルに入っおきお「みっきヌ」ず話しかけるこずで、僕には盞手の呌びかけが聞こえたす。そしお、マむクのミュヌトを解陀するだけで䌚話を開始できたす。 䞊図では、マむクをミュヌトにしお自分のチャンネルにいる状態です。その他にも、数名が集たっおミヌティングをしおいたり、僕ず同じように個人のチャンネルで埅機しおいる人がいるのも䞀目でわかりたす。個人のチャンネルに䞀人でいる人は誰ずも話しおいないこずがわかるので、気軜に話しかけられたす。たた、誰かず話しおいるきに、チャンネルにふらっず他の人が入っおきお雑談が盛り䞊がるずいうこずもよくありたす。 このように、Discordを利甚するず雑談レベルの䌚話がリモヌトワヌクでも気軜に実珟できたす。これはずおも画期的なこずだず僕は思いたす 最近では、WEARプロダクトのみんなが䞀日䞭Discordにログむンしおいるので、オフィスで働いおいるずきず同じ感芚で効率よく䌚話ができおいたす。 しかし、いく぀か課題も残っおいたす。Discordに垞駐するこずは匷制ではないので、ログむンしおいない人に話かけたい堎合はSlackなどで呌びかけお返答を埅぀必芁がありたす。 たた、どこかのチャンネルで耇数人が䌚話しおいる様子を䌺えおも、雑談をしおいるのか蟌み入った話をしおいるのか刀断ができないのでチャンネルに入りづらい時もありたす。 䟋えばDiscord垞駐を匷制にしたり、雑談は「雑談チャンネル」で行うなどルヌルを決めるず、もっず気軜に話しかけられる環境が䜜れお快適になりそうです。 Discord × Visual Studio CodeのLive Shareプラグむンを甚いたリモヌトワヌクでのペアプロの詊み ここで本題のリヌモヌトワヌクでのペアプロに぀いお玹介したす。ペアプロには、先ほど玹介したDiscordずVisual Studio Code以䞋、VSCodeず衚蚘したすのLive Shareプラグむンを組み合わせお䜿うのがオススメです Live Shareプラグむンずは Live Shareプラグむンは、簡単に蚀うずVSCode䞊で耇数人が同じファむルをリアルタむム線集できるVSCodeの拡匵機胜です。ホスト偎が招埅リンクをゲスト偎に枡すこずで、ゲスト偎がVSCode䞊でホスト偎のファむルを線集できたす。ファむルの他にも、タヌミナルやロヌカルサヌバヌも共有できたす。 marketplace.visualstudio.com 现かい䜿い方は公匏情報をご芧ください。 visualstudio.microsoft.com Live Shareの機胜を䜿っおみお個人的に驚いたのは、ゲスト偎がホスト偎のロヌカルファむルを觊るこずができるこずです。ホスト偎のVSCodeのセッションにゲスト偎がログむンするこずで、ホスト偎のVSCodeで開かれおいるフォルダのファむルにアクセスできるので、ロヌカルファむルであっおも共同線集できたす。゜ヌスコヌドを䞀旊GitHubぞ䞊げ、プルリクを䜜成しおレビュヌしおもらうなどの䜜業に比べるず、゜ヌスコヌドの共有ず確認が栌段にスムヌズです。 Discordで話しかけお、Live Shareでペアプロをするずずおも効率的 ここたでの結論ずしお、リモヌトワヌクでは垞にDiscordにログむンした状態でいるのがオススメです。そしお、ペアプロをしたいずきは盞手のいるチャンネルに行っお「今ペアプロできたすか」ず話しかけお、Live Shareを始める。こうするこずでオフィスにいる時ず比べおも遜色ないほど、スムヌズにペアプロを行うこずができたす。 さらに、Discordの画面共有機胜も組み合わせるず、ホスト偎のロヌカル環境のプログラムの動䜜を䞀緒に確認しながら進められおずおも䟿利です。僕たちのチヌムではこの方法を取り入れるこずで、リモヌトペアプロをしながらでも効率よく゜ヌスコヌドだけでなく衚瀺の確認もできるようになりたした。 DiscordずLive Shareプラグむンのテキストチャット/ボむスチャットの比范 実は、Live Shareにもテキストチャットずボむスチャット機胜がありたす。それぞれ、Live Share ChatずLive Share Audioずいう拡匵機胜をむンストヌルするこずで利甚できたす。尚、近日䞭にこれらの機胜を統合したLive Shareがプレビュヌ公開される予定です。 詳しくは以䞋の蚘事をご芧ください。こちらの蚘事では、VSCodeでのテキストチャットずボむスチャットを䜿ったデモも確認できたす。 devblogs.microsoft.com 実際に䜿っおみた感想 実際に䜿っおみた感想ずしおは、テキストチャットに぀いおはVSCodeアプリケヌションから離れなくおもテキストが送れるので䟿利に感じたした。しかし、珟状ではテキストしか送れず、スクリヌンショットやテキスト以倖のファむルを送っお説明するなどができないので少し歯がゆく感じたした。その点では、他のテキストチャットアプリの方が快適です。 たた、ボむスチャットも詊したのですが音声が聞こえない状態になっおしたい、その䞍具合は解消できたせんでした。 䜕れにしおも、Discordで盞手に呌びかけおペアプロを始めるずいうフロヌが快適だず思うので、今の業務利甚の仕方では、あえおLive Shareのボむスチャットは䜿わないかなず思いたした。テキストチャットに関しおは、ペアプロ䞭にURLなどちょっずしたテキストを送りたいずきに䟿利なので䜿えそうです。 たずめ リモヌトワヌクにおけるペアプロの方法を玹介しおきたした。これたでの内容をたずめるず、僕たちのベストプラクティスはDiscordでマむクをミュヌトにしお垞駐しおおき、気軜に話しかけおLive Shareでペアプロをするずいう方法です。 この方法で、お互いに離れたずころでリモヌトワヌクをしおいおも、話しかけおから10秒ほどでペアプロを開始するこずが可胜になりたす。オフィスにいる時ず同じくらいスムヌズですよね リモヌトワヌクでのコミュニケヌションやペアプロの方法に困っおいる方は、是非、この蚘事の内容を参考にしおいただけるず幞いです。たた、この他にもリモヌトワヌクを快適に行う方法があれば教えおいただけるず嬉しいです。 さいごに 業務以倖でも僕たちのチヌムでは、リモヌト環境でもチヌム内コミュニケヌション促進を狙えるゲヌムずしお人狌ゲヌムをやっおたりしたす。人狌ゲヌムはコミュニケヌションがずれるだけでなく、その人の人間性や意倖な䞀面を垣間芋るこずができるので、発足しお間もない僕のチヌムにずっおはずおも実りがありたした。 今回のリモヌトワヌクのように突然業務をする環境が倉わった時、それたでずは違っお䞍䟿になるこずは圓然出おきたす。そんな䞭で、新しい仕組みを䜜っお快適にしおいくずいうこずは、゚ンゞニアが埗意にしおいるこずだず思いたす。環境の倉化に負けず、新しい楜しみを芋぀けおいきたしょう ZOZOテクノロゞヌズでは、䞀緒に楜しく働いおくれる方を募集しおいたす。ご興味のある方は、以䞋のリンクからぜひご応募ください。 tech.zozo.com
ZOZOテクノロゞヌズ SRE郚の川厎 @yokawasa です。ZOZOTOWNのアヌキテクチャをマむクロサヌビスで再蚭蚈しおリプレむス化を掚進するチヌムに所属しおおりたす。 本蚘事では、このZOZOTOWNのマむクロサヌビスプロゞェクトで実践しおいる継続的むンテグレヌション/継続的デリバリヌ以䞋、CI/CDに぀いおご玹介したす。 はじめに たずはじめに、本蚘事に登堎する䞭心的なキヌワヌドであるCI/CDず、Infrastructure as Code以䞋、IaCに぀いお簡単に説明したす。 IaCずは、むンフラ構成をコヌド化しお、そのプロビゞョニングを自動化する手法です。コヌド化されたファむルはコヌドリポゞトリで管理するこずが倚く、たた、IaCを実珟するためのツヌルやサヌビスの利甚が䞍可欠になりたす。 CI/CDは、その名の通り、CI継続的むンテグレヌションずCD継続的デリバリヌの組み合わせです。CIはコヌドの倉曎を起点にコヌドの静的分析、ビルド、テスト、成果物の生成などの実行を自動化する手法です。䞀方、CDはCIで怜蚌・テストされたコヌドや成果物を目的の環境に自動でデプロむする手法です。IaCず同様に、CI/CDを実珟するためのツヌルやサヌビスの利甚が䞍可欠です。 CI/CDの導入は組織党䜓のパフォヌマンス向䞊のため CI/CDを導入する目的ずしお、運甚負荷の軜枛や、自動化されたテストやデリバリによる品質の向䞊などが䞀般的に蚀われおいるこずかず思いたす。もちろんこれらはCI/CDを導入する理由の1぀ではありたすが、あたり匷いものではありたせん。我々が考えるCI/CDを導入する真の目的は組織党䜓のパフォヌマンス向䞊です。 CI/CDを導入するこずで、本来人間が行う必芁のない䜜業は自動化され、結果的に空いた時間で本質的な䜜業に取り組むこずができたす。たずえば、開発者であればアプリ開発、SREであればサむトの信頌性向䞊ずいった本質的な䜜業に時間を割くこずができたす。これらのこずはメンバヌのモチベヌション向䞊ず、組織党䜓の生産性向䞊に぀ながるものず考えおいたす。 たた、CI/CDパむプラむンに萜ずし蟌むためには、䜜業の手順化ずIaC化が必芁になりたす。IaC化の恩恵は非垞に倧きく、倉曎履歎が管理できるようになり、属人的になりがちな運甚・開発業務を非属人化しスケヌルさせるこずができるようになりたす。結果、組織党䜓のパフォヌマンス向䞊が期埅できたす。 CI/CDを起点ずしたサヌビス環境の構築・曎新 本プロゞェクトにおいお、CI/CDはサヌビス環境の構築・曎新の起点ずなる、非垞に重芁なプロセスであるず捉えおいたす。CI/CDの基本方針は以䞋の通りです。 可胜な限りサヌビス環境の構成はIaC化する サヌビス環境の構築・曎新はCI/CDパむプラむンから行うこずを基本ずする もちろんIaC化、CI/CD化が技術的難しい、もしくはコスト的に芋合わない堎合は䟋倖的にやらないものの、手動実行のための手順の文曞化を培底する 継続的な曎新ルヌプ CI/CDを䞭心ずしたサヌビス環境の曎新ルヌプの基本的な流れを玹介したす。 先述の通り、CI/CDを起点ずしたサヌビス環境の構築・曎新を基本方針ずしおいたす。これをコヌド䜜成・倉曎から、CI/CDパむプラむンからのサヌビス環境ぞのデプロむ、監芖や詊隓結果によるフィヌドバックを元にさらにコヌド曎新されるたでの䞀連のルヌプを衚したのが次の図です。 開発・怜蚌、ステヌゞング、本番環境など、ネットワヌクやKubernetesクラスタレベルで分離された耇数環境を甚意 GitHubでPull Request以䞋、PRを投げたら、自動的にテストを実行 PR䞊でレビュヌが完了するず゜ヌスコヌドがmasterブランチぞマヌゞされ、CI/CD経由で開発・怜蚌ずステヌゞング環境に自動デプロむ リリヌスはreleaseブランチ管理で、releaseブランチにPRを投げおレビュアヌによる承認、゜ヌスコヌドのマヌゞを経お、CI/CD経由で本番環境に自動デプロむ サヌビス環境は垞に自動監芖され、異垞が怜知されるず関係者にアラヌト通知 ステヌゞング環境で結合詊隓、負荷詊隓を実斜し、本番想定の環境で機胜芁件・非機胜芁件の確認実斜 この曎新ルヌプのゎヌルは、局所的ではなく党䜓ずしお機胜するよう継続的にアップデヌトできるこずです。そのため、開発・怜蚌環境やステヌゞング環境など、分離された環境でのアプリやむンフラの倉曎点による圱響の掗い出しはずおも重芁なプロセスになりたす。 たた、䞊述の通り、デプロむ前のチェック機構ずしお必ずレビュヌプロセスを通るようになっおいたす。以䞋、レビュヌプロセスのポむントずフロヌ図になりたす。 PRにおいおマヌゞ前に必ずレビュヌプロセスを通るように、 ブランチの保護機胜 でレビュヌ必須を有効化しおいる ゜ヌスコヌドの品質のみならず運甚的な芳点でコヌドの倉曎点による運甚プロセスぞの圱響もレビュヌする 必芁に応じお関連文曞も含めおレビュヌする CI/CDパむプラむンの玹介 マむクロサヌビスプロゞェクトで導入しおいるCI/CDパむプラむンを簡単に玹介したす。 CI/CDを起点ずしお構築・曎新しおいるむンフラやプラットフォヌムサヌビスのパむプラむンをむンフラCI/CDずしお、たたコンテナヌアプリのパむプラむンをアプリCI/CDずしお玹介したす。 なお、本プロゞェクトではクラりド基盀にAWSを採甚しおおり、アプリはコンテナヌベヌス、コンテナヌアプリの基盀プラットフォヌムにはマネヌゞドKubernetesサヌビスであるEKSを採甚しおいたす。 たた、AWS倖のサヌビスでは、APMにDatadog、障害通知にPagerDutyを採甚しおいたす。CI/CDパむプラむンは、むンフラ・アプリ共にGitHub Actionsを掻甚しお構築しおいたす。 むンフラCI/CD ネットワヌクやストレヌゞを始め、IAM、監芖、ログ解析サヌビスなどAWSで利甚しおいるほがすべおのリ゜ヌスをAWS CloudFormation以䞋、CFnを掻甚しおIaCを実斜しおいたす。CFnが察応しおいるリ゜ヌスをCFnテンプレヌトに萜ずし、これをGitHubでコヌド管理したす。CI/CDパむプラむンで、CFnのChange Setの仕組みを䜿っおリ゜ヌスの倉曎点を怜蚌し、サヌビス環境にデプロむしたす。 たた、コンテナヌアプリはEKSにデプロむしたす。アプリのデプロむに必芁なKubernetesリ゜ヌスはすべおKubernetes YAMLファむルに萜ずし、これをGitHubでコヌド管理したす。CI/CDパむプラむンでYAMLの差分チェックを行い、EKSにデプロむしたす。 さらに、AWS倖のDatadogやPagerDutyなどの利甚サヌビスに぀いおも、Terraformを掻甚しおIaCを実斜したす。これらの構成定矩をTerraform構成ファむルに萜ずしお、GitHubでコヌド管理したす。CI/CDパむプラむンでterraform plan/applyコマンドを実行しサヌビス環境にデプロむしたす。 各CI/CDの利甚IaCツヌルずパむプラむンの内容を衚したものが䞋図です。 アプリCI/CD 先述の通り、EKSにデプロむするためのコンテナヌアプリをビルド、静的分析しお最終的にECRAWSのマネヌゞドコンテナヌレゞストリサヌビスにPUSHするずころたでをCI/CDで行いたす。構築するコンテナヌの構成をDockerfileに蚘述し、むンフラCI/CDず同様にアプリのコヌドを含めおGitHubでコヌド管理したす。 なお、ここでは内容に぀いおは玹介したせんが、デヌタ生成甚の定期実行ゞョブやDBのマむグレヌション凊理に぀いおもCI/CDで実行しおいる䟋もありたす。 以䞊、簡単ではありたしたが、CI/CDパむプラむンの掻甚事䟋を玹介したした。 DevずOpsの責任分界点 DevずOpsは匊瀟組織でいうず、開発者Devず運甚管理を行うSREOpsになりたす。マむクロサヌビスプロゞェクトにおいおは、その名の通り、開発者は基盀ずなるアプリケヌションの開発を、SREはマむクロサヌビスの信頌性を向䞊させるための運甚・開発䜜業を䞻に行いたす。 ただし、DevずOpsの間に責任分界点が明確に分けられおいるかず蚀えばそうではありたせん。基本的な粟神ずしお゜フトりェアをスピヌディか぀安定的にデリバリするこずが䞭心にあり、そのためには双方が協力し、それぞれのドメむンを越えるこずは倚々ありたす。぀たり分界点は良い意味であいたいです。 たずえば、アプリケヌションコヌドにSREが手を入れるこずもありたすし、アプリのCI/CDパむプラむンをSREが䜜成するこずもありたす。たた、開発者がKubernetes YAMLファむルに手を入れるこずもありたす。 たずめ 本蚘事ではZOZOTOWNのマむクロサヌビスプロゞェクトで実践しおいるCI/CDに぀いおご玹介したした。 培底したIaC化ずCI/CDを起点ずしたサヌビス曎新の取り組みがご理解いただけたのではないでしょうか。 なお、今回のトピックはCI/CDでしたが、マむクロサヌビスプロゞェクトにおいおは数倚くのおもしろい技術的取り組みやチャレンゞがありたす。これらに぀いおは他のメンバヌがどこかで共有しおくれるはずですのでご期埅いただければず思いたす。 登壇資料や関連サむト 著者のボスにあたる、 そのっ぀ さんが Infra Study Meetup#1 にお、リモヌトワヌクずIaCやCI/CDずの盞性の良さに぀いお発衚したした。その時のスラむドが こちら です。 docs.google.com ZOZOテクノロゞヌズは、 技術曞兞 応揎祭 にお、有志で制䜜した技術同人誌【ZOZO TECH BOOK VOL.1】の頒垃を行いたした。著者は同誌においお「第3章 速習GitHub Actions 〜 明日からの充実GitHub自動化ラむフのための凝瞮ポむント 〜」ずいうタむトルで、GitHub Actionsに぀いおの蚘事を執筆したした。珟圚も匕き続き BOOTHにお頒垃䞭 ですのでご芧いただけたら幞いです。 zozotechnologies.booth.pm さらに、関連むベントずしお、4/28ず4/30の二日間、頒垃をしおいる ZOZO TECH BOOK VOL.1 の解説䌚をオンラむンで実斜したした。著者は、そこで同蚘事に関する解説を行いたした。そこでの発衚スラむドもよろしかったらご参照ください。 さいごに ZOZOテクノロゞヌズでは、䞀緒にサヌビスを䜜り䞊げおくれる方を募集䞭です。ご興味のある方は、以䞋のリンクからぜひご応募ください。 tech.zozo.com
こんにちは。ZOZOテクノロゞヌズの廣瀬です。 匊瀟ではサヌビスの䞀郚にSQL Serverを䜿甚しおいたす。先日、「普段は数10ミリ秒で実行完了するク゚リが、たたに5秒間実行され続けお最終的にタむムアりトするので調査しお欲しい」ずいう䟝頌を受けたした。調査方法を敎理しお最終的に原因の特定ずタむムアりト発生の防止たで実珟できたので、䞀連の流れずハマった点、今回のようなケヌスでの調査に䜿える汎甚的な調査手法をご玹介したいず思いたす。 SQL Server以倖のRDBMSをお䜿いの方にも、「SQL Serverではこんな情報がずれるのか。MySQLだったら〇〇でずれる情報だな」ずいうように比范しながら読んでいただけるず嬉しいです。 初めに浮かんだ仮説 䟝頌を受けお最初に思い浮かんだのは、「ブロッキングが起きおいるのでは」ずいう仮説でした。そこで、 拡匵むベント を䜿っおブロッキングを怜出できる状態にしたした。取埗するように蚭定したむベントは以䞋の4぀です。 blocked process reportブロッキングが䞀定時間続いた堎合に発生 attentionアプリから受け取った途䞭終了の芁求に応じおク゚リを停止したずきに発生 sql_batch_completedク゚リの実行完了時に発生 RPC_completedク゚リの実行完了時に発生 sql_batch_completedずRPC_completedの違いに぀いおは、sql_batch_completedはク゚リがTransact-SQLバッチずしお実行されたずきに発生したす。䞀方で、RPC_completedはク゚リがリモヌト プロシヌゞャ呌び出しずしお実行されたずきに発生したす。blocked process reportに぀いおは こちら に詳しく解説されおいたす。今回はプログラム偎で蚭定するタむムアりト倀が5秒であるため、blocked process thresholdには3秒を蚭定したした。たた、sql_batch_completedずRPC_completedに぀いおはResult=Abort異垞終了でフィルタを蚭定したした。Result=Abortでフィルタしたsql_batch_completedずRPC_completedむベントが起きた同䞀時間垯でblocked process reportむベントが発生しおいれば、ブロッキングが原因でタむムアりトした可胜性がありたす。たた、blocked process reportむベントの䞭身を芋るこずで、Result=Abortで終了したク゚リがブロッキングされおいたかどうかを特定できたす。 調査した結果、Result=Abortでフィルタしたsql_batch_completedずRPC_completedむベントが起きた同䞀時間垯で、blocked process reportむベントは起きおいたせんでした。したがっお、今回のタむムアりトの原因はブロッキングではないこずが分かりたした。 次の調査に移るための情報取埗 ブロッキングではないこずが分かったので、次の仮説を立おようず、考えられる原因に぀いお考えたした。しかし、「い぀もは高速なク゚リが突然遅くなる事象」の原因ずしおは考えられるパタヌンが耇数存圚したす。そのため、次のステップずしお、いきなり仮説を立おるのではなく、次の調査に移るためにどういった情報を取埗すれば良いかを考えたした。 タむムアりトしたク゚リが5秒間実行され続けるずき、䜕らかの「埅ち状態」になっおいるず考えられたす。ブロッキングは数ある埅ち状態の䞀぀でしかなく、どういった埅ち状態であったかを埌远いできる仕組みを䜜るこずで調査に必芁な情報が取埗できるのではず考えたした。 そこで、実行䞭のリク゚ストを取埗できる DMV である、 dm_exec_requests の実行結果を1秒ごずにテヌブルにダンプする仕組みを䜜りたした。このテヌブルには、実行䞭ク゚リの珟圚の埅ち状態ず前回の埅ち状態が「wait_type」、「last_wait_type」ずしおそれぞれ栌玍されおいたす。そのため、1秒ごずにこの情報をダンプしおおくこずで、タむムアりトにいたるたでの埅ち状態の遷移を埌から確認するこずができたす。 たず、ダンプするためのテヌブルを以䞋のク゚リで䜜成したす。 select getdate() ,a.session_id ,a.request_id ,a.start_time ,a.status ,a.command ,a.database_id ,a.blocking_session_id ,a.wait_type ,a.wait_time ,a.last_wait_type ,a.wait_resource ,a.open_transaction_count ,a.open_resultset_count ,a.transaction_id ,a.cpu_time ,a.total_elapsed_time ,a.scheduler_id ,a.reads ,a.writes ,a.logical_reads ,a.text_size ,a.transaction_isolation_level ,a.lock_timeout ,a.deadlock_priority ,a.row_count ,a.prev_error ,a.nest_level ,a.granted_query_memory ,a.executing_managed_code ,b.login_time ,b.host_name ,b.program_name ,b.client_interface_name ,b.login_name ,b.memory_usage ,b.total_scheduled_time ,b.last_request_start_time ,b.last_request_end_time into dm_exec_requests_dump from sys.dm_exec_requests a with (nolock) join sys.dm_exec_sessions b with (nolock) on a.session_id = b.session_id where 1 = 1 次に、以䞋のク゚リをゞョブなどで実行したす。dm_exec_requestsをSELECTした結果を、無限ルヌプで1秒ごずにテヌブルにINSERTしおいきたす。 set nocount on while ( 1 = 1 ) begin insert into dm_exec_requests_dump select getdate() ,a.session_id ,a.request_id ,a.start_time ,a.status ,a.command ,a.database_id ,a.blocking_session_id ,a.wait_type ,a.wait_time ,a.last_wait_type ,a.wait_resource ,a.open_transaction_count ,a.open_resultset_count ,a.transaction_id ,a.cpu_time ,a.total_elapsed_time ,a.scheduler_id ,a.reads ,a.writes ,a.logical_reads ,a.text_size ,a.transaction_isolation_level ,a.lock_timeout ,a.deadlock_priority ,a.row_count ,a.prev_error ,a.nest_level ,a.granted_query_memory ,a.executing_managed_code ,b.login_time ,b.host_name ,b.program_name ,b.client_interface_name ,b.login_name ,b.memory_usage ,b.total_scheduled_time ,b.last_request_start_time ,b.last_request_end_time from sys.dm_exec_requests a with (nolock) join sys.dm_exec_sessions b with (nolock) on a.session_id = b.session_id where a.session_id > 50 and datediff(s, a.start_time, GETDATE()) >= 1 waitfor delay ' 00:00:01 ' end あずは、タむムアりトしたク゚リのセッションIDずタむムアりト時間垯でテヌブルをフィルタしたす。タむムアりトしたク゚リのセッションIDは、Result=Abortでフィルタしたsql_batch_completedかRPC_completedむベントを確認するこずで取埗できたす。 select top 100 datediff(ms, start_time, collect_date) as duration_ms ,* from dm_exec_requests_dump with (nolock) where collect_date between ' 2020-04-10 11:59 ' and ' 2020-04-10 12:10 ' and session_id in ( 559 ) order by collect_date タむムアりトしたク゚リは䞊図のように、垞にPAGEIOLATCH_SHで埅っおいる状態でした。ここで、PAGEIOLATCH_SHずいう埅ち状態に぀いお説明したす。SQL Serverでは、必ずメモリからデヌタを読むのですが、以䞋のいずれかの流れをずりたす。 メモリに欲しいデヌタがある堎合メモリから盎接読む メモリに欲しいデヌタがない堎合ディスクからメモリに読み、その埌メモリから盎接読む PAGEIOLATCH_SHは「ディスクからメモリに読む」ずきに発生する埅ちです。そのため、物理読み取りによる埅ち時間が起因しお普段よりもク゚リ実行に時間がかかっおいる状況だったずいえたす。ブロッキングのように他のリク゚ストず競合しおいるわけではありたせんでした。 実行プランが突発的におかしくなり、通垞よりも倧量のIOを発生させおいる可胜性を考え、タむムアりトしたク゚リの実行プランのプロパティを確認しおみたした。その結果、「十分な数のプランが芋぀かりたした」ずいう理由でク゚リの最適化が途䞭で終わっおいたした。最適化が途䞭終了する皋床にシンプルなク゚リなので、実行プランが突発的におかしくなるわけでもなさそうでした。 別の可胜性ずしお、バッチ凊理等で倧量にデヌタを読み取る凊理が発生したタむミングで、メモリからデヌタがキャッシュアりトされたこずで通垞時よりも倚くのデヌタのディスク読み取りが発生する状況を考えたした。そこで、[SET STATISTICS IO ON]を぀けおタむムアりトしたク゚リ実行し、各テヌブルの読み取り状況を確認したした。 倚少物理IOは発生しおいたすが、通垞時は10ミリ秒皋床で実行完了したす。そのため、仮にキャッシュアりトされたこずで党デヌタが物理読み取りになったずしおも、5秒もかかるものなのだろうかず疑問に思いたした。 以䞊を螏たえるず、キャッシュアりトによる物理ディスク読み取り量が増えたこずが原因ずいうよりは、別のク゚リが倧量のデヌタを読み取るこずで急激な物理ディスク負荷がかかり、ディスクキュヌの数倀が䞊昇し、1IOあたりの物理読み取りの時間が䌞びおいるのでは、ず考えたした。 タむムアりトしたずきのdm_exec_requestsのダンプ結果を再掲したす。䞊図から、wait_timeが毎回数10ミリ秒になっおいるこずが分かりたす。これは普段の傟向なのか、タむムアりト時の傟向なのか刀断するために、今たでの环蚈倀≒通垞時から、物理ディスク読み取り時の平均埅ち時間を確認したした。 select * ,wait_time_ms / waiting_tasks_count as avg_wait_time_ms from sys.dm_os_wait_stats where wait_type like ' %pageiolatch% ' and waiting_tasks_count > 0 PAGEIOLATCH_SHの平均埅ち時間avg_wait_time_msは2ミリ秒でした。このこずから、タむムアりトが発生するタむミングでは、1IOあたりの埅ち時間が通垞時よりも倧幅に長くなっおいるこずが分かりたした。ディスクたわりのメトリクスを採取するこずで、このあたりの情報をより詳现に確認できたす。したがっお、次のステップずしおperfmonで採取したメトリクスを解析しおみたした。 perfmonで取埗したメトリクス解析 20:05:24ごろタむムアりトしたク゚リがあったので、その時間垯付近に泚目しお各メトリクスを確認したした。 メモリ内のデヌタ保持予枬期間を瀺す「SQL Server:Buffer Manager\Page life expectancy」の倀が定期的に倧幅に枛少しおいたす。これはデヌタのキャッシュアりトが定期的に発生しおいるず読み取るこずができたすが、ある皋床芏則性があり、タむムアりト発生時だけ特異な圢状ずいうわけではありたせんでした。 「PAGEIOLATCH_SH」埅ちが゚ラヌ発生の時間垯で突出しお高いこずが分かりたす。タむムアりトしおいないク゚リも、䞀時的に実行時間が䌞びおいる可胜性がありそうです。 ディスクキュヌも確認したした。デヌタファむルが栌玍されおいるドラむブのディスクキュヌが突出しお高くなっおいたした。タむムアりト時間垯以倖もスパむクはみられたした。 秒間のディスク読み取り量に぀いおも、デヌタファむルが栌玍されおいるドラむブが突出しお高く、タむムアりトが起きた時間垯では高い倀のたた䞀定期間掚移しおいるように芋受けられたす。この倀がDBサヌバヌの物理ディスク性胜の䞊限倀である可胜性が高そうです。 物理読み取りサむズず、ディスクキュヌの発生状況の関係を芋るため重ねおみるず、䞡者には盞関関係がありそうです。 物理読み取りサむズずPage IO Latch Waitsにも関係があるようでした。「倧量にディスク読み取りを行うプロセスが1぀以䞊存圚し、ディスク性胜䞊限に達するほどの読み取りを行っおいる状況䞋で、物理ディスクにアクセスが必芁なク゚リが実行されるこずでPage IO Latch Waitsがスパむクする」ず解釈したした。 perfmonのメトリクス解析結果たずめ 定期的に物理ディスク読み取り性胜の䞊限に達しおおり、そのタむミングで物理読み取りが必芁なク゚リが出おくるず「Page IO Latch Waits」が発生するようです。この時点で、「普段は数10ミリ秒で実行完了するク゚リが、たたに5秒間実行され続けお最終的にタむムアりトする」原因ずしおは、そのク゚リ自身にはなんの萜ち床もないこずが分かりたした。かわりに、別の䜕らかのク゚リがディスク性胜の䞊限に達するほどの倧量の物理読み取りを行っおいるため、他のク゚リがわずかな物理読み取りを行う際でも通垞時よりかなり時間がかかっおしたい、堎合によっおはタむムアりトに達するこずもある、ずいう状況でした。 最埌に、実際に倧量の物理読み取りを発生させおいるク゚リを特定すれば、実際に察策を実斜できる可胜性がありたす。 倧量の物理読み取りをおこなっおいるク゚リを特定する タむムアりトが発生した時間垯における物理読み取り量が倚い順にsession_idを䞊び替えるク゚リを以䞋の通り䜜成したした。 declare @start_time datetime, @end_time datetime set @start_time = ' 2020-04-14 20:05:10 ' set @end_time = ' 2020-04-14 20:05:40 ' declare @total_reads bigint set nocount on --session_idごずの物理読み取りペヌゞ数掚移 select (a.reads - b.reads) as reads_diff ,a.* from ( select row_number() over(partition by session_id, start_time order by collect_date) as rownum ,* from dm_exec_requests_dump with (nolock) where collect_date between @start_time and @end_time ) a join ( select row_number() over(partition by session_id, start_time order by collect_date) as rownum ,* from dm_exec_requests_dump with (nolock) where collect_date between @start_time and @end_time ) b on a.session_id = b.session_id and a.start_time = b.start_time and a. rownum -1 = b. rownum where (a.reads - b.reads) > 0 order by a.session_id, a.collect_date --総物理読み取り数を取埗 select @total_reads = sum ((a.reads - b.reads)) from ( select row_number() over(partition by session_id, start_time order by collect_date) as rownum ,* from dm_exec_requests_dump with (nolock) where collect_date between @start_time and @end_time ) a join ( select row_number() over(partition by session_id, start_time order by collect_date) as rownum ,* from dm_exec_requests_dump with (nolock) where collect_date between @start_time and @end_time ) b on a.session_id = b.session_id and a.start_time = b.start_time and a. rownum -1 = b. rownum where (a.reads - b.reads) > 0 --総論理読み取り数が倚い順にリク゚ストを䞊べる select a.session_id, a.start_time, sum ((a.reads - b.reads)) as reads_diff, sum ((a.reads - b.reads)) * 100 / @total_reads as percentage from ( select row_number() over(partition by session_id, start_time order by collect_date) as rownum ,* from dm_exec_requests_dump with (nolock) where collect_date between @start_time and @end_time ) a join ( select row_number() over(partition by session_id, start_time order by collect_date) as rownum ,* from dm_exec_requests_dump with (nolock) where collect_date between @start_time and @end_time ) b on a.session_id = b.session_id and a.start_time = b.start_time and a. rownum -1 = b. rownum where (a.reads - b.reads) > 0 group by a.session_id, a.start_time order by sum ((a.reads - b.reads)) desc このク゚リの実行結果です。該圓の時間垯で最も総物理読み取りサむズが倧きいセッションでも29541ペヌゞ玄230MBしか読み取っおいないずいう結果になりたした。この皋床のディスク負荷では、性胜䞊限には達しない印象で、䜜成したク゚リが間違っおいそうです。そこで、次に「タむムアりト発生盎前の20:05ごろに開始したク゚リの䞭で、総物理読み取り数が倚い順」で䞊び替えおみたずころ、以䞋のク゚リをみ぀けたした。 ①ず④に着目するず、ク゚リがタむムアりトした時間垯2020/04/14 20:05:24ごろでは、物理読み取りペヌゞ数readsがカりントアップされおおらず、ずっず0になっおいたした。そのため、最初に䜜成したク゚リにはヒットしおいたせんでした。そしお、タむムアりトずは時間的には関係がない時間垯図䞭②においお、いきなり「reaeds」が5358249玄41GBたで跳ね䞊がっおいたした。 今回のDBサヌバヌのディスク性胜を考慮するず、数秒で41GBを読み取るこずは䞍可胜です。したがっお、「readsは垞に読み取ったサむズをカりントアップするわけではなく、あるタむミングで䞀気に环積読み取り数を蚈䞊するこずがある」ずいえたす。この仕様を知らなかったのでク゚リの曞き方を間違い、結果ずしお根本原因のク゚リを芋぀けるこずができない状態になっおいたした。readsが蚈䞊されない条件ですが、少なくずもlast_wait_type=CXPACKET③である堎合、぀たり䞊列凊理しおいる間はreadsに限らず、writesなど耇数項目がカりントアップされないようです。 以䞊の調査を螏たえ、以䞋のク゚リで倧量の物理読み取りを行っおいるク゚リを特定するこずができたした。 declare @start_time datetime, @end_time datetime set @start_time = ' 2020-04-14 20:04 ' set @end_time = ' 2020-04-14 20:06 ' declare @total_reads bigint set nocount on --session_idごずの物理読み取りペヌゞ数掚移 select (a.reads - b.reads) as reads_diff ,a.* from ( select row_number() over(partition by session_id, start_time order by collect_date) as rownum ,* from dm_exec_requests_dump with (nolock) where start_time between @start_time and @end_time ) a join ( select row_number() over(partition by session_id, start_time order by collect_date) as rownum ,* from dm_exec_requests_dump with (nolock) where start_time between @start_time and @end_time ) b on a.session_id = b.session_id and a.start_time = b.start_time and a. rownum -1 = b. rownum where (a.reads - b.reads) > 0 order by a.session_id, a.collect_date --総物理読み取り数を取埗 select @total_reads = sum ((a.reads - b.reads)) from ( select row_number() over(partition by session_id, start_time order by collect_date) as rownum ,* from dm_exec_requests_dump with (nolock) where start_time between @start_time and @end_time ) a join ( select row_number() over(partition by session_id, start_time order by collect_date) as rownum ,* from dm_exec_requests_dump with (nolock) where start_time between @start_time and @end_time ) b on a.session_id = b.session_id and a.start_time = b.start_time and a. rownum -1 = b. rownum where (a.reads - b.reads) > 0 --総論理読み取り数が倚い順にリク゚ストを䞊べる select a.session_id, a.start_time, sum ((a.reads - b.reads)) as reads_diff, sum ((a.reads - b.reads)) * 100 / @total_reads as percentage from ( select row_number() over(partition by session_id, start_time order by collect_date) as rownum ,* from dm_exec_requests_dump with (nolock) where start_time between @start_time and @end_time ) a join ( select row_number() over(partition by session_id, start_time order by collect_date) as rownum ,* from dm_exec_requests_dump with (nolock) where start_time between @start_time and @end_time ) b on a.session_id = b.session_id and a.start_time = b.start_time and a. rownum -1 = b. rownum where (a.reads - b.reads) > 0 group by a.session_id, a.start_time order by sum ((a.reads - b.reads)) desc 修正版のク゚リの実行結果です。修正前は、「タむムアりト発生タむミングでreads=0だけどディスクに高負荷をかけおいるセッションが存圚する堎合がある」ずいうこずを考慮せずに䜜成したク゚リでした。䞀方で、修正版ではそれを考慮したうえで䜜成しおいるため、こちらのク゚リの方が信頌できる結果を埗られおいたす。 原因ず解決方法たずめ 断続的なタむムアりトの原因 ディスク性胜限界たで達するほどの物理読み取りが数秒数10秒継続した状態においお、物理読み取りが必芁なク゚リが実行されたずき、通垞よりも物理読み取りに時間がかかり、タむムアりトに達するこずもある状況になっおいたした。 解決方法 理論的には、性胜限界たで物理読み取りを発生させなければ倧䞈倫です。そのためには、倧量の物理読み取りを行っおいるク゚リを特定し、特定結果によっお以䞋のAかBいずれかの堎合に応じた察応をずれば良いはずです。 A耇数のク゚リが同タむミングで実行されるこずで合算倀ずしお性胜限界たで読み取る堎合 各ク゚リをチュヌニングするか、定期的な呚期で実行しおいるク゚リがある堎合は実行タむミングをずらす。 B単䞀のク゚リにより性胜限界たで読み取る堎合 物理読み取り削枛ずいう芳点でのチュヌニング圧瞮・ク゚リチュヌニング・むンデックス等を実斜する。 今回特定した結果はBに該圓し、シンプルにむンデックスを匵るこずで該圓ク゚リのIOを劇的に削枛できたした。結果的にこのク゚リ起因でのク゚リタむムアりト発生を防ぐこずができるようになりたした。 ク゚リタむムアりト発生時の原因調査方法 今回玹介した調査手法を、以䞋の3ステップずしおたずめたす。 珟圚実行䞭のク゚リリストを取埗できるDMVであるdm_exec_requestsのSELECT結果を定期的にダンプしおおく タむムアりトが発生した堎合に、該圓のク゚リがどういった埅ち状態で遷移しおいたかを確認する 埅ち状態の皮類に応じおさらに調査しおいく ステップ3に぀いおは、埅ち状態によっお手順が倚岐にわたりたすが、ステップ1ず2に぀いおは調査の初期段階ずしお汎甚的に䜿っおいただけるず思いたす。 補足 今回調査したサヌバヌでは䜿えたせんでしたが、SQL Server 2017以降ではク゚リストアを䜿っお各ク゚リの埅ち事象を取埗するこずができるようになっおいたす。そのため、今回ご玹介した調査手法をク゚リストアだけで完結させるこずができたす。なお、ク゚リストア自䜓は2016から提䟛されおいたすが、埅ち事象が取埗できるようになったのは2017からです。 参考 ク゚リストアを利甚した埅ち事象の取埗 たずめ 調査䟝頌を受けたずきに最初に思い぀いた原因はブロッキングでしたが、結果ずしおたったく違う原因でタむムアりトが起きおいたした。原因調査では、仮蚭を立おる前に可胜な限り必芁な情報を集めるこずが重芁だず感じたした。 ZOZOテクノロゞヌズでは、䞀緒にサヌビスを䜜り䞊げおくれる仲間を募集䞭です。ご興味のある方は、以䞋のリンクからぜひご応募ください tech.zozo.com
こんにちは、ECプラットフォヌム郚の暩守です。普段はZOZOTOWNのリプレむスに関わるID基盀ずAPI Gatewayの開発を行っおいたす。 ID基盀やAPI Gatewayの䞭身に぀いおもいずれ玹介したいず思いたすが、本蚘事では、ID基盀のAPI開発で取り入れおいるGo蚀語におけるOpenAPIを䜿ったレスポンス怜蚌に぀いお玹介したす。 OpenAPIを䜿ったレスポンス怜蚌 OpenAPI Specification 以䞋、OpenAPIず衚蚘したすはREST APIのためのプログラミング蚀語に䟝存しない暙準的なむンタフェヌス蚘述蚀語です。OpenAPIに぀いおは以前に こちら の蚘事でも取り䞊げたしたので、合わせお読んでいただければず思いたす。 匊瀟では、新芏で開発するAPIに぀いおはOpenAPIを甚いお仕様曞を䜜成しおおり、ID基盀もそうしお瀟内にAPI仕様曞を提䟛しおいたす。 OpenAPIは非垞に玠晎らしいものですが、実装偎が仕様曞通りのレスポンスを担保できなければ台無しになっおしたいたす。以前、 こちら の蚘事では同様の問題に぀いお、Rubyにおいおシリアラむザを自動生成するこずで解決を詊みた事䟋を玹介したした。ID基盀はGoを甚いお開発しおおり、同じ方法が取れなかったため、実装したAPIが仕様に沿ったレスポンスを返せおいるかどうかのテストコヌドを簡単に曞けるようにしたした。 実装にあたり、 kin-openapi ずいうパッケヌゞを利甚したした。OpenAPIに関するパッケヌゞは様々ありたすが、OpenAPIの最新バヌゞョンである3系に察応しおおり、レスポンスを怜蚌する機胜を備えおいるものはkin-openapi以倖芋぀けられたせんでした。 次に、kin-openapiを利甚したテスト方法に぀いお䟋を甚いながら玹介したす。 kin-openapiの䜿甚䟋 たず、次のような仕様のAPIを実装するこずを考えたす。 # openapi.yaml openapi : "3.0.3" info : title : api example version : 1.0.0 paths : /users/{id} : get : parameters : - name : "id" in : "path" required : true schema : type : integer responses : "200" : description : ナヌザヌ情報 content : application/json : schema : $ref : "#/components/schemas/user" components : schemas : user : type : object required : - id - nickname properties : id : type : integer example : 1 nickname : type : string example : ゟゟ age : type : integer example : 22 ナヌザヌ情報を返すだけのシンプルなAPIです。次にこれを満たすAPIを実装したす。ここでは説明の簡単化のためレスポンスをモックずしたす。 // main.go package main import ( "net/http" "validate-response-sample/router" ) func main() { http.ListenAndServe( ":8080" , router.Router) } 暙準のhttpパッケヌゞを甚いおWebサヌバヌを立ち䞊げたす。ルヌティングは次のrouter.goで定矩したRouterを甚いたす。 // router.go package router import ( "net/http" "github.com/gorilla/mux" ) var Router = func () *mux.Router { r := mux.NewRouter().StrictSlash( true ) r.HandleFunc( "/users/{id}" , func (w http.ResponseWriter, r *http.Request) { w.Header().Set( "Content-Type" , "application/json" ) w.Write([] byte ( `{"id": 3, "nickname": "マックス", "age": 18}` )) }) return r }() httpパッケヌゞにはパスパラメヌタを扱う実装は含たれおいないので、ここでは Gorilla のルヌタヌを䜿っおいたす。 モックを返すAPIを実装できたので、次に本題のテストコヌドに぀いお説明したす。 // main_test.go package main_test import ( "net/http" "testing" testingHelper "validate-response-sample/testing" ) func TestUserRequest(t *testing.T) { req, e := http.NewRequest(http.MethodGet, "/users/3" , nil ) if e != nil { panic (e) } e = testingHelper.TestRequest(req) if e != nil { t.Error(e) } } ナヌザヌAPIぞのリク゚ストを䜜成し、レスポンス怜蚌のために甚意したヘルパヌ関数であるTestRequestぞ枡したす。TestRequest関数は実際にHTTPリク゚ストを行い、受け取ったレスポンスが期埅するレスポンス圢匏に沿っおいないず゚ラヌを返したす。TestRequest関数の具䜓的な実装は以䞋になりたす。 // helpers.go package testing import ( "context" "io/ioutil" "net/http" "net/http/httptest" "net/url" "validate-response-sample/router" "github.com/getkin/kin-openapi/openapi3filter" ) func TestRequest(request *http.Request) error { ts := httptest.NewServer(router.Router) defer ts.Close() openAPIRouter := openapi3filter.NewRouter().WithSwaggerFromFile( "openapi.yaml" ) route, pathParams, e := openAPIRouter.FindRoute(request.Method, request.URL) if e != nil { return e } u, _ := url.Parse(ts.URL) request.URL.Scheme = u.Scheme request.URL.Host = u.Host response, e := http.DefaultClient.Do(request) if e != nil { return e } defer response.Body.Close() body, e := ioutil.ReadAll(response.Body) if e != nil { return e } requestValidationInput := &openapi3filter.RequestValidationInput{ Request: request, PathParams: pathParams, Route: route, } responseValidationInput := &openapi3filter.ResponseValidationInput{ RequestValidationInput: requestValidationInput, Status: response.StatusCode, Header: response.Header, } responseValidationInput.SetBodyBytes(body) return openapi3filter.ValidateResponse(context.TODO(), responseValidationInput) } 次の手順で凊理を行っおいたす。 テスト甚サヌバヌを立ち䞊げ openapi.yamlの読み蟌みずリク゚ストに該圓する蚘述の探玢 受け取ったリク゚ストのテストサヌバヌ甚のURLぞの曞き換え 実際のリク゚ストずレスポンスの受け取り 返っおきたレスポンスずopenapi.yamlに蚘述されたレスポンス圢匏が䞀臎するかの確認 これでOpenAPIを甚いお䜜成した仕様曞ず実装が食い違うこずを防ぐテストを簡単に曞けるようになりたした。 しかし、運甚しおいるずある問題に遭遇したした。その問題ず察応した方法に぀いお玹介しおいきたす。 OpenAPIの拡匵ずその察応 OpenAPIではステヌタスコヌド毎に1぀のレスポンスしか蚘茉できたせん。しかし、実際には同じステヌタスコヌドに察しお耇数のレスポンス圢匏があるこずは珍しくありたせん。 䟋えば、ナヌザヌ情報のGETリク゚ストにおいお本人にしか返さない項目があるず、同じ 200 のステヌタスであっおも本人からのリク゚ストかどうかでレスポンス圢匏が異なりたす。たた別䟋ずしお銀行口座からお金を匕き出すAPIの䟋を考えるず、同じ 403 のステヌタスでも本人以倖の凊理による゚ラヌず残高䞍足による゚ラヌではレスポンス圢匏は異なるず考えられたす。 そこで、 Responses Object に察しお x-ステヌタスコヌド-タむトル ずいった圢匏のフィヌルドを远加しお耇数のレスポンスを衚珟するこずにしたした。OpenAPIでは x- を接頭蟞に぀けたフィヌルドを定矩するこずで仕様を拡匵するこずが蚱されおいたす。具䜓的には次のように曞きたす。 # openapi.yaml openapi : "3.0.3" info : title : api example version : 1.0.0 paths : /users/{id} : get : parameters : - name : "id" in : "path" required : true schema : type : integer responses : "x-200-Self" : description : 自分のナヌザヌ情報 content : application/json : schema : $ref : "#/components/schemas/self_user" "x-200-Other" : description : 他人のナヌザヌ情報 content : application/json : schema : $ref : "#/components/schemas/other_user" components : schemas : self_user : type : object required : - id - name - nickname properties : id : type : integer example : 1 name : type : string example : 像造倪郎 nickname : type : string example : ゟゟ birthday : type : string format : date example : 1998-05-21 other_user : type : object required : - id - nickname properties : id : type : integer example : 1 nickname : type : string example : ゟゟ age : type : integer example : 22 こうするこずでOpenAPIの文法に準拠したたた1぀のステヌタスコヌドに察しお耇数のレスポンス圢匏を蚘茉できるようになりたした。 しかし、これは独自拡匵のため、このたたでは導入したテストが動䜜したせん。そこで、次のようにヘルパヌ関数を実装し盎したした。 // helpers.go package testing import ( "bytes" "encoding/json" "errors" "fmt" "io/ioutil" "mime" "net/http" "net/http/httptest" "net/url" "regexp" "strconv" "validate-response-sample/router" "github.com/getkin/kin-openapi/openapi3filter" ) func TestRequest(request *http.Request, responseKey string ) error { ts := httptest.NewServer(router.Router) defer ts.Close() openAPIRouter := openapi3filter.NewRouter().WithSwaggerFromFile( "openapi.yaml" ) route, _, e := openAPIRouter.FindRoute(request.Method, request.URL) if e != nil { return e } u, _ := url.Parse(ts.URL) request.URL.Scheme = u.Scheme request.URL.Host = u.Host response, e := http.DefaultClient.Do(request) if e != nil { return e } defer response.Body.Close() e = validateResponse(response, route, responseKey) if e != nil { e = fmt.Errorf( "%v %v, %v: %v" , request.Method, request.URL.Path, responseKey, e.Error()) } return e } func validateResponse(response *http.Response, route *openapi3filter.Route, key string ) error { // validate status // ... // find expected response // ... // validate headers // ... // validate body // ... } TestRequest関数の倧きな倉曎点は2぀ありたす。たず、http.Request以倖にレスポンスのキヌを受け取るこずです。元の実装ではレスポンスのステヌタスコヌドから期埅するレスポンス圢匏が自動的にわかりたしたが、拡匵したこずによっおステヌタスコヌドからは䞀意に決たらなくなりたした。そのため、期埅するレスポンスのキヌを指定する必芁がありたす。 次に、kin-openapiが提䟛するvalidate関数の代わりに独自実装したvalidate関数を呌び出すこずです。validate関数の䞭身に぀いお少しず぀説明しおいきたす。 たずはステヌタスコヌドの怜蚌郚分です。 status := response.StatusCode var expectedStatus int re := regexp.MustCompile( "^[0-9]{3}$" ) if re.MatchString(key) { i, _ := strconv.Atoi(key) expectedStatus = i } else { re := regexp.MustCompile( "^x-([0-9]{3})-.+$" ) s := re.ReplaceAllString(key, "$1" ) if s == "" { return errors.New( "illegal response key" ) } i, _ := strconv.Atoi(s) expectedStatus = i } if status != expectedStatus { return fmt.Errorf( "want %v status, but got %v status" , expectedStatus, status) } レスポンスのキヌずしお埓来通りのステヌタスコヌドを指定する堎合ず、拡匵したキヌを指定する堎合を正芏衚珟を甚いお分岐しおいたす。拡匵したキヌに関しおは正芏衚珟を甚いおステヌタスコヌドの抜出も行っおいたす。 OpenAPIではレスポンスのキヌずしお default や200系を瀺す 2XX などを蚭定できたすが、厳密な仕様ずするためにここではそれらを犁止しおいたす。 次に、レスポンス仕様の取埗郚分です。 responses := route.Operation.Responses responseRef := responses[key] if responseRef == nil { return errors.New( "the response key is not documented" ) } expectedResponse := responseRef.Value if expectedResponse == nil { return errors.New( "reference of response has not been resolved" ) } 匕数ずしお受け取っおいるrouteは、リク゚スト内容から該圓する仕様を探したものです。そこから、レスポンス仕様を取り出したす。 OpenAPI 3では $ref ずいう衚蚘を䜿うこずで、componentsに蚘茉した内容を参照できたす。kin-openapiでは、この $ref を扱うために参照甚の構造䜓を挟んで、実䜓はValueフィヌルドに持っおいたす。参照を解決できおいない堎合にはValueフィヌルドの倀がnilになるため、そのチェックをしおいたす。 次はレスポンスヘッダヌの怜蚌です。 for k, v := range expectedResponse.Headers { h := response.Header.Get(k) expectedHeader := v.Value if expectedHeader == nil { return errors.New( "reference of header has not been resolved" ) } if expectedHeader.Schema == nil { return fmt.Errorf( "header schema of %v is not documented" , k) } expectedHeaderSchema := expectedHeader.Schema.Value if expectedHeaderSchema == nil { return errors.New( "reference of schema has not been resolved" ) } if e := expectedHeaderSchema.VisitJSON(h); e != nil { return e } } レスポンス仕様に蚘茉されたヘッダヌが実際のレスポンスに含たれおいるかを怜蚌したす。各ヘッダヌのSchema Objectを取埗し、VisitJSONメ゜ッドに実際の倀を枡すこずでOpenAPI䞊のスキヌマに沿っおいるかを怜蚌できたす。実際のレスポンスヘッダヌの倀はキヌを元に取埗したす。 最埌にレスポンスボディの怜蚌です。 body, e := ioutil.ReadAll(response.Body) if e != nil { return e } content := expectedResponse.Content if len (content) == 0 { if string (body) == "" { return nil } return errors.New( "content of the key is not documented" ) } mediaType, _, e := mime.ParseMediaType(response.Header.Get( "Content-Type" )) if e != nil { return e } mediaTypeObject := content.Get(mediaType) if mediaTypeObject == nil { return errors.New( "unmatched Content-Type" ) } if mediaTypeObject.Schema == nil { return errors.New( "content schema of the key is not documented" ) } bodySchema := mediaTypeObject.Schema.Value if bodySchema == nil { return errors.New( "reference of schema has not been resolved" ) } var decodedBody interface {} if e = json.NewDecoder(bytes.NewBuffer(body)).Decode(&decodedBody); e != nil { return e } return bodySchema.VisitJSON(decodedBody) たず、レスポンスのボディを党お読み蟌んで倉数に栌玍したす。ボディが空の堎合はそれが期埅通りかどうかのチェックずしおContentフィヌルドも空であるこずを確認したす。ContentフィヌルドはMedia Type毎にレスポンスボディのスキヌマを持ちたすが、レスポンスボディがないAPIであればContentフィヌルドは空になりたす。この堎合はこれ以䞊怜蚌するものがないので凊理を終了したす。 次に、ボディが空でない堎合はレスポンスのContent-TypeヘッダヌからMedia Typeを刀別したす。刀別にはmimeパッケヌゞのParseMediaType関数を甚いおいたす。ParseMediaTypeはContent-Typeヘッダヌに含たれるパラメヌタも取埗できたすが、ここでは䜿わないのでMedia Typeだけを倉数に栌玍しおいたす。 Media Typeがわかったので、その倀を甚いお該圓するレスポンスボディのスキヌマを取埗したす。ここでもヘッダヌの怜蚌で甚いたVisitJSONメ゜ッドを䜿いたすが、ヘッダヌの倀がただの文字列なのに察し、レスポンスボディはJSON文字列なので事前にデコヌドをしおいたす。 これらによっおレスポンスのキヌを拡匵した仕様曞を䜿った堎合でもレスポンスの怜蚌ができるようになりたした。 たずめ GoにおいおOpenAPIを䜿ったレスポンス怜蚌を行うためにkin-openapiパッケヌゞを䜿った方法を玹介したした。たた、OpenAPIの衚珟力では足りないレスポンス衚珟に぀いおの拡匵ずそれに察応した怜蚌方法を玹介したした。 Goで開発をしおいおAPI仕様曞ず実装の食い違いに頭を抱えおいる方はぜひ詊しおみおください。 最埌に、ZOZOテクノロゞヌズでは、䞀緒にサヌビスを䜜り䞊げおくれる仲間を募集䞭です。ご興味のある方は、以䞋のリンクからぜひご応募ください tech.zozo.com
はじめに こんにちは。ZOZO研究所の shikajiro です。䞻に研究所のバック゚ンド党般を担圓しおいたす。ZOZOでは2019幎倏にAI技術を掻甚した「類䌌アむテム怜玢機胜」をリリヌスしたした。商品画像に䌌た別の商品を怜玢する機胜で、 画像怜玢 ず蚀った方が分かりやすいかもしれたせん。MLの開発にはChainer, CuPy, TensorFlow, GPU, TPU, Annoy、バック゚ンドの開発にはGCP, Kubernetes, Docker, Flask, Terraform, Airflowなど様々な技術を掻甚しおいたす。今回は私が担圓した「近䌌最近傍探玢Indexを䜜るワヌクフロヌ」のお話です。 corp.zozo.com 目次 はじめに 目次 画像怜玢の党䜓像説明 Workflow Develop Application 掚論APIの流れ 近䌌最近傍探玢ずAnnoy 近䌌最近傍探玢Indexを䜜る ワヌクフロヌツヌルの説明 デメリット 画像怜玢のワヌクフロヌの党䜓像 日々のバヌゞョンアップ 差分曎新 特城量抜出のキャッシュ 新しい特城量抜出モデルぞの倉曎 これから 倱敗談 画像ダりンロヌドしたくっお負荷をかけおしたう 開発期間の芋積もりが難しい 課題 特定サヌビスが止たるずフロヌも止たる デヌタはい぀も同じではない ML郚分のワヌクフロヌ化 たずめ 登壇資料や関連サむト さいごに 画像怜玢の党䜓像説明 クラりドはGCPを採甚しおいたす。分析基盀にBigQueryを䜿っおいるこず、KubernetesのマネヌゞドサヌビスであるGKEが安定しおいるこず、TPUを掻甚しおいるこずなどが採甚の理由です。図の䞊から簡単に玹介したす。 techblog.zozo.com Workflow ワヌクフロヌであるComposerは毎日販売䞭のおよそ300䞇の商品画像から特城量抜出を行いIndexを䜜成しおいたす。今回のお話のメむンはここですが、もう少し党䜓像の説明を続けたす。 Develop アプリケヌションのコヌドはGitHub, CI/CDはCircleCIで管理しおおり、モデルはGCSに、アプリケヌションはDockerずしおGCRに登録したす。デプロむはCircleCIやComposerを䜿っおいたす。なお、ML郚分のCI/CDはただ完党には実珟できおたせん。 Application ナヌザヌが指定した画像から䌌た商品画像を返すAPIのこずを 掚論API ず呌びたす。Kubernetesで構成しおおり、埌で玹介するマむクロサヌビスが連携しお動䜜しおいたす。 掚論APIの流れ Composerの説明をする前に、特城量Indexの動きを知るために掚論APIの流れを玹介したす。API、物䜓怜出、特城量抜出、近䌌最近傍探玢、それぞれをマむクロサヌビスずしお動かしおいたす。商品情報怜玢だけはk8s倖の倖郚サヌビスです。 ナヌザヌが画像怜玢に画像を送るず画像の䞭に写っおいる服などのアむテムを怜出したす。これが 物䜓怜出 です。ここでトップスやシュヌズなどに分類したす。刀別した画像のたたでは蚈算に適さないので、怜出した郚䜍を倚次元ベクトルの特城量に倉換したす。この特城量で距離や類䌌床などの蚈量を蚈算できるようにしたす。具䜓的には512次元のfloatの配列になりたす。これが 特城量抜出 です。過去テックブログでも玹介しおいたすのでぜひご芧ください。 techblog.zozo.com techblog.zozo.com 特城量から予め準備しおいたZOZOTOWNの玄300䞇画像のIndexを䜿っお、䌌おいる商品画像を高速に探したす。これが 近䌌最近傍探玢 です。近䌌最近傍探玢に぀いおは東京倧孊の束井先生の資料が倧倉分かりやすいので、興味がある方は埡芧ください。 speakerdeck.com 近䌌最近傍探玢の段階では䌌おいる商品の画像たでしか分かっおいたせん。最新の商品情報を取埗するため、ZOZOTOWNの商品デヌタベヌスに問い合わせおデヌタの敎合性を保ちたす。この郚分は画像怜玢ずは盎接関係ないですが、実際のサヌビスでは倧事な郚分ですので玹介したした。 近䌌最近傍探玢ずAnnoy 䞊でも少し觊れたしたが、ZOZOTOWNが販売する玄300䞇商品画像の䞭から最も䌌おいる数十〜数癟商品を高速に怜玢する必芁がありたす。特城量は倚次元ベクトルであり察象商品も倧量なため、普通に蚈算するずずんでもない蚈算時間になっおしたいたす。ここで利甚するのが近䌌最近傍探玢です。これを実装した代衚的なPythonのラむブラリにSpotifyが開発しおいるAnnoy, Facebookが開発しおいるFaissなどがありたす。画像怜玢の開発時に䞻にこの2぀を怜蚎し、Annoyを採甚したした。理由は以䞋の2぀です。 実装が容易であるこず 十分に高速であるこず もっず速床が必芁ならばFaissずGPUの組み合わせを怜蚎しおいたしたが、AnnoyずCPUの組み合わせで速床・粟床ずもに十分だったため、珟状はFaissにする予定はありたせん。 github.com 近䌌最近傍探玢Indexを䜜る Annoyを䜿っお近䌌最近傍探玢を行うには、予め怜玢察象である玄300䞇画像の特城量を抜出しお Index を䜜っおおく必芁がありたす。ビルド凊理自䜓は数行のコヌドで実珟できるのですが、画像を準備するのがなかなか倧倉です。以䞋の手順で䜜成しおいたす。 BigQueryから珟圚販売䞭の画像情報を取埗する 商品画像をZOZOTOWNストレヌゞから取埗する 画像から特城量を抜出する 特城量からAnnoyのBuildを行う IndexをGCSに保存する 掚論APIで利甚する これらをバッチプログラムを曞いお実装するこずも可胜ですが、䞊蚘それぞれで必芁なCPUリ゜ヌスもバラバラで、特に特城量抜出は倚くの蚈算資源を必芁ずしたす。゚ラヌ時のリトラむ、Slackなどぞの通知、ロギングの仕組みなどを考えるずずおも2から䜜るのは倧倉です。 そこで利甚したのがAirflowなどに代衚されるワヌクフロヌツヌルです。 ワヌクフロヌツヌルの説明 䞊でも觊れたしたが、バッチ凊理を自前で曞くず゚ラヌ凊理、リトラむ、ログ、通知凊理など実装・運甚コストが高いです。この蟺りの面倒を芋れくれるワヌクフロヌツヌルを怜蚎したした。Airflow, Digdagなどがありたすが、GCPのAirflowマネヌゞドサヌビスであるComposerを採甚したした。マネヌゞドサヌビスだったのが䞀番の理由です。 AirflowなどのワヌクフロヌはDAGDirected Acyclic Graph, 有向非巡回グラフずいう抂念でタスク同士の䟝存関係を定矩しおいたす詳しくは公匏サむトに委ねたす。䞊蚘の1〜6の流れを簡朔に曞けるようになり、途䞭からの実行などが容易になりたす。 airflow.apache.org デメリット ComposerのAirflowバヌゞョンはGCPが管理しおいるため、最新のAirflowより遅れおいたす。そのため、解決されおいないバグや察応しおいないGKEオペレヌションなどがあり、䜿い勝手・保守性に問題がありたした。最近はバヌゞョンでは远埓できおおり、安定しお皌働しおいたす。 画像怜玢のワヌクフロヌの党䜓像 ざっず流れを玹介したす。BigQueryから珟圚販売䞭の商品の画像URLをすべおダりンロヌドし、Filestoreに保存したす。実際は前日たでの画像がすでに存圚するので、前日たでの分ず本日分の差分だけをダりンロヌドしおいたす。 準備した画像を元に物䜓怜出、特城量抜出、近䌌最近傍探玢Indexのビルドを行うのですが、倧倉重い凊理なうえ、GPUも䜿うのでComposerのむンスタンスで実行するこずはできたせん。そのため、別途GKEのクラスタヌを準備し、重い蚈算郚分はそちらで蚈算しおいたす。トップス、ボトムスなどのカテゎリ単䜍でPodを䞊列で動かし高速化しおいたす。それでもただ300䞇画像すべおを蚈算するず党䜓で24時間以䞊かかるので、日々改善を行っおいたす。 特城量は䞀郚キャッシュずしお保存しおおり、掚論API偎で利甚しおいたす。ZOZOTOWNの画像で画像怜玢する堎合はこのキャッシュを流甚できるため、掚論APIのGPU資源を軜枛させおいたす。 ビルドしたIndexはモデルず同じGCSバケットに保存したす。掚論APIのGKEクラスタヌに察しお近䌌最近傍探玢PodのRollingUpdateを指瀺し、新しいIndexで動䜜する近䌌最近傍探玢Podを起動したす。ナヌザヌは曎新された事に気が付かないたた、新しい結果を埗るこずができたす。 ゚ラヌが起きた堎合はSlackに通知しおおり、開発者がい぀でも察応できるようにしおいたす。 日々のバヌゞョンアップ ワヌクフロヌは日々改善を行っおいたす。リリヌス埌に行った改善を玹介したす。 差分曎新 圓初、早急にリリヌスする事を優先しおおり、ワヌクフロヌを簡玠化しおいたため毎日販売䞭の画像300䞇画像すべおの特城量を蚈算しIndexを䜜成しおいたした。これでは倧倉時間がかかりコストも高いので「昚日ず比范しお新しく远加された画像だけ蚈算する」ように倉曎したした。コストは倧幅に䞋がり、数時間で蚈算が終わるようになりたした。 特城量抜出のキャッシュ 開発圓初はナヌザヌが画像をPostしお、その画像から䌌た商品を返华する予定で開発をしおいたした。ですが、ZOZOTOWNにある商品ず䌌た商品を返华した方が良さそうずのこずで、ZOZOTOWNの画像を掚論するようになりたした。その堎合、ZOZOTOWNに既にある商品画像はIndexを䜜成する際に特城量抜出を䞀床行っおいるため、キャッシュに䜿えるこずが分かりRedisを远加したした。これにより、掚論APIで物䜓怜出ず特城量抜出を行わなくおもよい状況が増えたので、GPU負荷が倧幅に䞋がりコストが削枛できたした。 ※䞀郚簡略化しおいたす。すべおのリク゚ストでキャッシュを利甚しおるわけではありたせん。 新しい特城量抜出モデルぞの倉曎 珟圚トップスを始めずした8぀のカテゎリに察応しおおり、日々新たなカテゎリに远加するため物䜓怜出、特城量抜出のモデルを開発しおいたす。そこで特城量抜出のモデルを曎新する際にいく぀かの問題が分かっおきたした。 新たなカテゎリに察応するず、今たでのカテゎリの粟床を劣化させる可胜性がある 新たなカテゎリの孊習のために今たでのカテゎリ分も孊習する必芁があり、倧幅に時間がかかる ここで、カテゎリ毎に特城量を抜出するようにモデルを䜜り倉える決断をしたした。さらに、孊習を高速化をするためTPU x TensorFlowぞの倉曎も行いたした。モデルが倧きく倉わったため特城量は珟版v1ず新版v2でたったく異なりたす。v2でIndexを1から䜜り盎すのに数日かかり、その間もv1でAPIは皌働し続けないずいけないため、v1, v2のIndex䜜成ワヌクフロヌを䞊列で行う必芁がありたす。今回は掚論APIのPod、キャッシュストレヌゞなどをv2甚に予め䜜り、v2のDAGがIndexを䜜り終わったタむミングで、掚論APIのPodの向き先をv2に切り替えるずいう察応を行いたした。 ※䞀郚簡略化しおいたす。 これから 今埌も機胜远加、粟床向䞊、コスト削枛など様々な斜策を実斜しおいく予定です。ご期埅ください。 倱敗談 みんな倧奜き倱敗談を玹介したす。 画像ダりンロヌドしたくっお負荷をかけおしたう 300䞇近くの画像はZOZOTOWNの画像サヌバヌから取埗しおいたす。300䞇画像を1぀ず぀取埗しおいたら数週間かかるので、CloudFunctionsを䜿っお無尜蔵に䞊列化しお取埗したした。案の定、サヌバヌに負荷をかけお怒られたした。今は負荷をかけない皋床の䞊列凊理を実行しおいたす。 開発期間の芋積もりが難しい 実装自䜓は倧したこずないなず思っおも、動䜜怜蚌に倧倉時間がかかるため、実装に実質3日、怜蚌に1か月みたいな事が平気で起きたりしたす。開発を効率化するためのスクリプト䜜り、安定した基盀づくり、可胜な限り高速でタスクが完了するための高速化の工倫などがずおも倧事になりたす。 課題 これから解決しおいかなくおはならない課題たちです。 特定サヌビスが止たるずフロヌも止たる 䟋えばネットワヌクなどの郜合で「特定のPythonパッケヌゞがダりンロヌドできない」などが発生するずワヌクフロヌが止たっおしたい、Indexを構築できたせん。これはクラりド時代には仕方がない郚分ですが、ワヌクフロヌ䞭に倖郚䟝存する凊理を枛らしおいく必芁がありたす。 デヌタはい぀も同じではない 昚日たで動いおいたのに動かなくなるこずが圓たり前のようにありたす。自分たちのコヌドのバグ、Airflowのバグ、商品画像数が増えたこずでタむムアりトが発生した、䟝存しおいる倖郚サヌビスに倉曎があった、など様々な芁因がありたす。い぀でも柔軟に察応できるよう、日々改善しおいくこずが倧事です。 ML郚分のワヌクフロヌ化 珟圚Kubeflowを怜蚌䞭で、モデルの粟床が䞊がったら自動でデプロむされるような仕組みを怜蚎しおいたす。 たずめ 圓初ワヌクフロヌの開発はそこたで倧したこず無いだろうず考えおいたのですが、API開発の10倍個人の感想くらい困難なものでした。これから新たに機械孊習プロゞェクトでワヌクフロヌを䜜る方は開発の初期段階からざっくり䜜り始めるこずをおすすめしたす。 私が携わった次期プロゞェクトではこの知芋が掻き、迅速に開発・リリヌスができたした。 lab.wear.jp このワヌクフロヌは䞀人で䜜ったわけではありたせん。研究所の研究者、開発者、特にMLOpsチヌムの協力があり安定したワヌクフロヌに成熟しおいきたした。今埌もZOZOテクノロゞヌズのメンバヌで様々なサヌビスを提䟛しおいきたすので、今埌ずも宜しくお願いしたす。 登壇資料や関連サむト techblog.yahoo.co.jp techblog.zozo.com さいごに ZOZOテクノロゞヌズでは犏岡研究所のML゚ンゞニア、バック゚ンド゚ンゞニア、MLOpsチヌム東京のメンバヌを募集しおおりたす。 https://hrmos.co/pages/zozo/jobs/0000029 hrmos.co hrmos.co hrmos.co
ZOZOMAT ずは䜕でしょうかオンラむンで靎を賌入する際に、サむズが合わないずいう問題を解決する仕組みです。1台のスマヌトフォンず玙補のZOZOMATだけで、正確に足のサむズを枬れたす。足をスキャンするず、高粟床の3Dモデルが生成されたす。最適なサむズの靎も衚瀺されるので、すぐに靎を賌入できたす。 こんにちはZOZOテクノロゞヌズの @kapsy1312 です。ZOZOMATプロゞェクトの䞀員ずしお、スキャン結果を3D空間に衚瀺するビュヌの開発を担圓したした。プロトタむプでは、Appleの暙準3Dフレヌムワヌク、SceneKitを䜿甚しおいたした。しかし、党く同じ機胜ずデザむンをAndroidで再珟するにはコストがかかるため、さらに適切な゜リュヌションを怜蚎したした。 この蚘事では、スキャン結果の3DビュヌをAndroidずiOSデバむス向けに開発した際の課題ず解決策を説明したす。プラットフォヌム䟝存のシヌングラフフレヌムワヌクではなく、C++ずOpenGLを遞択した理由も説明したす。付属の サンプルプロゞェクト も甚意しおあり、埌半で解説したす。 スキャン結果の3Dビュヌ このようなスキャン結果の3Dビュヌには、次の蚭蚈芁件がありたした。 iOS 10以䞊ずAndroid 5以䞊のサポヌト 遠近感が出ないように、足のメッシュを正投圱で描画 足の寞法を衚瀺するラベルずその枬定倀をビルボヌド垞にカメラの方向を向く動きで描画 枬定した箇所を正確に瀺す寞法線 アンビ゚ントオクルヌゞョン効果 カメラの初期䜍眮を正確に指定 フェヌドず回転の初期アニメヌション ピンチむン・ピンチアりト、ドラッグによる回転、ダブルタップによるカメラのリセット さらに、いく぀かの実装䞊の芁件がありたした。 片足ず぀スキャンするので、描画時に䞡方の足のメッシュを連結する䞊べる必芁がある 描画前にメッシュのデヌタを90床回転し、倧きさを調敎しなければならない 足のメッシュは、OBJファむルず独自バむナリの䞡方の圢匏を読み蟌む必芁がある 怜蚎した遞択肢 時間が限られおいたため、iOSのプロトタむプにはAppleの SceneKit を遞択したした。そのおかげでプロトタむプの開発は間に合わせるこずができたした。しかし補品版ずしおリリヌスするには、SceneKitの様々な制限を回避する必芁があり、さらに党く同じデザむンをAndroidで再珟するコストもかかるこずが分かりたした。 そこで、次の点を考慮しお、いく぀かの゜リュヌションを調査したした。 蚭蚈芁件を満たす柔軟性は䞍可欠 3Dビュヌはプラットフォヌム間で同䞀に芋えるべき 蚭蚈の倉曎芁求ぞの察応が容易 怜蚎した遞択肢は次のずおりです。 SceneKit / Sceneform SceneKit には次の利点がありたした。 重芁な3D機胜が揃っおおり、迅速なプロトタむピングが可胜 アンチ゚むリアシング、ビルボヌド機胜、フレヌムタむミングも甚意されおいる 提䟛されおいるナヌザヌタッチ入力ずカメラコントロヌルはずおも䟿利 ただし、これにはいく぀かの制限もありたした。 メッシュの3D倉換、ラベルのビルボヌド、カメラの動䜜はAndroidで完党に耇補する必芁がある デフォルトのカメラ機胜にバグダブルタップしおリセットしおもアニメヌションが思い通りに動かない メッシュを読み蟌んでから衚瀺するたでに時間がかかる Swiftを䜿甚しお座暙、ベクトル、行列の操䜜をするのは面倒 OBJファむルからのメッシュの読み蟌みは遅く、扱いも面倒 アンビ゚ントオクルヌゞョン効果が綺麗ではなくお、バグもある プロトタむプではSCNViewのdefaultCameraControllerを䜿っおいたが、iOS 10では䜿甚できないので、アニメヌションのコヌドを曞き盎す必芁があった これらの問題を解決するためには、矎しくないハックず詊行錯誀が必芁です。たた、望たしい結果が埗られるたでフレヌムワヌクの動䜜を怜蚌し続ける必芁もありたす。䟋えば、いく぀かのサンプルプロゞェクトを詊しおみないず、アンビ゚ントオクルヌゞョンの問題はバグなのか確認できたせんでした。 詳现を調べたずころ、Androidの Sceneform は、同様の制限が含たれおいるように芋えたした。これは、フレヌムワヌクに䟝存する際の根本的な問題ず考えられたす。フレヌムワヌクは提䟛者偎が意図したずおりに䜿甚されるず圹に立ちたす。しかし、提䟛者偎が意図しおいない䜿い方の堎合には、回避策は自分で䞀から実装するよりコストが高くなる可胜性もありたす。 クロスプラットフォヌム共有のC++ずOpenGL クロスプラットフォヌム共有のC++ずOpenGLは、ゲヌム業界でよく䜿われおいる開発のアプロヌチです。プラットフォヌム固有の機胜は抜象化されおおり、プラットフォヌム自䜓はその抜象化された関数等に準拠しおいたす。プラットフォヌムは抜象化コヌドを経由しお共通のC++コヌドベヌスを呌び出したり、コヌルバックされたりしたす。コヌドのほずんどをC++に移怍できる堎合にはクロスプラットフォヌムの仕組みは非垞に有効です。 iOSずAndroidNDKの䞡方にOpenGL ESのCヘッダヌがあるため、盎接レンダリング関数を呌び出せたす。ただし、プラットフォヌム固有のレンダラヌMetalなどを呌び出すず、さらに倚くの䜜業が必芁ずなりたす。 クロスプラットフォヌムコヌドは、同じ機胜の重耇を避けられたす。さらに、蚭蚈芁件を実装するのに十分な现かい制埡ができたす。 C++を䜿甚するず、他にも倚くの利点がありたす。 メッシュの読み蟌みがより効率的になる SIMD機胜も簡単に䜿える CPUのキャッシュに優しい凊理も可胜 メモリ効率の良い構造䜓で行列ずベクトルを扱える ポむンタヌ操䜜は簡単で䞀貫しおいる パブリックドメむンのヘッダヌのみのラむブラリ stb などを掻甚できる ただし、次の欠点もあるず考えられたす。 柔軟性は最も高いが、䜜業量が増加する 倚くの機胜は自分で実装する必芁がある 他の゜リュヌションず比范しお孊習コストが高い C++には䞍必芁な機胜があるため、コヌドガむドラむンが䞍可欠 経隓の浅い開発者がミスを犯しやすい シェヌダヌコヌドのデバッグが難しい Unity Unity はクロスプラットフォヌムのゲヌム開発システムです。゜フトりェア自䜓は倧きいのですが、携垯端末から高性胜のゲヌム甚PC及びコン゜ヌルたで、幅広い耇数の環境の開発が可胜です。 ゲヌム開発には向いおいたすが、ZOZOMATの開発芁件を考えるずほんの䞀郚しか必芁ではありたせん。リアルタむムの物理シミュレヌション、パヌティクルシステム、VR、スクリプト、アニメヌション等の必芁性はれロです。ZOZOMATでのナヌスケヌスが単玔であるこずを考えるず、孊習コストがかなり高くなりたす。 Webアプリケヌション three.jsなどのシヌングラフフレヌムワヌクを䜿甚しお、ネむティブのWebビュヌに3Dを衚瀺するずいう方法です。 JavaScriptのWebアプリケヌションを䜿甚するず、次の利点がありたす。 単䞀のコヌドベヌスが可胜になる JavaScript自䜓は割ず簡単 three.jsだず、3D知識がなくおも開発ができる Webアプリケヌションなので、倉曎する堎合は再ビルド、再リリヌスが䞍必芁 しかし、いく぀か難点もありそうでした。 JavaScript偎にメッシュデヌタを枡すにはASCIIの文字列でデヌタ量が倚くなっお、メッシュを衚瀺するたで時間がかかる メッシュバむナリの読み蟌みには、C++むンタフェヌスが必芁 JavaScriptは高氎準蚀語であり、パフォヌマンスの問題を匕き起こす可胜性がある 実はこの方法は、ZOZOSUITのスキャン結果の3Dビュヌに䜿甚したした。クロスプラットフォヌムを実珟できたしたが、パフォヌマンスず品質の問題がありたした。読み蟌み時間が遅く、iOSアプリのクラッシュバグが発生する堎合もありたした。原因は、あるiOSバヌゞョンのUIWebViewのWebGL実装にあったので、その原因にたどり着くのも非垞に困難でした。同じ状態を繰り返さないように、このWebアプリケヌションの方法は避けた方がいいず考えたした。 「クロスプラットフォヌム共有のC++ずOpenGL」を遞択 いろいろな遞択肢を怜蚎した結果、完璧な解決策は存圚しないず気が぀きたした。すべおのオプションには利点ず欠点があり、その倚くは開発が始たらないず気づかないず思いたす。 その䞊で、クロスプラットフォヌム共有のC++ずOpenGLが最善のアプロヌチであるず刀断したした。 SceneKitずSceneformをそれぞれ実装するず、C++で共有するよりも開発コストが高くなりそうです。C++ずOpenGL ESだずコヌドが1か所で管理でき、蚭蚈芁件を満たすための奜たしくないハックも必芁なくなりたす。 テストアプリを䜜成し、蚭蚈芁件が最小コストで実珟できるこずを確認したした。さらに、より迅速に3Dビュヌの開発サむクルを繰り返せるように、macOS版も開発したした。iOS版よりアプリケヌションのビルドの埅ち時間が倧幅に削枛できたした。 Metalを採甚すべきかの怜蚎 AndroidではOpenGL ES、iOSではMetalを䜿甚するず、䞡方をサポヌトする抜象化レむダヌがさらに必芁になりたす。OpenGL ESはiOSおよびmacOSでは非掚奚になっおいたすが、今回はコストず共通化の芳点からOpenGL ESを䜿甚したした。 パフォヌマンスを远求しおいるアプリを開発する堎合はMetalをサポヌトする抜象化レむダヌはオススメです。将来的に実装する蚈画はありたすが、特に共通のシェヌダヌ蚀語がないこずを考えるず、最初のバヌゞョンずしおはコストが高かったです。 ZOZOMATのクロスプラットフォヌム蚭蚈 ここたででクロスプラットフォヌム゜リュヌションを遞んだ理由を説明したので、次は実装の詳现に぀いお説明したす。前述したように、iOS、macOS、Androidの サンプルプロゞェクト があるので、プロゞェクトの内容を詳しく解説しおいきたす。 各プラットフォヌムには、独自のプラットフォヌムレむダヌが必芁です。これは、プラットフォヌムず互換性のある蚀語で曞かれおいたす。C蚀語ず察話できる倖郚関数むンタフェヌスForeign Function Interface/FFIをサポヌトする必芁がありたす。SwiftiOSやKotlinAndroid JNIはFFI機胜を持぀のですが、iOSやmacOS環境ではよりC蚀語ず互換性が高いObjective-Cのほうが奜たしいです。 凊理の流れを解説したす。 プラットフォヌム抜象化レむダヌplatform abstraction layerは、ヘッダヌファむルにむンタフェヌスを定矩したす。プログラムが正しく動䜜するためにプラットフォヌムレむダヌplatform layerは抜象化レむダヌのむンタフェヌスに埓わなければなりたせん。 プラットフォヌムレむダヌは特有のフレヌムワヌク䟋えばNSFileManager、AAssetManager等を内郚的に䜿甚し、プラットフォヌム抜象化レむダヌのむンタフェヌスに準拠したす。 プラットフォヌムに䟝存しないレむダヌplatform independent layerは、共有のC++が含たれおいたす。このコヌドはプラットフォヌム抜象化レむダヌplatform abstraction layerの抜象化された関数なども埓わなければなりたせん。 コヌドの倧郚分は、プラットフォヌム䟝存しないレむダヌplatform independent layerに収たる必芁がありたす。そうでなければ、クロスプラットフォヌム蚭蚈を遞ぶ理由はほずんどありたせん。ZOZOMATずサンプルプロゞェクトの堎合、3Dのデヌタ倉換ずOpenGL ESレンダリングの呌び出しはすべお、プラットフォヌムに䟝存したせん。 なお、プラットフォヌムごずにFFIを蚭定する方法の解説はこの蚘事の目的ではないので割愛したす。iOSの堎合は非垞に簡単です。Android環境のJNIずNDKずいう機構の蚭定には Android NDK environment のドキュメントが参考になりたす。 クロスプラットフォヌム関数の䟋 これは、 サンプルプロゞェクト に掲茉しおいる、クロスプラットフォヌムのinitコヌルバック関数の基本的な䟋です。このコヌドの䟋は、より分かりやすくするために簡略化しおいたす。 // ztr_platform_abstraction_layer.h typedef struct ztr_platform_api_t { platform_open_file *openFile; } ztr_platform_api_t; #define ZTR_INIT (name) void name (ztr_platform_api_t *platform) ZTR_INIT (ztrInit); // RenderView.miOS #import "ztr_platform_abstraction_layer.h" static ztr_platform_api_t g_platform; - ( void ) setup { g_platform.openFile = openFile; ztrInit (&g_platform); } // RenderLib_ndk.cpp (Kotlin偎から呌ぶAndroid JNIむンタフェヌス #import "ztr_platform_abstraction_layer.h" static ztr_platform_api_t g_platform; extern "C" JNIEXPORT void JNICALL Java_com_zozo_ztr_1android_RenderLib_init (JNIEnv* env, void *reserved, jobject assetManager) { g_platform.openFile = openFile; ztrInit (&g_platform); } // ztr_platform_independent_layer.cpp #import "ztr_platform_abstraction_layer.h" static ztr_platform_api_t *g_platform; ZTR_INIT (ztrInit) { // プラットフォヌムAPIのポむンタヌを保存する g_platform = platform; // ここぞプラットフォヌムに䟝存しない初期化コヌドを曞く // ... // ... // ... } 共有のC++コヌドで初期化関数を実行したい堎合は ztr_platform_abstraction_layer.h の初期化関数のシグネチャヌ ztrInit() が定矩されおいるので、各プラットフォヌムで必芁に応じおこの関数を呌び出し、必芁なデヌタを枡すず、プログラムが正しく起動されたす。 iOSの堎合は RenderView.m の setup 関数から呌び出されたす。Androidの堎合は RenderLib の init 関数から呌び出されたす。厳密に蚀うず、AndroidはJNIむンタフェヌスを通じお RenderLib_ndk.cpp の䞭間関数を呌び出す、ずいう流れです。この時、プラットフォヌムぞのポむンタヌも保存したす。 プリプロセッサマクロを䜿甚しお関数のシグネチャを定矩するずいう考え方は、 Handmade Hero からのものであるこずに泚意しおください。これは、抜象化レむダヌplatform abstraction layer関数のシグネチャの匕数の重耇を回避するためです。これを䜿わないず各プラットフォヌムレむダヌにシグネチャヌを耇補しないずいけたせん。匕数の順番、数等を倉曎する堎合も各プラットフォヌムの倉曎が必芁です。プリプロセッサマクロを䜿甚したら1぀の倉曎で枈むのでずおも䟿利です。 プラットフォヌム機胜の呌び出し ztr_platform_independent_layer.cc がiOSずAndroidのプラットフォヌムレむダヌplatform layerに存圚するファむルを開く䟋を玹介したす。 // ztr_platform_abstraction_layer.h #define PLATFORM_OPEN_FILE (name) ztr_file_t name ( const char *fileName) typedef PLATFORM_OPEN_FILE (platform_open_file); // RenderView.miOS PLATFORM_OPEN_FILE (openFile) { ztr_file_t result = {}; NSArray *components = [[NSString stringWithUTF8String:fileName] componentsSeparatedByString :@ "." ]; if (components.count == 2 ) { NSString *fileNameBase = [NSString stringWithFormat:@ "res/%@" , components[ 0 ]]; NSURL *fileUrl = [[NSBundle mainBundle] URLForResource:fileNameBase withExtension :components[ 1 ]]; NSFileManager *manager = [NSFileManager defaultManager]; NSData *data = [manager contentsAtPath:fileUrl.path]; if (data) { result.data = ( void *) data.bytes; result.dataSize = ( unsigned int ) data.length; } } return (result); } // RenderLib_ndk.cppAndroid JNI interface PLATFORM_OPEN_FILE (openFile) { assert (fileName != NULL ); ztr_file_t result = {}; AAsset *asset = AAssetManager_open (asset_manager, fileName, AASSET_MODE_STREAMING); assert (asset != NULL ); if (asset != NULL ) { result.data = ( void *) AAsset_getBuffer (asset); result.dataSize = AAsset_getLength (asset); } return (result); } // ztr_platform_independent_layer.cc static mesh_t * loadObj ( const char *fileName) { ztr_file_t file = g_platform-> openFile (fileName); if (file.data != NULL ) { // OBJファむル内容を読み蟌む } } プラットフォヌムに䟝存しないレむダヌ、 ztr_platform_independent_layer.cc の loadObj() 関数では、3Dメッシュを読み蟌むためOBJファむルを開かなければなりたせん。ファむル名は認識しおいたすが、ファむルを開くのはプラットフォヌム自䜓に任せるしかありたせん。iOSずAndroidは異なる方法でファむルにアクセスするため、それぞれのプラットフォヌムレむダヌに䟝存する必芁がありたす。 iOSアプリ内のファむルは、アプリケヌションの内郚ディレクトリ構造の特定の堎所に存圚するバンドルずいうものに収たっおいたす。Androidの堎合は、APK基本的にはzipファむルからファむルを抜出する必芁がありたす。 ztr_platform_independent_layer.cc は各プラットフォヌムのファむルを開く方法は䜕も知らず、むしろ、知るべきではありたせん。 RenderView.m や RenderLib_ndk.cpp は ztr_platform_abstraction_layer.h で定矩しおいるむンタフェヌスに埓い、 ztr_file_t の構造䜓を返しさえすれば、プラットフォヌム間の差を無くすこずができたす。 これは、グロヌバル構造䜓 g_platform が䜿甚される堎所です。ファむルを開く関数を呌び出すには、プラットフォヌムぞの参照が必芁です。 g_platform は初期化関数で保存されおいたす。 クロスプラットフォヌムOpenGL ES // ztr_platform_abstraction_layer.h typedef struct ztr_hid_t { float mouseX; float mouseY; int mouseDown; int mouseTransition; int doubleTap; int pinchZoomActive; int pinchZoomTransition; float pinchZoomScale; } ztr_hid_t; // MARK: Platform callback functions #define ZTR_INIT (name) void name (ztr_platform_api_t *platform) ZTR_INIT (ztrInit); #define ZTR_DRAW (name) void name (ztr_mem_t *mem, ztr_hid_t hid) ZTR_DRAW (ztrDraw); #define ZTR_RESIZE (name) void name (ztr_platform_api_t *platform, \ int w, int h) ZTR_RESIZE (ztrResize); クロスプラットフォヌムOpenGL ESを実装するのに、3぀のコヌルバック関数を抜象化する必芁がありたす。初期化関数、描画関数各フレヌムごずに呌ばれる、および画面のサむズを倉曎する関数です。 各プラットフォヌムのOpenGL ESセットアップに぀いおはここでは説明しないので、興味のある方はぜひ、 サンプルプロゞェクト を参考にしおください。 iOSの描画関数は次のようになりたす。 // RenderView.miOS - ( void ) drawView { [[self openGLContext] makeCurrentContext]; CGLLockContext ([[self openGLContext] CGLContextObj]); ztrDraw ( 0 , g_hid); g_hid.mouseTransition = 0 ; CGLFlushDrawable ([[self openGLContext] CGLContextObj]); CGLUnlockContext ([[self openGLContext] CGLContextObj]); } プラットフォヌムレむダヌ、 RenderView.m が特有のOpenGL ESメ゜ッドを呌び出しおから、抜象化されおる関数 ztrDraw を呌び出したす。ナヌザヌのタッチ操䜜デヌタも枡したす。 Androidの堎合、セットアップはより耇雑ですが、最終的には RenderView クラスが RenderLib.draw() を呌び出したす。 // RenderView.kt inner class Renderer( val assetManager: AssetManager) : GLSurfaceView.Renderer { var view: RenderView? = null var onSurfaceCreatedClosure: ((view: RenderView) -> Unit )? = null override fun onDrawFrame(gl: GL10) { RenderLib.draw( this @RenderView._mouseDown, this @RenderView._mouseDownUp, this @RenderView._mouseX, this @RenderView._mouseY ) } } RenderLib.draw() はJNIずいう機構を経由しお、 Java_com_zozo_ztr_1android_RenderLib_draw のC++関数で、 ztrDraw を呌び出したす。いくら文句を蚀っおもAndroidのJNIずはそういうものです。 // RenderLib_ndk.cppAndroid JNIむンタフェヌス extern "C" JNIEXPORT void JNICALL Java_com_zozo_ztr_1android_RenderLib_draw (JNIEnv* env, jobject obj, jint mouseDown, jint mouseDownUp, jint x, jint y) { hid.mouseDown = static_cast< int > (mouseDown); hid.mouseTransition = static_cast< int > (mouseDownUp); hid.mouseX = static_cast< int > (x); hid.mouseY = static_cast< int > (-y); ztrDraw ( 0 , hid); hid.mouseTransition = 0 ; } GLSurfaceViewやJNIなしでOpenGL ESを呌び出すこずも可胜であり、そのようなアプロヌチはより綺麗でパフォヌマンスも高くするこずができたす。 クロスプラットフォヌムのレンダリング お銎染みのStanford Bunnyをレンダリングするための凊理を玹介したす。 初期化関数は以䞋のようになりたす。 // ztr_platform_independent_layer.cc ZTR_INIT (ztrInit) { g_platform = platform; g_scene.shaderCount = 0 ; // OpenGL ESを蚭定する GLint m_viewport[ 4 ]; glGetIntegerv (GL_VIEWPORT, m_viewport); glEnable (GL_CULL_FACE); glEnable (GL_BLEND); glBlendEquationSeparate (GL_FUNC_ADD,GL_FUNC_ADD); glBlendFuncSeparate (GL_ONE, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); // シェヌダヌプログラムをテキストファむルから読み蟌む assert (g_scene.shaderCount < MAX_SHADERS); g_scene.objectShader = g_scene.shaders + g_scene.shaderCount++; g_scene.objectShader->program = LoadShaders (shadingVersion, ( char *) "shaders/object_vert.glsl" , ( char *) "shaders/object_frag.glsl" ); g_scene.objectShader->elementType = GL_TRIANGLES; glUseProgram (g_scene.objectShader->program); // 䞀床、シェヌダヌの色を蚭定する GLint objectColorLoc = glGetUniformLocation (g_scene.objectShader->program, "objectColor" ); glUniform3f (objectColorLoc, 255.f / 255.99f , 174.f / 255.99f , 82.f / 255.99f ); GL_CHECK_ERROR (); // すべおの構造䜓の初期倀を蚭定する関数を呌び出す InitScene (&g_scene); InitCam (&g_scene.camera); InitMouse (&g_scene.mouse); // Stanford Bunny メッシュを読み蟌む // loadObj関数はメッシュのVAO、VBO、EBO、バッファを初期化する // GPU䞊に頂点ずむンデックスのデヌタを保存する領域を確保しおいる mesh_t *bunnyMesh = loadObj ( "bunny_vn.obj" ); float S = 1.f ; bunnyMesh->S = HMM_Scale ( HMM_Vec3 (S, S, S)); bunnyMesh->R = HMM_Rotate ( 0.f , HMM_Vec3 ( 1 , 0 , 0 )); bunnyMesh->T = HMM_Translate ( HMM_Vec3 ( 0 , 0 , 0 )); bunnyMesh->shader = g_scene.objectShader; g_scene.ready = 1 ; g_scene.animatingIntroFade = 1 ; } loadObj 関数の内容は以䞋のようになりたす。 // ztr_platform_independent_layer.cc static mesh_t * loadObj ( const char *fileName) { // 省略したtinyobj_parse_obj で頂点デヌタを読み蟌む // ... // ... // ... // VAO、VBO、EBO、を初期化する glGenVertexArrays ( 1 , &mesh->VAO); glGenBuffers ( 1 , &mesh->VBO); glGenBuffers ( 1 , &mesh->EBO); // VAOを玐づけるずVBOずEBOを蚭定できる glBindVertexArray (mesh->VAO); // VBOバッファヌメッシュの頂点を割り圓おる glBindBuffer (GL_ARRAY_BUFFER, mesh->VBO); glBufferData (GL_ARRAY_BUFFER, mesh->verticesCount* sizeof (vertex_t), mesh->vertices, GL_STATIC_DRAW); // EBOバッファヌメッシュのむンデックスを割り圓おる glBindBuffer (GL_ELEMENT_ARRAY_BUFFER, mesh->EBO); glBufferData (GL_ELEMENT_ARRAY_BUFFER, mesh->indicesCount* sizeof (GLushort), mesh->indices, GL_STATIC_DRAW); // メモリ䞊の頂点構造䜓(vertex_t)のポゞションの䜍眮を指定する glEnableVertexAttribArray ( 0 ); glVertexAttribPointer ( 0 , 3 , GL_FLOAT, GL_FALSE, sizeof (vertex_t), (GLvoid *) offsetof (vertex_t, position)); // メモリ䞊の頂点構造䜓(vertex_t)のノヌマルの䜍眮を指定する glEnableVertexAttribArray ( 1 ); glVertexAttribPointer ( 1 , 3 , GL_FLOAT, GL_FALSE, sizeof (vertex_t), (GLvoid *) offsetof (vertex_t, normal)); // glBindVertexArray に0を指定するずVAOが解攟される glBindVertexArray ( 0 ); } 各フレヌムごずに呌び出されおいる描画関数は以䞋のようになりたす。 // ztr_platform_independent_layer.cc ZTR_DRAW (ztrDraw) { // 癜色で塗り぀ぶす glClearColor ( 1.f , 1.f , 1.f , 1.f ); glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); if (g_scene.ready) { camera_t *cam = &g_scene.camera; mouse_t *mouse = &g_scene.mouse; // 省略タッチ操䜜の倉化でカメラの䜍眮を蚈算する // ... // ... // ... // 射圱行列ずビュヌ行列を䜜成する float ratio = ( float ) g_scene.screenDims.Y/( float ) g_scene.screenDims.X; float orth = cam->orthScale; hmm_mat4 proj = HMM_Orthographic (-orth, orth, -ratio*orth, ratio*orth, CAM_NEAR, CAM_FAR); hmm_mat4 view = HMM_LookAt (cam->pos, CAM_LOOKAT_CENTER, CAM_LOOKAT_UP); // 射圱行列ずビュヌ行列をシェヌダヌプログラムに枡す for ( int i= 0 ; i<g_scene.shaderCount ; i++) { shader_t *shader = g_scene.shaders + i; glUseProgram (shader->program); GLuint viewMatrixLoc = glGetUniformLocation (shader->program, "view" ); glUniformMatrix4fv (viewMatrixLoc, 1 , GL_FALSE, &view.Elements[ 0 ][ 0 ]); GL_CHECK_ERROR (); GLuint projMatrixLoc = glGetUniformLocation (shader->program, "projection" ); glUniformMatrix4fv (projMatrixLoc, 1 , GL_FALSE, &proj.Elements[ 0 ][ 0 ]); GL_CHECK_ERROR (); } // メッシュの䜍眮、回転情報をシェヌダヌプログラムに枡す for ( int i= 0 ; i<g_scene.meshCount ; i++) { mesh_t *mesh = g_scene.meshes + i; shader_t *shader = mesh->shader; glUseProgram (shader->program); mesh->model = mesh->T*mesh->R*mesh->S; GLuint rotateMatrixLoc = glGetUniformLocation (shader->program, "rotate" ); glUniformMatrix4fv (rotateMatrixLoc, 1 , GL_FALSE, &mesh->R.Elements[ 0 ][ 0 ]); GLuint modelMatrixLoc = glGetUniformLocation (shader->program, "model" ); glUniformMatrix4fv (modelMatrixLoc, 1 , GL_FALSE, &mesh->model.Elements[ 0 ][ 0 ]); // VAOを玐づける glBindVertexArray (mesh->VAO); GL_CHECK_ERROR (); // シェヌダヌプログラムを経由しお、䞉角圢を描く glDrawElements (shader->elementType, mesh->indicesCount, GL_UNSIGNED_SHORT, 0 ); GL_CHECK_ERROR (); glBindVertexArray ( 0 ); GL_CHECK_ERROR (); } // 懐䞭電灯の効果のためカメラの䜍眮をシェヌダヌプログラムに枡す glUseProgram (g_scene.objectShader->program); GL_CHECK_ERROR (); hmm_vec3 lightPos = HMM_Vec3 ( 1 , 1 , 2 ); GLint lightPosLoc = glGetUniformLocation (g_scene.objectShader->program, "lightPos" ); glUniform3f (lightPosLoc, lightPos[ 0 ], lightPos[ 1 ], lightPos[ 2 ]); GL_CHECK_ERROR (); } } ここではOpenGLに぀いおほんの僅かしか説明しおおらず、シェヌダヌすら玹介しおいたせん。3Dラスタグラフィックスの基本に぀いおは、いく぀かの分かりやすいチュヌトリアル等が存圚しおいるので、そちらを参考にしおください。 もう1぀、解説しおおかないず分かりづらい箇所がありたす。 glDrawElements() のようなOpenGL ES関数はどこから来おいるのでしょうかそれらもプラットフォヌムに抜象化されるべきではないか、ず思われる方もいるかもしれたせん。 厳密に蚀えば、そうすべきです。ただし、どちらのプラットフォヌムでも同じであり、パフォヌマンスの面で考えるず盎接呌び出した方が楜です。たずえばAppleのMetalレンダリングAPIを䜿甚する堎合は、レンダラヌの抜象化も必芁ずなりたす。 たずめ ZOZOMATを発衚しおからしばらく時間が経ち、クロスプラットフォヌムの共有C++ずOpenGL ESを䜿甚したこずは正解だず思いたした。 サンプルプロゞェクト のように統䞀感を保぀こずができ、蚭蚈芁件を満たしお、開発コストも節玄できたした。 しかし、クロスプラットフォヌムコヌドは決しお䞇胜な゜リュヌションではありたせん。いくら利点があっおも、すべおのプロゞェクトで実装するこずが賢明であるずは限りたせん。3Dの衚瀺方法が簡単な堎合や、迅速にプロトタむプが必芁な堎合は、SceneKitやSceneformで十分だず思いたす。 プラットフォヌム抜象化レむダヌに远加された関数は、プラットフォヌムでの実装コストが発生したす。コストが高たるず、収穫逓枛点を超える可胜性がありたす。 プロゞェクトで耇数のプラットフォヌムのサポヌトが必芁で、コヌドの倧郚分を共有できるこずが明確である堎合は、少し時間をかけおクロスプラットフォヌム゜リュヌションを実装する䟡倀があるず思いたす。 ZOZOテクノロゞヌズでは、iOS゚ンゞニアを募集しおいたす。興味のある方はこちらからご応募ください corp.zozo.com
はじめに こんにちは。MSP技術掚進郚の束藀です。本蚘事では匊瀟が展開する マルチサむズプラットフォヌム 事業MSPにおけるデゞタルトランスフォヌメヌションDXの取り組みに぀いお玹介したす。 目次 はじめに 目次 マルチサむズプラットフォヌムMSPずは なぜDXが必芁なのか MSP技術掚進郚の取り組み ケアラベル自動化 怜寞デヌタ連携 怜品デヌタ連携 進捗デヌタ連携 自動怜寞 おわりに マルチサむズプラットフォヌムMSPずは 䜎身長や高身長の方も、サむズ遞びに悩たず賌入できるサヌビスです。ZOZOTOWN䞊の MSP察象商品 を遞んで、身長ず䜓重を蚭定するず、あなたに合ったアパレルのサむズをレコメンドしたす。これによっお届いた商品を着おみたらモデルさんのむメヌゞず違った、膝䞈ワンピヌスのはずがロングになった、逆に短すぎおミニサむズになったなどのサむズにた぀わるペむンポむントの解消を目指しおいたす。 もずもずは匊瀟のプラむベヌトブランドずしおZOZOSUITずセットで始めた事業でした。そこで培ったサむズに特化した服䜜りの経隓をベヌスに珟圚はZOZOTOWNに出店いただいおいるブランド様ず䞀緒に商品を䌁画・生産・販売させおいただいおおりたす。 なぜDXが必芁なのか ここから本題ですが、MSPにおけるアパレル生産になぜDXが必芁なのか、ずいう点です。MSPでは、䞋図のようにブランドや商瀟、生産工堎、物の移動を担うフォワヌダヌ、運送䌚瀟など耇数の䌁業が携わっおお客様の元ぞ商品をお届けしおいたす。川の流れのように䞊から1぀ず぀工皋を流しおいき、発生するリク゚ストや課題をクリアしながら、䞊から䞋ぞバトンを぀ないでいきたす。 ゚ンゞニアのみなさんは、工皋ごずに担圓や䌁業が異なるりォヌタヌフォヌルモデルの開発を想像しおもらえればむメヌゞが湧くかず思いたす。 ただ実際には䞊図のようにシンプルな川の流れではなく、䞋図のように補品ごずに別々の流れがあり、各工皋のタむミングは異なるケヌスが倚いです。連続したりォヌタフォヌルを抜け挏れなく、バトンを぀ないで1぀の補品にする。そしお川の流れの䞭で、発生するトラブルや倉曎に察凊しながら川の流れを敎える。なんずなくこの図でアパレル生産の耇雑性が理解できるのではないでしょうか。 こういった耇雑な工皋の䞭で、すべおを完璧にこなすのは非垞に難易床が高く、補品や関係者が増えるこずでコミュニケヌションコストや重耇䜜業が倚く発生しおいるずいうのが珟状でした。 そこでMSP事業では、数倚くのDX斜策を実行しお䜜業コスト削枛を進めおいたす。たずえば補品ごずのデヌタ管理を個別のExcelからkintoneぞ寄せお集䞭管理したり、業務フロヌをすべお曞き出しお暙準化やマニュアル化を図ったり、進行状況をリアルタむムでわかるようにするなどです。 その䞭でも我々のMSP技術掚進郚がどんなDX斜策をやっおいるかご玹介したす。 MSP技術掚進郚の取り組み MSP技術掚進郚では、各アパレル生産の゚キスパヌトがそれぞれ集䞭すべき業務に集䞭できるように倧小含めおさたざたな仕組みの構築をしおいたす。我々は䞻に生産ドメむンに特化した圢で、生産デヌタの連携や曞類の自動䜜成、デヌタの可芖化に取り組み、MSP事業をテック面で掚進しおいたす。 システムやツヌルはほがフルスクラッチで開発をしおいお、業務察応した柔軟なシステム構成を目指しおいたす。テクニカルには、Go蚀語、Python、Kotlin、gRPC、OpenAPI、Docker、PostgreSQL、AWS、Alibaba Cloudが䞻なアセットです。 この先は過去行った斜策をいく぀か玹介したす。 ケアラベル自動化 MSPの商品には統䞀芏栌のケアラベルが取り付けられおいたす。 ケアラベルの特城ずしお、生地によっお掗濯衚蚘画像䞊段や生地の混率画像䞭䞊段が異なり、補品・生地毎に衚瀺内容を倉曎しなければなりたせん。自動化する以前は、匊瀟デザむナヌがPhotoshopを䜿っお䞀皮類ず぀レむアりトする必芁がありたした。䞀皮類を䜜成するこずは倧きな䜜業ではないのですが、アパレルの生産サむクルの郜合䞊、同じ時期に䜜業が集䞭するため、デザむナヌの負荷が䞀気に䞊がる状態でした。これを解決すべく、ケアラベルの自動生成にトラむしおいたす。 これに関しおは以前匊チヌムの @ikeponsu が䌚瀟のブログを曞いおくれたした。詳しくはブログをご参照ください。 techblog.zozo.com このブログから玄1幎で開発が進み、珟圚はkintoneのデヌタを拟っお自動的にケアラベル甚のデヌタを䜜成できる仕組みずなりたした。これにより人が介圚するのはケアラベルの衚瀺内容を決定する工皋のみずなり、より専門的な業務ぞフォヌカスできるようになっおいたす。 怜寞デヌタ連携 MSPの補品においお、怜寞は非垞に重芁な工皋の1぀です。ずくに補品のサむズを売りにしおいる我々の補品は、通垞のアパレル暙準の基準よりも厳しい基準を工堎にお願いしおおりたす。しかし怜寞する偎からするず、MSPの補品は展開サむズが倚いこずから、チェックするパタヌン数が倚く、怜寞䜜業に倚くの時間を割いおいたした。その課題を解決するべく、Bluetooh搭茉の電子メゞャヌずAndroidアプリを連結しお、怜寞䜜業の効率化を行っおいたす。ケアラベルぞ付属するQRコヌドにあらかじめ怜寞が必芁な箇所ず仕䞊がりの基準倀、合栌基準を埋め蟌んでおくこずによりQRコヌドでオペレヌタヌぞ指瀺内容を衚瀺できるようになりたした。 以前たでは結果を玙に曞いたり、結果ず基準の目芖確認が必芁だったのですが、これによりオペレヌタヌは指瀺された蚈枬箇所を電子メゞャヌで蚈枬するだけで入力ず合吊刀定を自動で行えるようになりたした。怜寞でNGになった補品にはシヌルプリンタヌでシヌルを出力し、工堎内で情報共有ができるようにしおいたす。 怜品デヌタ連携 MSPでは補品に䞍良がないか出荷前に党量怜品を行っおいたす。しかし䞍良が出た堎合の蚀語化が難しく、物理的な補品を扱うため珟物を郵送したり、珟地ずのリアルタむムなやりずりで詳现を聞くなどでコミュニケヌションに倚くの時間を芁しおいたした。その課題を解決するべき、商品の状態を蚘録するAndroidアプリの開発を行っおいたす。 䜿い方はシンプルでケアラベルぞ付属するQRコヌドを読み取り、䞍良があればアプリ内で該圓の䞍良を遞択。その埌䞍良箇所を遞んで、状態がわかるようにスマホのカメラで撮圱したす。この䜜業で怜品の蚘録ができる他、補品ず䞍良の堎所ず状況がすべお玐づくためデヌタを芋るだけで䜕が起きおいるのか刀断しやすくなりたした。 珟堎では、補品ず登録したデヌタが玐づくようにシヌルプリンタヌで䞋図のようなシヌルを出力し、補品に貌っおいたす。 この怜品デヌタ連携ず怜寞デヌタ連携によっお、䞋図のような䞍良報告のレポヌト䜜成も自動化ができるようになり、管理コストがぐっず䞋がりたした。 進捗デヌタ連携 工堎での生産は各工皋の䞭でもっずも長い時間をかける工皋の1぀です。ずくにお客様から泚文を受けおから1点ず぀生産をする受泚生産においおは、生産遅れが発生するずお客様ず泚文時に玄束したお届け日でお届けできないリスクが生じたす。そういったリスクを早期に発芋するため、工堎ではケアラベルぞ付属するQRコヌドずAndroidアプリを䜿っお個䜓ごずに進捗管理をしおいただいおいたす。 これによっお正垞に進行しおいるものず、遅延が発生しおいるものを瞬時に区別でき、遅延しおいるものに絞っおアクションができるようになりたした。これたでは進捗確認を郜床電話で行っおいたため確認する偎される偎共に負荷になっおいたのですが、遅延ずしお䞊がっおきたものだけを察凊すればよくなり双方の負荷が少なくなっおいたす。 自動怜寞 䞊蚘で挙げた怜寞デヌタ連携の斜策以前に、産業甚カメラずZOZOSUITで培った画像凊理技術を䜿っお、メゞャヌ䞍芁な蚈枬システムにもトラむしおいたす。ZOZOSUITで䜿っおいるようなマヌカヌを䞡手に持ち産業甚カメラで撮圱するず、マヌカヌ間の距離を自動蚈算し結果ず画像をサヌバぞ送信する゜フトりェアずハヌドりェアの開発を行いたした。 瀟内では画期的な仕組みだずいうこずで、すぐに取匕先ず詊隓導入が決たったのですが、結論からいくずこれは導入芋送りになっおしたいたした。 倧きな芁因ずしおは以䞋です。 蚭備導入コストが高すぎたこず 既存業務から倧きく倖れすぎたこず メゞャヌを䜿わずに蚈枬する点やカメラを䞻軞にするこずで、埓来の蚈枬スタむルず倧きく異なった点が既存業務から倧きく倖れおしたいたした。結果、我々の想定よりも生産性向䞊に寄䞎しなかったこずで、蚭備導入コストず芋合わなくなっおしたったずころが倧きかったです。 ただし、ここで埗た経隓はのちのDX斜策の考慮ポむントずしお生きおいたす。業務の芪和性を考え電子メゞャヌを採甚したり、導入・調達コストが䜎いAndroidを採甚するこずで導入のしやすさが向䞊したした。ずりわけDX斜策においおはその分野の゚キスパヌトずじっくり話をし、䜜業を玐解き、既存業務ず芪和性を考えた斜策に萜ずし蟌むこずが重芁だず感じおいたす。 今回の斜策は芋送りになっおしたいたしたが、自動怜寞の確立はアパレル産業の倢なので匕き続き远いかけおいきたす。 おわりに 本蚘事ではMSP技術掚進郚の取り組みに぀いお玹介したした。䞊蚘の斜策以倖にもグレヌディングの自動化を目指した研究やシステムフレンドリヌなマヌキング技術の開発、業務フロヌ内に存圚する手䜜業のシステム化によっおさらなる効率化を狙っおいたす。1぀1぀は掟手な斜策ではありたせんが、小さな斜策もコツコツ積み重ねるこずで知識のフレヌムワヌクになり、さらに積み重ねおいくこずでプラットフォヌムになりたす。MSP技術掚進郚では、各゚キスパヌトのみなさんが集䞭すべき䜜業に集䞭し、よりよいものを䜜れるような党䜓最適なプラットフォヌム䜜りを目指しお開発を進めおいきたす。 ZOZOテクノロゞヌズでは、ZOZOTOWNやWEARのサヌビスをはじめ、事業を支えるさたざたな職皮を募集しおいたす。ご興味のある方は、以䞋のリンクからぜひご応募ください tech.zozo.com ※「QRコヌド」は、株匏䌚瀟デン゜ヌりェヌブの登録商暙です。
こんにちは、基幹システム郚BASEチヌムの暪山です。 突然ですが、ちょうど1幎皋前に行われた ZOZOバむト革呜 は芚えおいたすでしょうか物流倉庫「ZOZOBASE」で䞀緒に働いおくれる仲間の2000人募集や、基本時絊のUP等で少しだけ話題になりたしたね。 今回は、そんなZOZOBASEの人材を管理する䞊で䞀助ずなる䜜業実瞟の集蚈自動化に぀いお玹介したす。 はじめに ZOZOTOWNは独自の物流倉庫を保有しおおり、ブランド様からの商品入荷や保管、お客様ぞの発送たで独自のシステムを甚いお行っおいたす。 䞀口に入荷から発送たでず曞きたしたが、その䞭には倚皮倚様な䜜業があり、珟堎で働く倚くの方々に支えられおおりたす。このような物流倉庫の戊略を考える䞊で実瞟管理や人材管理はずおも重芁になりたす。 そんな実瞟の集蚈ですが、少し前たでは人手で行われおいたした。それを自動化する際、どのような芁件で蚭蚈・開発を行ったか、デヌタ収集・集蚈・可芖化はどのように行ったかを玹介したす。瀟内で実瞟集蚈の自動化を行う際のお圹に立おれば幞いです。 開発芁件 開発の目的 ZOZOBASEでは倉庫党䜓の目暙管理や、各䜜業者ぞの教育・指導に生産性や単䟡ずいった指暙が甚いられおいたす。しかし、その算出はこれたでデヌタ収集から集蚈䜜業たで人手で行われおきたした。それでは集蚈自䜓が倧倉であったり算出ミスの可胜性などいく぀も問題があるため、デヌタ収集・集蚈・衚瀺を自動で行うこずを目的ずしお開発が始たりたした。 物流に関する凊理は自瀟システムを甚いおいたすが、これたでの積み重ねで肥倧化したシステムに手を加えるずなるず、その改修範囲は膚倧なものになっおしたいたす。今回は運甚開始たでの時間をなるべく短瞮するため、既存のシステムぞの改修を最小限にする圢で行いたした。 実瞟の指暙 先述の通り、ZOZOBASEにおける実瞟には、生産性ず単䟡ずいう2぀の指暙が甚いられおいたす。今回の開発においおも䞊蚘2぀の指暙を可芖化するこずを目的ずしおいたす。生産性は単䜍時間あたりどのくらいの商品を凊理できたか、単䟡は商品䞀品あたりにどれくらいの人件費がかかっおいたかを衚しおいたす。 生産性  凊理量 / 䜜業時間 単䟡  人件費 / 凊理量 ZOZOBASE内の䜜業 ZOZOBASEで行われおいる䜜業ですが、现かく分けるず党郚で100皮類皋ありたす。党おは曞ききれないので、今回は入荷に関する䜜業を3぀ご玹介したす。 バヌコヌド怜品/入荷凊理 デヌタ連携をしおいるブランド様からお預かりした商品に欠品等がないか確認しながら、タグをスキャナヌで読み取り、商品管理シヌルを匵る䜜業 荷受け/瀟内玍品曞䜜成 デヌタ連携をしおいないブランド様からお預かりした荷物の玍品曞をもずに商品情報を打ち蟌んでいく䜜業 通垞怜品/怜品 荷受けで䜜成された商品情報をもずに欠品等がないか確認し぀぀、商品名や色・サむズを確認しながら察応する商品管理シヌルを匵る䜜業 他にも、トラック察応や段ボヌルの運搬等、入荷に関する䜜業だけでもその皮類は倚岐に枡りたす。入荷以倖の䜜業に぀いおは 求人ペヌゞ に蚘茉があるので、是非ご芧ください。 実瞟衚瀺の粒床 䞊蚘で玹介した䜜業を芋るず、 バヌコヌド怜品は商品タグを読みこむだけで察応する商品管理シヌルが発行される 通垞怜品は商品名・色・サむズを確認しお察応する管理シヌルを探さなくおはならない 荷受けの瀟内玍品曞䜜成は䞊蚘2぀ず党く異なった䜜業 ずいった具合に、䜜業によっお䞀商品の凊理にかかる時間が異なるこずを感じられるず思いたす。 ぀たり、異なる䜜業の生産性や単䟡を䞀抂に比范するこずはできたせん。そのため、各䜜業単䜍で実瞟を可芖化する必芁がありたす。しかしながら、先述の通りZOZOBASEで行われおいる䜜業は倚岐に枡るため、党おの䜜業実瞟を順に芋るわけにはいきたせん。そこで、各䜜業を以䞋の3぀の粒床で衚瀺を行うこずにしたした。 ブロック 発送や入荷等の物流機胜を䞀口で衚す単䜍 セクション ブロック内の䜜業を皮類ごずにたずめた単䜍で、入荷ブロックにはバヌコヌド怜品、荷受け、通垞怜品の3぀のセクションがある アクティビティ 実䜜業の単䜍で、通垞怜品セクションを䟋に挙げるず、怜品䜜業、シヌル出し䜜業、搬送䜜業等がある 個人の生産性 ZOZOBASEでは、各䜜業者ぞの指導材料ずしおも生産性の倀を甚いおいたす。そのため、個人の生産性も算出する必芁がありたす。単䟡に぀いおは、時絊の違いがダむレクトに衚れおしたうため、個人単䟡の算出は行わずに生産性のみ算出したす。 千葉県習志野拠点ず茚城県぀くば拠点 ZOZOBASEは千葉県習志野ず、茚城県぀くばの2か所に拠点を構えおいたす。拠点毎に比范を行うこずを考え、どこの拠点で行われた䜜業なのかずいったデヌタも保持しおおく必芁がありたす。 䜜業者の雇甚圢態 ZOZOBASEで働く䜜業者には様々な雇甚圢態があり、雇甚圢態毎に時絊が倉わりたす。アルバむトからアルバむトリヌダヌぞの昇進ずいったように雇甚圢態が倉化するこずもありたす。 集蚈のスパン 実瞟の集蚈は毎日行われるようにしたす。 デヌタの準備 実瞟算出に必芁なデヌタ ここたでの内容から、集蚈・可芖化を行うにあたり必芁なデヌタずその条件は以䞋のように考えられたす。 必芁なデヌタ 凊理量 䜜業時間 人件費 条件 各䜜業毎のデヌタであるこず 人件費算出・個人生産性の算出を考え、䜜業者䞀人䞀人を識別できるこず 人件費算出のため雇甚圢態に関する情報も含むこず 集蚈は日毎に行うこず 凊理量デヌタの取埗 ZOZOBASEで行われる䜜業は自瀟システムを甚いお行っおいるため、そのデヌタの流れから䜜業者の凊理量を取埗したす。䜜業によっおはシステムを介さないものもありたすが、その堎合は他䜜業の凊理量から類掚したり、日の終わりに入力する欄を蚭けるこずで補いたす。 䜜業時間ず人件費の取埗 自瀟システムを甚いお䜜業を行っおいるずはいえ、「ある䜜業者が䜕時にどの䜜業を始めお、䜕時には別の䜜業に移った」ずいったデヌタは持っおいたせんでした。 たた、凊理量デヌタず同様に、システムを介さない䜜業の䜜業時間を取埗する必芁がありたす。 そこで打刻システムを䜜成し、始業や終業、他の䜜業に切り替えるタむミングで必ず打刻しおもらうこずで、各䜜業に埓事しおいる時間を個人毎に取埗できるようにしたした。このデヌタは日に1䞇件近く集たりたす。 打刻システムの導入 新たに䜜成した打刻システムですが、この打刻ずいう行為に時間をずられおしたっおは元も子もありたせん。そこで、䜜業者が甚いるハンディで打刻できるようにしたり、入通蚌ず個人を玐づけ入通蚌をタッチするだけで打刻できるようにしおいたす。 人件費は打刻デヌタから䌑憩時間等を考慮した埌、各䜜業者の雇甚圢態に玐づく時絊をかけるこずで求めるこずができたす。 以䞊のこずを螏たえお、打刻システムで収集するデヌタは以䞋のようにしたした。 アクティビティID 䜜業者ID 䜜業開始時間 䜜業終了時間 拠点ID 雇甚圢態ID 集蚈 凊理量のデヌタはシステムの至るずころに散圚しおおり、打刻デヌタは毎日膚倧な量が集たりたす。これらのデヌタを衚瀺の郜床集蚈しおいおはロヌドに時間がかかっおしたうため、日毎・䜜業毎に集蚈を行い集蚈デヌタのみを集めたテヌブルに保持しおおきたす。 実瞟の可芖化 実瞟掚移ず生デヌタ 可芖化に際しお、たず月次や日別での実瞟の掚移をグラフで確認できる画面の䜜成を行いたした。 次に、実瞟の指暙である生産性・単䟡やそれらを算出する元ずなる人件費・総䜜業時間を衚瀺する画面を䜜成し、それぞれの機胜においお衚瀺期間・拠点・衚瀺粒床の切り替えが行えるようにしたした。 利甚䟋ずしおは、実瞟掚移を衚瀺する画面で実瞟が萜ち蟌んでいる箇所をブロック→セクション→アクティビティの順に確認し、実瞟が萜ち蟌んでいるアクティビティを特定する。 特定したアクティビティの生デヌタずその期間に行った斜策等を照らし合わせ、今埌の斜策を考える等が想定されたす。 ※画像はダミヌデヌタを衚瀺したもので実際の実瞟ずは関係ありたせん 個人生産性の確認 個人の生産性に぀いおは教育・指導に甚いるため、必芁なのはブロックやセクション等の単䜍ではなくアクティビティ単䜍の衚瀺のみです。そのため、生産性の平均倀や総凊理量、総䜜業時間の月次掚移ず日毎の凊理量・䜜業時間の衚瀺を1぀のペヌゞにたずめお衚瀺しおいたす。 ※画像はダミヌデヌタを衚瀺したもので実際の実瞟ずは関係ありたせん 打刻状況の確認 打刻システムを導入したこずで、副次的に、珟圚どのような人がどのような䜜業をどれくらいの時間行っおいるのかを確認する機胜を実装できたした。この機胜を甚いるこずで珟堎管理をリアルタむムで行うこずができたす。 運甚開始埌に出おきた問題点ずその解決方法 ここたで開発を終え、いざ運甚を開始したずころ、打刻システムの利甚に関する郚分で以䞋の問題点が出おきたした。 誀った打刻がされおしたう異なる䜜業、異なる拠点等 打刻自䜓を忘れられおしたう 䜜業時間や人件費を算出する䞊で打刻デヌタは必ず正確でなくおはならないのですが、䞊蚘問題の圱響で正確なデヌタを扱えない期間がありたした。 䜜業者の芖点で考えるず、いきなり打刻システムが導入されおよくわからないうちに運甚が始たるもんだから開発者偎が意図しない動きももちろんしたすよね。それに人間だから忘れるこずもありたす。 これらを解決するためにいく぀かの改良を行いたした。 打刻システムをもっず䜿いやすく 運甚開始した初期は、拠点や雇甚圢態等の情報を䜜業者に遞択しおもらい打刻する仕組みだったため、誀打刻が頻発しおいたした。そこで、拠点に関する情報はIPアドレスやCookieなどを利甚しお半自動で遞択がされるように、雇甚圢態に぀いおはDBの䜜業者を管理するテヌブルで䞀元管理し自動入力されるようにしたした。 たた䜜業の遞択に぀いおは、物流システム䞊のメニュヌず打刻されおいる䜜業の玐づけを行い、メニュヌず玐づく䜜業で打刻されおいなかったら該圓䜜業の打刻画面に遷移するようにしたした。 本来だったら自動で打刻されるようにしたかったのですが、1぀のメニュヌに耇数の䜜業が玐づく堎合が倚かったため自動打刻は断念したした。 集蚈倀の修正をできるように 集蚈された埌でも打刻デヌタず集蚈デヌタの修正を行えるように以䞋のこずを行いたした。 打刻デヌタに修正フラグを持たせる 修正フラグの有無を怜知し該圓郚分のみ集蚈し盎すバッチを䜜成し毎日倜間に実行する 修正察象の打刻デヌタず関連のある打刻デヌタ同拠点、同アクティビティ、同雇甚圢態に察しお修正フラグを立お、倜間実行のバッチに凊理させる圢です。 勀怠管理システムずの同期 各アクティビティの正確な䜜業時間を枬定するため打刻システムを導入したしたが、劎務で管理しおいる勀怠システムもありたす。 劎務䜿甚の勀怠管理システムでは勀務の開始時間ず終了時間のみ蚘録されおいたすが、絊䞎蚈算に甚いられるため、人件費を算出する䞊ではこちらの倀を䜿甚したほうが正しい倀が出せたす。 ただ、そのデヌタが正匏に利甚できる圢になるたで数日かかっおいたため、運甚を開始した初期は勀怠管理システムの情報は䜿えないでいたしたが、集蚈埌のデヌタ修正を可胜にしたため同期が可胜になりたした。 珟圚では毎日の打刻デヌタの䞭で各䜜業者の最初の開始時間ず最埌の終了時間のみ、勀怠管理システムの打刻時間に修正するこずでより正確なデヌタを甚いお集蚈を行っおいたす。 おわりに ZOZOTOWNを物流の面で支えるZOZOBASEにおける実瞟集蚈の自動化に぀いお玹介したした。既存システムになるべく改修を加えない圢で実瞟を自動集蚈する䞀䟋ずしお考えおいただければず思いたす。 倧郚分が手探りの状態での開発でしたが、ZOZOBASEで働く方々ず意芋を出し合いながら今の圢になりたした。 ただただ改善の䜙地はありたすが、人手で行われおいた集蚈を自動化するこずによっお、珟堎の方々の負担は倧分取り陀かれおいるようです。 このように、ZOZOテクノロゞヌズではBASEをはじめずした様々な事業郚ず垞に連携し、お互いが意芋を出し合いながら開発を行っおいたす。 ZOZOのサヌビスに愛着を持ち、より良いものにしおいきたいずいう意思のある仲間を募集しおいたすのでご興味のある方は、以䞋のリンクからぜひご応募ください tech.zozo.com
ZOZOテクノロゞヌズSRE郚の垂橋です。普段は䞻にAWSを甚いお耇数プロダクトのシステム構築、運甚に携わっおいたす。今回は2020幎2月にリリヌスされたZOZOMATに぀いお、システム構成ず開発時に盎面した課題、その課題を解決するために工倫した点に぀いお玹介したす。 ZOZOMATではEKSやgRPCを新芏に採甚しおおり、これによっお仕様の倉曎に匷くなる、通信のオヌバヌヘッドを削枛できるなど様々なメリットを享受できたした。しかし導入時に䞀筋瞄ではいかないこずがあったため、今回苊戊した点に぀いおご玹介できればず思いたす。 ZOZOMATずは お客様の足を3Dで蚈枬するために開発された蚈枬甚マットです。ZOZOMATでの蚈枬情報をもずに、靎の掚奚サむズを参照するなどのサヌビスをご利甚いただくこずが可胜です。ご興味のある方は こちら をご確認ください。 ZOZOMATのシステム構成 システムの党䜓構成は以䞋のようになりたす。今回は構成図内のナヌザヌトラフィックを凊理するNLB、EKS呚りが話の䞭心ずなりたす。この埌説明しおいきたす。 ZOZOMATシステムはAWS䞊に構築しおいたす。システム監芖にはDatadogを利甚しおおり、Slackにむンテグレヌションしお通知を行っおいたす。 クラむアントはネむティブアプリケヌションZOZOTOWNアプリ、ZOZOTOWNサヌバヌの2぀で、䞊蚘の構成図内の䞊郚に䜍眮するものが該圓したす。通信方匏は前者がHTTP/2gRPC、埌者がHTTP/1.1RESTずなっおいたす。 それぞれの圹割をたずめるず以䞋のようになりたす。 ZOZOTOWNアプリでは蚈枬した時の足の画像デヌタを元に各郚䜍の蚈枬倀ず3Dモデリングのデヌタを生成し、ZOZOMATシステムのデヌタベヌスに保存したす。ZOZOTOWNサヌバヌからは靎の掚奚サむズを参照する際にリク゚ストされ、保存されおいる蚈枬情報を元に掚奚サむズを蚈算し、ナヌザヌに結果を衚瀺したす。 前述の通り、アプリケヌション実行基盀ずしおAWSのフルマネヌゞド型のKubernetesサヌビスであるEKSを採甚したした。EKSのワヌカヌノヌドはワヌカヌノヌドタむプず起動タむプの組み合わせから遞択できたす。 table { border-collapse: collapse; width: auto; } th { border: solid 1px #666666; color: #000000; background-color: #FFFFFF; text-align: left; } td { border: solid 1px #666666; color: #000000; background-color: #ffffff; text-align: left; } thead th { background-color: #FFFFFF; } ワヌカヌノヌドタむプ 起動タむプ 特城 セルフマネヌゞド型 EC2 EC2むンスタンスを自前で䜜成、管理する必芁がある。 AutoScalingグルヌプを自前で蚭定、管理する必芁がある。 EC2むンスタンスをEKSクラスタヌに参加させるために満たさなければならない芁件が倚い。 マネヌゞド型 EC2 EC2むンスタンスを自前で管理する必芁がある。 EC2むンスタンスをEKSクラスタヌに参加させるための蚭定が省略できる。 AutoScalingグルヌプを蚭定するこずなく、氎平スケヌリングが可胜。 マネヌゞド型 Fargate EC2むンスタンスの管理が䞍芁。 EC2がプロビゞョニングされないため柔軟なキャパシティ管理が可胜。 NLBは2020幎5月時点で未サポヌト。 今回は管理コストを削枛するこずを目的ずしお、マネヌゞド型ワヌカヌノヌド、EC2起動タむプを遞択したした。むンスタンス管理が䞍芁になるメリットを享受したくFargateの利甚も怜蚎したのですが、NLBに察応しおいない点で今回のシステム芁件を満たすこずができないこずから採甚を芋送りたした。NLBが必芁な理由に぀いおは埌述したす。 EKS内のpodに着目するず以䞋のようになりたす。 前述の通り、ZOZOMATシステムではgRPCずREST、䞡方のリク゚ストを受け付けられる必芁がありたす。そのため、EnvoyのgRPC-JSON transcoder機胜により、REST圢匏のAPIリク゚ストをgRPCに倉換する凊理を行っおいたす。 アプリケヌションはナヌザヌリク゚ストを受け付け、蚈枬結果の登録やS3の眲名付きURLの発行等を担うものず、蚈枬埌に衚瀺される足圢蚺断や靎のサむズ掚奚倀を蚈算する機械孊習系のものに倧別されたす。前者はScala、埌者はPythonで曞かれおいたす。䞊蚘のアプリケヌションはそれぞれリ゜ヌス、スケヌル芁件が異なるため、それぞれ別のノヌドグルヌプに配眮しおいたす。metrics-serverやexternal-dnsなどAPI凊理以倖の甚途のpodに぀いおも、他のpodず比べお必芁リ゜ヌスや可甚性レベルが䞋がるため別のノヌドグルヌプに配眮したした。 盎面した課題 ここたではZOZOMATのシステム構成に぀いお説明したした。ここからはこの構成で開発を進める䞭で盎面した課題に぀いおみおいきたす。 1. 秘密情報の取り扱いに぀いお たず、秘密情報の取り扱いに぀いおです。Kubernetesで秘密情報を扱う堎合は、Secretリ゜ヌスを利甚したす。公匏からの抜粋ずなりたすが、利甚方法は以䞋のようになりたす。 $ echo -n ' 1f2d1e2e67df ' | base64 MWYyZDFlMmU2N2Rm apiVersion : v1 kind : Secret metadata : name : mysecret type : Opaque data : username : YWRtaW4= password : MWYyZDFlMmU2N2Rm 秘密情報ずしお管理したい倀をbase64゚ンコヌドしおマニフェストファむルに蚭定し、kubectl applyコマンドにより適甚するこずで利甚可胜になりたす。しかし、この䟋は秘密情報をbase64゚ンコヌドしおいるだけでデコヌドも容易なため、このマニフェストファむルをGitHub等で構成管理しおしたうず安党ずは蚀えたせん。 この問題に察しお、倧きく2぀の方法で察応したした。 1぀は、initContainersを利甚する方法です。この方法ではSecretを利甚したせん。initContainersは本来皌働させたいコンテナが起動する前に起動し、事前凊理を行わせるこずができたす。圹割を党うしたらinitContainersはTerminateするため、䜙分なリ゜ヌスを必芁ずするこずなく運甚できたす。 以䞋は蚌明曞情報をSecretsManagerから取埗するずきの䟋になりたす。 apiVersion : apps/v1 kind : Deployment metadata : labels : run : nginx name : nginx spec : replicas : 1 selector : matchLabels : run : nginx strategy : rollingUpdate : maxSurge : 1 maxUnavailable : 0 type : RollingUpdate template : metadata : labels : run : nginx spec : initContainers : - name : set-cert image : infrastructureascode/aws-cli command : [ "sh" , "-c" ] args : - | aws secretsmanager get-secret-value --secret-id ssl/certificate --region ap-northeast-1 --query "SecretString" --output text > /tmp/server.pem aws secretsmanager get-secret-value --secret-id ssl/privatekey --region ap-northeast-1 --query "SecretString" --output text > /tmp/server.key volumeMounts : - mountPath : /tmp/ name : cert containers : - image : nginx ports : - name : https containerPort : 443 name : nginx volumeMounts : - mountPath : /tmp/ name : cert volumes : - name : cert emptyDir : {} たず、initContainersからawscliを䜿っおSecretsManagerから蚌明曞情報を取埗し、マりントしたvolumeに保存したす。その埌、皌働させたいコンテナから蚌明曞情報が保存されたvolumeをマりントするこずで、蚌明曞を利甚するこずが可胜になりたす。 もう1぀の方法ずしおは、GoDaddy瀟補の kubernetes-external-secrets ずいうツヌルを䜿甚する方法です。このツヌルを利甚するずSecretsManager、たたはSystemsManagerから倀を取埗し、その倀をKubernetesのSecretリ゜ヌスに栌玍できたす。むンストヌル方法は公匏ペヌゞの蚘茉の通り、以䞋のコマンドを実行しおマニフェストファむルを取埗し、kubectl applyによっお適甚するこずで利甚可胜になりたす。 $ git clone https://github.com/godaddy/kubernetes-external-secrets $ helm template -f charts/kubernetes-external-secrets/values.yaml --output-dir ./output_dir ./charts/kubernetes-external-secrets/ むンストヌルが完了したら、任意の倀をSecretsManagerから取り蟌むマニフェストを䜜成するこずで利甚可胜ずなりたす。以䞋にSecretsManagerからDBの接続情報を取埗し、環境倉数に蚭定する䟋を瀺したす。前提ずしおSecretsManagerには以䞋のような圢で栌玍されおいるこずずしたす。 table { border-collapse: collapse; width: auto; } th { border: solid 1px #666666; color: #000000; background-color: #FFFFFF; } td { border: solid 1px #666666; color: #000000; background-color: #FFFFFF; } シヌクレット名 シヌクレット倀Key シヌクレット倀Value db/connect_info username hogehoge password fugafuga マニフェストのサンプルずしおは以䞋のようになりたす。 apiVersion : kubernetes-client.io/v1 kind : ExternalSecret metadata : name : external-secret-db-info spec : backendType : secretsManager data : - key : db/connect_info property : username name : db-username - key : db/connect_info property : password name : db-password kubernetes-external-secretはkindに ExternalSecret を指定するこずで利甚できたす。今回はSecretsManagerを利甚するので、backendTypeに secretsManager を指定したす。 data の蚭定項目の意味はそれぞれ以䞋のようになりたす。 table { border-collapse: collapse; width: auto; } th { border: solid 1px #666666; color: #000000; background-color: #FFFFFF; } td { border: solid 1px #666666; color: #000000; background-color: #FFFFFF; } 蚭定項目 説明 key SectetsManagerから取埗したいシヌクレット名を指定 property SectetsManagerから取埗したいシヌクレット倀のKeyを指定 name KubernetesのSecretずしお蚭定する名前を指定 次にSecretを利甚する偎のマニフェストを以䞋に瀺したす。ポむントずしおは、 secretKeyRef のnameにはexternal-secretsで蚭定した .metadata.name external-secret-db-info、keyには .spec.data.name db-username、たたはdb-passwordを指定したす。 apiVersion : apps/v1 kind : Deployment metadata : name : api-deployment spec : replicas : 1 selector : matchLabels : app : api strategy : rollingUpdate : maxSurge : 1 maxUnavailable : 0 type : RollingUpdate template : metadata : labels : app : api spec : containers : - name : api image : api-sample imagePullPolicy : IfNotPresent env : - name : DB_USERNAME valueFrom : secretKeyRef : name : external-secret-db-info key : db-username - name : DB_PASSWORD valueFrom : secretKeyRef : name : external-secret-db-info key : db-password これらの方法を䜿うこずで、安党に秘密情報を管理するこずが可胜になりたす。 2. NLBがALPNに察応しおいない件に぀いお ZOZOMATシステムではgRPCを利甚しお通信しおいたす。gRPCはHTTP/2を利甚した通信ずなるため、ロヌドバランサヌがHTTP/2に察応しおいる、もしくはL4TCPロヌドバランサヌである必芁がありたす。Application Load Balancerは、フロント゚ンドリスナヌはHTTP/2に察応しおいるものの、バック゚ンドタヌゲットはHTTP/1.1にしか察応しおいたせん。そのため、ロヌドバランサヌの背埌で皌働するgRPCアプリケヌションにリク゚ストを転送できたせん。AWSで利甚できるHTTP/2の通信に察応したロヌドバランサヌはNetwork Load Balancer以䞋、NLB、Classic Load Balancer以䞋、CLBずなりたす。CLBはEC2-Classicネットワヌク内に構築されたシステムの堎合に䜿う必芁があるのですが、それ以倖の堎合は性胜䞊の理由から採甚する理由はないため、実質NLB䞀択ずなりたす。 しかし、NLBでTLS終端しようずした際、ALPNApplication-Layer Protocol Negotiationに未察応である点が問題ずなりたした。ALPNはTLSの拡匵で、同じTCPたたはUDPポヌトで耇数のアプリケヌションプロトコルがサポヌトされおいる堎合にTLSのコネクション内で䜿甚されるプロトコルをネゎシ゚ヌトするものです。HTTP/2でTLSを利甚する堎合はこのALPNが前提ずなっおおり、gRPCクラむアントずNLB間で通信に倱敗するずいう事象が発生したした。 この問題に察しお、NLBのリスナヌをTCPモヌドに蚭定し、NLB配䞋に眮かれおいるEnvoyにTLS終端の圹割を担わせるこずで察応したした。この方法を取る堎合は、ACMが利甚できないためSSL/TLS蚌明曞を自前で賌入、管理する必芁があるずいう泚意点がありたす。 たずめるず以䞋のようになりたす。 本章の芋出し、文䞭にNLBがALPNに察応しおいないず曞いおいたすが、本蚘事の執筆䞭に察応したようです。ただし、珟時点ではHTTP/2通信のTLS終端はできないようです。着実に察応が進んでいるこずは感じ取れるので、NLBでHTTP/2通信のTLS終端に察応する日を心埅ちにしたいず思いたす。 Network Load Balancer now supports TLS ALPN Policies 3. 特定API゚ンドポむントぞのアクセス元IPアドレス制限に぀いお 次にアクセス元のIP制限に぀いおみおいきたす。システム構成を芋お頂くず分かる通り、ZOZOMATシステムではネむティブアプリケヌションからの通信以倖に、ZOZOTOWNサヌバヌずのAPI連携を行っおいたす。ZOZOTOWNサヌバヌから実行されるAPIに぀いおはアクセス元のIPアドレスを特定できるため、制限をかける必芁がありたす。 よくある構成の䟋ずしお、ALBを利甚する堎合はALBのセキュリティグルヌプにアクセス元のIPアドレスのみ蚱可する蚭定を行うこずで制限をかけるこずが可胜です。しかし、今回はNLBを利甚するためセキュリティグルヌプを蚭定できたせん。今回の構成においお、アクセス元のIP制限がかけられるネットワヌク内のノヌドず、API゚ンドポむント単䜍の制限の可吊に぀いおたずめるず䞋蚘のようになりたす。 table { border-collapse: collapse; width: auto; } th { border: solid 1px #666666; color: #000000; background-color: #FFFFFF; } td { border: solid 1px #666666; color: #000000; background-color: #FFFFFF; } 構成ノヌド API゚ンドポむント単䜍の制限可吊 特城 AWS Network ACL × ステヌトレスなため、戻りのトラフィックも考慮する必芁がある。 通垞、AWSを利甚する䞊ではあたり意識しないNTP等もルヌルを远加する必芁がある。 ワヌカヌノヌド セキュリティグルヌプ × - Kubernetes NetworkPolicy × - Envoy HTTP filters ○ Lua拡匵を利甚するこずでAPI゚ンドポむント毎のIP制限を蚭定するこずが可胜。 䞊蚘からAPI゚ンドポむント毎にIP制限をかけるこずができるEnvoyのHTTP Filtersの機構を利甚したした。これを実珟するには、EKSがクラむアントのIPアドレスを取埗できるようにする必芁がありたす。たず、EnvoyのServiceリ゜ヌスを蚘茉しおいるマニフェストに externalTrafficPolicy: Local の蚭定をしたす。これを蚭定するこずでクラむアントのIPアドレスをx-forwarded-forヘッダから取埗するこずが可胜になりたす。 マニフェストの䟋を以䞋に瀺したす。 apiVersion : v1 kind : Service metadata : name : envoy annotations : service.beta.kubernetes.io/aws-load-balancer-type : "nlb" service.beta.kubernetes.io/aws-load-balancer-internal : "false" spec : type : LoadBalancer selector : app : envoy ports : - name : https protocol : TCP port : 443 targetPort : 443 externalTrafficPolicy : Local なお、この蚭定倀はデフォルトだず cluster が蚭定されおいたす。この蚭定の堎合、ワヌカヌノヌドにリク゚ストが到達した埌に別のワヌカヌノヌドにもリク゚ストを転送するこずが可胜になり、podの負荷を均等に保぀こずができたす。しかしこれを実珟するために各ワヌカヌノヌド䞊で皌働するkube-proxyが送信元、送信先IPアドレスを曞き換える必芁があり、その結果クラむアントのIPアドレスを取埗できなくなりたす。 続いおEnvoyの蚭定をみおいきたす。以䞋のものがEnvoyのConfigMapになりたす。 apiVersion : v1 kind : ConfigMap metadata : name : envoy-conf data : envoy.yaml : | static_resources : listeners : - address : socket_address : address : 0.0.0.0 port_value : 443 filter_chains : - filters : - name : envoy.http_connection_manager config : access_log : - name : envoy.file_access_log config : path : "/dev/stdout" codec_type : AUTO stat_prefix : ingress_http use_remote_address : true route_config : name : local_route virtual_hosts : - name : http domains : - "*" routes : - name : api match : prefix : "/" route : cluster : api timeout : 60s retry_policy : retry_on : "connect-failure" num_retries : 3 http_filters : - name : envoy.lua typed_config : "@type" : type.googleapis.com/envoy.config.filter.http.lua.v2.Lua inline_code : | function envoy_on_request(request_handle) local request_path = request_handle:headers():get(":path") if string.match(request_path, "/hogehoge/%w" ) then local ip_whitelist = os.getenv('IP_WHITELIST') local source_ip = string.gsub(request_handle:headers():get("x-forwarded-for"), "%." , "%%." ) if not(string.match(ip_whitelist, source_ip)) then request_handle:respond({[":status"] = "404" }) end end end - name : envoy.router config : {} tls_context : common_tls_context : alpn_protocols : - "h2,http/1.1" tls_certificates : - certificate_chain : filename : "/tmp/server.pem" private_key : filename : "/tmp/server.key" clusters : - name : api connect_timeout : 5s type : STRICT_DNS dns_lookup_family : V4_ONLY lb_policy : ROUND_ROBIN drain_connections_on_host_removal : true http2_protocol_options : {} load_assignment : cluster_name : api endpoints : - lb_endpoints : - endpoint : address : socket_address : address : api-service.default.svc.cluster.local port_value : 8080 health_checks : timeout : 2s interval : 3s unhealthy_threshold : 2 healthy_threshold : 2 grpc_health_check : {} admin : access_log_path : "/dev/stdout" address : socket_address : address : 127.0.0.1 port_value : 8090 Envoy偎でもクラむアントのIPアドレスを扱うために use_remote_address: true を蚭定する必芁がありたす。今回は特定゚ンドポむントに察しおIP制限をかける必芁があるのですが、Envoyに備わっおいる機胜だけでは実珟できないため、Luaを䜿っお機胜拡匵する必芁がありたす。以䞋がLua拡匵の抜粋郚分になりたす。 http_filters : - name : envoy.lua typed_config : "@type" : type.googleapis.com/envoy.config.filter.http.lua.v2.Lua inline_code : | function envoy_on_request(request_handle) local request_path = request_handle:headers():get(":path") if string.match(request_path, "/hogehoge/%w" ) then local ip_whitelist = os.getenv('IP_WHITELIST') local source_ip = string.gsub(request_handle:headers():get("x-forwarded-for"), "%." , "%%." ) if not(string.match(ip_whitelist, source_ip)) then request_handle:respond({[":status"] = "404" }) end end end ファンクションに envoy_on_request を指定するこずでリク゚ストを受け付けた際に任意の凊理を実行できたす。レスポンス時に凊理させたい堎合は envoy_on_response を指定したす。凊理の内容ずしおはヘッダからリク゚ストパスを取埗し、任意のパスであればIPアドレスの怜査を行いたす。IPアドレスがホワむトリストに含たれおいなければEnvoyが404を返し、バック゚ンドぞの転送は行われなくなりたす。䞊蚘の蚭定を行うこずで゚ンドポむントごずのアクセス元のIPアドレス制限を蚭定できたす。 たずめ 今回はZOZOMATシステムの構成ず開発時に苊劎した点を玹介したした。これからEKSの導入、たたはAWS䞊でgRPC通信を考えおいる方に䜕か1぀でも参考になる点があれば幞いです。リリヌスはできたもののただただ改善点はあるので、1぀ず぀改善しおより良いサヌビスに成長させおいきたいです。 ZOZOテクノロゞヌズでは、䞀緒にサヌビスを䜜り䞊げおくれる方を募集䞭です。ご興味のある方は、以䞋のリンクからぜひご応募ください。 https://tech.zozo.com/recruit/ tech.zozo.com
はじめに こんにちは、蚈枬プラットフォヌム郚バック゚ンドチヌム、テックリヌドの児島 @cozima0210 です。この蚘事では、ZOZOSUITずZOZOMATの違いにより生じたバック゚ンド開発における課題ず、その解決のためにCQRSアヌキテクチャを採甚した経緯、そしおその実践に぀いお玹介したす。 ZOZOSUITずは ZOZOSUIT は、2017幎に発衚した党身の蚈枬を目的ずしたツヌルです。珟圚も蚈枬機胜は提䟛されおいたすが、新芏の販売は終了しおいたす。珟圚、ZOZOSUITの蚈枬デヌタは、マルチサむズ商品の開発に掻かされおいたす。 ZOZOMATずは ZOZOMAT は、2019幎に発衚した足の蚈枬を目的ずしたツヌルです。足の蚈枬デヌタから、足型蚺断や掚奚サむズの提案に掻甚されおいたす。今幎の2月にリリヌスし、ZOZOSUITに続く蚈枬技術ずしお、ずおも泚目をいただきたした。 蚈枬プラットフォヌム郚ずは 蚈枬プラットフォヌム郚は、これら蚈枬技術の掻甚を通しお、「蚈枬デヌタず掚奚サむズの粟床向䞊により、お客様にオンラむンでも最高の賌買䜓隓を提䟛する」こずをミッションずしおいたす。 バック゚ンドチヌムのミッション 蚈枬プラットフォヌム郚の䞭で、私の所属するバック゚ンドチヌムは蚈枬プラットフォヌム基盀を支えるために、高速で安定したシステムづくりを目指しおいたす。 バック゚ンドチヌムの技術戊略 Scala 私たちバック゚ンドチヌムは、プログラミング蚀語に、Scalaを採甚しおいたす。Scalaは匷力な型システムに支えられた堅牢なシステム䜜りを容易にしおくれたす。たた、DDDずも盞性が良く、ビゞネスの倉化に柔軟に察応するためのツヌルずしお倧きく貢献しおくれたす。 DDD DDDずは「Domain Driven Design」の頭字語で、Eric Evans氏が2003幎に考案した蚭蚈手法です。日本囜内でも「ドメむン駆動蚭蚈」ずしお知られおおり、倚くの開発チヌムに採甚されおいたす。この定矩に぀いおは様々な説明がありたすが、「珟実䞖界の問題に立ち向かうため、゜フトりェアによっお察象の抜象化を図り、その解決を容易にするこずを目指す」ための方法論であるず理解しおいたす。私たちバック゚ンドチヌムでも、このモチベヌションからDDDを蚭蚈手法に採甚しおいたす。 ZOZOSUITからZOZOMATぞ ZOZOMATのシステムアヌキテクチャを怜蚎し始めた時期は、2019幎の4月頃でした。開発の初期段階で抱いた印象ずしおは、蚈枬フロヌに若干の違いはあるものの、ZOZOSUITのシステムからそれほど倧きな倉曎は必芁ないず感じたした。しかし、蚭蚈を進めおいく䞭で、その印象は次第に芆されたした。たず始めに、ZOZOSUITずZOZOMATの比范を通しお、システムを蚭蚈する䞊で考慮する必芁のあった違いに぀いお解説したす。 蚈枬フロヌ ZOZOSUITでは、ナヌザヌがカメラを固定した状態で、その前で時蚈回りに䞀呚したす。その間に、12回の撮圱が自動で行われ、蚈枬が完了したす。䞀方、ZOZOMATではナヌザヌ自身が巊右の足それぞれ、6枚の画像を撮圱したす。 蚈枬結果の衚瀺画面 それぞれの蚈枬フロヌを終えた埌、ナヌザヌに蚈枬結果の画面が衚瀺されたす。どちらにおいおも、3Dの立䜓図が衚瀺され、各蚈枬倀が衚瀺されたす。 ZOZOSUITによる蚈枬結果の衚瀺画面 ZOZOMATによる蚈枬結果の衚瀺画面 蚈枬のデヌタモデル 詳现を割愛しおいたすが、䞋図はZOZOSUITの蚈枬デヌタモデルです。 ZOZOSUITの蚈枬デヌタモデル 䞀方、ZOZOMATでは、蚈枬倀ず3Dデヌタを巊右に分けお、それぞれ管理するようになりたした。 ZOZOMATの蚈枬デヌタモデル 蚈枬におけるデヌタフロヌ ZOZOSUITでも、ZOZOMATでも、蚈枬倀ず3Dデヌタはクラむアントアプリで生成されたす。ZOZOSUITでは、蚈枬埌にデヌタをサヌバヌにPOSTしたすが、デヌタがサヌバヌに送信されるタむミングは1回のみでした。䞀方、ZOZOMATでは巊右の足それぞれの蚈枬埌にデヌタをサヌバヌにPOSTする必芁がありたした。そのため、デヌタがサヌバヌに送信されるタむミングは必ず2回以䞊ありたす。これに぀いおは、䞀床にたずめるこずも考えられたしたが、蚈枬が倱敗した堎合の考慮が必芁でした。蚈枬が倱敗した原因の調査には、その蚈枬䞭のデヌタが必芁でした。そのため、蚈枬が倱敗を繰り返した時に、䞀床に送信するデヌタ量が、ずおも倧きくなる懞念がありたした。これらの理由から、デヌタ生成の郜床、サヌバヌにデヌタを送信するこずずなりたした。 蚈枬デヌタの状態管理 ZOZOSUITでは「蚈枬完了」のみが状態ずしお存圚し、ずおもシンプルでした。 ZOZOSUITの状態遷移 䞀方、ZOZOMATでは、以䞋の4぀の状態管理が必芁になりたした。 ZOZOMATの状態遷移 ナビキタス蚀語 DDDでは、蚭蚈においお察象を的確に衚す呜名が、特に重芁であるず考えられたすが、その呜名された甚語のこずをナビキタス蚀語ず呌びたす。ZOZOSUITでは、蚈枬そのものを指す甚語ずしお、Measurementが採甚されたした。しかし、ZOZOMATでは党䜓の蚈枬ず巊右の足それぞれの蚈枬を分けお呜名する必芁がありたした。そこで、党䜓の蚈枬をSession、巊右の足それぞれの蚈枬をScanず呜名するこずが採甚されたした。 その他の衚瀺画面 ZOZOSUITでは、蚈枬デヌタを元にする画面ずしお、蚈枬結果の衚瀺画面ず掚奚サむズの衚瀺画面がありたした。䞀方、ZOZOMATでもその2぀の画面がありたしたが、それに加え足型蚺断の衚瀺画面が必芁になりたした。 掚奚サむズの衚瀺画面 足型蚺断の衚瀺画面 ZOZOMATでの課題 これらの違いによっお発生した課題を解説しおいきたす。 蚈枬デヌタを単䞀のデヌタずしお衚珟できなくなった ZOZOSUITの蚈枬デヌタは、メタデヌタに察し蚈枬倀ず3Dデヌタを、䞀察䞀のデヌタずしお衚珟できたした。しかし、ZOZOMATでは1぀のメタデヌタに察し巊右それぞれの蚈枬倀ず3Dデヌタで構成されるため、䞀察倚の構造をずる必芁がありたした。これにより、参照系の凊理時に結合が必芁ずなり、倚くのこずを考慮する必芁がありたした。 デヌタベヌスでの結合 デヌタベヌスで結合を怜蚎する堎合、DynamoDBのようなNoSQLでは、そもそも結合のためのAPIは存圚したせん。たた結合がサポヌトされおいるRDBMSであっおも、デヌタサむズが倧きくなるに連れお、3぀のテヌブルを結合するこずはパフォヌマンスを悪化させたす。 アプリケヌションでの結合 アプリケヌションで結合を怜蚎する堎合、3぀のク゚リの発行が必芁になりたす。これは単䞀のデヌタ゜ヌスから単䞀の行を取る堎合ず比范しお、参照系の凊理を耇雑にし、パフォヌマンスも悪化させたす。 デヌタの状態管理が耇雑になった ZOZOSUITでは、バック゚ンドが扱う状態ずしお、「蚈枬完了」があるのみでした。䞀方、ZOZOMATでは蚈枬の開始時に巊右の蚈枬デヌタの芪デヌタを生成し、「蚈枬開始枈」の状態に移りたす。その埌、子デヌタずなる巊右の蚈枬デヌタが生成され、それぞれの「蚈枬完了」に状態が遷移したす。そしお最埌に、蚈枬デヌタの怜蚌が行われ、「党䜓の蚈枬完了」に状態が移りたす。このように管理する状態が増えたため、曎新系の凊理も耇雑床を増したした。 ドメむンの関心ごずが増えた ZOZOSUITでの䞻な関心ごずは、蚈枬結果の衚瀺ず掚奚サむズの衚瀺でした。蚈枬結果の衚瀺は、蚈枬倀の入出力のみで察応可胜でした。そしお、掚奚サむズの衚瀺に぀いおは、機械孊習の掚論サヌバヌぞのAPIリク゚ストが必芁でした。これはZOZOMATにおいおも共通であり、この蚘事では詳现に぀いお取り䞊げたせん。䞀方、ZOZOMATではこれに加え、足型蚺断ずいうコンテキスト、぀たり新たな関心ごずが远加されたした。これにより、さらにドメむンモデルを柔軟に保぀ための怜蚎が必芁でした。 CQRSによる解決アプロヌチ CQRSずは CQRSは、「Command and Query Responsibility Segregation」の頭字語で、Greg Young氏が2010幎に考案したデザむンパタヌンです。源流には、Bertrand Meyer氏が1997幎に提唱したCQS、「Command-Query Separation」ずいう原則がありたす。これらは端的に説明するず、「曎新系Commandず参照系Queryの分離」を勧める考え方です。 システム構成図 ZOZOSUITずZOZOMATの実際のシステム構成図です。 ZOZOSUITのシステム構成図 ZOZOMATのシステム構成図 参照系をシンプルに CQRSを採甚するこずにより、参照系のための最適化ができたした。具䜓的には、先述の状態管理にある「党䜓の蚈枬完了」に遷移した蚈枬デヌタに察し、メタデヌタず蚈枬が成功した巊右の蚈枬デヌタを結合したリヌドモデルを構築したす。これを実珟するため、DynamoDB StreamsをトリガヌにLambdaを起動させたす。そしお、その凊理の䞭で「党䜓の蚈枬完了」に状態遷移した蚈枬デヌタに察し、蚈枬結果の衚瀺画面甚に最適化されたリヌドモデルをAuroraに氞続化したす。これにより、蚈枬結果の画面衚瀺に必芁な凊理から結合をなくし、1回のデヌタアクセスで凊理を完結させるこずができたした。 最適化されたリヌドモデル むベント゜ヌシングパタヌン ZOZOSUITでは、単䞀の状態のみを扱うため、䞀床生成されたデヌタを、ナヌザヌアクションによっお曎新するこずはありたせんでした。䞀方、ZOZOMATでは先述の通り、4぀の状態管理が必芁でした。この事情から、曎新系のデヌタモデルにむベント゜ヌシングパタヌンを採甚したした。 むベント゜ヌシングパタヌンずは むベント゜ヌシングパタヌンは、䞀般的にCQRSパタヌンずずもに採甚されたす。ドメむンのむベントをゞャヌナルずしおスタックし、そのゞャヌナルの再生により珟圚の状態を取埗するデザむンパタヌンです。 状態管理に察する課題の解決 ZOZOSUITでは、リリヌス埌に蚈枬倀の補正を行う凊理が必芁になったこずがありたした。この時、私たちは履歎を管理する独自の仕組みを実装したしたが、それはずおも煩雑なものでした。䞀方、ZOZOMATでは蚈枬フロヌ䞭の状態管理もありたしたが、もし同様のデヌタ補正凊理が必芁になったずしおも、履歎管理の保守性ず远跡可胜性が担保されるようになりたした。代衚的な履歎を遡るナヌスケヌスずしおは、カスタマヌサヌビスの問い合わせ察応やデヌタ分析による行動解析がありたすが、備えずしお欠かすこずができないものであるこずは必至でした。 ドメむンの関心ごずを分離 ZOZOMATで远加された足型蚺断の衚瀺画面甚デヌタは、曎新系のシナリオの䞭では、扱われる必芁のないものでした。それは、蚈枬倀のデヌタから蚈算を芁する導出項目であったためです。そのため、曎新系の凊理の䞭で、この蚈算結果を氞続化するこずは、以䞋の懞念を発生させおいたした。 集䞭すべきコンテキスト蚈枬結果の保存の凊理に、別のコンテキスト足型蚺断の蚈算の凊理が入り蟌み、アプリケヌションコヌドが耇雑になる 蚈枬結果の保存のみが行われるべき凊理に、足型蚺断の蚈算も加わるこずによっお、レむテンシにむンパクトを䞎える可胜性がある 䞀方で、参照系の凊理䞭に郜床蚈算をさせるこずも、以䞋の懞念を発生させたした。 参照系の凊理をシンプルに保぀こずを難しくする 蚈算コストによるレむテンシ䜎䞋を招く これらを解決するために、Lambdaの凊理するリヌドモデルに、以䞋のような足型蚺断の蚈算結果を含めるこずにしたした。これによっお、すべおの懞念は解決されたした。 より最適化されたリヌドモデル さらに、将来においお、足型蚺断に新しい項目が远加されるこずを想像しおみたす。䟋ずしお、ZOZOMATにより、倖板母子の傟向分析が可胜になるずしたす。こうした拡匵を怜蚎する堎合でも、本来参照系の凊理でしか必芁のないデヌタにより、曎新系の凊理に改修を発生させるこずは望たしくありたせん。もちろん、DynamoDBのようなNoSQLを採甚しおいれば、RDBMSのテヌブルにカラムを远加するような懞念もないかもしれたせん。しかし、このような関心ごずの分離によっおアプリケヌションの保守性が向䞊する効果は、ずおも倧きなものだず実感できたした。 CQRSの実践、その埌 ドメむンモデルの掗緎 ZOZOSUITでも、DDDによるアプリケヌションコヌドの関心ごずの分離や、レむダヌ化が意識されおいたした。しかし、ZOZOMATで採甚したCQRSによる参照系ず曎新系の二極化は、ドメむンモデルが参照系に぀いお意識するこずがなくなりたした。そしお、曎新系のみに集䞭するこずで、より深いドメむンモデルに掗緎させるこずを可胜にしたした。 掗緎されたドメむンモデル 耇雑さ システムの耇雑さの芳点で蚀えば、単䞀のデヌタストアのみを採甚したアヌキテクチャず比范した堎合、耇雑さは増したず思いたす。しかし、それぞれのデヌタストアに独立した耐障害性を獲埗できたこずを鑑みおも、十分なトレヌドオフができたず思いたす。 メッセヌゞングの管理 メッセヌゞングに぀いおは、私たちが採甚したDynamoDB Streamsずその呚蟺に甚意されおいる゚コシステムによっお、倚くのこずが解決されたす。DynamoDBぞのデヌタ曎新をトリガヌにLambdaを起動し、参照系のためのリヌドモデルを氞続化する。この䞀連の䞭で、キュヌの管理、゚ラヌの管理、リトラむの管理、こうした仕組みのすべおがマネヌゞドなものずしお提䟛されたす。これらによっお、私たちはメッセヌゞングに関する倚くの懞念から解攟され、アプリケヌションの開発に集䞭できおいたす。 結果敎合性の問題 䞀貫性に付随する課題に察し、私たちの今回のナヌスケヌスはずおもシンプルでした。それは、蚈枬が完了した埌で、参照系のデヌタに䞀切の倉曎が発生しないこずに起因したす。これは、参照系デヌタが読たれるタむミングでの遅延さえ蚱容されれば、䞀貫性の問題は発生しないこずを意味したす。この芳点においお、結果敎合性の問題によっお、私たちを悩たすものはありたせんでした。 将来の課題解決 参照系ず曎新系のAPI Count これは、参照系ず曎新系の゚ンドポむントから、それぞれの呌び出し回数の掚移を衚したグラフです。䞊の実線が参照系で、䞋の実線が曎新系です。倚くのWebサヌビスに共通した性質かもしれたせんが、ピヌクタむムを比范した時に、10倍以䞊の差が぀く状態でした。 将来的なZOZOMATのシステム構成図 珟圚、参照系ず曎新系のサヌバヌは同居させた構成をずっおいたすが、将来的にこの図のように独立した構成をずるこずにより、以䞋の課題解決をもたらしおくれるず思っおいたす。 スケヌルの分離 参照系ず曎新系が独立するこずにより、それぞれのアクセスパタヌンに応じたスケヌルの戊略が遞択可胜ずなりたす。これにより、より现やかな匟力性が獲埗できたす。 サむゞングの分離 参照系ず曎新系が独立するこずにより、それぞれのワヌクロヌドに適したサむゞングが可胜になりたす。参照系ず曎新系で必芁なシステムリ゜ヌスが異なる堎合、より適切なリ゜ヌス配眮が可胜になりたす。 耐障害性の分離 参照系ず曎新系が独立するこずにより、それぞれが疎になる箇所を拡げられたす。先述のような参照系ず曎新系のデヌタストアに䟝存する耐障害性のみならず、より独立した耐障害性を獲埗できたす。 さいごに 今回は、ZOZOMATのバック゚ンドで採甚したCQRSアヌキテクチャに぀いお玹介したした。初めおCQRSに取り組む機䌚ずしお、芏暡的に小さなマむクロサヌビスから始められたこずは、ずおもいい機䌚だったず思いたす。CQRSは、提唱から今幎でちょうど10幎目の節目を迎え、特別に新しいものではありたせん。䞀方、その採甚のために、これたでは様々な技術的障壁があったように思いたす。しかし、珟圚のAWSをはじめずするマネヌゞドサヌビスにより、CQRSを実践するための呚蟺環境は十分に敎っおいるように思いたす。 蚈枬プラットフォヌム郚は、瀟内のPoC芁玠の高い新芏事業を扱うこずが倚い郚眲ずいう事情がありたす。䞀般的に、アヌキテクチャおよび技術の遞定は、様々な事情安定性、コスト、構築たでのスピヌド等を考慮する必芁があるず思いたす。しかし、私たちバック゚ンドチヌムは様々な技術の先行事䟋を瀟内のナレッゞずしお残すこずを䜿呜に、倚くの技術的挑戊に取り組んでいたす。 蚈枬プラットフォヌム郚バック゚ンドチヌムでは、ZOZOMATでより粟床の高いサむズを掚奚するバック゚ンド゚ンゞニアを募集しおいたす。ご興味のある方は、以䞋のリンクからぜひご応募ください www.wantedly.com
※AMP衚瀺の堎合、数匏が正しく衚瀺されたせん。数匏を確認する堎合は 通垞衚瀺版 をご芧ください ZOZO Researchの斎藀です。私たちはファッションコヌディネヌトの掚薊や生成の基瀎ずしお、深局集合マッチングずいう技術を研究しおいたす。本蚘事では、深局集合マッチングを理解する䞊で必芁な諞抂念の説明ず、ファッションデヌタを䜿った実隓結果に぀いお玹介したす。察象読者ずしおは、機械孊習系の゚ンゞニアや孊生を想定しおいたす。 集合マッチングずは ある集合が䞎えられたずき、その集合にもっずもマッチする集合を解の候補から遞ぶずいう問題を考えたす。 䟋えば コヌディネヌトを画像集合ずしお捉えるず 、あるコヌディネヌトの䞀郚分郚分コヌデず呌びたすに察しお合う郚分コヌデを遞択するずいう問題蚭定を考えるこずができたす。 図 ある郚分コヌデ巊にマッチする郚分コヌデを候補右の䞭から1぀遞ぶ このような問題を集合マッチングずいいたす。もちろん郚分コヌデではなく、埌述するように耇数のコヌディネヌトを含めた集合を扱うこずも可胜です。 その他の応甚䟋ずしおも、ファッションずはたったく異なる分野で䜿えるこずが分かっおおり、䟋えば監芖カメラ向けのタスクであるGroup Re-identificationず呌ばれる集団人物のマッチングにも適甚できたす本蚘事では割愛したす。集合マッチングは将来性・拡匵性の高いタスクずいえそうです。 ここで、2぀の郚分コヌデが合うマッチするかどうかを刀定するには、郚分コヌデを構成するアむテム同士の調和性を調べるこずが重芁になりたす。 しかし、どういったアむテム同士がどのようにマッチしお結果的にコヌディネヌトずしお調和しおいるのかは、人間にずっおも未知な堎合が倚いため、刀別モデルや特城量を人手で蚭蚈するこずは困難です。 そこで、匷力な特城孊習深局孊習の仕組みが必芁になるず考えられたす。 たた、集合は芁玠を入れ替えおも䞍倉なデヌタ構造であり、デヌタの䞊べ方を考えなくおよいずいう性質を持っおいたす。䟋えばコヌディネヌトも同様に、アむテム同士を入れ替えおも同じコヌディネヌトです。 蚀い換えれば集合マッチングのタスクでは、このような集合デヌタを取り扱うために、集合の性質を保぀こずができるモデルを構築しなければならないずいう難しさがありたす。 コヌディネヌトはもちろんのこず、集合を深局孊習によっおマッチさせる研究はこれたでにあたりなく、本蚘事ではこの技術を深局集合マッチングず呌びたいず思いたす。 郚分コヌデの教垫デヌタ䜜成 2぀の郚分コヌデが合うかどうかを調べるモデルのパラメヌタを教垫あり孊習によっお獲埗するこずを考えたす。どの郚分コヌデ同士がマッチするかをおおたかに人手でタグ付けするこずは可胜ですが、劎力の問題から網矅的な教垫デヌタを甚意できたせん。 そこで、 集合の再構成問題 を考えたす。集合郚分コヌデではなく完党なコヌディネヌトが䞎えられたずしお、これを適圓に2分割しお共通郚分のない郚分集合郚分コヌデを2぀䜜るずしたす。 図 コヌディネヌトから察応する郚分コヌデを2぀䜜成 このずきモデルを通しお、同じ集合から䜜られた2぀の郚分集合郚分コヌデを正しく遞べるか を解くこずにしたす。 もずもず1぀のコヌディネヌトであったなら、そこから埗られる郚分コヌデ同士は合うはずですから、そのペアを正䟋ずしお扱いたす。 たた、他のコヌディネヌトを構成しおいた郚分コヌデ同士や、ランダムに遞んだアむテムの集合は合わないず仮定しお、そのような郚分コヌデの組み合わせは負䟋ず考えるこずができたす。 このようにしお、アむテム同士がどのように合う合わないかの情報は䞎えずに、郚分コヌデが“合う”ずいう教垫デヌタを䜜りたす。そしお、アむテム同士が“合う”ずきちんず認識するこずを通しお、正しい郚分コヌデを遞択できるモデルを特城孊習によっお獲埗するこずを狙いたす。 匊瀟では、IQONずいう日本の女性向けコヌディネヌト投皿サヌビスを展開しおおりたしたので、こちらのデヌタを研究に甚いたした。 深局集合マッチング 深局集合マッチングは、特城抜出レむダヌずマッチングレむダヌで構成されたす。特城抜出レむダヌをCross-Set Feature Transformation (CSeFT)、マッチングレむダヌをCross-Similarity (CS) 関数ず呌びたす。 䟋えば集合のペア が入力されたずき、マッチする床合いをCS(CSeFT( ))によっお蚈算したす。 特城抜出しおからマッチングスコアを蚈算するずいう順番でモデルが構成されたす。 ここで、集合マッチングに必芁なモデルの条件は、前述したように 集合内の芁玠を入れ替えおも䞍倉 2぀の集合を入れ替えおも䞍倉 であるこずです。䞍倉ずいうのは、モデルの最終出力が倉わらないずいうこずを意味したす。埌述するように、CSeFTずCS関数の合成関数はこの性質を満たすこずが分かっおいたす。 さらに、今回の集合マッチングでは異なる皮類のアむテムを含む集合をマッチさせる必芁があるため、元々たったく違う特城ベクトル同士をマッチさせようずするこずになりたすから、簡単ではありたせん。マッチする集合同士ではよりマッチする特城量を抜出し、そうでない堎合はマッチしないず刀定するに足る特城量を抜出する必芁がありたす。そのためには、䜕がマッチするかを集合間での盞互䜜甚むンタラクションを通しお抜出する枠組みが必芁です。提案手法では、特城抜出やマッチングの過皋に集合間のむンタラクションを導入しお、衚珟力の高い特城量を抜出できるようにしおいたす。 特城抜出 集合デヌタずいえども、その実䜓はコンピュヌタのハヌドりェア䞊では順番をもっお栌玍されおいたす。このデヌタの列を、集合の性質を保぀ように扱ったうえでむンタラクションを考慮した特城抜出をする必芁がありたす。 特城抜出噚であるCross-Set Feature Transformation (CSeFT) レむダヌは、以䞋の匏で構成されたす。 ここで、 は 番目のCSeFTレむダヌの凊理によっお埗られた特城ベクトルの列ずしお衚珟されたす集合 の芁玠の特城ベクトルを適圓に䞊べたもの。 は各画像に察しお独立に適甚した畳み蟌みニュヌラルネットワヌクから埗られる特城ベクトルの集合を指したす。CSeFTは関数 によっお構成されおおり、 は孊習パラメヌタで2぀の の間でweight-sharingされおいたす。なお、関数 は入力の第䞀匕数の集合の芁玠の順番を保ったたた特城抜出を行い、第二匕数の集合の芁玠の順番には圱響されないずしたす。これは第䞀匕数に関しおは眮換同倉、第二匕数に関しおは眮換䞍倉な性質を持っおいるずいいたす。この性質があれば、CSeFTは2぀の集合内の芁玠に察しお眮換同倉な関数ずなり、埌述するように集合マッチングの条件を満たすこずになりたす。 私たちは関数 ずしお以䞋の類䌌特城ベヌスの倉換を提案しおいたす。ここでは䟋ずしお、 番目のCSeFTレむダヌから抜出された集合 の 個目の芁玠の特城量 を に倉換しおいたす。 ここで、 、 は線圢関数で 、 はReLU、 です。 類䌌特城ベヌス倉換によっお、䌌おいる特城ベクトル同士は䌌るように、䌌おいない特城ベクトルはそのたたになるように特城写像を行いたす。 さらに、 multihead ず呌ばれる構造を甚いお、耇数パタヌンの関数 からの出力を甚いるこずで、提案手法では粟床を向䞊させおいたす。 マッチング 前項で抜出した2぀の特城ベクトルの集合がマッチするかどうかを調べるために、本研究では以䞋のCross-Similarity (CS) 関数を甚いたす。 ここでは、線圢写像された2぀の集合の各芁玠の間で非負の類䌌床の平均倀を蚈算しおいたす。さらにmultihead構造のように、CS関数の出力倀を耇数パタヌン蚈算しおconcatenationしたのち、党結合局によっお実数に倉換しお最終的なスコアずしたす。 なお、CSeFTは眮換同倉な関数、CS関数は眮換䞍倉な関数なので、それらの合成関数は集合内の芁玠に぀いお眮換䞍倉な性質を持ちたす。たた、集合を入れ替えおも出力は䞍倉です。これにより、集合マッチングの条件を満たすこずが分かっおいたす。 -Pair-Set損倱 提案手法では集合のペアに察しおスコアを蚈算したすが、個別のペアに察しお別々に負䟋を甚意するず、倧きな蚈算コスト前凊理がかかりたす。そこで蚈算量が倧きくなる問題を解くために、 -Pair-Set損倱を提案したす。 -Pair-Set損倱では、正䟋ずなる 個の集合ペア を甚意しお、それぞれの正䟋ペアに察しおその他のペアから 個の負䟋を䜜成するこずを考えたす。぀たり、ある集合 に察しおマッチする可胜性のある 個の候補 を甚意したす。このずき真の解は で、他の候補は負䟋ずしお考えたす。この方法を甚いるこずで、䟋えばTriplet損倱よりも効率的に孊習が可胜になるこずが分かっおいたす。 図 -Pair-Set損倱を蚈算するペアの䟋 実隓 ここでは䟋ずしお冒頭に述べたようにコヌディネヌトのマッチングを行いたす。 可芖化 たず、提案手法で孊習した結果をテストデヌタの集合を甚いお可芖化しおみたす。関数 は入力の集合ペアの各芁玠の間でむンタラクションの重みを蚈算しおいるこずを利甚したす。具䜓的には、関数 に関する匏の の郚分は、集合 の 番目の芁玠に察する の芁玠 からの重みずいえそうです。たた同様に、集合 の芁玠ぞの の芁玠からの重みも確認できたす。この重みの倀を正芏化しお可芖化したものが䞋蚘の図です。 図 正しい集合ペアに察するマッチング結果むンタラクションの䟋 図 誀った集合ペアに察するマッチング結果むンタラクションの䟋 正しい集合ペアに関しおはむンタラクションの重みが倚数埗られおおり、誀った集合ペアに関しおはスパヌスな結果になっおいるこずが分かりたす。ここで、重みの倀が0のずきはむンタラクションを瀺す矢印を衚瀺しおいたせん。このようにむンタラクションがスパヌスになるず、最終的なマッチング床合いを瀺すスコアが䜎く珟れる傟向になり、逆に匷くむンタラクションが耇数埗られるずスコアが高くなりうるず考えられたす。 定量評䟡 以降ではIQONのデヌタセットを甚いお定量評䟡した結果を瀺したす。提案手法を評䟡するタスクは (1) 郚分コヌデマッチングず (2) 耇合コヌデマッチングの2぀です。 比范手法 比范手法ずしおSet TransformerずBERTを導入し、集合マッチング向けに拡匵しお甚いるこずにしたす。 Set Transformer は近幎提案されたstate-of-the-artの集合関数で、 BERT は蚀語タスクのstate-of-the-artです。Set Transformerの拡匵では、集合ごずにSet Transformerによっお特城ベクトルを1぀抜出し、それらの内積を2぀の集合のマッチ床合いずしお定矩したす。BERTの拡匵では、BERTの入力に2぀の集合の和集合を甚いたす。比范のためにBERTのpre-trainingは甚いず、たた個別のtoken embeddingは甚いずに、segment embeddingのみ導入しお内郚的に2぀の集合を区別したす。Set Transformerの拡匵では集合マッチングに必芁な眮換䞍倉性は満たしたすが、特城抜出の過皋で集合間のむンタラクションは提䟛されたせん。BERTの拡匵では集合間のむンタラクションは提䟛されたすが、眮換䞍倉ではないずいう性質がありたす。 衚 比范手法の特城 手法 眮換䞍倉性 むンタラクション Set Transformer   BERT   Cross-Affinity (ours)     (1) 郚分コヌデマッチング 冒頭で述べたように、1぀のコヌディネヌトを分割しお正しい郚分コヌデのペアを䜜成したす。このずき、正しくない郚分コヌデの候補をランダムに3぀甚意したずき、提案手法は正しい郚分コヌデを遞べるか を調べたした。なお、負䟋のアむテムは正䟋のアむテムず同じカテゎリになるように制玄を加えたした䟋えばトップスずボトムス。この制玄を実装するために、本実隓ではTriplet損倱を甚いたした。 図 郚分コヌデマッチングの定量評䟡結果 Set Transformer、BERT、提案手法の粟床はそれぞれ39.2、50.5、60.2でした。この結果から、提案手法が倧きく勝っおいるこずが分かりたす。 (2) 耇合コヌデマッチング 耇合コヌデマッチングでは、より耇雑なデヌタに察応できるか調べるために、ランダムに遞んだ4぀の郚分コヌデの和集合耇合コヌデをマッチングしたす。ランダムに遞ぶので、耇合コヌデは様々なファッションスタむルの乱雑な混合を衚珟しおいたす。こちらでは -Pair-Set損倱を甚いたした。 図 ランダムに遞んだ耇数のコヌディネヌトから耇合コヌデを2぀䜜成 このような集合でもうたくマッチングできれば、どのように耇合的な趣向を備えおいるナヌザに察しおも察応できるモデルが原理的には孊習できるず考えられたす。実隓結果は以䞋の通りです。 図 耇合コヌデマッチングの定量評䟡結果 Set Transformer、BERT、提案手法の粟床はそれぞれ65.3、66.1、75.9でした。提案手法が倧幅に勝っおいるこずが分かりたす。郚分コヌデを䜿甚した際よりも党䜓的に粟床が高くなっおいるのは興味深く、色々な考察が可胜です。䟋えば集合に含たれるアむテムの数がある皋床倚くなれば、より識別に効くアむテムを含む確率が高たるため、粟床向䞊を期埅できたす。しかしながら、ノむズのようなアむテムも同時に増えるはずであり、䞀抂にはいえたせん。今埌より深い怜蚎が必芁ず考えられたす。 結論 深局集合マッチングを提案し、ファッションデヌタで実隓を行いたした。近接するタスクでのstate-of-the-artの手法ず比范し、提案手法は倧幅に粟床が高いこずが確認できたした。たた可芖化を通しお、コヌディネヌトの郚分同士が“合う”ずは䜕なのかを、結果的にモデルが孊習しおいるずいう瀺唆を埗たした。今埌、私たちはこのモデルを継続的に発展させおいく予定です。 謝蟞 本蚘事に含たれる研究は、和歌山倧孊の八谷倧岳先生、筆者の博士課皋での指導教員である統蚈数理研究所の犏氎健次先生、匊所の䞭村拓磚氏の協力のもず行われたした。 さいごに 本蚘事の内容はGroup Re-identificationぞの応甚も含めおMIRU2020で発衚する予定です。ご興味のある方は口頭発衚ショヌトをチェックしおいただき、ぜひディスカッションしたしょう たた、ZOZOテクノロゞヌズでは䞀緒にサヌビスを䜜り䞊げおくれる仲間を募集䞭です。ご興味のある方は、以䞋のリンクからぜひご応募ください tech.zozo.com
はじめに こんにちは。SRE郚BtoBチヌムの田村です。BtoBチヌムにおECサむトの賌入テストや䌚員登録等のテストを行う際には、これたでSeleniumを利甚しお毎日LinuxのChrome環境にお実行しおおりたした。しかしながらフロント゚ンドが倉曎された堎合に、゜ヌスコヌドの調敎をしたりサヌバヌ保守察応も必芁で、運甚コストを割かれるこずもしばしばありたした。テストにおける自動化やテスト品質の向䞊及び運甚コストの削枛を目的ずしお、今回AutifyずいうE2E自動テストツヌルを導入したした。 BtoBチヌムのE2Eテスト BtoBチヌムのE2Eテストは、Seleniumを甚いお䌚員登録や賌入テストを毎日実行しおおり、Slackにテスト結果を通知しおいたす。゚ラヌ時には、サヌバヌに入っおログ閲芧し問題ないかを確認しおいたした。そしお、新しいテストパタヌン远加の芁望があった堎合には゜ヌスコヌドを远加する必芁があり、1パタヌンあたりに数時間の工数が発生しお倧きな運甚コストが割かれおいたした。 このように運甚コストが割かれおおりたしたが、Autifyを調査しおみるずダッシュボヌド䞊で゚ラヌ内容を即座に確認可胜ずのこずでした。さらにはSelenium IDEのようなレコヌディングをするだけでテストパタヌンが䜜成可胜で゜ヌスコヌドの調敎が䞍芁ずなり、運甚コスト削枛を芋蟌めたずいうこずもありAutifyを導入したした。 Autify 特城 コヌドを曞かずにテストシナリオを䜜成・修正可胜 耇数OSでテスト実行可胜 特定シナリオの定期実行が可胜 クラりドで実行されるため、実行環境ずしお実機を甚意する必芁はない AIによりUI倉化を怜知するため゜ヌスコヌド調敎が䞍芁 BASIC認蚌蚭定も可胜 チャットで気軜に問い合わせ可胜 耇数OSでテスト実行可胜ずいう点が玠晎らしく、さらにAIによりUI倉化を怜知しおメンテナンス工数を削枛しおくれるずころも良い点です。困ったこずがあればAutifyのダッシュボヌド䞊からチャットで気軜に問い合わせするこずも可胜です。 シナリオ䜜成手順 シナリオ䜜成開始 開始URLを指定するず新芏ブラりザりィンドりが立ち䞊がり、シナリオ䜜成が開始されたす。詊しに、 Seleniumに準備されおいるテストサむト を甚いおシナリオ䜜成を行っおみたす。 レコヌディング 自動でレコヌデむングされるので、シナリオパタヌンに沿っお操䜜したす。むメヌゞずしおはSelenium IDEのように、レコヌディングされる感じです。 怜蚌 怜蚌したいテキスト等があれば、画面右䞋にあるAutifyツヌルのチェックボックスアむコンで蚭定できたす。デベロッパヌツヌルのむンスペクトモヌドのように芁玠を遞択可胜で、芁玠によっお怜蚌項目が倉動したすが、倧枠は䞋蚘のようなチェックが可胜でした。 タむトルチェック URLチェック テキストチェック 芁玠衚瀺チェック オンオフチェック 存圚チェック シナリオ線集画面 埮調敎したい箇所は線集可胜ずなっおたす。入力テキストの内容などを倉曎するこずが可胜です。たた、特定の操䜜たでロヌカルブラりザで自動実行し、新芏操䜜を远加するこずも可胜です。Selenium IDEの堎合は、ファむル共有などする必芁があったのですが、Autifyではダッシュボヌド䞊にお最新シナリオ状態を確認できる点が䟿利です。 シナリオ実行結果 ステップごずに前回ずの比范ができ、わかりやすくなっおたす。前回からの芋た目の倉曎点をすぐに確認可胜ずなっおいたす。 マルチデバむスで実行可胜 耇数OSでテスト実行が可胜ずなっおいたす。 SameSiteデフォルト倉曎の圱響確認に利甚 Chrome 80のSameSiteデフォルト倉曎の察応を行う際に圹立った実䟋を玹介したす。 iOS 12におけるSafariの堎合は、 WebKit Bugzilla (Bug 198181) に蚘茉ある通り、SameSite=None指定はStrictず扱われおしたうので、特定条件のみSameSite指定を倖す察応が必芁でした。 圱響を確認するために、AutifyにおiOS 12の端末を指定しテストするこずで、修正の確認が即座にできたした。通垞であれば実機にお手動テストを実行しおいたずころですが、Autify導入しおいたおかげで自動テストが可胜でした。 たずめ 良かった点 耇数プラットフォヌムにお即座にテスト可胜 シナリオファむルを共有する必芁がなく、りェブで党お完結しおいる 䞍明点、改善芁望があれば、チャットですぐ問い合わせが可胜 気になった点 现かい挙動の調敎ができない 䟋えば、お届け予定日をコンボボックスで遞択する堎合、実行日によっお動的にラベル内容が曎新されるようなサむトの堎合です。Autifyの堎合は、ラベル名で遞択しおいるので、レコヌディング時に遞択した日付が無くなった堎合に゚ラヌずなっおしたいたす。このような堎合は、むンデックス遞択できれば解決できそうなので、珟圚は改善芁望䞭です。 床々アップデヌトが行われおおり、改善されおいくかず思いたす。 さいごに ZOZOテクノロゞヌズでは、䞀緒にサヌビスを䜜り䞊げおくれる方を募集䞭です。ご興味のある方は、以䞋のリンクからぜひご応募ください tech.zozo.com
ZOZOテクノロゞヌズでVRやARずいったXR領域の利掻甚を掚進しおいるWEAR郚の諞星 @ikkou です。 匊瀟に限った話ではありたせんがCOVID-19の圱響により、今たでのようなオンサむトでのむベントをなかなか実斜し難い状況が続いおいたす。 䟋えば先日の『#技術曞兞 頒垃本「ZOZO TECH BOOK」解説䌚』は匊瀟ずしお初のオンラむンむベントずなりたした。 techblog.zozo.com いわゆる「勉匷䌚」系のむベントもそうですが、オフィス芋孊ずいった瀟内の雰囲気を知るために重芁なむベントも同様に実斜できない状況です。 そこで先日、これもたた匊瀟ずしおは初の詊みずなる『バヌチャルオフィス芋孊䌚』を実斜するこずにしたした。 zozotech-inc.connpass.com 『バヌチャルオフィス芋孊䌚』に先駆けお、clusterに『ZOZOテクノロゞヌズ バヌチャルオフィス』を公開しおいたす。 cluster.mu 私はこのバヌチャルオフィス䜜りの技術・運甚たわりで携わったので、本蚘事ではその背景を玹介したす。 手段の遞定 プラットフォヌムの遞定 ワヌルド䜜り Cluster Creator Kitの導入 clusterに最適化したシェヌダヌぞの倉曎 VRChat向けシステムの削陀 歩き回るこずを想定したコラむダヌの削陀ず远加 怍物の削陀 バヌチャルならではの「遊び」 ゚ントランスのZOZOMATず箱猫マックス 持ち䞊げられるZOZOç®± リアルアバタヌの利甚 プラットフォヌム遞定の補足 VRChatを遞択しなかった理由 Mozilla Hubsを遞択しなかった理由 たずめ 最埌に 手段の遞定 バヌチャルオフィス芋孊を実斜するにあたり、たずどのような手段で実斜するか怜蚎したした。倧別するず次の2぀になりたす。 1぀目はフォトリアルな党倩球360床の写真や動画を䜿った方法です。 䟋えば囜立科孊博物通による「 おうちで䜓隓かはくVR 」は党倩球写真を甚いたりォヌクスルヌ型のバヌチャル展瀺です。Matterportずいう特殊なカメラを䜿甚しお撮圱しおいたす。 www.kahaku.go.jp 2぀目は3D CGを䜿った方法です。 䟋えば「 Grani VR Office Tour 」はレヌザヌスキャンを甚いお実際のオフィスず同等の空間を3D CGで再珟したバヌチャルオフィスツアヌです。 grani.jp それぞれにPros/Consがあり、個別の詳现は省きたすが、今回は埌者の3D CGで再珟する方法を採りたした。 これはオフィスの党倩球写真が存圚せず、しかし撮圱のため倖出自粛が求められる期間䞭にオフィスぞの移動を避けたかったこず、そしお埌述する3D CGのアセットが既に存圚しおいたこずが理由です。 プラットフォヌムの遞定 手段が決たった埌、『バヌチャルオフィス芋孊䌚』を実斜するプラットフォヌムを遞定したした。 具䜓的にはVRChat, cluster, Mozilla Hubsの3぀の候補に絞りたした。その䞊で、今回はマルチプラットフォヌム察応のバヌチャルSNSである「cluster」に青山オフィスを暡した空間を再珟する圢を採りたした。 cluster.mu clusterは誰もが自由に䜿える公匏のむベント䌚堎の他に、ナヌザヌ独自の䌚堎を䜜れるワヌルド機胜がありたす。 ぀い最近ではグルヌプ䌚瀟でもあるダフヌの『オヌプンコラボレヌションスペヌス「LODGE」』が『バヌチャルLODGE』ずしお䞀足早くclusterのワヌルドずしお公開されたした。 note.com 今回はこのワヌルド機胜で「バヌチャルオフィス」を䜜成するこずにしたした。 ワヌルド䜜り プラットフォヌムずしおclusterを遞択したしたがclusterが提䟛するのは奜きなむベント䌚堎を䜜り、そこに集たっおむベントを開催するこずで、䌚堎そのものは自分自身で䜜る必芁がありたす。 幞いなこずに匊瀟では2019幎に実斜した瀟員総䌚で、VRChatに最適化した「バヌチャルオフィス」を䜜成しおいたした。今回はこのワヌルドをcluster向けに修正する圢で察応したした。 techblog.zozo.com 修正点は次の通りです。空間そのものは出来䞊がっおいたので、倧きく手を入れる必芁はありたせんでした。 Cluster Creator Kitの導入 公匏SDKずしお提䟛されおいるCluster Creator Kitを導入し、もずもず存圚しおいたスクリヌンず差し替える圢で Standard Main Screen View ず新たにコメントを衚瀺する Standard Comment Screen View その他、最䜎限必芁なオブゞェクトを远加しおいたす。 github.com 難しいポむントはないので、ドキュメント通りに蚭定すれば問題ありたせん。 VRChat向けの「バヌチャルオフィス」では、゚ントランスから入っお盎ぐ目の前にある円䌚議宀の䞭にのみスクリヌンが甚意されおいたした。しかし、数十人が1床に参加する可胜性があるオフィス芋孊ずいう特性を考慮しおcluster向けの「バヌチャルオフィス」では円䌚議宀を出たずころにもスクリヌンを蚭眮しおいたす。 あわせお円䌚議宀内のスクリヌンは芋やすさを考慮しお「珟実䞖界」よりも数割倧きめに蚭眮しおいたす。 clusterに最適化したシェヌダヌぞの倉曎 clusterはWindows, Mac, Android, iOSずいうマルチプラットフォヌムで動䜜する性質䞊、そのすべおのプラットフォヌムで期埅する動䜜を求めるためにはゞオメトリシェヌダヌが䜿えたせん。 VRChat向けの「バヌチャルオフィス」では、円䌚議宀を構成するガラス郚分をはじめずする耇数箇所でNGずなるシェヌダヌが䜿われおいたした。 ガラスの衚珟には、モバむルプラットフォヌムでも䜿えるシェヌダヌを遞択したした。このシェヌダヌは、UnityのAssetStoreで無料でダりンロヌドできるのですが、擬䌌的な屈折衚珟なども行える優れたものでした。金属やガラスなどに物䜓が反射する衚珟には、リフレクションプロヌブを䜿甚しおおり、蚈算負荷を抑えおながら品質の向䞊を目指したした。 https://techblog.zozo.com/entry/compass2019ss より匕甚 芋栄えはずおも良いのですが、様々な環境からオフィス芋孊を実珟できるよう、今回はUnity暙準のStandardシェヌダヌに倉曎したした。 VRChat向けに蚭定されおいたシェヌダヌ Unity暙準のStandardシェヌダヌ Standardシェヌダヌでも特城的なガラスの曲面は再珟できおいたす。 VRChat向けシステムの削陀 VRChat向けの「バヌチャルオフィス」は文字通りVRChatで動䜜させるこずを意図しおいるので、VRChat向けの機胜がいく぀か内包されおいたした。これらは䞍芁なので削陀したした。clusterのワヌルドは䞍芁なアセットを削陀した方がアップロヌドもプレむ時のダりンロヌドも早くなりたす。 歩き回るこずを想定したコラむダヌの削陀ず远加 VRChat向けの「バヌチャルオフィス」は前述の通り「瀟員総䌚」で利甚するこずを意識しおいたこずもあっおか、オフィス内を歩き回る「オフィス芋孊」甚途ずしおは成り立たない箇所がいく぀かありたした。そういった箇所は透明な壁ずなるコラむダヌを削陀あるいは远加したした。 怍物の削陀 珟実䞖界の青山オフィスには実に100鉢以䞊の緑が生い茂っおいたす。これらをバヌチャル䞖界でそのたた再珟するず、少し歩きにくく感じおしたいたす。その察策ずしお青山オフィスの雰囲気を損なわない範囲で怍物を削陀したした。 オンサむトでのオフィス芋孊が再開した際には、ぜひ「バヌチャルオフィス」ずの差分をその目で確かめおもらいたいです。 バヌチャルならではの「遊び」 せっかくの「バヌチャル」なので、珟実䞖界の「青山オフィス」ずは異なるちょっずしたアむテムを甚意したした。 ゚ントランスのZOZOMATず箱猫マックス 乗っかったずころで実際に足のサむズは枬れたせんが、゚ントランスの巊偎足元に「ZOZOMAT」を蚭眮したした。たた、同゚ントランス右偎にはZOZOTOWNの公匏キャラクタヌである「箱猫マックス」を蚭眮したした。 å·Š: ZOZOMAT 右: ZOZOTOWN公匏キャラクタヌ「箱猫マックス」 持ち䞊げられるZOZOç®± 箱猫マックスの身䜓を流甚しおオフィス内の耇数箇所に「ZOZO箱」を耇数蚭眮したした。ZOZOTOWNを利甚したこずがある方ならお銎染みのあの黒い段ボヌル箱です。 Reference: https://note.com/zoooom/n/n06d63160f4bb 単玔に眮いおあるだけでは面癜みに欠けるので、持ち䞊げたり積み䞊げられるようにしたした。 ZOZO箱を持ち䞊げおいる様子 これはCluster Creator Kitで甚意されおいる Grabbable Item コンポヌネントを䜿うだけで簡単に実装できたす。あわせお必芁な Item , RigidBody , Movable Item 各コンポヌネントも䞀緒に蚭定されるので、別途必芁になるのは Item コンポヌネントの名前を倉えお、コラむダヌを远加するだけです。 Grabbable Itemの蚭定 ちなみに本蚘事の公開時点ではアむテムのリスポヌン初期䜍眮に戻る仕組みが実装されおいたせん。そのため、1床動かされた「ZOZO箱」を「掃陀」する手間を省くために公開版のワヌルドには含たれおいたせん。 リアルアバタヌの利甚 clusterの䞖界での芋た目ずなるアバタヌは、原則ずしお党ナヌザヌ共通のものが甚意され、顔の郚分のみアカりントにアむコンずしお蚭定しおいる画像が衚瀺される仕組みになっおいたす。 暙準アバタヌは顔郚分にアむコンに蚭定した画像が衚瀺される それずは別に、VRMずいう囜産のVR向け3Dアバタヌファむルフォヌマットのアバタヌを甚意するこずで、自分が䜿いたいアバタヌを䜿甚できたす。 vrm.dev 今回は䞀郚の瀟員に限りたすが、フルボディ3Dスキャンした身䜓をclusterに最適化したVRMデヌタずするこずで、いわゆる「リアルアバタヌ」ずしおオフィス芋孊の旗振り圹を務めたした。 仕様に沿ったVRM圢匏のリアルアバタヌを蚭定した様子 リアルアバタヌを制䜜する手法は色々ずありたすが、今回は奇しくも1月時点でリアルアバタヌ株匏䌚瀟さんに撮圱しおもらっおいたデヌタを掻甚しおいたす。 www.real-avatar.com clusterでのVRMアバタヌは32,000ポリゎン制限があるので、UnityのMesh Simplifyで手早くポリゎン数を削枛しおいたす。 プラットフォヌム遞定の補足 補足にはなりたすが、冒頭のプラットフォヌム遞定で挙げたVRChatずMozilla Hubsを遞択しなかった理由を蚘茉したす。 VRChatを遞択しなかった理由 今回は囜産のVR SNSであるclusterを遞択したしたが、実はVR SNSは党䞖界で100以䞊存圚しおいたす。その䞭でも日本囜内のVRが奜きな方々の䞭で特に有名なのが「 VRChat 」です。 ぀い最近では株匏䌚瀟りィゎヌさんや、株匏䌚瀟䞉越䌊勢䞹ホヌルディングスさんが䌁業ずしお参加したバヌチャルマヌケット4のプラットフォヌムもこのVRChatです。 www.wwdjapan.com 前述の通り既存の「バヌチャルオフィス」はVRChat向けに䜜られおいたので、このVRChatを䜿えばcluster向けの修正も必芁ありたせんでした。 しかし、VRChatは䞀定以䞊のスペックを持ったWindows PCを必芁ずするこず、そしおプラむベヌトなワヌルドは運営ず事前にフレンド登録が必芁なこずから遞択したせんでした。 匊瀟がVR領域を䞭心ずした事業を展開しおいるのであれば、VRChatを遞択するこずもやぶさかではありたせん。しかし、今回は幅広い職皮・職域の方が「来瀟」できるこずを考慮し、スマヌトフォンを含むマルチプラットフォヌムに察応しおいるclusterを遞択した圢になりたす。 Mozilla Hubsを遞択しなかった理由 「MoziLla Hubs」はアプリのむンストヌルを必芁ずせず、ブラりザだけで䜓隓できる、いわゆるWebXR技術を掻甚したプラットフォヌムです。私自身はXR領域の䞭でも特にWebXRを掚しおいるので、この Mozilla Hubs もリリヌス圓初から匷く掚しおいたす。 Mozilla Hubsでは「 Spoke 」ずいうりェブアプリケヌションを通しおclusterやVRChatのように自分独自のバヌチャル空間を構築できたす。 SpokeにはVRChat向けのアセットであるFBXファむルをそのたた持ち蟌めないので、UniGLTFでSpokeでも扱えるGLBファむルに゚クスポヌトしたものをむンポヌトする必芁がありたした。しかし、Spokeに持っおいくだけであれば倧きな手間はかかりたせんでした。 Spokeで円䌚議宀を蚭眮した様子 clusterやVRChatず違い、Mozilla Hubsは専甚アプリのむンストヌルを必芁ずせず、Windows, Mac, Android, iOSのどれでも普段䜿っおいるブラりザから気軜にアクセスできたす そんな良いこず尜くしのMozilla Hubsですが、求める「バヌチャルオフィス」を再珟するにはアセットの容量制限掚奚は12MBで䞊限は128MBのずころGLBファむルの容量だけで600MB超えが厳しく、今回は諊めたした。 公開を芋合わせたMozilla Hubs版のバヌチャル青山オフィス 緑ずデスクを取り陀いた圢で、オフィスそのものず特城的な円䌚議宀だけであれば再珟できたので、䜕らの圢で䜿える機䌚を䌺っおいたす。 たずめ バヌチャルSNSであるclusterをプラットフォヌムずしお、VRChat向けワヌルドを改倉したcluster向けのワヌルドで、『バヌチャルオフィス芋孊䌚』を実斜するたでの取り組みを玹介したした。 今回はVRChat向けの玠材が手元にあったため、アむデア出しから実斜たでのスパンを短くできたした。もしも手元になかった堎合はれロむチで「バヌチャルオフィス」を䜜る必芁があったので、高い再珟性を求める堎合は盞応の工数が発生しおいたはずです。 5月25日を以お党郜道府県で緊急事態宣蚀は解陀されたしたが、いわゆるアフタヌコロナ/りィズコロナの䞖界ではオンサむトではなくオンラむン、バヌチャルで物事を実斜する機䌚が増えおいくず考えおいたす。そのような䞖界で、こういった圢でバヌチャルオフィスを䜜るずいう手段もあるずいうこずが䌝わりたすず幞いです。 最埌に ZOZOテクノロゞヌズでは今埌も「オンラむン配信」や『バヌチャルオフィス芋孊䌚』など今たで取り組んでいなかったこずにも積極的に取り組んでいきたす。 䞀緒にサヌビスを䜜り䞊げおくれる方だけではなく、゚ンゞニアの技術力向䞊や倖郚発信に興味のある方も募集䞭です。ご興味のある方は、以䞋のリンクからぜひご応募ください tech.zozo.com たた、再掲になりたすが、6月9日の『バヌチャルオフィス芋孊䌚』も受付䞭です zozotech-inc.connpass.com 珟堎からは以䞊です
こんにちは、基幹システム郚メンテナンスチヌムの矢野です。 今回は僕のチヌムで行っおいる毎日勉匷䌚に぀いお曞いおいきたいず思いたす。 新しいむンプットの機䌚創出 組織内の技術力のベヌスアップ斜策 瀟内コミュニケヌション このようなこずを考えおいる方の参考になればず思いたす。 経緯 たず毎日勉匷䌚ずいうものが圢䜜られた経緯ですが、チヌムたたは郚眲のために䞋蚘の3぀の事柄の質を向䞊できないかずがんやり頭の䞭で考えおいたこずがきっかけでした。 自郚眲のブランディング必芁ずされる郚眲になる、自分たちの芋解を持぀ 郚眲内コミュニケヌション向䞊朝瀌など 郚眲のメンバヌが゚ンゞニアずしお枡り歩いおいくための手助け心理的安党性 たず1぀目は自郚眲のブランディングです。 ブランディングず曞くずちょっずお高い感じに聞こえちゃいたすが、芁は瀟内で必芁ずされるよう郚眲の䟡倀を䞊げおいきたいずいうこずです。「ZOZOの基幹のこずは基幹システム郚に任せおおけば倧䞈倫」ずいう認識を瀟内に䞀局持っおもらいたい、そういった瀟内の信頌を䞊げるためにはどのようなこずをしおいけばいいか、どのような組織に成長させたいかを考えおいたした。 2぀目がコミュニケヌションの向䞊です。 僕が所属しおいるメンテナンスチヌムは、2019幎5月から発足した比范的新しいチヌムです。今たで別々のチヌムに所属しおいた4人が集たり、緊急斜策で優先床が䞋がった案件やリファクタリングなどのビゞネスにはかかわらないが、必芁なシステム改修を行うチヌムずしおスタヌトしたした。 党く別々のチヌムで業務を行っおいたメンバヌが集たったため、発足圓初はコミュニケヌションがうたく図れず4人で黙々ず䜜業をこなす日々でした。チヌムリヌダヌずしおは「これはもうちょっず雑談ずかできるような雰囲気にしたほうがいいな」ず感じ毎朝5分間の雑談タむムを始めたした。ランダムでネタを提䟛しおくれるアプリを䜿いながら毎日やっおいたため、ネタには困りたせんでした。しかし、3か月もするずマンネリ化しおきたすし、メンバヌの距離も瞮たっおきたため朝の雑談タむムは䞀旊ストップしたした。 でもこの朝の雑談タむムがきっかけで、チヌム党員で䜕か1぀のこずをやるずいう時間は、別の圢で続けおいきたいなず思うようになりたした。 朝瀌は自分の䞭で氞遠のテヌマですね。マンネリ化しない有意矩な朝瀌。これが思い぀いたらたたテックブログ曞きたすね。 3぀目に郚眲のメンバヌが゚ンゞニアずしお枡り歩いおいくための手助けです。 ZOZOの基幹システムはすでに安定した環境が出来䞊がっおいるので技術的にはその環境内での改修が䞻になりたす。ビゞネス郚門や倉庫の芁望を改修し圢にしおいきたすがそうなるずどうしおも業務だけでは新しい技術ぞの接点が少なくなりたす。メンバヌには、゚ンゞニアずしおの芖野を少しず぀でも広げおいっおもらいたい。そのためにぱンゞニアずしおのアンテナの匵り方や新しい技術に觊れる機䌚をこちら偎から提䟛できれば成長の支揎になるのではないか。そんな思いもありたした。自分たちは基幹システムを改修する人ではなく、あらゆる問題をシステムで解決する集団ずいう颚に意識を䞀段階アップできれば先に曞いた他郚眲からの信頌にも寄䞎できるのではないかず思っおいたす。 枠組み・やるこず では、䞊蚘のような考えを圢にするにはどうすればいいんだろう 3぀の軞で考えおみたした。 絶察やりたくないこず 期埅するこず 珟状珟実 絶察やりたくないこず たず1぀目の軞ですが、これらを達成する手段ずしお絶察にやりたくないこずを考えおみたずころ2぀ありたした。 匷制はむダだ 途䞭離脱はむダだ 真っ先に思ったのは匷制的に䜕かをやらせるこずだけは避けたいずいうこずです。自䞻性を重んじた枠組みを䜜るこずがこの枠組み自䜓を最倧限有意矩に掻甚でき、掻甚しおいくこずで埗られる成長やコミュニケヌションにおいお郜合よく働くず思ったからです。 䞭孊生の時の実䜓隓ずしお「ギタヌを匟けるようになりたい」ず思ったその時のモチベヌション・初期衝動がギタヌを匟けるようになった䞀番の理由だず確信しおいたす。 このこずからも自䞻的に䜕かをやりたいず思った時が䞀番吞収する時期であるこずは間違いないです。 たたやるからには途䞭で離脱できるような環境は䜜りたくないず思いたした。ただ「途䞭離脱できない環境を䜜る」ず考えるず「絶察やりたくないこず」で曞いた匷制力が顔を出しおきそうだったので、途䞭でやめられないようにレヌルを敷くのではなく、途䞭でやめおしたう理由を排陀しおいっお結果的に途䞭離脱がなくなるようにするずいったむメヌゞで考えを組み立おおいくようにしたした。 期埅するこず 2぀目の軞でこの枠組みに期埅するこずは3぀ありたした。 新しい技術に察するハヌドルを䞋げおおきたい チヌムをたたいだ亀流の掻性化に぀なげたい 曞籍賌入補助制床を有効掻甚したい 先に曞いたように珟状ZOZOの基幹システムの開発は䞀定の技術を芚えればあずはビゞネス郚門や倉庫ず話を詰めお案件を進めお行くこずができたす。ですが、今埌モダンな環境ぞずリプレヌスする時期が必ずやっおきたす。そうなったずき、いきなりメンバヌに䜿ったこずのない技術を䜿っお開発しろずなるずそれこそ効率的な開発などできたせんし、その技術を習埗するたでに時間もかかっおしたい最悪案件を進められない時間が出おくる可胜性もありたす。経緯のずころで蚘茉した自郚眲のブランディングも保おなくなるかもしれたせん。なので、たずは新しい技術に察するハヌドルを䞋げおおけるようなものにしたいず考えたした。 次はチヌムをたたいだ亀流を盛んにしたいずいうものです。匊瀟では、チヌムが組織の䞀番小さい単䜍になりたす。このチヌムずいう単䜍で業務を遂行する堎面がほずんどなのでチヌム内の亀流は自ずず図れるのですが、その1぀䞊の「郚」ずいう単䜍での亀流もさらに掻性化させられたらいいなず思いたした。最終的には郚ずいう枠も取っ払っお瀟内の誰もが亀流できる堎を提䟛できたら最高ですね。 最埌は曞籍賌入補助制床の有効掻甚です。匊瀟には曞籍賌入補助制床ずいうものがありたす。これは賌入した曞籍をレビュヌしお経費申請すれば党額を粟算できる制床です。䌚瀟の経費で賌入した曞籍は絶察に無駄にしたくないので自腹で買った本であれば自分の奜きにすればいいですが、経費はみんなが頑匵っお皌いだお金ですから無駄にしたくないですね買ったからには最倧限有効掻甚できる方法を芋出しおこの制床をさらに有意矩に䜿えないかず考えたした。ずもあれ曞籍を最埌たで読むっお達成感埗られたすよね。 珟状珟実 3぀目の軞には珟状珟実ず曞きたしたが、これは実際に行われおいる勉匷䌚などスキルアップするための機䌚に぀いおの問題点を考えおみたした。 瀟内勉匷䌚などで自分の興味が有るものが開催されるずは限らない実䜓隓 講垫がいる勉匷䌚はわかった぀もりになっお終わるこずも結構ある実䜓隓 スケゞュヌル調敎できずに参加しなくなるずそのたた離脱しおしたう実䜓隓 興味があっおもなかなか勉匷に着手できる時間がずれない実䜓隓 本を買っお䞀人で勉匷しおも最埌たで続かない実䜓隓 党郚実䜓隓です。 こう芋るずやっぱり自䞻性っお成長にずっお最倧の栄逊玠なんだなず思えおきたす。自䞻性をうたく成長ぞのモチベヌションに倉えられるような枠組みが䜜れれば䞊蚘のような問題も解決できるのではず思いたした。 そしお、ここから導き出した1぀の答えがこちらです。 「 勉匷したい人には勉匷する時間を毎日1時間䞎える 」 これにより前述した問題点や垌望するこずの䞭で解決できるこずがいく぀かありたす。 問題点・期埅するこず 解決理由 匷制はむダだ 勉匷したいず思った人が䜿える時間なので匷制ではなく完党自䞻性 新しい技術に察するハヌドルを䞋げおおきたい 新しい技術も含め興味のある分野を習埗できる時間ずしお䜿える 瀟内勉匷䌚などはあるが、自分の興味が有るものが開催されるずは限らない 興味を持った段階でそれに぀いお孊習できる時間が埗られる 興味があっおもなかなか勉匷に着手できる時間が取れなそう 䞊長ず盞談の䞊、業務調敎ができれば時間も確保できそう、ずいうか時間を確保するために調敎するずいうメリハリが぀けられそう ただ、これだけではこの時間に䜕をやればいいか迷いそうなのでもう少し決めごずを䜜りたした。 远加で考慮したいこず 途䞭離脱はむダだ 曞籍賌入補助制床を有効掻甚したい 講垫がいる勉匷䌚はわかった぀もりになっお終わるこずも結構ある スケゞュヌル調敎できずに参加しなくなるずそのたた離脱しおしたう 本を買っお䞀人で勉匷しおも最埌たで続かない チヌムをたたいだ亀流の掻性化に぀なげたい この蟺りを䜕ずか枠組みに远加できないかず考え、出おきた答えがこちらです。 「冊の本を興味のあるメンバヌを募っお最埌たでやる」 これで远加で考慮したいこずがカバヌできそうです。 問題点・期埅するこず 解決理由 途䞭離脱はむダだ 䞀冊の本を最埌たでやりきるずいう枠組みを䜜るこずにより途䞭離脱を無くしたす。終わらせる期限を぀けないこずがポむント 曞籍賌入補助制床を有効掻甚したい 曞籍を䞀冊最埌たでやりきるずいうこずを枠組みずしたす。 講垫がいる勉匷䌚はわかった぀もりになっお終わるこずも結構ある 興味がある人が集たっお同レベルで勉匷しおいくこずで党員に圓事者意識が生たれる。 スケゞュヌル調敎できずに参加しなくなるずそのたた離脱しおしたう あえお期限を蚭けないので離脱する芁因が枛りたす埌述したす 本を買っお䞀人で勉匷しおも最埌たで続かない 耇数人でやるこずで補いあいながら最埌たで進められる耇数人いるこずで芋えない抑止効果もあるかも チヌムをたたいだ亀流の掻性化に぀なげたい 勉匷したい本が芋぀かった人はこの本の内容に興味がある人を誘いたす。賛同者をチヌム倖からも集められるので亀流の堎が広がりたす。 できた 䞊蚘をたずめるずこんな枠組みが出来䞊がりたした 勉匷したい本が芋぀かった人は同じ興味を持った人を募り最倧4人毎日1時間党員でその本を最埌たで勉匷する ここで補足です この枠組がなぜ「毎日」なのか、なぜ「4人」なのかずいうずころです。補足だけど重芁なポむント 参加型の勉匷䌚を芋おきお運営が難しそうなだず思ったずころがありたす。 問題点 理由 参加者の続けるモチベヌション 回数を远うごずに参加者が枛っおいく 参加者の圓事者意識 参加しおいるずいう事実だけでわかった気になっおしたっおいる。自分はこの手の人間です 1回の欠垭がフェヌドアりトのきっかけになる 講矩を䞀床欠垭するずだんだん内容がわからなくなり途䞭離脱を助長させる これっお倧勢を集めおやるからこそ生じる問題点ではないかず考えたした。 講矩の開催者偎ずしおは受講生は倧勢いるので䞀人が䌑んだくらいでは講矩を止められない。受講者偎の心理ずしおは倧勢だず自分ひずりが䌑んだくらいでは講矩は止たらない、最悪自分は぀いおいけなくなるかもしれないが他の受講者に迷惑をかけるこずはないので欠垭するこずぞのハヌドルが䞋がる。䞀回䌑むず講矩は進むので理解に遅れが生じ途䞭離脱ぞ・・・ この蟺りは「毎日やる」「最倧4人での開催」ずいうルヌルを定めるこずでいい方向に持っおいけそうでした。 なぜ毎日なのか たず前提ずしおこの枠組みは有䌑や急なミヌティング等で参加できなくなるのはOKずしおいたす。勉匷䌚のこずは気にせず有䌑をずったり緊急案件の察応しおもらいたいです。䞀人が参加できなくなった堎合はその日の䌚はスキップしたすが翌日たた党員が集たった日に続きをやればいいのです。毎日ずいっおいるのに矛盟しおいたすが毎日参加者が党員集たれる日に開催するずいうラフな感じです。 スキップOKが前提なので䟋えば開催日を毎日ではなく週1回にするず次の䌚が次週になっおしたいたす。1週開くず進みが遅く途䞭離脱を助長させそうなので開催は基本毎日です。ここが「毎日」ずした理由です。 このような枠組みなので前述したしたが期限は蚭けおいたせん。誰も離脱するこずなく最埌たで終わらせるため、できる日は毎日曞籍が終わるたで党員参加で行うずいうルヌルです。 なぜ4人なのか 有䌑や急甚での䌚のスキップを参加者に切り出しやすい最倧人数は4人䜍ず想定しおいたす。講垫なしで進めるので個人個人が圓事者意識を持おる最倧人数も4人ず想定しおいたす。みんなで協力しあえる最倧人数も4人ず想定しおいたす。倱敗しおも恥ずかしくない最倧人数も4人ず想定しおいたす。完党に感芚倀なのですが皆さんも4人ず5人では5人の方が䞊蚘のバランスが厩れそうな感じがしたせんか こうしお出来䞊がった毎日勉匷䌚の仕組みを利甚しお僕たちメンテナンスチヌムでは珟圚3冊目の本を絶賛勉匷䞭です。 コロナ犍で党員圚宅勀務ですが毎日14時にテレビ䌚議を぀ないでDockerの勉匷をしおいたす。進め方は扱う曞籍によっお倉わっおくるので枠組みの䞭には入れおいたせん。適宜集たったメンバヌで進め方を考えお勉匷しおいけばいいず思いたす。挔習やハンズオンが倚くある本であればみんなでやりながら党員が同じようにできるたで進めるでもいいですし読み進めるような曞籍であれば章や区切りやすいずころたで読み進めたずめでディスカッションずいう圢匏でもいいず思いたす。そこは自由です。 4人のうちだれか䞀人でも眮いおけがりにならないようにずいうずころにだけ気を付けお理解が早い人はフォロヌしお進めるこずが倧事だず思いたす。 䌚瀟や組織によっお毎日1時間の時間を割くずいうこずは調敎が難しい堎面も出おくるかもしれたせん。䞊長や呚囲ず盞談し業務調敎の䞊、毎日1時間の勉匷時間が取れればなるべく毎日4人がそろった日にみんなの興味のある曞籍を進めるずいう気軜な気持ちで始めおもらえるずいいず思いたす。 たずめるず 毎日勉匷䌚を開催するず参加者党員が興味のある曞籍を圓事者意識をもっお最埌たで読み切るこずができたす。 これにより、参加者は勉匷したこずはもちろんコミュニケヌションの向䞊などが埗られたす。管理者ずしおはメンバヌの孊習機䌚の創出ができたす。 たたこの枠組みは䞀冊の本を最埌たでやりきるこずを目的ずしおいおそれを達成できるようにスキップOK、毎日やる、参加者は4人、期限を蚭けないなど手軜に始められるようにも考慮されおいるのでぜひ調敎が぀いたら䞀回やっおみおもらいたいです。 今埌瀟内に広がっお所々で自然発生的に行われる文化になれば最高だなず思っおいたす。 いかにシヌムレスに始められそしお参加者がドラむブしやすいむンプット支揎の方法を考えたら、毎日勉匷䌚ずいう1぀の方法にたどり着いたずいうお話でした。 あずがき 䞊蚘のこずが党郚ひずりでできちゃう人はもちろんたくさんいるず思いたす。自分はHowToやメ゜ッドを考えるプロではないので実䜓隓などから自分だったらこうやればストレスなく始められるな、こうやれば途䞭で諊めるこずなく続けられるなずいう目線で組み立おおいきたした。 仕組みを䜜る䞊で、はみ出さずにゎヌルたで導きたいずきにはレヌルを敷くのではなく、なぜはみ出すのかを考えその理由を1぀ず぀排陀しおいくこずで自ずずはみ出さずにゎヌルたで行き぀くずいう考え方があるこずに気付けたのもいい経隓になりたした。 この毎日勉匷䌚の枠組みもなるべくレヌルを敷かないようにしおいたすのでフレキシブルな察応に頌っおいるずころは倚々ありたす。ルヌルずしお決めるずころは決める、でもそれ以倖のずころは圓事者同士でフレキシブルに察応ずいう圢が取れれば管理しなくおも自発的に動いおいく仕組みができおいくのかなず思いたした。 ZOZOテクノロゞヌズでは、䞀緒にサヌビスを䜜り䞊げおくれる仲間を募集䞭です。ご興味のある方は、以䞋のリンクからぜひご応募ください tech.zozo.com