TECH PLAY

PHP

イベント

マガジン

技術ブログ

SCSKの畑です。 今回は実案件における Redis から Elasticashe(Redis OSS)への移行において直面したいくつかの仕様差異について、どのような対策を取ったのかも合わせて紹介したいと思います。ちなみに移行に関する初回のエントリは以下となります。 Amazon Elasticache 移行方式のまとめ とある案件において 他クラウド IaaS 上の Redis から Elasticache(Redis OSS)へのデータ移行要件があったため、移行方式についてどの方式を採用したのかを含めてまとめてみました。 blog.usize-tech.com 2026.02.12   差異その1:Elasticache は停止ができない まずはベーシックな内容から。 よく知られていることだと思うのですが、Redis と異なり Elasticache は停止ができません。メモリ上にデータを保持する以上、インスタンスを停止するとデータが失われてしまうが故の仕様かと類推するのですが、停止できないということは一度インスタンスを立ち上げた後は常時課金が発生してしまうことになります。特に性能試験用の環境のように、使用中は本番環境と同様の大きいインスタンスを必要とする環境ではその弊害もより大きくなってしまいます。 Redis も停止すればデータは失われる以上、(データを保持したままの)停止ができないというのは同様と言えるかもしれません。ただ、Redis の場合はデフォルトで起動時にバックアップ(dump.rdb ファイルなど)からのデータロードが可能なため、起動停止を前提とした運用は Elasticache より実施しやすいと言えると思います。 そこで、大きなインスタンスサイズを必要とする環境については、環境を使用していない時間帯はインスタンスサイズを縮小することで課金額を低減しようと考えていたのですが・・ふと、縮小先のメモリサイズより大きなデータが Elasticache 上に存在したらどういう挙動になるんだろう?という疑問が。実運用時においても同じような状況になることが予想できたため事前に検証しておくことにしました。 試しに 10 GB のキャッシュデータを cache.r7g.xlarge のインスタンスにロードした後、t3.micro にサイズを変更してみたところ・・ Failed to scale down to cache node type Replication Group redis-downsize-test because the node has insufficient memory. Please select a different node type or reduce current memory usage and retry のようなエラーが出力されてしまったため、(ある意味予想通りでしたが)縮小できませんでした。よって、Elasticache の(再)作成・削除により起動・停止を代替する方法が唯一の回避策という結論となりました。削除時にデータをバックアップとして残しておいて、それを(再)作成時に使用するような流れです。先述した Redis の挙動を Elasticache で実現しようとするとこうなります、とも言えますね。 直近にリリースした Elasticache で早速この対応が必要となったため、 一旦は AWS CLI で実装することで解決しました 。 ただし、この手法だと各環境ごとに Elasticache の(再)作成コマンドが必要になってしまうためあまり効率が良いとは言えません。本案件における AWS リソース/サービスのデプロイには CloudFormation を使用しているため、将来的にはそちらに移行したいところです。DeletionPolicy あたりを使用すればできるのかしら・・?   差異その2:一括移行の場合 Elasticache をバックアップから新規作成する必要がある 続いてはこちらのテーマ。上記内容(差異その1)とも関連する内容でもあります。 先般のエントリ でも言及していた通り、本案件における Elasticache のデータ移行は一括移行で実施する旨決定したのですが、一括移行において現行環境で取得したバックアップを新環境に移行する際において、そのタイミングでバックアップから Elasticache を新規作成する必要があります。言い換えると、作成済みの Elasticache に対して特定のバックアップをリストアするというオペレーションが行えません。 よって、一括移行のタイミングまで新環境(Elasticache)のエンドポイントが不明な状態になってしまうという懸念点がありました。当日移行(切替)のタイミングでアプリケーション側の各種設定を変更する必要がある訳ですが、その直前まで新環境(Elasticache)のエンドポイントが分からないというのは作業への影響が大きいと考えたためです。 当初この仕様にものすごく違和感があったのですが、Redis の場合も起動時にバックアップ(dump.rdb ファイルなど)のデータを読み込む挙動をしており、実のところ同じ仕様でした。。ただ、仮に同様のシナリオで別の IaaS 上の Redis に移行するケースを考えてみると、移行先サーバへの接続情報(IPアドレス/FQDN)は Redis 移行前に分かっていることになるので、その点においては差異があると思います。 一方で、過去の経験や上記(差異その1)の対応において Elasticache を同じ設定で再作成した場合、再作成前後で必ず同じエンドポイント名となったことから、裏取りも兼ねてエンドポイントの命名規則が分かれば(少なくとも現在の仕様において)事前に新環境でのエンドポイント名を導出することができると考えました。 AWS のドキュメントには該当するような内容がなさそうだったので、大人しく AWS サポートに確認しました。その結果、命名規則に関する公開情報はないという前提において現在の仕様を確認頂くことができたので、以下に共有します。クラスターモードや転送中の暗号化の差異によりエンドポイントの FQDN が異なるというのは正直気付かなかったところです・・ ◆クラスターモード無効・転送中の暗号化が有効 ・プライマリエンドポイント master.<クラスター名>.<6文字のランダム文字列(※).<リージョン名>.cache.amazonaws.com ・リーダーエンドポイント replica.<クラスター名>.<6文字のランダム文字列(※).<リージョン名>.cache.amazonaws.com ・ノードエンドポイント <ノード名>.<クラスター名>.<6文字のランダム文字列(※)>.<リージョン名>.cache.amazonaws.com ◆クラスターモード無効・転送中の暗号化が無効 ・プライマリエンドポイント <クラスター名>.<6文字のランダム文字列(※)>.ng.0001.<リージョン名>.cache.amazonaws.com ・リーダーエンドポイント <クラスター名>-ro.<6文字のランダム文字列(※)>.ng.0001.<リージョン名>.cache.amazonaws.com ・ノードエンドポイント <ノード名>.<クラスター名>.<6文字のランダム文字列(※)>.0001.<リージョン名>.cache.amazonaws.com ◆クラスターモード有効・転送中の暗号化が有効 ・設定エンドポイント clustercfg.<クラスター名>.<6文字のランダム文字列(※)>.<リージョン名>.cache.amazonaws.com ・ノードエンドポイント <ノード名>.<クラスター名>.<6文字のランダム文字列(※)>.<リージョン名>.cache.amazonaws.com ◆クラスターモード有効・転送中の暗号化が無効 ・設定エンドポイント <クラスター名>.<6文字のランダム文字列(※)>.clustercfg.<リージョン名>.cache.amazonaws.com ・ノードエンドポイント <ノード名>.<6文字のランダム文字列(※)>.0001.<リージョン名>.cache.amazonaws.com (※) 「6文字のランダム文字列」は、同一アカウント・同一リージョンであれば同じ値となる 今回使用するのは 「クラスターモード無効・転送中の暗号化が無効」 のパターンに該当するので、こちらの命名規則を連携して一旦解決となりました。   差異その3:通信暗号化方式と認証方式の組み合わせにおける制約がある さて、ある意味本題というか、相対的に影響が大きかったトピックがこちらとなります。 現行の Redis では 通信暗号化方式:暗号化なし 認証方式:AUTH 認証 という設定だったため Elasticache でも踏襲しようとしたところ、なんと Elasticache の仕様として設定できない ことがわかりました。設定可能な組み合わせは 通信暗号化方式:暗号化あり、認証方式:AUTH 認証 通信暗号化方式:暗号化あり、認証方式:認証なし 通信暗号化方式:暗号化なし、認証方式:認証なし のどちらかに限定されており、どれを選択した場合においても現行 Redis との非互換が発生してしまいます。また、現行 Redis との互換性を考えると、上記 3 つの組み合わせの内、2 についてはどちらの項目も現行 Redis からの変更になるため採用するメリットがないと判断し、それ以外の方式(1 or 3)のメリット・デメリットを整理した上でどちらの組み合わせを採用するかお客さんも交えて検討しました。 Elasticache における方式の組み合わせが限定されている理由として考えられるのは、「通信暗号化なしの場合は認証情報も平文で通信路を流れてしまうため、認証を設ける意味がない」というところだと思います。その意図は理解できるのですが、サービスレベルで組み合わせを限定するほどの意義があるのかというと・・正直ないのでは?というのが個人的な感想です。 ざっくりメリット・デメリットをまとめると以下の通りです。平たく言うと、現行環境と同一にする(ことで影響を抑えたい)項目としてどちらを取るかというような内容ですね。 通信暗号化方式:暗号化あり、認証方式:AUTH 認証 メリット:AUTH 認証に関連するアプリケーションコードの変更が不要 通信暗号化に関連するアプリケーションコードの変更は必要 デメリット:Elasticache への移行により、通信暗号化に伴う性能への影響が生じる可能性あり 通信暗号化方式:暗号化なし、認証方式:認証なし メリット:Elasticache への移行により性能への影響が生じる可能性を相対的に抑えられる(通信暗号化しないため) デメリット:AUTH 認証に関連するアプリケーションコードの変更が必要 結論から言いますと、本案件では性能への影響を重視して 「通信暗号化方式:暗号化なし、認証方式:認証なし」 の組み合わせを選択するになりました。また、現在 AWS へのマイグレーションを先行して実施している別の案件でも同一方式が選択されていたことも理由の一つとなりました。   補足:今回のケースにおける、上記変更に伴うアプリケーションへの影響について 上記にまとめた通り、通信暗号化を有効にする場合・AUTH 認証を無効にする場合どちらもアプリケーションコードの変更はいずれにせよ必要になりますが、実際にどのような変更が必要かはアプリケーション側の実装に依存します。 今回のケースの場合、通信暗号化関連についてはいわゆるアプリケーションのコンフィグ変更が必要でしたが、いずれにせよ移行(切替)時に接続先を Elasticache のエンドポイントに変更する必要があることも鑑みると、影響はほぼなしという判断になりました。 対して、AUTH 認証の無効化については一部のライブラリを使用しているアプリケーションコードにおいて影響がありました。例えば、phpredis ライブラリを使用した以下のような php のコードで AUTH 認証なしのElasticache (Redis) に対して接続しようとすると $redis = new Redis(); $redis->connect($host, $port, $timeout); $authenticated = $redis->auth($password); 以下のように、3行目の $redis->auth($password) 実行部分においてエラーが出力されてしまいます。AUTH 認証が無効であるにも関わらず AUTH コマンドが実行されているという内容ですね。よって、このようなコードについて、対象処理の削除、Elasticache (Redis) に接続できた時点で各種操作ができるようなロジックへの変更などの修正が必要となりました。 PHP Fatal error:  Uncaught RedisException: ERR AUTH <password> called without any password configured for the default user. Are you sure your configuration is correct? in /home/ec2-user/redis_test.php:14 ちなみに、AUTH 認証無効の Elasticache (Redis) に接続した状態でこの処理を実行したとしても、もしライブラリ側でエラーを返さないような実装になっていればコード変更が不要になった可能性もあります。そのあたりは使用しているライブラリに依存するところですが、上記については redis-cli のような公式ツールでも同じ挙動になったので、(言い方が適切がどうかはさておき)この実装自体は正しいのかなと思います。   まとめ 1点目・2点目については仕様だけ見てこういうものなのね、と一旦流していたのですが、よくよくユースケースを考えると困るみたいな内容でした。幸いどちらも事前に気づけてひとまず対策できたので良かったです。 トータルで一番影響が大きかったのはやはり3点目です。パラメータレベルでの互換性は事前にチェックしていたのですが、Elasticache においてはパラメータで設定できない内容だったことに加えて、個々の設定(通信暗号化/ユーザ認証)としては可能だけど組み合わせパターンに制約がある、という非互換性はちょっと予見できておらず面食らいました。先述の通りその意図は理解できなくはないんですけど、Redis との互換性を考えるとできるようにしておいても損しないんじゃないかと思うんですけどどうなんでしょうか。Elasticashe(Redis OSS)を選択する以上は、Redis との互換性を最優先するという意図があるでしょうし。 本記事がどなたかの役に立てば幸いです。
はじめに こんにちは、リテールハブ開発部でバックエンドエンジニアをしているホシと申します。 現在、Laravel などを利用しながら小売アプリ開発に取り組んでいます。 先日、サービスのリリースに伴い、旧サービスの外部システムから当社のMySQL DBへユーザーデータ移行を行う機会がありました。 ただ今回、今まで行ったデータ移行と大きく違うのは、ユーザーの個人情報を含んだデータ移行でした。 データ移行自体はこれまでも経験していましたが、個人情報を含む移行は前提が異なり、多くの学びと反省点がありました。 そこで本記事では以下の点についてお話できればと思います。 実データを自由に扱えない状況での事前準備の進め方 リハーサルの重要性と、実施できる場合の考え方 今回採用した移行方式と「変換できたのに正しく入っていない」問題と確認点 移行当日に意識しておくべき判断と心構え 次回のデータ移行に向けた改善点 それぞれの中で経験したことや反省点を記載しながら、今後に向けた改善点などを記載しています。 また、個別の移行内容というよりは、データ移行を進める際の準備・検証・判断の考え方に焦点を当てています。 1. 実データを自由に扱えない状況での事前準備の進め方 個人情報を含むデータは「自由に触れない」 個人情報が含まれる場合の制約 開発環境・検証環境に簡単に持ち込めない ログ出力、スクリーンショット、共有方法にも制限がある データ配置・保管場所にも慎重な判断が必要 事前確認が十分にできない 「本番で初めて見るデータ」が発生しがち など通常とは異なる制約がある中で行う必要がありました。 この部分をもっと考慮した上で、事前準備が必要であったところは大きな反省点でした。 「できないから仕方ない」で済ませると危険 事前にできることはできる限りやり、仕様書・IF定義だけで満足しないことが大事です。 とはいえ対応できる範囲も限界はあるので以下の点を特に注意できればと思っています。 NULL / 空文字 / 不正値の扱いは各項目でどうなっているのかを明確にする。 桁数・文字種・フォーマットのばらつきがあることを前提とした考慮をする。 仕様上はOKでも、実データでは違う可能性を考える。 (ここは正直難しいですが、データパターンを確認し、できる限り考慮したいです。) あるあるの話ですが、通常は仕様に基づいて対応するのが当たり前ですが、 こういった大量データになるとおかしなデータはほぼ混ざっているのが逆に普通かと思っています。 2. リハーサルの重要性と、実施できる場合の考え方 今回は事前にリハーサルが実施できる状況でした。 しかし、以下の点でしか検証を行えていませんでした。 データ移行手順が問題ないこと(スムーズに移行作業が完了できる) 個人情報データの取り扱いに問題がないこと データ変換がエラーなく行われ、正常にDBへ投入できること(想定通りのフォーマットであること) 実際に移行したデータを使用して簡単な動作確認を実施し問題ないこと 上記はどれもリハーサルで行う必要な項目で、どれも大事なのですが、 ただ、本番データを想定した観点としては以下の点でもっと時間をかけて行うべきでした。 DBに入った内容に想定していないデータが入っていないか データパターンを各項目で洗い出し、システム上問題ない値であること 想定していないパターンの場合、どう対処するかを事前に明確にすること しかし、これも個人情報のデータとなると、あまり時間をかけてのリハーサルや ローカルに保存して後ほど詳細に確認もしにくいのもあり、簡単な確認で済ませてしまっていました。 元データを最大限に利用する 一番確実なのはやはり元データを使用できることです。 当日のデータ移行の検証という意味では、これを利用した検証が一番確実だと思います。 リハーサル当日だけで出来ない部分は、別日に詳細にできればと良いと思います。 しかし、今回のような個人情報データは自由に扱えないことを理由にうまく利用できていなかったのも反省点です。 いかにここでそのファイルを活用したダミーデータを作れるかも非常に有効だったのではと思っています。 3. 今回採用した移行方式と「変換できたのに正しく入っていない」問題と確認点 どうやって移行を行おうとしたか 今回は以下の方法で行いました。 移行元データ ↓ phpでデータを読み込み、MySQLのLoadData用TSVファイルにコンバートするコードを作成 ↓ Load DataでTSVデータをDBへ投入 ↓ データ移行完了 特別な処理は特になく、シンプルな変換処理でした。 「変換できたのに正しく入っていない」問題と確認点 コンバートまでは特に問題なく変換できて、件数・エラーチェックは行えていましたが、 以下の点が見落としポイントでした。 データ投入できていて、かつ全件「自動変換」など発生なく投入できているか? Load時にWarningなどが発生していないか?(投入はできていても実は正常に入っていないケースがある) カラム定義上は問題なく入っているが、値が想定していないものではないか? Load Data はデータ投入時に非常に便利ですが、上記の点をしっかりと考慮した上で使用しないとデータ移行時の確認内容としては不十分になってしまいます。 特に日付はNULLの場合と「0000-00-00」で入る場合で全く挙動が異なります。 MySQLでは「0000-00-00」はNULLではなく「値」として扱われます。 そのためアプリケーション側では未設定ではなく異常値として存在してしまうことになり、 日付計算・バリデーション・ORM変換で後から問題を引き起こす可能性があるので特に注意が必要です。 今回の移行処理の責務を分離して考える 本来は以下のようにそれぞれのフェーズの責務を明確にして、対応をしていく必要がありました。 フェーズ 役割 保証すること 保証できないこと コンバーター 生データをLoad Data用形式へ変換 TSV構造・文字コード・基本的な値変換 DBがどう解釈するか、業務的な正しさ Load Data DBへ高速に一括投入 指定件数の取り込み、物理的な格納 型変換の影響、暗黙変換、Warningの発生 DB格納後の確認 実データの妥当性検証 業務的に正しい値であることの確認 この確認を行わないと移行成功とは言えない 特に今回は、Load Data の部分とDB格納後の確認が混在した確認になっていたと反省しています。 実際のデータパターンの検証例 パターンは膨大にあるようで、実はシンプルなものをいくつか用意しておくだけでも違うと思っています。 -- 不正日付確認 SELECT COUNT (*) FROM users WHERE birthday = ' 0000-00-00 ' ; -- NULL発生率確認 SELECT COUNT (*), SUM (email IS NULL ) FROM users; -- 想定外形式確認(都道府県以外のパターン確認) SELECT prefecture, COUNT (*) FROM users GROUP BY prefecture; AIを活用したパターン洗い出し・事前テストの試み 今回、AIをうまく使いこなせていなかった点も反省点だったと思っています。 まさにAIをうまく活用できる点として、 前述したデータパターンを様々な観点で出すことができる 個人情報部分は適当なパターンデータに変換して検証することもできる 当時は本番データをそのまま使用できないことで、ちょっとしたサンプルデータ、パターンデータで行い、 十分な事前検証も不足していました。 4. 移行当日に意識しておくべき判断と心構え 今までいくつか事前準備と慎重な検証が必要と記載をしていますが、 当日は必ず想定外が起きると思って計画を立てた方が良いかと思っています。 特に膨大なデータや内容が多いほど顕著になるかと思います。 以下の点に注意して当日は望めるようにしておきたいです。 1つ1つの作業完了条件を明確にしておくこと。 ロジックや仕様変更をその場でする修正は原則しないこと。 移行を中止、延期する、または後日対応でOKかなどの判断が当日できる人がいること。 移行がもし出来ない場合のリカバリ方法があること。 また、時間も想定しているよりも掛かってしまうことが多いと思います。 なるべく余裕をもった計画にしたいです。 今回は投入データの件数確認でさえ、すぐに終わるつもりが件数の正解を事前に用意していなかったため、 非常に大きく時間をかけてしまったのも今回の反省点でした。(完了条件が明確になっていない) 5. 次回のデータ移行に向けた改善点 今回の経験から以下の点を意識し改善できるようにしていきたいです。 一連の手順、動作確認は事前リハーサルでできる限り行うこと。 本番当日に向けた事前準備はしっかり時間を確保して対応する。(当日は必ず何か起きる前提) 当日の作業の完了基準の明確化(データ件数、エラー有無、動作確認など) Load Dataなどデータ投入後の部分が一番大事かつ明確にする部分であること。 仕様通りに作成しても、不正データは必ずある前提で行い、それらも考慮すること。 個人情報を扱うデータの場合は、同等のダミーデータを用意できると検証時に非常に有効。 検証パターン、データ生成などはAIも活用し、検証精度やコスト減に役立てる。 6. まとめ 通常、データ移行は当日一度きりの作業で、 同じ内容で再度実施するケースは少なく、個別のノウハウは蓄積しにくいところもありますが、 共通の考え方、対応として、 事前準備の重要性 検証設計の明確化 当日の判断基準 何かあった時のリカバリ方法 これらを意識することで、当日の障害確率は下げられると思っています。 改めて今回を通じて、データ移行は技術作業というより、検証設計と判断設計の仕事だったと感じています。 正直、完璧に準備をして全てスムーズに完了させることはなかなか難しいところですが、 もし今後データ移行などの作業をする際に本記事が少しでも参考になれば幸いです。 最後までお読みいただきありがとうございました。
はじめに 触ってみた Step 1:Agent Space の作成 Step 2: DevOps Centerでアプリ全体を把握 Step 3: Amazon CloudWatch Alarmの調査 Step 4: Investigation(原因調査) Step 5: Mitigation Plan(緩和策の生成) Step 6: Prevention(再発防止策) ワークショップを通じて 今後の展望 テスト工程への参加 学びの機会が減る!? まとめ はじめに 皆さま、お久しぶりです。入社5年目の堀内です。普段はJavaやPHPで開発・運用保守を担当しています。 2025年12月、AWS r…

動画

書籍