Slide 1

Slide 1 text

ZOZOTOWNカート決済システムのリ プレイス〜歩みとこれから〜
 2023-03-23 ZOZO Tech Meetup〜Java活用事例紹介〜
 株式会社ZOZO
 技術本部 カート決済部 カート決済基盤ブロック
 高橋 和太郎 Copyright © ZOZO, Inc. 1

Slide 2

Slide 2 text

© ZOZO, Inc. 株式会社ZOZO
 技術本部 カート決済部 カート決済基盤ブロック 高橋 和太郎
 2019年よりZOZOTOWNリプレイスプロジェクトに参画し、 2021年よりカート決済システムリプレイスに従事。趣味は猫 と遊ぶこと。
 2

Slide 3

Slide 3 text

© ZOZO, Inc. https://zozo.jp/
 ● ファッションEC
 ● 1,500以上のショップ、8,500以上のブランドの取り扱い
 ● 常時90万点以上の商品アイテム数と毎日平均2,600点以上の新着 商品 を掲載(2022年12月末時点)
 ● ブランド古着のファッションゾーン「ZOZOUSED」や
 コスメ専門モール「ZOZOCOSME」、靴の専門モール
 「ZOZOSHOES」、ラグジュアリー&デザイナーズゾーン
 「ZOZOVILLA」を展開
 ● 即日配送サービス
 ● ギフトラッピングサービス
 ● ツケ払い など
 3

Slide 4

Slide 4 text

© ZOZO, Inc. 4 Agenda
 ● カートリプレイスについて
 ● カートリプレイスPhase1
 ● カートリプレイスPhase2
 ● 技術選定・ツール
 ● 部内の取り組み
 ● リプレイスの今後


Slide 5

Slide 5 text

© ZOZO, Inc. 5 カートリプレイスについて


Slide 6

Slide 6 text

© ZOZO, Inc. カートリプレイスのこれまで
 Qiita: ZOZO開発組織の2022年の振り返りと現状 6 ※ 2022年12月公開時点

Slide 7

Slide 7 text

© ZOZO, Inc. カートリプレイスの目的
 成長し続けるZOZOTOWNを支え、お客様にいつでも快適に買い物をしていただけるサービスを提供 するため
 ● セールなどの高負荷イベントに対応できること
 ○ スケール可能であること
 ○ キャパシティコントロールが可能であること
 ● Datadog、SentryなどのSaaSを利用した運用監視の効率化ができること
 ● CI/CDなどを取り入れ、開発生産性を向上できること
 ● レガシー技術をモダン化できること
 7

Slide 8

Slide 8 text

© ZOZO, Inc. 8 カートリプレイスPhase1


Slide 9

Slide 9 text

© ZOZO, Inc. カートリプレイス前の構成概要
 ● リクエストをIISで受け、VBScriptからSQL Serverのストアドプロシージャを呼び出し、処理を実行
 ● ストアドプロシージャでは、在庫の引き当てとカート投入処理を実施
 9

Slide 10

Slide 10 text

© ZOZO, Inc. 構成概要
 TECH BLOG:ZOZOTOWN カート決済機能リプレイス Phase1 〜 キャパシティコントロールの実現
 10

Slide 11

Slide 11 text

© ZOZO, Inc. Cart Queuing Systemの概要
 11

Slide 12

Slide 12 text

© ZOZO, Inc. 12 カートリプレイスPhase2


Slide 13

Slide 13 text

© ZOZO, Inc. 構成概要(Before)
 
 13

Slide 14

Slide 14 text

© ZOZO, Inc. 構成概要(After)
 
 14

Slide 15

Slide 15 text

© ZOZO, Inc. Cart Stock Systemの概要
 ● 在庫情報テーブルで在庫を管理
 ● オンプレの在庫情報との整合性を担保するために在庫変更ログテーブルを使用
 15

Slide 16

Slide 16 text

© ZOZO, Inc. 16 技術選定・ツール


Slide 17

Slide 17 text

© ZOZO, Inc. 技術選定・開発ツールについて
 社内のOSS利用ガイドラインに基づいて実施
 ● Javaのバージョン
 ● Spring Bootのバージョン
 ● ソフトウェアアーキテクチャ
 ● ビルドツール
 ● テストフレームワーク
 ● AWSの使用サービス
 ● ライブラリ
 ○ O/R Mapper
 ○ コードフォーマッター
 ○ DBマイグレーションツール
 ○ OpenAPI
 
 17 開発に使用しているツール
 ● IntelliJ IDEA
 ● GitHub
 ○ GitHub Actions
 ■ 単体テスト
 ■ コードの自動フォーマット
 ■ 必要に応じてDocker Imageの作成
 ● Sentry
 ● Datadog
 ○ 監視
 ○ 分析
 ● SonarCloud
 ○ 静的コード解析
 カート決済専任のSREがいるため、インフラ面で気軽に相談ができる


Slide 18

Slide 18 text

© ZOZO, Inc. 検討中概要
 ● APIからSQL Serverのストアドプロシージャの呼び出しを想定
 ● Java + Spring Bootを使用して実現するためのライブラリの選定などを実施中
 18

Slide 19

Slide 19 text

© ZOZO, Inc. 技術選定
 要件
 ● APIからSQL Serverのストアドプロシージャを呼び出す
 ● ストアドプロシージャは複数のResultSetを返 す
 
 検証対象ライブラリ(O/R Mapper)
 ● JPA
 ● Spring Data JDBC
 ● MyBatis
 ● Doma 2
 
 比較内容
 ● レイテンシ
 ● コード量
 19

Slide 20

Slide 20 text

© ZOZO, Inc. 技術選定(JPA)
 20 ● 平均レイテンシ:45ms
 ● コード量:
 ● 問題点:2つ目のResultSetを取得する ために2回目のDB接続が必要
 StoredProcedureQuery procedureQuery = createStoredProcedure( entityManager.createStoredProcedureQuery( "SampleProcedure", SampleProcedure.class)); setParameterForProcedure(procedureQuery, id); // 1回目の実行 if(procedureQuery.execute()) { // Outputパラメータ取得 Integer outputId = (Integer) procedureQuery.getOutputParameterValue("OutputId"); // 1つ目のResultSetの取得 List firstResults = procedureQuery.getResultList(); // 2回目の実行準備 procedureQuery = createStoredProcedure( entityManager.createStoredProcedureQuery( "SampleProcedure", SampleProcedure.class)); setParameterForProcedure(procedureQuery, id); List secondResults = new ArrayList<>(); if(procedureQuery.hasMoreResults()) { // 2つ目のResultSetの取得 secondResults = procedureQuery.getResultList(); }

Slide 21

Slide 21 text

© ZOZO, Inc. 技術選定(Spring Data JDBC)
 21 ● 平均レイテンシ:22ms
 ● コード量:他のライブラリに比べると多 い
 CallableStatement callableStatement = connection.prepareCall("{call SampleProcedure(?,?)}"); callableStatement.setLong("id", id.value()); callableStatement.registerOutParameter("OutputId", Types.INTEGER); // 1つ目のResultSetの取得 ResultSet firstResultSet = callableStatement.executeQuery(); List firstResults = new ArrayList<>(); while(firstResultSet.next()) { firstResults.add(new FirstResult( new Id(firstResultSet.getLong("Id")), new Name(firstResultSet.getString("Name")); } List secondResults = new ArrayList<>(); if(callableStatement.getMoreResults()) { // 2つ目のResultSetの取得 ResultSet secondResultSet = callableStatement.getResultSet(); while(secondResultSet.next()) { secondResults.add(new SecondResult( new ItemId(secondResultSet.getLong("ItemId")), new ItemName(secondResultSet.getString("ItemName"))); } }

Slide 22

Slide 22 text

© ZOZO, Inc. 技術選定(MyBatis)
 22 ● 平均レイテンシ:149ms
 ● コード量:Repository層としての量は少ないが、XMLにストアドプロシージャ呼び出し用の定義を書くため、全体とし てはあまり少なくならない
 List> resultSet = procedureMapper.executeSampleProcedure(id.value(),name); // 1つ目のResultSetを取得 List firstResultObjects = (List) resultSet.get(0); List firstResults = new ArrayList<>(); for (Object obj: firstResultObjects) { FirstResult firstResult = (FirstResult) obj; firstResults.add(new FirstResult( new Id(firstResult.getId())), new Name(firstResult.getName()); } // 2つ目のResultSetを取得 List secondResultObjects = (List) resultSet.get(1); List secondResults = new ArrayList<>(); for (Object obj: secondResultObjects) { SecondResult secondResult = (SecondResult) obj; secondResults.add(new SecondResult( new ItemId(secondResult.getItemId())), new ItemName(secondResult.getItemName()); } {call SampleProcedure(#{id,jdbcType=BIGINT,mode=IN}, #{name,jdbcType=VARCHAR,mode=OUT})}

Slide 23

Slide 23 text

© ZOZO, Inc. 技術選定(Doma 2)
 23 ● 平均レイテンシ:19ms
 ● コード量:ライブラリ内に必要なアノテーションが用意されており、コード量はかなり少ない
 ○ ドメインオブジェクトへの変換もアノテーションにより可能
 @Procedure(name = "SampleProcedure") void execute( @ResultSet(ensureResultMapping = true) List firstResults, @ResultSet(ensureResultMapping = true) List secondResults, @In Id id, @Out Reference outputId); import org.seasar.doma.Domain; @Domain(valueType = Long.class, accessorMethod = "value") public record Id(Long value) { }

Slide 24

Slide 24 text

© ZOZO, Inc. 24 技術選定のまとめ
 平均レイテンシ コード量 複数ResultSetのDB接続回数 Doma 2 19 ms 少 1回 Spring Data JDBC 22 ms 多 1回 JPA 45 ms 中 n回 MyBatis 149 ms 多 1回

Slide 25

Slide 25 text

© ZOZO, Inc. 25 部内の取り組み


Slide 26

Slide 26 text

© ZOZO, Inc. 部内でのJavaへの取り組み
 カート決済部
 ● 事業案件を担当するチーム
 ○ VBScriptを使用して開発
 ○ 今後リプレイスしたコードも管理していく
 ● リプレイスを担当するチーム
 
 事業案件を担当するチームでの取り組み
 ● Java未経験者もいたが、外部講師によるJava講習会を受講して基礎を身につけた
 ● チーム内でJavaを使用した勉強会を週に2回程度実施
 
 26

Slide 27

Slide 27 text

© ZOZO, Inc. 27 リプレイスの今後


Slide 28

Slide 28 text

© ZOZO, Inc. リプレイスのこれから
 Qiita: ZOZO開発組織の2022年の振り返りと現状 28 ※ 2022年12月公開時点

Slide 29

Slide 29 text

© ZOZO, Inc. 29 一緒にカート決済部で働く仲間を募集しています


Slide 30

Slide 30 text

No content