Sansan×gloops インフラ合同勉強会 http://connpass.com/event/33442/
スケーラビリティのためのSansanアプリケーション基盤2016年7月28日#Sansan_gloops
View Slide
Copyright © 2014 Sansan, Inc. All rights reserved.> 自己紹介1• 和田潤也• 某SIerで8年弱 ⇒ SansanにJOIN• C#、JavaScript 辺り• 主にUI基盤とかを開発していた• 情弱GitHub: chocolamint
Copyright © 2014 Sansan, Inc. All rights reserved.> え?「インフラ勉強会」…?2• インフラの話とはちょっと違います。。。• アプリケーション基盤の話をします• インフラ要素とも多少絡められたらいいな…
Copyright © 2014 Sansan, Inc. All rights reserved.> スケーラビリティのための仕組み3• DBの垂直・水平分散• 垂直分散• 役割によってDBを分割• 水平分散• ShardingKey によってDBを分割• ユーザーごとに使うDBを分散するイメージ• メッセージ基盤• Pub-Sub 型の分散処理基盤• キューイングサービスを利用
Copyright © 2014 Sansan, Inc. All rights reserved.> DBの分散4
Copyright © 2014 Sansan, Inc. All rights reserved.> 水平・垂直分散5Query Shard MappingCommon DatabaseUseMain data DatabasesShard1Shard3Shard2Shard4News Databases
Copyright © 2014 Sansan, Inc. All rights reserved.> Sansan.Data6using (new ShardingScope(shardingKey)){// ここでの接続は指定されたシャードにいく...}
Copyright © 2014 Sansan, Inc. All rights reserved.> Sansan.Data7Webにおいては ActionFilterAttribute を継承したShardingFilterAttribute を使ってShardingScope の生成・破棄(Dispose)をしているusing (var cn = await ConnectionHelper.OpenDataAsync()){// 勝手に現在のユーザーが繋ぐべきシャードに繋がるreturn await cn.Connection.QueryAsync(sql);}
Copyright © 2014 Sansan, Inc. All rights reserved.> メッセージ基盤8
Copyright © 2014 Sansan, Inc. All rights reserved.> ちょっと前までのツラみ9• 統一的な非同期処理基盤がない• Webアプリのボタンクリックで数分かえって来ない• 同時実行できない• 古い自作基盤が並列処理で死ぬ :yami:• リトライで成功するのにアラート• リレー式の処理の滞留具合がわからない• メンテナンス時の停止と開始がツラい
Copyright © 2014 Sansan, Inc. All rights reserved.> 非同期処理基盤がない10• Webアプリで数分かかるボタンクリック• 非同期処理するには個別にバッチ開発が必要Button ClickInsert Recordwith status = 0Polling withTask SchedulerFooBar.exeFooBarJobBatch ServerWeb Server
Copyright © 2014 Sansan, Inc. All rights reserved.> 同時実行できない11status = 0 を取得↓何か処理↓status = 1 に更新複数台(プロセス)で対象データを取り合うと死ぬ↓複雑な排他制御が必要(しんどい)↓スケールしないBatch Server 1 Batch Server 2
Copyright © 2014 Sansan, Inc. All rights reserved.> リトライで成功するのにアラート12タスクマネージャーによるプロセスの定期起動1分後アクセス失敗成功アラート発砲
Copyright © 2014 Sansan, Inc. All rights reserved.> 処理の滞留がわかりづらい13スループット?対象データの流入
Copyright © 2014 Sansan, Inc. All rights reserved.> 停止と開始の嵐14バッチAバッチBバッチCバッチD
Copyright © 2014 Sansan, Inc. All rights reserved. 15殺伐としたバッチ界にメッセージ基盤が!!
Copyright © 2014 Sansan, Inc. All rights reserved.> メッセージ基盤16Message QueueWeb Server Batch ServerEnqueueDequeueMessage ServerExecute messageconcurrencySaaS のキューサービスを利用Message
Copyright © 2014 Sansan, Inc. All rights reserved.> メッセージ基盤のいいところ17• スケールできる• 1プロセス内でマルチスレッドによる並列処理• キューの種類ごとに並列数を調整可能• ノードを増やせばさらにスケール可能• 自動リトライ• 複数回の exponential な自動リトライ• リトライに成功しない場合は dead letter 行き• 自動でアラートメール発砲• 各処理は冪等であるべき
Copyright © 2014 Sansan, Inc. All rights reserved.> メッセージ基盤のいいところ18• 負荷が安定する• セマフォで並列数制御• メッセージ毎に異なるキューにルーティング• キューの滞留を監視可能• グラフでモニタリングも出来る• SaaS でアラームを定義できるので滞留を監視できる
Copyright © 2014 Sansan, Inc. All rights reserved.> メッセージ基盤で出来ること19• 1つのメッセージに複数の Subscriber を定義可能• システムイベントに対する複数処理を割り当て• ex) 新しい名刺が登録されたら…• ○○処理を実行• △△処理を実行• 全て完了したら××処理を実行• 安全に停止できる• Windows サービスとして実装• OnStop でキャンセル要求• 優先度の高いものから処理できる• キューの種類ごとに優先度別のキューを用意できる
Copyright © 2014 Sansan, Inc. All rights reserved. 20Mail Queue (High)Mail Queue (Normal)Mail Queue (Low)News Queue (High)News Queue (Normal)News Queue (Low)4 parallel8 parallel
Copyright © 2014 Sansan, Inc. All rights reserved.> コードのイメージ21MessageQueue queue;while (true){var message = queue.ReceiveMessage();if (message != null)Task.Run(() => DispatchMessage(message));}var msg = new SendMailMessage("title", "body");await msg.SendAsync(priority: MessagePriority.Background);標準で用意されているメッセージ• SendMailMessage• SendAllMailMessage• EventMessage
Copyright © 2014 Sansan, Inc. All rights reserved.> Next...22• 実際に基盤に乗っかった処理はまだ一部• 随時効果の高いところから乗せ換え中• 現状はメッセージ基盤/バッチのログがテキスト• ツラい• fluentd で Elasticsearch に送り込み Kibana で見れるように• 絶賛対応中