はじめまして。インフラ・開発部のtorigakiと申します。 入社して初めての投稿となります。よろしくお願いします。
弊社は検索エンジンとしてgroongaを使用しているのですが、今回はgroongaの運用改善をした話を書きたいと思います。
groongaの運用構成
groongaにはElasticSearchのように複数台でクラスタを構成する機能がないため、弊社では2台のgroongaサーバーを立ててマスター・スレーブの冗長構成をとっています。
しかしながら、MySQLのようにレプリケーション機能がないため、マスター・スレーブそれぞれに対してインサート処理を実施していました。 しかし、この方法ではマスター・スレーブ間でデータの整合性がとれなくなる可能性があります。
そこで、インサート後にマスターのデータをスレーブにリストアすることによりこの問題を解決させました。
以下に具体的な方法を記載してきます。
改善前のインサートとバックアップ取得の構成
改善前の構成は以下になります。
- マスターにデータをインサート後、スレーブにデータをインサート(インサートは週1回)。
- バックアップの取得
- マスターのgroongaプロセスを停止。(マスターを停止してもアプリからの接続はスレーブで賄うことができるので問題ありません)
- gsutilコマンドでgroongaのデータファイルをアップロード。
- アップロード完了後groongaプロセスを起動。
改善後の構成
- スレーブのデータはバックアップからリストアするためスレーブへの更新処理は停止。
- GCSからスレーブにファイルコピー(リストア)する。
- 各処理の処理工程をリアルタイムで確認するため、各処理の完了時にSlackに通知する。
リストア処理概要
- スレーブのgroongaプロセスを停止。
- 既存データファイルを削除(gsutil rsyncではファイル上書きされないため、データファイルは一旦削除します)。
- gsutilコマンドでデータファイルをダウンロード。
- ダウンロード完了後groongaプロセスを起動。
データチェック
- スレーブのgroonga起動後にマスターとのデータ整合性をチェックします。
- チェック方法は各テーブルのレコード数を取得しマスターとスレーブで一致するか確認をします。
全体の処理の流れ
- マスター機のデータ更新
- マスター機のgroongaプロセス停止
- マスター機のデータファイルをアップロード
- マスター機のgroongaプロセス起動
- スレーブ機のgroongaプロセス停止
- スレーブ機のデータ削除
- スレーブ機にデータファイルをダウンロード
- スレーブ機のgroongaプロセス起動
- マスターとスレーブのデータ整合性チェック
上記処理を順番に実行するバッチスクリプトを作成し、cronで定期実行するようにしました。
バッチスクリプトで工夫したこと
バッチスクリプトはシェルで書きました。 以下にスクリプトで工夫した点について記載していきます。
Slack通知スクリプト
Slackに通知するスクリプトはこちらのサイトを参考にさせていただきました。
エラー処理
エラー発生時にSlackにエラーコード込で通知されるように以下のように書きました。
# slack通知用スクリプト SLACK_NOTI_PATH="bin/webhooks.sh" # エラー処理 error() { echo ''$1'の実行結果はエラーコード('$2')でした。' | ${SLACK_NOTI_PATH} echo 'groongaバッチ処理: 異常終了' | ${SLACK_NOTI_PATH} exit 1 } # backup backup.sh || error 'backup.sh' $?
上記の場合、backup.sh でエラーが発生するとその旨をSlackに通知してexit 1 でスクリプトを停止させます。
gsutilのオプション
rsync に「-m」 オプションをつけることにより、並列に同期をさせるようにします。 サーバー負荷は上がりますが、ファイルのアップロード・ダウンロードが高速なります。 (ファイルのアップロード・ダウンロードじはgroongaプロセスを停止しているので、サーバー負荷が上がっても問題ありません)
gsutil -m rsync -r ${DIR} gs://${GCS_BACKET_NAME}/${HOSTNAME}/${DATE}/
データ整合性チェック
以下コマンドでマスター・スレーブ両方のgroonga各テーブルのレコード数を取得し、比較することによって同一データであるとことをチェックします。
# テーブル一覧取得 for table1 in `curl -s http://${HOST}:${port}/d/table_list | jq -r -c '.[1][][1]' | sed -e '1,1d'` do # カウント取得 COUNT1=`curl -s http://${HOST}:${port}/d/select.json?table=${table1}\&limit=0 | jq '.[1][][0][]'` echo ${port} ":" ${table} ":" ${COUNT} >> /tmp/${HOST}_count.txt done
データはJSON形式で取得できるのでjqコマンドで加工し、取得した結果をファイル出力して最後にdiffコマンドで差分がないことを確認しています。
まとめ
今回の改善により、マスター・スレーブ間でデータの不整合が出ることを防ぐことができました。
また、スレーブへのデータ更新につきましても、リストア処理がインサート処理よりも高速なため改善することができました。
あと、各処理の完了時にSlackに通知するようにしたため、サーバーにログインして確認するという手間が省け、かつ処理異常時にも即座に気づくことができるようにもなりました。
弊社では引き続きエンジニア・デザイナーを募集中ですので、ご興味のある方は下からご応募いただければと思います。