Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.
大規模映像配信サービスの
Java8による全面リニューアルの裏側
Hello!
氏名 秋穂 賢(あきほ すぐる)
所属 株式会社U-NEXT システム開発部
リリース管理や開発用ミドルウェア管理
DBFlute & Java8でのAPI開発 など
見習いスクラムマスターとして精進中
仕事
このページ以降、U-...
そもそもU-NEXT?
最新情報はWebで http://video.unext.jp/introduction
2015/10/8
全面リニューアルを実施!
◉ 12万本以上の映像コンテ
ンツ
◉ 20万冊以上の電子書籍
そもそもU-NEXT?
最新情報はWebで http://video.unext.jp/introduction/device
そもそもU-NEXT?
最新情報はWebで http://video.unext.jp/introduction/family
そもそもU-NEXT?
最新情報はWebで http://video.unext.jp/introduction/fee
そもそもU-NEXT?
2015年2月〜
2015年10月〜
そもそもU-NEXT?
◉ 動画配信サービスを軸として、書籍・音楽コンテンツのサービスも
提供
◉ 多種多様なデバイス・複数アカウント
◉ 見放題・ポイント
◉ 各社とアライアンスを提携
◉ FHD配信・アダプティブストリーミング配信
◉ コン...
第1章
リニューアルの背景
U-NEXTの歴史
Pay per
View開始
GyaONEXT
サービス開始
マルチ
デバイス
2007年6月
1デバイス1顧客
デバイス認証
見放題のみ
2008年11月
都度課金の仕組み
コンテンツDB
顧客・課金DB
2010年6月
TVデバイス対応
オ...
PlayStati
on Vita
U-NEXT
TV
PC
スマホ
タブレット
2012年 2014年
増える対応デバイス
● 様々な環境と異なるバージョンで動いていたPHP
● 様々なPHPアプリケーションから直接リクエストされる
DB
● 各テーブルが触るな危険状態に
● 新しいサービスを開始する際には同じようなテーブル
が次々と拡張されていく
2007年から拡...
アニメ放題サービス提携の決定
これ以上の拡張は不可能
アニメ放題の先を見据えて
既存システムを捨て
U-NEXTサービスサイトの
リニューアルを決断
U-NEXT
大幅
リニューアル
2015年10月
アニメ放題
サービス開始
2015年2月
リニューアルで目指す姿
性能にこだわるシステム
よりよいユーザ体験の為に性能にこだわる
アプリケーションだけでなく
システムアーキテクチャとして高い性能を出せるような
設計に
メンテナンス性の高いシステム
DBの集中管理
● どのDBがどのアプリケーションからアクセスさ
れているか、管理したい
● DB毎に管理するAPIを実装する方針に
アーキテクチャの最適化を測った結果
自然とマイクロサービスアーキテクチャ
よりの...
FW選定
FW選定で重視したポイント
● 強力なORM
○ 生のSQLは書かなくてもよいように
■ 人によって書くSQLが違うとか...
○ DB Migration機能
● 静的型付け言語
○ 規模の大きな開発
○ IDEによるサポート
○ コンパイル...
● PlayFramework
● (NodeJS + TypeScript)
● DBFlute
いくつかの選択肢があった
縁があってDBFluteメインコミッターのjfluteさん
にDBFluteを紹介してもらえることに
● DBFluteの強力なORM
● DB Migrationツール
● コードとドキュメント自動生成
● Javaによる静的型付けとコンパイ...
何より
DBFlute / SAFluteはサービス開発のためのFW
サービス開発で便利な機能が豊富
(詳細は後ほど)
DBFluteとの出会い
これらのメリットからORMはDBFluteに決定
WebFWは一緒に紹介してもらったDBFluteとの
親和性が高いSAFluteに
DBFluteとの出会い
Java8
+
DBFlute / SAFlute
第2章
アニメ放題サービスの開始
◉ 迫り来る決まったリリース日
◉ 決まらない要求仕様
◉ この期間でサーバ構成を検討
◉ そして開発メンバーがDBFluteの習得
○ jfluteさんが勉強会をひらいてくれた
○ DBFluteハンズオン(チュートリアル)をしっかり実施
ア...
DBFluteハンズオン?
DBFluteハンズオン = DBFluteのチュートリアル
セクション1 〜 セクション11で構成されている
DBFluteハンズオンで修行する
=
業務で出てくる技術の習得
http://dbflute.seas...
DBFlute Live Demo
そんなDBFluteを生で見てもらいます
サーバ構成
クライアントむけの
API
永続層は持たない
リバースプロキシ
のキャッシュ
コンテンツDBを
管理するAPI
コンテンツDB
Slaveに全文検索エ
ンジンのMroonga
MySQL Atlas
中国企業のOSS
SB認証基盤
...
アーキテクチャ課題
クライアントむけの
API
永続層は持たない
リバースプロキシ
のキャッシュ
コンテンツDBを
管理するAPI
コンテンツDB
Slaveに全文検索エ
ンジンのMroonga
MySQL Atlas
中国企業のOSS
SB認...
課題1 Redisへのアクセス
大きく2種類の使い方
◉ データキャッシュとしてのRedis
○ マスタデータはDBに格納
○ キャッシュとしてRedis上にも保存
○ ユーザDBのデータはキャッシュへ
◉ データストアとしてのRedis
○ ...
キャッシュとしてのRedis
◉ 対象テーブル毎にCRUDのI/Fを持ったLogicクラスを実装
○ キャッシュを意識したくないテーブルを作るタイミングでLogicクラ
スも一緒に実装
◉ RedisへのアクセスはFacadeを使って統一で使い...
キャッシュとしてのRedis
@Resource
protected ViewingHistoryCacheLogic viewingHistoryCacheLogic;
…
UsrViewingHistory viewingHistory =...
データストアとしてのRedis
◉ Logic / Facadeクラスは変わらず実装
◉ もう一歩発展
◉ jsonでスキーマ定義
◉ それを元に共通して使えるクラスについてテンプレート化
○ Velocityテンプレートを利用
○ DBFlu...
データストアとしてのRedis
EVALUATION: {
$comment : "評価点",
$type : "table",
PLATFORM_CODE : {
type: "varchar",
comment: "プラットフォームコード"...
◉ 本当は専用の検索エンジン(Solr/Elasticsearch)を使いたかっ
た
◉ 時間の都合上、手軽に全文検索ができるMroongaを選択
◉ 一部Slaveの全文検索したいテーブルだけのEngineを
Mroongaにして利用
○ 初...
課題2 Mroongaへの対応
Mroongaを使うとSQLで手軽に全文検索が出来る
DBFluteはmatch構文をサポート
mysql> SELECT * FROM diaries WHERE MATCH(content) AGAINST(...
課題2 Mroongaへの対応
Engine
Innodb
Engine
Innodb
Engine
Innodb
Mroonga
Mroongaへの検索かど
うかで向け先を変える
課題2 Mroongaへの対応
Engine
Innodb
Engine
Innodb
Engine
Innodb
Mroonga
Mroongaへの検索かど
うかで向け先を変える
SelectableDataSource
SelectableDataSource
◉ Seasar2が提供しているMaster/Slaveを切り替える仕組
みを利用
// e.g. SelectableDataSource のベタな実装方法 @Java
protected Membe...
SelectableDataSource
◉ SAFluteの機能を使ってSelectableDataSourceをベー
スに汎用性を持たせて使いやすいようにして利用
PagingResultBean<Sakuhin> sakuhinPage ...
◉ MySQL Atlasはトランザ
クションを更新処理とみ
なしてmasterへ
◉ SAFlute(SAStruts)はリク
エストでトランザクション
◉ 各API毎に自前でトラン
ザクションをかけるのは
つらい
課題3 MySQLとAtl...
LazyTransaction
◉ 更新系処理が開始した時点で初めてトランザクションを開始す
るように
◉ DBFluteでBehavior(SQL実行)の処理前後にHookができる
LazyTransaction?
protected BehaviorCommandHook...
◉ 課題1 Redisへのアクセス
○ キャッシュ / ストアとしての使い方
○ FacadeやLogicで処理をまとめたり、DBFluteの自動
生成機能に乗せて独自の自動生成機能を作った
◉ 課題2 Mroongaへの対応
○ DBFlut...
Special Thanks
アーキテクチャ周りはDBFluteコアユーザの
@p1us2er0 さん
に多大なるご協力を頂きました
その他
日々のサービス開発で
便利なこと
工夫してること
などなど
一挙にご紹介!!6連発
DB変更を行うとき、どのようにしていますか?
DBFluteの場合、こんな感じです
1. ERDドリブン開発
1. ERDドリブン開発
1. EclipseプラグインのERMasterでER図を変更
1. ERDドリブン開発
2. ERMasterからDDLを出力
1. ERDドリブン開発
3. manage.shのrenewalを実行
renewalはDB定義から
Javaのエンティティクラスな
どを自動生成する機能
1. ERDドリブン開発
4. DB変更した内容のJavaが自動生成
1. ERDドリブン開発
4. DB変更した内容のJavaが自動生成
DB変更完了!
U-NEXTではDBFluteの流儀に沿って
DB変更する場合はまずERDを修正する
というフローで実施
ER図と実態が一致しない、はありえない
2. ReplaceSchema
テストデータを追加
開発メンバーと共有 & 最新化
みなさんどのようにやってますか?
DBFluteの場合、こんな感じです
2. ReplaceSchema
1. テストデータの修正と出力
1. まず、MySQLへテストデータ
を追加
2. manage.shでload data
reverse実行!
3. DBに入っているテストデータ
がxlsやtsv形式で出力
...
2. ReplaceSchema
2. データ共有 & Load
1. git pull
2. sh manage.sh
3. 0
4. Enter!
http://dbflute.seasar.org/ja/manual/function/g...
2. ReplaceSchema
2. データ共有 & Load
1. git pull
2. sh manage.sh
3. 0
4. Enter!
http://dbflute.seasar.org/ja/manual/function/g...
3. AlterCheck (DB Migration)
ローカルと開発と本番のDBスキーマが違う!
なんてことが起こらないようにするための
DB Migrationツール
DBFluteの場合、こんな感じです
DB変更後にmanage.shの8
◉ 前回のDBの状態で
ReplaceSchema
◉ 最新のDBの状態で
ReplaceSchema
◉ 前回と今回の差分を提示し
てFailure
3. AlterCheck (DB Migration)
3. AlterCheck (DB Migration)
差分を確認
alterSQLを定義
今回の場合は
create table hoge
再度AlterCheckで
Success!
後は各環境へ差分を
反映させるだけ
3. AlterCheck (DB Migration)
差分を確認
alterSQLを定義
今回の場合は
create table hoge
再度AlterCheckで
Success!
AlterCheckを運用として実施していくことで
各...
4. Schemaドキュメント
ER図だけでなく、DBFluteはHTML形式のドキュメントも自動
生成してくれる
4. Schemaドキュメント
ER図だけでなく、DBFluteはHTML形式のドキュメントも自動
生成してくれる
U-NEXTでは
人によってER図とSchema.htmlを
使い分けて開発作業を行っている
5. 見やすいログ
開発やテスト時は何度もデバッグを行うため、ログが見やすい
ことは重要
今回は一部のログをご紹介
http://dbflute.seasar.org/ja/manual/function/helper/saflute/frie...
5. 見やすいログ
Requestの開始と終了
http://dbflute.seasar.org/ja/manual/function/helper/saflute/friendlylogging.html
...-DEBUG (...#be...
5. 見やすいログ
SQLの実行時間と結果概要
http://dbflute.seasar.org/ja/manual/function/helper/saflute/friendlylogging.html
2016-05-20 17:28:...
5. 見やすいログ
その他、色々とログが見やすく工夫されています
詳細は公式ページで!
http://dbflute.seasar.
org/ja/manual/function/helper/saflute/friendlylogg
ing....
6. 書きやすいUT
みなさん、テストは書いていますか?
UTFluteを使えば楽々テスト
UTFluteはDBFluteファミリーのJUnit拡張ライブラリ
UTFlute は、自分で new したものにDIできる JUnit
拡張 です。
...
6. 書きやすいUT
ActionクラスのisHogeメソッドを実行してbooleanを
Assert
public void test_isHoge_hogeはhogeだったらtrue() throws Exception {
// ## A...
6. 書きやすいUT
http://dbflute.seasar.org/ja/manual/function/helper/utflute/index.html
UTFluteのおかげで単体テストの自動化は結構して
いる
◉ Jenkinsで...
その他、UTFluteでの便利機能が提供されています
詳細は公式ページで!
http://dbflute.seasar.
org/ja/manual/function/helper/utflute/index.html
6. 書きやすいUT
アニメ放題
無事に予定通りリリース!!
振り返ってみると
◉ 最初にDBFluteハンズオンをみっちりと実施した効果は
大
○ 業務アプリ実装時に役立つTipsがたくさん
◉ 困った時の拡張ポイントがしっかりしてる
○ アーキテクチャ課題は無事...
第3章
U-NEXTサービスサイト
リニューアル
◉ アニメ放題と比較すると遥かに複雑な業務
○ アニメ放題はアニメのみ、U-NEXTは洋画・邦画・ドラマなど、ジャン
ルの多さ
○ アニメ放題はiOS/Android/PC、U-NEXTはTV、ゲーム機、STBなど、
対応デバイスの多さ
○ ア...
激しいDB変更の嵐
DBFlute採用から約1年半、DB変更の回数は 186 回
=> 単純計算すると 約 3 日に 1 回はDB変更してる
毎日のようにER図を変更して
AlterCheckして
本番へDDL実行!をしていた日々もあった
怒涛...
検索のインクリメンタルサーチを目指していた
=> Mroongaでは性能で不利
ElasticsearchとSolrが候補に
「検索」の実績から Solr を選択
Demo:http://video.unext.jp
詳細:http://www...
solrjをそのまま使うとタイプセーフではない...
MroongaからSolrへ
try (HttpSolrClient httpSolrClient = new HttpSolrClient(“http://localhost:
8983/...
Schema.xmlから各種クラスを自動生成
全文検索システムFessで使っていたSolr用CBを拡張
MroongaからSolrへ
SolrPagingResultBean<General> list = generalBhv.selectP...
MroongaからSolrへ
とある1日のフリーワード検索の平均レスポンス:39ms
2016年9月26日、Seasar2のサポートが終了
SAFluteはSAStrutsの拡張FW
リニューアルが終わってないのにFW移行の危機...
そんな時、jfluteさん
「Seasar2フォークしてJava8で書き換えてLastaFlu...
2016年9月26日、Seasar2のサポートが終了
SAFluteはSAStrutsの拡張FW
リニューアルが終わってないのにFW移行の危機...
そんな時、jfluteさん
「Seasar2フォークしてJava8で書き換えてLastaFlu...
LastaFluteのいいところ
◉ 起動が圧倒的に早い
○ SAFluteは7〜8秒程度、Lastaは2〜3秒程度
◉ ログが見やすい
○ DBFluteイズムで見やすいログ
◉ よりシンプルに書けるコード
○ formが引数, formで型...
APIドキュメント自動生成
API開発をしている場合、クライアントへI/F定義を提示
する必要がある
=> 自動生成
2015年 6月U-NEXTリニューアルリリース予定
 リニューアルに向けて開発..開発..開発..
膨大な開発
2015年 6月U-NEXTリニューアルリリース予定
 リニューアルに向けて開発..開発..開発..
2015年 8月へ延期
 開発..開発..開発..開発..開発..開発..
膨大な開発
2015年 6月U-NEXTリニューアルリリース予定
 リニューアルに向けて開発..開発..開発..
2015年 8月へ延期
 開発..開発..開発..開発..開発..開発..
2015年 9月へ延期
 開発..開発..開発..開発..開発.....
膨大な開発
2015年 6月U-NEXTリニューアルリリース予定
 リニューアルに向けて開発..開発..開発..
2015年 8月へ延期
 開発..開発..開発..開発..開発..開発..
2015年 9月へ延期
 開発..開発..開発..開発...
ボリューム満点の開発
SAFlute / LastaFlute / DBFluteの軽快さ
実装 => リリース => 修正 => リリース => …
のサイクルをとても軽快に回すことが出来る
リニューアルを乗り越えられたのは
この軽快さのおか...
第4章
更なる高みへ
リニューアルで全力疾走を続けた結果
◉ 個々のソロプレーを足しあわせて何とかなっていた
○ チーム力・組織力が全くない状況
◉ ソースコードがちぐはぐ
○ とにかく動くコードを早くリリースするのが正義
○ その結果、ちぐはぐなコードが生まれる
...
スクラム開発
◉ 今まで
○ 複数人のディレクターやQAからの要望を各分野に精通している人
が個々の判断で優先度を決定し、開発
◉ これから
○ スクラム開発を導入
○ 優先度はプロダクトオーナーが決定
○ 開発タスクは開発チームで決定
○ 2...
より働きやすい環境
◉ ハイスペックな開発マシン
○ メモリ32GB、250GB SSD、インテル® Core™i7-
5930k
◉ 高級なイス(予定)
○ 候補:アーロンチェアなど
◉ 自由に買える書籍
○ 申請して5分後に電子書籍が届くと...
コードの品質
◉ これまで
○ コードを書いた人以外の目に触れずに本番へリリースされる
コードがたくさん
◉ これから
○ コーディングガイドラインを整備
■ 規約は文章化せず、自動で判別できるものに
○ プルリクベースでのコードレビューを導入...
より良いアーキテクチャへ
◉ 当初目指していたDB単位のAPI
○ これは実現出来た
○ DB変更は比較的簡単に出来る
◉ リポジトリはそれなりにでかい
○ 分割出来るプロジェクトが同じリポジトリに存在している
■ 時間の都合上
◉ もっと最適...
◉ まだまだたくさんある開発案件
○ これからはチームでよりよいものをより楽しく開発出来るように
○ そして競合に負けないように
◉ 個々の技術力
○ コードレビュー・勉強会などを通じてメンバーそれぞれがお互いを
高め合える環境・そして文化に
...
U-NEXTでは人材を募集しています
映画やアニメが好きなひと
エンターテイメントが好きなひと
配信プラットフォームに興味のあるひと
技術的なことが好きなひと
一緒に仕事をしましょう
http://unext.co.jp/recruit/
Thank you for your attention
20160521 大規模映像配信サービスの Java8による全面リニューアルの裏側
Upcoming SlideShare
Loading in …5
×

20160521 大規模映像配信サービスの Java8による全面リニューアルの裏側

3,270 views

Published on

JJUG CCC 2016での資料です。U-NEXTリニューアルをDBFluteとLastaFluteで実施した話

Published in: Technology
  • Be the first to comment

20160521 大規模映像配信サービスの Java8による全面リニューアルの裏側

  1. 1. 大規模映像配信サービスの Java8による全面リニューアルの裏側
  2. 2. Hello! 氏名 秋穂 賢(あきほ すぐる) 所属 株式会社U-NEXT システム開発部 リリース管理や開発用ミドルウェア管理 DBFlute & Java8でのAPI開発 など 見習いスクラムマスターとして精進中 仕事 このページ以降、U-NEXTは サービス名称を表します
  3. 3. そもそもU-NEXT? 最新情報はWebで http://video.unext.jp/introduction 2015/10/8 全面リニューアルを実施! ◉ 12万本以上の映像コンテ ンツ ◉ 20万冊以上の電子書籍
  4. 4. そもそもU-NEXT? 最新情報はWebで http://video.unext.jp/introduction/device
  5. 5. そもそもU-NEXT? 最新情報はWebで http://video.unext.jp/introduction/family
  6. 6. そもそもU-NEXT? 最新情報はWebで http://video.unext.jp/introduction/fee
  7. 7. そもそもU-NEXT? 2015年2月〜 2015年10月〜
  8. 8. そもそもU-NEXT? ◉ 動画配信サービスを軸として、書籍・音楽コンテンツのサービスも 提供 ◉ 多種多様なデバイス・複数アカウント ◉ 見放題・ポイント ◉ 各社とアライアンスを提携 ◉ FHD配信・アダプティブストリーミング配信 ◉ コンテンツホルダーに応じた最高ビットレートのフレキシブルな制御 ◉ などなど.... 細やかな制御
  9. 9. 第1章 リニューアルの背景
  10. 10. U-NEXTの歴史
  11. 11. Pay per View開始 GyaONEXT サービス開始 マルチ デバイス 2007年6月 1デバイス1顧客 デバイス認証 見放題のみ 2008年11月 都度課金の仕組み コンテンツDB 顧客・課金DB 2010年6月 TVデバイス対応 オンライン認証 の仕組み 新 顧客課金DB 新 顧客課金DB
  12. 12. PlayStati on Vita U-NEXT TV PC スマホ タブレット 2012年 2014年 増える対応デバイス
  13. 13. ● 様々な環境と異なるバージョンで動いていたPHP ● 様々なPHPアプリケーションから直接リクエストされる DB ● 各テーブルが触るな危険状態に ● 新しいサービスを開始する際には同じようなテーブル が次々と拡張されていく 2007年から拡張し続けた複雑怪奇 なシステム
  14. 14. アニメ放題サービス提携の決定
  15. 15. これ以上の拡張は不可能 アニメ放題の先を見据えて 既存システムを捨て U-NEXTサービスサイトの リニューアルを決断
  16. 16. U-NEXT 大幅 リニューアル 2015年10月 アニメ放題 サービス開始 2015年2月
  17. 17. リニューアルで目指す姿
  18. 18. 性能にこだわるシステム よりよいユーザ体験の為に性能にこだわる アプリケーションだけでなく システムアーキテクチャとして高い性能を出せるような 設計に
  19. 19. メンテナンス性の高いシステム DBの集中管理 ● どのDBがどのアプリケーションからアクセスさ れているか、管理したい ● DB毎に管理するAPIを実装する方針に アーキテクチャの最適化を測った結果 自然とマイクロサービスアーキテクチャ よりの思想に (実際はミディアムサービスくらい)
  20. 20. FW選定
  21. 21. FW選定で重視したポイント ● 強力なORM ○ 生のSQLは書かなくてもよいように ■ 人によって書くSQLが違うとか... ○ DB Migration機能 ● 静的型付け言語 ○ 規模の大きな開発 ○ IDEによるサポート ○ コンパイルによるエラー検知
  22. 22. ● PlayFramework ● (NodeJS + TypeScript) ● DBFlute いくつかの選択肢があった
  23. 23. 縁があってDBFluteメインコミッターのjfluteさん にDBFluteを紹介してもらえることに ● DBFluteの強力なORM ● DB Migrationツール ● コードとドキュメント自動生成 ● Javaによる静的型付けとコンパイル ● IDEのサポート ● 豊富な公式ドキュメント ● (24時間戦えるjfluteさんが開発してる) DBFluteとの出会い
  24. 24. 何より DBFlute / SAFluteはサービス開発のためのFW サービス開発で便利な機能が豊富 (詳細は後ほど) DBFluteとの出会い
  25. 25. これらのメリットからORMはDBFluteに決定 WebFWは一緒に紹介してもらったDBFluteとの 親和性が高いSAFluteに DBFluteとの出会い
  26. 26. Java8 + DBFlute / SAFlute
  27. 27. 第2章 アニメ放題サービスの開始
  28. 28. ◉ 迫り来る決まったリリース日 ◉ 決まらない要求仕様 ◉ この期間でサーバ構成を検討 ◉ そして開発メンバーがDBFluteの習得 ○ jfluteさんが勉強会をひらいてくれた ○ DBFluteハンズオン(チュートリアル)をしっかり実施 アニメ放題 http://dbflute.seasar.org/ja/tutorial/handson/
  29. 29. DBFluteハンズオン? DBFluteハンズオン = DBFluteのチュートリアル セクション1 〜 セクション11で構成されている DBFluteハンズオンで修行する = 業務で出てくる技術の習得 http://dbflute.seasar.org/ja/tutorial/handson/
  30. 30. DBFlute Live Demo そんなDBFluteを生で見てもらいます
  31. 31. サーバ構成 クライアントむけの API 永続層は持たない リバースプロキシ のキャッシュ コンテンツDBを 管理するAPI コンテンツDB Slaveに全文検索エ ンジンのMroonga MySQL Atlas 中国企業のOSS SB認証基盤 コンテンツと紐付 いたユーザ情報 のDB
  32. 32. アーキテクチャ課題 クライアントむけの API 永続層は持たない リバースプロキシ のキャッシュ コンテンツDBを 管理するAPI コンテンツDB Slaveに全文検索エ ンジンのMroonga MySQL Atlas 中国企業のOSS SB認証基盤 コンテンツと紐付 いたユーザ情報 のDB ① ② ③
  33. 33. 課題1 Redisへのアクセス 大きく2種類の使い方 ◉ データキャッシュとしてのRedis ○ マスタデータはDBに格納 ○ キャッシュとしてRedis上にも保存 ○ ユーザDBのデータはキャッシュへ ◉ データストアとしてのRedis ○ マスタデータをRedisに格納 キャッシュを意識しないデータのCRUD 構造を意識したデータのCRUD
  34. 34. キャッシュとしてのRedis ◉ 対象テーブル毎にCRUDのI/Fを持ったLogicクラスを実装 ○ キャッシュを意識したくないテーブルを作るタイミングでLogicクラ スも一緒に実装 ◉ RedisへのアクセスはFacadeを使って統一で使い回し ○ insert or update時には内部でキャッシュを削除 ○ delete時は一緒にキャッシュを削除 ○ select時はキャッシュがあればキャッシュから、なければDBから のデータをキャッシュに ◉ 内部ではJedisを利用 キャッシュを意識しないデータのCRUD
  35. 35. キャッシュとしてのRedis @Resource protected ViewingHistoryCacheLogic viewingHistoryCacheLogic; … UsrViewingHistory viewingHistory = new UsrViewingHistory(); viewingHistory.setUserId(userId); … viewingHistoryCacheLogic.insertOrUpdate(viewingHistory); ViewingHistoryParam param = new ViewingHistoryParam(); param.setUserId(userId); param.addOrderByList(ViewingHistoryDbm.getInstance(). columnUpdateDatetime()); … return viewingHistoryCacheLogic.getList(param);
  36. 36. データストアとしてのRedis ◉ Logic / Facadeクラスは変わらず実装 ◉ もう一歩発展 ◉ jsonでスキーマ定義 ◉ それを元に共通して使えるクラスについてテンプレート化 ○ Velocityテンプレートを利用 ○ DBFluteの自動生成の仕組みに乗せて、Redisにスキーマ定義を もたせて自動生成!! ◉ IDEのコード補完の恩恵を存分に受けられるように 構造を意識したデータのCRUD
  37. 37. データストアとしてのRedis EVALUATION: { $comment : "評価点", $type : "table", PLATFORM_CODE : { type: "varchar", comment: "プラットフォームコード", kvsKey: true , notNull: true }, SAKUHIN_CODE : { type: "varchar", comment: "作品コード", kvsKey: true, notNull: true }, EVALUATION_POINT : { type: "varchar", comment: "評価点", notNull: true }, TTL : { type: "java.time.LocalDateTime", comment: "有効期限", notNull: true } } public class EvaluationMeta implements KvsStoreMeta { …(Meta data. name, column, ...) } public class BsEvaluation implements KvsStoreEntity, Serializable { …(getter / setter / util methods) } public class Evaluation extends BsEvaluation { … (extends local methods) } 自 動 生 成
  38. 38. ◉ 本当は専用の検索エンジン(Solr/Elasticsearch)を使いたかっ た ◉ 時間の都合上、手軽に全文検索ができるMroongaを選択 ◉ 一部Slaveの全文検索したいテーブルだけのEngineを Mroongaにして利用 ○ 初めて利用するため、何かあった場合の影響を最小限に 課題2 Mroongaへの対応 Mroonga? Groongaをベースとした全文検索エンジン。MySQLのストレー ジエンジンの1つとしてMySQLに全文検索機能を提供
  39. 39. 課題2 Mroongaへの対応 Mroongaを使うとSQLで手軽に全文検索が出来る DBFluteはmatch構文をサポート mysql> SELECT * FROM diaries WHERE MATCH(content) AGAINST("fine"); +----+-----------------------------------------+ | id | content | +----+-----------------------------------------+ | 1 | It'll be fine tomorrow. | +----+-----------------------------------------+ 1 row in set (0.00 sec)
  40. 40. 課題2 Mroongaへの対応 Engine Innodb Engine Innodb Engine Innodb Mroonga Mroongaへの検索かど うかで向け先を変える
  41. 41. 課題2 Mroongaへの対応 Engine Innodb Engine Innodb Engine Innodb Mroonga Mroongaへの検索かど うかで向け先を変える SelectableDataSource
  42. 42. SelectableDataSource ◉ Seasar2が提供しているMaster/Slaveを切り替える仕組 みを利用 // e.g. SelectableDataSource のベタな実装方法 @Java protected MemberBhv memberBhv; protected DataSourceFactory dataSourceFactory; // injected public void fooAndBar() { dataSourceFactory.setSelectableDataSourceName("master"); Member member = ... ... memberBhv.update(member); // master の会員を更新 dataSourceFactory.setSelectableDataSourceName("slave"); MemberCB cb = ... ... ... = memberBhv.select(cb); // slave の会員を検索 } http://dbflute.seasar.org/ja/manual/reference/diway/seasar/selectabledatasource.html
  43. 43. SelectableDataSource ◉ SAFluteの機能を使ってSelectableDataSourceをベー スに汎用性を持たせて使いやすいようにして利用 PagingResultBean<Sakuhin> sakuhinPage = slaveDBAccessor.accessIfNeeds(() -> { return sakuhinBhv.selectPage(cb -> { cb.specify().... cb.query().... }); }, isNotEmpty(searchWord)); http://dbflute.seasar.org/ja/manual/reference/diway/seasar/selectabledatasource.html 検索ワードがあれば強制的にSlave へ Slaveのhost設定をMroongaな MySQLへ向くように設定
  44. 44. ◉ MySQL Atlasはトランザ クションを更新処理とみ なしてmasterへ ◉ SAFlute(SAStruts)はリク エストでトランザクション ◉ 各API毎に自前でトラン ザクションをかけるのは つらい 課題3 MySQLとAtlas ここのLBは MySQL Atlas にお任せ
  45. 45. LazyTransaction
  46. 46. ◉ 更新系処理が開始した時点で初めてトランザクションを開始す るように ◉ DBFluteでBehavior(SQL実行)の処理前後にHookができる LazyTransaction? protected BehaviorCommandHook createLazyTransactionHook() { return new BehaviorCommandHook() { public void hookBefore(BehaviorCommandMeta meta) { if (!meta.isSelect() || meta.isProcedure()) { LazyHookedUserTransaction.beginRealTransactionLazily(); } } public void hookFinally(BehaviorCommandMeta meta, RuntimeException cause) { } @Override public boolean inheritsExistingHook() { return true; } }; } SAFluteのリクエ スト開始時点の Hookへ登録
  47. 47. ◉ 課題1 Redisへのアクセス ○ キャッシュ / ストアとしての使い方 ○ FacadeやLogicで処理をまとめたり、DBFluteの自動 生成機能に乗せて独自の自動生成機能を作った ◉ 課題2 Mroongaへの対応 ○ DBFluteのSelectableDataSourceを使ってMaster / Slaveの切り替えを汎用的に実装 ◉ 課題3 MySQLとAtlas ○ BehaviorCommandHookを使って全てのBehavior の実行前にHookを入れることでLazyTransaction機 能を実現 アーキテクチャ課題への対応
  48. 48. Special Thanks アーキテクチャ周りはDBFluteコアユーザの @p1us2er0 さん に多大なるご協力を頂きました
  49. 49. その他 日々のサービス開発で 便利なこと 工夫してること などなど 一挙にご紹介!!6連発
  50. 50. DB変更を行うとき、どのようにしていますか? DBFluteの場合、こんな感じです 1. ERDドリブン開発
  51. 51. 1. ERDドリブン開発 1. EclipseプラグインのERMasterでER図を変更
  52. 52. 1. ERDドリブン開発 2. ERMasterからDDLを出力
  53. 53. 1. ERDドリブン開発 3. manage.shのrenewalを実行 renewalはDB定義から Javaのエンティティクラスな どを自動生成する機能
  54. 54. 1. ERDドリブン開発 4. DB変更した内容のJavaが自動生成
  55. 55. 1. ERDドリブン開発 4. DB変更した内容のJavaが自動生成 DB変更完了! U-NEXTではDBFluteの流儀に沿って DB変更する場合はまずERDを修正する というフローで実施 ER図と実態が一致しない、はありえない
  56. 56. 2. ReplaceSchema テストデータを追加 開発メンバーと共有 & 最新化 みなさんどのようにやってますか? DBFluteの場合、こんな感じです
  57. 57. 2. ReplaceSchema 1. テストデータの修正と出力 1. まず、MySQLへテストデータ を追加 2. manage.shでload data reverse実行! 3. DBに入っているテストデータ がxlsやtsv形式で出力 4. git commit & push http://dbflute.seasar.org/ja/manual/function/generator/task/doc/loaddatareverse.html
  58. 58. 2. ReplaceSchema 2. データ共有 & Load 1. git pull 2. sh manage.sh 3. 0 4. Enter! http://dbflute.seasar.org/ja/manual/function/generator/task/doc/loaddatareverse.html drop table create table insert into
  59. 59. 2. ReplaceSchema 2. データ共有 & Load 1. git pull 2. sh manage.sh 3. 0 4. Enter! http://dbflute.seasar.org/ja/manual/function/generator/task/doc/loaddatareverse.html drop table create table insert into 修正したデータをgit経由で簡単に共有 開発前にReplaceSchemaをしておけば テストデータの共有漏れは起こらない
  60. 60. 3. AlterCheck (DB Migration) ローカルと開発と本番のDBスキーマが違う! なんてことが起こらないようにするための DB Migrationツール DBFluteの場合、こんな感じです
  61. 61. DB変更後にmanage.shの8 ◉ 前回のDBの状態で ReplaceSchema ◉ 最新のDBの状態で ReplaceSchema ◉ 前回と今回の差分を提示し てFailure 3. AlterCheck (DB Migration)
  62. 62. 3. AlterCheck (DB Migration) 差分を確認 alterSQLを定義 今回の場合は create table hoge 再度AlterCheckで Success! 後は各環境へ差分を 反映させるだけ
  63. 63. 3. AlterCheck (DB Migration) 差分を確認 alterSQLを定義 今回の場合は create table hoge 再度AlterCheckで Success! AlterCheckを運用として実施していくことで 各環境でのDBスキーマで差分が出ないように
  64. 64. 4. Schemaドキュメント ER図だけでなく、DBFluteはHTML形式のドキュメントも自動 生成してくれる
  65. 65. 4. Schemaドキュメント ER図だけでなく、DBFluteはHTML形式のドキュメントも自動 生成してくれる U-NEXTでは 人によってER図とSchema.htmlを 使い分けて開発作業を行っている
  66. 66. 5. 見やすいログ 開発やテスト時は何度もデバッグを行うため、ログが見やすい ことは重要 今回は一部のログをご紹介 http://dbflute.seasar.org/ja/manual/function/helper/saflute/friendlylogging.html
  67. 67. 5. 見やすいログ Requestの開始と終了 http://dbflute.seasar.org/ja/manual/function/helper/saflute/friendlylogging.html ...-DEBUG (...#before():268) - * * * * * * * * * * {BEGIN}: /member/list/ Request class=org.seasar.framework.container.hotdeploy.HotdeployHttpSer... , REQUEST_URI=/dockside/member/list/, SERVLET_PATH=/member/list/, Chara... , ContentType=application/x-www-form-urlencoded, Locale=ja, Locales=ja,... ... ... Response class=org.mortbay.jetty.Response, ContentType=text/html; chars... , toString()=HTTP/1.1 200 Content-Type: text/html; charset=utf-8 Expir... [session] javax.servlet.jsp.jstl.fmt.request.charset=UTF-8 [session] member_memberListForm=org.dbflute.maihama.app.web.member. Memb... [session] org.apache.struts.action.LOCALE=ja [session] org.dbflute.maihama.domainfw.action.DocksideUserBean={userId=... * * * * * * * * * * {END}: /member/list/ [00m00s247ms]
  68. 68. 5. 見やすいログ SQLの実行時間と結果概要 http://dbflute.seasar.org/ja/manual/function/helper/saflute/friendlylogging.html 2016-05-20 17:28:22,346 [main]-DEBUG (XLog#log():43) - SakuhinListActionTest.testname():131 -> ... 2016-05-20 17:28:22,693 [main]-DEBUG (QLog#log():43) - select dfloc.SAKUHIN_ID as SAKUHIN_ID, dfloc.DISPLAY_NAME as DISPLAY_NAME from SAKUHIN dfloc where dfloc.SAKUHIN_ID = 1 2016-05-20 17:28:22,694 [main]-DEBUG (XLog#log():43) - ===========/ [00m00s348ms (1) result={1, null, ほげ作品, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null}@729c021d]
  69. 69. 5. 見やすいログ その他、色々とログが見やすく工夫されています 詳細は公式ページで! http://dbflute.seasar. org/ja/manual/function/helper/saflute/friendlylogg ing.html
  70. 70. 6. 書きやすいUT みなさん、テストは書いていますか? UTFluteを使えば楽々テスト UTFluteはDBFluteファミリーのJUnit拡張ライブラリ UTFlute は、自分で new したものにDIできる JUnit 拡張 です。 http://dbflute.seasar.org/ja/manual/function/helper/utflute/index.html
  71. 71. 6. 書きやすいUT ActionクラスのisHogeメソッドを実行してbooleanを Assert public void test_isHoge_hogeはhogeだったらtrue() throws Exception { // ## Arrange ## SakuhinListAction action = new SakuhinListAction(); inject(action); // ## Act ## boolean isHoge = action.isHoge("hoge"); // ## Assert ## assertTrue("hogeはtrueだ", isHoge); } http://dbflute.seasar.org/ja/manual/function/helper/utflute/index.html
  72. 72. 6. 書きやすいUT http://dbflute.seasar.org/ja/manual/function/helper/utflute/index.html UTFluteのおかげで単体テストの自動化は結構して いる ◉ JenkinsでのCIも実施 ○ エラーが出たらHipChatに通知 ◉ UTで事前に不具合を検知できた コード品質が向上!
  73. 73. その他、UTFluteでの便利機能が提供されています 詳細は公式ページで! http://dbflute.seasar. org/ja/manual/function/helper/utflute/index.html 6. 書きやすいUT
  74. 74. アニメ放題 無事に予定通りリリース!! 振り返ってみると ◉ 最初にDBFluteハンズオンをみっちりと実施した効果は 大 ○ 業務アプリ実装時に役立つTipsがたくさん ◉ 困った時の拡張ポイントがしっかりしてる ○ アーキテクチャ課題は無事にクリア ◉ その他諸々サービス開発で役立つ機能 ○ 細かいけどあったらとても役立つ機能がたくさん
  75. 75. 第3章 U-NEXTサービスサイト リニューアル
  76. 76. ◉ アニメ放題と比較すると遥かに複雑な業務 ○ アニメ放題はアニメのみ、U-NEXTは洋画・邦画・ドラマなど、ジャン ルの多さ ○ アニメ放題はiOS/Android/PC、U-NEXTはTV、ゲーム機、STBなど、 対応デバイスの多さ ○ アニメ放題は見放題のみ、U-NEXTは見放題と単品でのレンタル作 品も ○ U-NEXTはユーザへの見せ方がよりきめ細やか ◉ 複雑な業務 = 開発が大変 ◉ 複雑な業務 = 複雑なDB U-NEXTリニューアルでの難関 API数 10倍程度のAPI テーブル数 125テーブル から253テーブルに (区分値除く 29 => 89)
  77. 77. 激しいDB変更の嵐 DBFlute採用から約1年半、DB変更の回数は 186 回 => 単純計算すると 約 3 日に 1 回はDB変更してる 毎日のようにER図を変更して AlterCheckして 本番へDDL実行!をしていた日々もあった 怒涛のDB変更ラッシュもDBFluteで乗り越えた
  78. 78. 検索のインクリメンタルサーチを目指していた => Mroongaでは性能で不利 ElasticsearchとSolrが候補に 「検索」の実績から Solr を選択 Demo:http://video.unext.jp 詳細:http://www.slideshare.net/SuguruAkiho/20151028-17-solr-unext MroongaからSolrへ
  79. 79. solrjをそのまま使うとタイプセーフではない... MroongaからSolrへ try (HttpSolrClient httpSolrClient = new HttpSolrClient(“http://localhost: 8983/solr/schema”)) { httpSolrClient.setParser(new XMLResponseParser()); ModifiableSolrParams params = new ModifiableSolrParams(); params.add("q", "あの日"); params.add("defType", "dismax"); params.add("qf", "name kana^10"); QueryResponse response = httpSolrClient.query(params); SolrDocumentList results = response.getResults(); } …
  80. 80. Schema.xmlから各種クラスを自動生成 全文検索システムFessで使っていたSolr用CBを拡張 MroongaからSolrへ SolrPagingResultBean<General> list = generalBhv.selectPage(cb -> { cb.query().dismax("あの日", queryField -> { queryField.put(GeneralMeta.Name, null); queryField.put(GeneralMeta.Kana, 10); queryField.put(GeneralMeta.NameGeneral, 20); queryField.put(GeneralMeta.Synonym, null); }); cb.specify().fieldUid(); cb.paging(10, 2); }); LOG.debug("list={}", list); DBFluteの機能で ページング検索が 出来る dismax検索出来る対象 のフィールドがタイプ セーフに指定可能 specifyでflをタイプセー フに指定可能
  81. 81. MroongaからSolrへ とある1日のフリーワード検索の平均レスポンス:39ms
  82. 82. 2016年9月26日、Seasar2のサポートが終了 SAFluteはSAStrutsの拡張FW リニューアルが終わってないのにFW移行の危機... そんな時、jfluteさん 「Seasar2フォークしてJava8で書き換えてLastaFlute 作っちゃった」 SAFluteからLastaFluteへ
  83. 83. 2016年9月26日、Seasar2のサポートが終了 SAFluteはSAStrutsの拡張FW リニューアルが終わってないのにFW移行の危機... そんな時、jfluteさん 「Seasar2フォークしてJava8で書き換えてLastaFlute 作っちゃった」 SAFluteからLastaFluteへ 使うしかないでしょう
  84. 84. LastaFluteのいいところ ◉ 起動が圧倒的に早い ○ SAFluteは7〜8秒程度、Lastaは2〜3秒程度 ◉ ログが見やすい ○ DBFluteイズムで見やすいログ ◉ よりシンプルに書けるコード ○ formが引数, formで型定義、Hibernate Validatorが使え る、などなど
  85. 85. APIドキュメント自動生成 API開発をしている場合、クライアントへI/F定義を提示 する必要がある => 自動生成
  86. 86. 2015年 6月U-NEXTリニューアルリリース予定  リニューアルに向けて開発..開発..開発.. 膨大な開発
  87. 87. 2015年 6月U-NEXTリニューアルリリース予定  リニューアルに向けて開発..開発..開発.. 2015年 8月へ延期  開発..開発..開発..開発..開発..開発.. 膨大な開発
  88. 88. 2015年 6月U-NEXTリニューアルリリース予定  リニューアルに向けて開発..開発..開発.. 2015年 8月へ延期  開発..開発..開発..開発..開発..開発.. 2015年 9月へ延期  開発..開発..開発..開発..開発..開発..開発..開発..開発.. 膨大な開発
  89. 89. 膨大な開発 2015年 6月U-NEXTリニューアルリリース予定  リニューアルに向けて開発..開発..開発.. 2015年 8月へ延期  開発..開発..開発..開発..開発..開発.. 2015年 9月へ延期  開発..開発..開発..開発..開発..開発..開発..開発..開発.. 2015年 10月9日へ延期  開発..開発..開発.. リリース!!
  90. 90. ボリューム満点の開発 SAFlute / LastaFlute / DBFluteの軽快さ 実装 => リリース => 修正 => リリース => … のサイクルをとても軽快に回すことが出来る リニューアルを乗り越えられたのは この軽快さのおかげ 膨大な開発
  91. 91. 第4章 更なる高みへ
  92. 92. リニューアルで全力疾走を続けた結果 ◉ 個々のソロプレーを足しあわせて何とかなっていた ○ チーム力・組織力が全くない状況 ◉ ソースコードがちぐはぐ ○ とにかく動くコードを早くリリースするのが正義 ○ その結果、ちぐはぐなコードが生まれる ○ それでもテストコードは書いてCIはしていたし、DBFlute部分の コードは問題なし ■ これはDBFluteハンズオンのおかげ 約1年半の開発である程度の技術的負債が生まれた
  93. 93. スクラム開発 ◉ 今まで ○ 複数人のディレクターやQAからの要望を各分野に精通している人 が個々の判断で優先度を決定し、開発 ◉ これから ○ スクラム開発を導入 ○ 優先度はプロダクトオーナーが決定 ○ 開発タスクは開発チームで決定 ○ 2週間のスプリント ○ スプリント計画ミーティングで実装タスクを決定 ○ デイリースクラムで日々の状況や問題点を洗い出し ○ スプリントレビューで成果物の検査 ○ スプリント振り返りでよりよいやり方に改善 ○ ビジネス開発:アーキテクチャ改善・リファクタリング=7:3
  94. 94. より働きやすい環境 ◉ ハイスペックな開発マシン ○ メモリ32GB、250GB SSD、インテル® Core™i7- 5930k ◉ 高級なイス(予定) ○ 候補:アーロンチェアなど ◉ 自由に買える書籍 ○ 申請して5分後に電子書籍が届くとか ◉ 定期的に開催される勉強会 ○ スクラム読書会 ○ 機械学習の勉強会 ○ データベースの勉強会 etc...
  95. 95. コードの品質 ◉ これまで ○ コードを書いた人以外の目に触れずに本番へリリースされる コードがたくさん ◉ これから ○ コーディングガイドラインを整備 ■ 規約は文章化せず、自動で判別できるものに ○ プルリクベースでのコードレビューを導入 ○ 対面でのコードレビュー会を導入 チーム内でよりよいコードを書く という意識が芽生え始める
  96. 96. より良いアーキテクチャへ ◉ 当初目指していたDB単位のAPI ○ これは実現出来た ○ DB変更は比較的簡単に出来る ◉ リポジトリはそれなりにでかい ○ 分割出来るプロジェクトが同じリポジトリに存在している ■ 時間の都合上 ◉ もっと最適に分割出来る マイクロサービスアーキテクチャの思想で アーキテクチャをリファクタリグ (やりすぎないようにミニマムサービスくらいを目指して)
  97. 97. ◉ まだまだたくさんある開発案件 ○ これからはチームでよりよいものをより楽しく開発出来るように ○ そして競合に負けないように ◉ 個々の技術力 ○ コードレビュー・勉強会などを通じてメンバーそれぞれがお互いを 高め合える環境・そして文化に ◉ より最適なアーキテクチャに ○ 既存の技術的負債を放置せず、少しずつ返却していく ○ 2年後、3年後も楽しく開発出来るように 今後
  98. 98. U-NEXTでは人材を募集しています 映画やアニメが好きなひと エンターテイメントが好きなひと 配信プラットフォームに興味のあるひと 技術的なことが好きなひと 一緒に仕事をしましょう http://unext.co.jp/recruit/
  99. 99. Thank you for your attention

×