Slide 1

Slide 1 text

クラウド時代だから Spring-Retry フレームワーク Y.Watanabe 2019-07-12 JSUG勉強会2019その7 ビズリーチにおけるSpringの活用

Slide 2

Slide 2 text

ストップウォッチ スタート 確認 2

Slide 3

Slide 3 text

ビズリーチでは エンジニアを募集しています 3

Slide 4

Slide 4 text

Who? ● 渡辺 祐
 ● (株)ビズリーチ
 ● SREグループ
 ○ Site Reliability Engeneering
 4

Slide 5

Slide 5 text

アンケート ● Java 5, 6, 7 ● Java 8 ● Java 9,10,11,12… ● まさかのJava1.3, 1.4 ● わからない 5

Slide 6

Slide 6 text

RDBMSは? ● オンプレミス ● AWS-RDS, Google Cloud SQL ● その他クラウド ● わからない 6

Slide 7

Slide 7 text

コネクションプールライブラリ ● apache commons-pool 1.x ● apache commons-pool 2.x ● Tomcat DBCP ● HikariCP ● その他 (c3po…. ● わからない 7

Slide 8

Slide 8 text

今日お話したいこと ● 数回の自動リトライで 得られる安眠がある ● 自動リトライを実装する前に やるべきことがある ● Spring-Retryの原始的な使い方 8

Slide 9

Slide 9 text

ある日の出来事 1. RDSが障害でフェイルオーバー 2. 90秒で自動復旧した 3. しかしアプリのエラーログアラートは10分以上鳴 りっぱなし 9

Slide 10

Slide 10 text

誰かがイイこと言った DBがフェイルオーバーしたくらいで なんでこんなに騒いでんの? 10

Slide 11

Slide 11 text

ある日の出来事(2) Slack APIが 「429 Too Many Request」を返却。 20分くらいエラーログアラートラッシュ 11

Slide 12

Slide 12 text

自動リトライに向いているのは? ● 短期間(数分レベル)で復旧している可能 性が高いなら自動リトライ ● そもそも通信過多の場合はスロットリング 12

Slide 13

Slide 13 text

aws-sdk-javaの場合 スロットリングとリトライの両方を内蔵している 13

Slide 14

Slide 14 text

1. JDBC接続のリトライ ↑今日はコレ 2. REST-APIへのhttpリクエストのリトライ ↑ ググった結果のコピペでイケます 14

Slide 15

Slide 15 text

RDSのフェイルオーバーとは? 15

Slide 16

Slide 16 text

RDSのフェイルオーバーとは ● 主系に障害が発生すると 自動的に副系に切り替わる ● 公式マニュアルでは 「60秒から120秒かかる」 ● 経験値では90秒 16

Slide 17

Slide 17 text

DBが90秒で復帰してるのに アプリが90秒で復帰できないってどゆこと? 17

Slide 18

Slide 18 text

jdbc:mysql://db.biz.internal/hogedb $ host db.biz.internal db.biz.internal is an alias for a.rds.amazonaws.com. a.rds.amazonaws.com has address 10.1.1.1 $ host db.biz.internal db.biz.internal is an alias for b.rds.amazonaws.com. b.rds.amazonaws.com has address 10.2.2.2 フェイルオーバー前 フェイルオーバー後 18

Slide 19

Slide 19 text

フェイルオーバーメカニズムでは、スタンバイ DB インスタンスをポイントするように DB インスタンスの DNS レコードが自動的に変更されます。したがって、DB インスタンスへ の既存の接続の再確立が必要になります。Java DNS キャッシュメカニズムがどのよう に機能するかによって、JVM 環境の再設定が必要になる場合があります。フェイルオー バーの際に DNS 値をキャッシュする Java アプリケーションの管理方法の詳細につい ては、「AWS SDK for Java」を参照してください。 https://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/UserGuide/Concepts.MultiAZ.html RDSのマニュアルなのになぜか 「Javaの場合は注意しろ」とわざわざ書いてある(笑) 19

Slide 20

Slide 20 text

まずやるべきこと -Dnetworkaddress.cache.ttl=3 デフォルトは”-1” つまりJVMが生きてる間はDNS検索結果を ずっとキャッシュするのがデフォルト 20

Slide 21

Slide 21 text

(講演後の追記) 実は前の -Dnetworkaddress.cache.ttl=3 は嘘です。これじゃ設定できないっす。 正確にはこんな感じのコードをpublic static void main(args)を持つクラスの最初の方に 埋め込んでいます。 java.security.Security.setProperty("networkaddress.cache.ttl", "3"); java.security.Security.setProperty("networkaddress.cache.negative.ttl", "3"); 21

Slide 22

Slide 22 text

他にもまだあるんじゃね? 22

Slide 23

Slide 23 text

@Bean public DataSource dataSource() { ds = new BasicDataSource(); ds.setUrl()...setUser()... setPassword()... ds.maxActive(10? 50? アプリによりけり) ds.setValidationQuery(“SELECT 1”) return new TransactionAwareDatasourceProxy(ds) } // えっ?これだけ? 23

Slide 24

Slide 24 text

commons-pool 1.x の他のパラメータ ● minEvictableIdleTimeMills ● numTestPerEvictionRun ● testWhileIdle ● validationQueryTimeout ● 他多数 24

Slide 25

Slide 25 text

commons-pool 2.x で増えたパラメータ ● fastFailValidation ● logAbandoned ● removeAbandonedOnBorrow ● 他多数 25

Slide 26

Slide 26 text

● Tomcat-DBCPというのも速いらしい ● 最近はやはりHikariCPがデファクトらしい 26

Slide 27

Slide 27 text

commons-pool 1.x は2012年で打ち止め 27

Slide 28

Slide 28 text

クラウド時代のRDBに向かって 7年前に開発打ち止めの コネクションプール機構を使い続けるとでも? 28

Slide 29

Slide 29 text

@Bean public DataSource dataSource() { conf = new HikariConfig(); conf.setUrl()...setUser()... conf.setMaxIdle(10? 50? アプリによりけり) conf.setConnectionInitSql(...) conf.setConnectionTimeout(数秒) conf.setValidationTimeout(数秒) 意外と少ない設 定で良さげ 29

Slide 30

Slide 30 text

1. ここまでで最低限の準備が完了 2. ここからが本番の 「RDSがフェイルオーバーしたときの エラーログアラートラッシュ緩和のための Spring-Retry」 30

Slide 31

Slide 31 text

ちょっと休憩 時間を確認 25分くらい? 31

Slide 32

Slide 32 text

@Configuration @EnableRetry public HogeConfig {... Javaコンフィグ ...} @Retryable(value = {FooException.class}, maxAttempts=3) public Bar barMethod(args...) { // なんか不安定かもしれない外部通信 } 32

Slide 33

Slide 33 text

● AOPはちょっぴり遅くなる ● RetryTemplateを明示的に使うほうが わかりやすくて確実 33

Slide 34

Slide 34 text

やりたいこと DB(RDS) JDBCドライバ コネプ アプリケーション DBコネクション取得失敗の場合 に、4回までリトライする 1sec後 -> 2sec -> 4sec -> 8sec 34

Slide 35

Slide 35 text

retryTemplate = new RetryTemplate(); retryTemplate.setBackOffPolicy(省略); retryTemplate.setRetryPolicy(省略); 例: Excepation.classはリトライ対象だが RuntimeExceptionは対象外にする、等 まずRetryTemplateを準備しておく 35

Slide 36

Slide 36 text

spring-jdbc提供のDataSourceを拡張 public class FooDataSource extends DelegatingDataSource { @Override public Connection getConnection() throws SQLException { return retryTemplate.execute(context -> { if (context.getRetryCount() > 0) { /* warnログなど */ } return super.getConnection(); }); 36

Slide 37

Slide 37 text

@Bean public java.sql.DataSource dataSource() { conf = new HikariConfig(); conf.set…(jdbc-url, user, その他もろもろ) hikariDs = new HikariDataSource(conf); fooDs = new 前ページのFooDataSource(hikariDs); ds = new TransactionAwareDatasourceProxy(fooDs); return ds; 37

Slide 38

Slide 38 text

手動でフェイルオーバーさせて試す 38

Slide 39

Slide 39 text

DBAさん 39

Slide 40

Slide 40 text

まとめ 40

Slide 41

Slide 41 text

● クラウドの向こう側の障害が90秒で回復しても、 それに依存する自分のアプリケーションも90秒で 回復するとは限らない。 ● フェイルオーバー試験するしかない。 41

Slide 42

Slide 42 text

AWS-SDKならその配布ライブラリ自体で リトライ機構が組み込み済みだが... aws-java-sdk-s3 aws-java-sdk-sqs aws-java-sdk-rdb ? aws-java-sdk-jdbc ? 存在しません 42

Slide 43

Slide 43 text

リトライは 最悪、無くてもいい。 リトライがあれば、DBがfail overから復帰するまでの90 秒のエラーログの飽和(からの精神的苦痛)をやわらげ ることができる DBCPの設定が ちゃんとできてれば 43

Slide 44

Slide 44 text

ほとんどのコードを書いてくれたS君に感謝 (自分はほぼレビューのみ) 44

Slide 45

Slide 45 text

週明け、皆さんのプロジェクトでやることは? ● DBCPライブラリ、何使ってるか確認する? ● DBCPの設定、確認する? ● fail over試験、する? ● (DBまわりに限らず)Spring-Retry どこかで使えそう? 45

Slide 46

Slide 46 text

ビズリーチでは エンジニアを募集しています 46