テーマ:

こんにちは。Amebaの基幹系インフラ担当している鳥垣です。

 

ユーザーのサービス用途でElasticSearch(0.19.10)を使用しているのですが、先日ElasticSearchの障害で一部のShardが読めなくなってしまいまして、それを力技で無理やり読めるように復旧させたのでその時の奮闘記を記載したいと思います。

 

運用情報

  • 台数:30台
  • CPU:24コア
  • Heap:8GB
  • インデックス数:3
  • 総データ容量:約300GB
  • Shard数:128
  • レプリカ数:2
  • バージョン:0.19.10

※OpenStackの仮想サーバ

 

ホスト障害発生

  • OpenStackのホストサーバがダウンし、ElasticSearchのノードが1台ダウン。
  • Shardの再配置処理が走り、ダウンしたノードが持っていたShardは他ノードに分散される。
  • この時点ではElasticSearchのクラスタステータスはグリーンだった(Headプラグインで確認)。
  • ElasticSearchと連携しているAPIサーバ側からのElasticSearchヘルスチェックをしているのだが、そのチェックがfalseを返していた。

 

ホスト復旧

  • ホストサーバが復旧し、ダウンしていたElasticSearchノードサーバも起動したことを確認。
  • 他のホストサーバにマイグレーションする(またいつホストダウンするかわからないため)。

 

ノード復旧

  • マイグレーション完了後、ElasticSearchのプロセスを起動しクラスタに入れる。
  • Shardの再配置処理が走り、クラスタに無事Joinできたことを確認。
  • クラスタステータスもグリーンになっていることを確認。
  • しかし、APIサーバ側からのElasticSearchヘルスチェックがfalseを返していた。。
  • 以前別環境で運用しているElasticSearchでもAPIサーバ側のヘルスチェックでfalseを返していたときに全ノードを再起動して復旧させたことがあったため、今回も全ノードの再起動を実施する。

 

※これが悲劇の始まりでした。。

 

全台再起動

  • 1号機から順番に再起動を実施。ログファイルにてステータス確認しながら順次再起動していく。
  • 20台目までを再起動したあたりからAPIサーバ側にて遅延発生。
  • 再起動オペレーションを一旦中断。
  • HeadプラグインでElasticSeachのステータスが見れなくなる。。

※Shardの再配置処理が走りまくったせいでクラスタが不安定になりました。。。

  • 再び1号機から順番に全台再起動を実施。
  • Headプラグインでステータスが見れるようになる。
  • APIサーバ側の遅延解消し、ヘルスチェックもtrueを返すようになる。

 

しかし、ここで12個のShardがクラスタに戻らない事象が発生

その時のShard状態のキャプチャがこちらです。

 

 

※プライマリShardまでクラスタから外れてしまい、クラスタに戻ってくれない状態になってしまいました。。

※APIサーバ自体は遅延もおさまり運用できるようになりましたが、データが一部ロストしている状態になってしまいました。。

 

復旧検証

allocateコマンドを使ってunassignedになっているShardの移動を検討。

以下のようなコマンドで移動をやってみました。

curl -XPOST 'http://nodeIP:9200/_cluster/reroute' -d '{
  "commands": [{
  "allocate": {
  "index": "index name",
  "shard": 53,
  "node": "node host name",
  "allow_primary": false
  }
  }]
}'

結果:失敗 

エラーになり移動できませんでした。

 

Shardファイル確認

unassignedになってしまっているShardのファイルがどのように保存されているか確認してみました。

※ここでは3つのインデックスを仮にA,B,Cと呼称。

Aインデックス

Shard番号:53

状態:

  • 3,10,22,29号機にディレクトリを確認
  • ただしファイルがあるのは22号機のみ
  • 3,10,29号機のディレクトリは空状態

ステータスファイル:「A/53/_state/state-93」ファイルの中身

{
"version" : 93,
"primary" : false
}

※レプリカとして認識されていると予測。

 

Bインデックス

Shard番号:51

状態:

  • 27,28号機にディレクトリを確認
  • 両方にデータがあるがファイル内容が異なっている

ステータスファイル:「B/51/_state/state-108」ファイルの中身

{
"version" : 108,
"primary" : false
}

※レプリカとして認識されていると予測 。

※27号機にはステータスファイルはありませんでした。

 

Cインデックス

Shard番号:2,4

状態:

  • 27号機にのみ2番のディレクトリを確認
  • 25号機にのみ4番のディレクトリを確認

ステータスファイル:

「C/2/_state/state-427」ファイルの中身

{
"version" : 427,
"primary" : true
}

「C/4/_state/state-417」ファイルの中身

{
"version" : 417,
"primary" : true
}

※両方ともプライマリとして認識されていると予測

 

無理やり復旧させてみる

上記の状態を踏まえて、それぞれのShardを以下方法で無理やり復旧させてみました。

AインデックスのShard復旧手順

ファイルコピー

※対象ノードのElasticSerchプロセスを最初に停止しておく。

  • 22号機にのみファイルが残っているので、そのファイルをディレクトリのみ残っている3,10号機にコピーする。
  • 29号機のディレクトリは放置しておく(放置しておいても自然に削除されることを検証済み)。

ステータスファイルの書き換え

  • 22号機のみ「   "primary"   : false 」の箇所を「true」に変更する。
  • 3,10号機は「false」のままにする。

※上記作業を完了後、ElasticSeachプロセスを起動する。

※HeadプラグインでShardがクラスタに戻っていることを確認する。

 

BインデックスのShard復旧手順

このサイトを参考にlucene-coreを使ったインデックスチェックを実施してみる。

27号機のほうは壊れており、28号機のほうは正常であることを確認。

ファイルコピー

※対象ノードのElasticSerchプロセスを最初に停止しておく。

  • 27号機のファイルは壊れているので削除する。
  • 28号機のファイルを27号機と他ノードにコピーする。

ステータスファイルの書き換え

  • 28号機のみ「   "primary"   : false 」の箇所を「true」に変更する。
  • 他ノードは「false」のままにする。

※上記作業を完了後、ElasticSeachプロセスを起動する。

※HeadプラグインでShardがクラスタに戻っていることを確認する。

 

CインデックスのShard復旧手順

ファイルコピー

※対象ノードのElasticSerchプロセスを最初に停止しておく。

  • 2番Shardは27号機にのみファイルが残っているので、そのファイルを他の2ノードにコピーする。
  • 4番Shardは25号機にのみファイルが残っているので、そのファイルを他の2ノードにコピーする。

ステータスファイルの書き換え

  • 27,25号機のみ「   "primary"   : true 」のままにする。
  • コピーした他ノードは「false」に変更する。

※上記作業を完了後、ElasticSeachプロセスを起動する。

※HeadプラグインでShardがクラスタに戻っていることを確認する。

 

今回の反省

  • 再起動するときは自動再配置をOFFにしてから作業するべきでした。
  • 1ノードの再起動後はログファイルの確認だけでなく、再配置処理が完全に終了するのを見届けてから次のノードの再起動をするべきでした。

今後について

バージョンアップします!

Cassandraの面倒を見るのが大変だったので今まで大きな障害もなく放置していましたが、もうこんな古いバージョン使いつづけるのはやめます。。

 

今回の記事が、Shardが戻らなくなって困ったという悩みを抱えてらっしゃる方(あまりいらっしゃらないと思いますが。。。)のお役に立てれば幸いです。

 

いいね!した人  |  リブログ(1)

テーマ:

 

みなさんこんにちは。

 

技術組織戦略G & 技術内閣の板敷です。

普段はAmebaのシステム障害の火消し → 障害対策ならびにエンジニアの育成評価等をしています。

 

今回は、先日終了したサイバーエージェント新卒エンジニア技術研修について紹介したいと思います。

 

研修概要

従来の研修内容を一新、内製での技術研修に挑戦

 

これまでの新卒技術研修は委託先講師の話を新卒全員が聞くという、いわゆる「座学中心」の研修でしたが、ここ数年の技術的進歩、組織内でのエンジニアに対する期待の変化を反映するため、内製での研修へとゼロから再設計しました。

 

 

研修のコンセプトと概要

ベースとなる研修のコンセプトは以下2点からなります。

  1. 全体のアーキテクチャを俯瞰して設計、技術選定をする
  2. 自分の頭で考え、動く

これらのコンセプトを実現するために今回の研修では、2つの某有名サービスを

自分たちで設計、実装するという形をとりました。

 

研修詳細

次に研修全体の流れに沿って、詳細内容を紹介します。

 

以下1~6の流れをお題を変えて2回繰り返すことで、1回目の反省を2回目に活かせる設計としました。(新卒だけではなく、運営側もw)

 

1.お題、レギュレーション、チーム分け発表

 

■お題

1回目は某有名SNSサービス、2回目は某有名検索エンジンの開発としました。

 

■開発レギュレーション

レギュレーションは機能面、性能面、コスト面の3軸からなります。

 

機能面

 ・投稿ができる、フィードが表示される、お気に入りができるなど(SNSサービス)

 ・and, or , not検索ができる、検索結果の関連度/適合率/網羅性など(検索エンジン)  

 

性能面

 ・40万フォロワーのいるユーザが投稿してからN秒以内にフォロワーのフィードに反映される(SNSサービス)

 ・継続的に検索結果がN秒以内に返ってくる(検索エンジン)

 

コスト面

 ・開発中のインスタンスコストを$300程度に抑える(今回はAWSを利用)

 

■チーム分け

・各チーム4名(一部3名)で構成。

・基本的に得意技術がバランスよくなるようなチーム分けを目指しました。

 

 

2.設計コンセプト、技術選定

次にお題、レギュレーションを踏まえ設計コンセプト、技術選定を行います。

 

 

※以下実際の例

 

設計コンセプト

・「疎結合で可搬性の高い、スケーラブルなアーキテクチャ」

技術選定

・Go, Python, AngularJS2, Elasticsearch, Docker, Kubernetes, GRPC, Terraformなど

 

設計コンセプト

・「完全に真似るのではなく遊び心を取り入れ楽しいアプリケーションを作る」

技術選定

・Unity, Scala, PlayFrameworkなど

 

設計コンセプト

・「自分達が慣れていなくても良いものを選ぶ」

技術選定

・Go, React.js, Webpack, ECS, Elastisearchなど

 

設計コンセプト

・「堅実な言語で実際の開発を意識し、コードやデザインパターンはモダンな仕様で設計」

技術選定

・Java, SpringBoot, Apache, Tomcat, MySQL, Swift, Realmなど

 

 

などなど。

チャレンジのいい機会としてモダンな技術を選択したチーム、完成度重視で扱い慣れた技術を選択するチームなど個性がはっきりと現れました。

 

 

3.役割決め、スケジュール作成

 

実際の開発に入る前に、役割を決めスケジュールを引きます。

 

1回目のお題時は見積もり精度が低かったり、得意なものからとりあえず実装、 というチームも見られましたが、2回目は開発する機能、メンバーのスキルセット踏まえた進め方へと大きく改善していました。

 

また2回目の開発では、従来クライアントしかやったことのないメンバーもサーバサイド担当になるなど、今回の研修ならではのチャレンジも見られました。

 

 

4.開発スタート

 

スムーズに開発がスタートできたチームもあれば、サンプルデータの投入でハマったチーム、技術選定の失敗に気づき1からやり直すチームなど、機能開発以前でのつまづきも見られましたが、毎日1時間メンタータイムとして先輩エンジニアがフォローすることでこれらを乗り越えました。(メンターのみなさんありがとう!)

 

 

 

5.中間発表     

 

各チームの進捗や設計/実装内容を発表、メンターからのフィードバックを受け軌道修正を行います。

 

1回目のお題では2度の中間発表を設けましたが、2回目は難易度を上げるため、中間発表を1度のみにするなど難易度調整にも役立ちました。

 

 

6.最終プレゼン

 

各チーム最終成果物を発表。 設計コンセプトやアピールポイントなど発表しつつデモンストレーションをし、審査員からの質問に答えます。

 

実装した機能の完成度はもちろん、スライドのクオリティも予想よりはるかに高く、

「最近の若手はなんでこんなに優秀なんだ」と一回り以上離れた新卒を見ながら改めて感じさせられるイベントでした・・・。

 

また最終プレゼンを受け、いくつかの賞の発表も行いました。

ベストクライアント賞、ベストアーキテクチャ賞、ベストサーチエンジン賞など。

 

研修振り返り&まとめ

今回は内容面でも運営面でも従来の方針を一新し、ゼロからの再設計となりましたが、全体としてはおおむね上手く行き、またいいチャレンジができたと感じています。

 

新卒の技術研修というのはエンジニアとしてのスタートでもあるので、最初だからこそ意識してほしいことや、チャレンジしてほしいことを実現するための研修を心がけました。

 

一方、研修後の振り返りでは課題も多く見つかったので、来年に向けてはこれらを解決する方法を取り込みながら、事業・技術・組織の変化に合わせて研修もアップデートしていければと思っています。

 

 

以上が今回の新卒エンジニア技術研修の紹介となります。

サイバーエージェントの技術研修に興味を持ってくれた学生のみなさん、ぜひコチラからエントリーしてみてくださいね!

 

お会いできるのを楽しみにしています。

以上です。

 

いいね!した人  |  リブログ(1)

テーマ:

SGE(Smartphone Games & Entertainment)のグレンジ所属の塚原と袴田です。

 

2016/04/20に開催されたリアルタイム通信ゲーム勉強会で発表してきたので報告をします。

 

グレンジについて

CAのゲーム事業部(SGE)の中の1つです。

ポコロンダンジョンズ

イグドラシル戦記

の2つを開発・運営しています。

勉強会ではポコロンダンジョンズの共闘(多人数の協力プレイ)の仕組みについて発表しました。

 

ポコロンダンジョンズについて

2014年夏にリリースされた「なぞるパズルRPG」です。

当初は1人プレイのみでしたが、2015年春に最大4人の協力プレイ「共闘」が実装されました。

共闘はSocket.IOを使ったリアルタイム通信システムによって動作していて、勉強会ではサーバサイド/クライアントサイドの仕組みを「そこまで見せるのか」というほど公開しています。

 

サーバサイド編(発表者:塚原)

主に、利用技術、サーバ構成、やりとりしているデータを例にどのようにマルチプレイを実現させているのかを説明しています。

サーバサイドは非リアルタイム通信部分をPHP、リアルタイム通信部分をNode.js(socket.io)で構成されているので、その棲み分けの話もしています。

ちなみに、発表の数日後に仕組みを改修し、課題としていたNodeプロセスのCluster化を行いました。(なので、発表資料の説明の一部は古いです)
1コア1ワーカプロセスでサーバを並べていたのを4コア4ワーカプロセスにしてサーバー台数を削減しています。

発表資料

 

クライアントサイド編(発表者:袴田)

こちらは利用技術、構成、発生した問題と解決方法の話を織り交ぜながら、どのように端末間での同期を実現しているのか処理の流れを追いながら説明しています。

クライアントサイドはcocos-2dxとsocket.ioでリアルタイム通信をしているのですが、ソケットが切断されてしまった際の復旧や、端末間で盤面にズレが生じた際の仕組み、通信データ量を抑えるためにどうしているのか、乱数を各端末で同期する仕組みの話とポコロンダンジョンズのリアルタイム通信のキモになっている部分の多くを公開しています。

発表資料

 

さいごに

今回はポコロンダンジョンズで行っているリアルタイム通信について公開しました。

自分達なりに試行錯誤してきた結果ですが、別の方法はあると考えています。

何かご意見等あれば是非お願いします。

 

 
いいね!した人  |  リブログ(0)