Dockerイメージアップデート:Redis 6と25%小さいイメージサイズ

新しいコンテナイメージをリリースしました。次回の ./launcher rebuild app で使用されます。これまで通り、Discourse 公式スタンダードインストール に従っていただければ、設定の変更は不要です。ただし、一部の環境で役立つ新機能が追加されています。

Redis 6

Discourse では、キャッシュ、Sidekiq、MessageBus、分散ロック、レート制限など、多くの箇所で Redis を大規模に利用しています。これまで、Redis は非常に安定した選択肢であり続けてきました。

しかし、ごく特定のワークロードでは、Redis がボトルネックになる可能性があります。Redis はシングルスレッドであり、LUA スクリプトの影響により複数のインスタンスを使用できないため、このボトルネックを回避するのは困難でした。

幸いにも、Redis 6 では I/O 操作にスレッドプールを使用するサポートが追加されました。テストでは、Redis がボトルネックとなっている Discourse クラスターでも非常に良好に動作することが確認されています。

したがって、多数のCPU コアを搭載したマシンで動作しており、メトリクス で Redis が負荷処理に苦戦していることが示されている場合は、app.yml の params セクションで書き込み操作にスレッドを使用するオプションを有効にできます。

params:
  redis_io_threads: "4" # 1 は無効、n>1 は IO 書き込み用に n-1 個の追加スレッドを使用

イメージサイズの縮小

プロジェクトの初期段階では、技術に詳しくない人でも Discourse を実行できるようにし、必要な依存関係、バージョン管理、アップグレードなどをすべて処理できるようにするため、大型のコンテナイメージをリリースすることを選びました。

とはいえ、最近、圧縮済みイメージのサイズが 1GB を超えてしまい、これは少し大きすぎました。

そこで、イメージサイズの増大を抑制するため、イメージ内の Discourse ソースコードを完全コピーから、最新のバージョンのみを含む「shallow clone」に変更しました。

これにより、圧縮済みイメージのサイズが 25% 削減され、必要なサーバー容量が減少し、新しいイメージがリリースされた際の再ビルドが高速化されます。また、時間の経過に伴うイメージの成長も抑制されるはずです。

tests-passed/beta/stable 環境で、再ビルドと Web アップデートの両方においてテストを実施しましたが、標準的なパスには問題が発生しませんでした。ただし、app.yml のフックで特殊な git 操作を行っているユーザーは、カスタマイズ内容の調整が必要になる可能性があります。

「いいね!」 42

このような Redis のアップグレード後、ブラウザの体験にどのような影響がありますか?キャッシュされたアセットへの影響はありますか?アップグレードの結果、キャッシュは空になりますか?

「いいね!」 3

ありません。

アセットはローカルディスクまたはオブジェクトストレージに保存され、CDN でキャッシュされます。Redis はこれに影響しません。

Redis のデータはアップグレード中に保持されます。

「いいね!」 10

デフォルト値は何ですか?1ですか?

「いいね!」 5

はい。これは Redis 自身の設定ファイルから来ており、1 は旧バージョンのように単一スレッドを意味します。

「いいね!」 8

以下のようなケースが発生しました。

after_redis:
  - replace:
      filename: "/etc/redis/redis.conf"
      from: /^databases.*/
      to: "databases 50"

これにより再構築が失敗しています。エラーは以下の通りです。

25:M 01 Dec 2020 20:21:08.830 # FATAL: Data file was created with a Redis server configured to handle
 more than 16 databases. Exiting

データベース数の更新を、移行処理(または他の処理)が実行される前に行えるような別のフックは存在しませんか?

さて、一見失敗した再構築の後、Docker ログに以下のようなメッセージが表示されました。

chgrp: invalid group: 'syslog'
「いいね!」 2

なぜ1つ以上のデータベースが必要なのでしょうか?

「いいね!」 3

マルチサイト。単一の Redis を使用する複数のインスタンス。もっと汎用的な Redis コンテナを使うべきだったかもしれませんが、あなたのものを使うことにしました。

「いいね!」 2

:face_with_raised_eyebrow:

マルチサイトは単一のデータベースと標準の Redis キーネームスペースを使用しませんか?私の知る限り、Redis データベースは薄いレイヤーであり、境界を越えてコマンドが実行されるため、それに依存すべきではありません。

「いいね!」 6

はい、マルチサイトは 1 つのデータベースを使用します。

「いいね!」 3

ああ、なるほど。マルチサイトではなく、単一のマシン上で動作する複数のインスタンスそれぞれに個別の Redis が必要ということですね。デフォルトの 16 を 50 に増やしたのは、どの Redis データベースが使用中かを厳密に管理するのが面倒だったからです。

ということは、各インスタンスごとに別々の Redis コンテナを実行すべきということでしょうか?

「いいね!」 2

はい、そうしないと、インスタンス間で通信が混ざってしまう可能性があります。

「いいね!」 5

ああ、しまった。

幸いにも、これはテスト専用サーバーで学んだことです。

他のサイトについては、新しい Redis を用意してスケジュールされたタスクを捨ててしまうべきでしょうか?それともバックアップ/リストアを行うべきでしょうか?

参考までに、過去1年ほどでクロストークに関する問題は特に気づいていません。:man_shrugging: DB を設定する方法もあります。

編集:良い知らせですが、コンテナにアクセスして redis.conf を編集し、再起動すると再び動作するようになりました。

もし DISCOURSE_REDIS_DB: 12 に設定されたサイトがある Redis コンテナから別の Redis コンテナへ移行する方法についてヒントがあれば、ぜひ教えてください。あるいは、スケジュールされたジョブを気にしなくてもよいのでしょうか?

「いいね!」 3

その通りです。Discourse は Redis のフラッシュ程度では問題なく稼働し続けるべきです。一部の情報喪失は避けられませんが、致命的な問題ではありません。

「いいね!」 7

その通りだと思います。バックアップがそれを復元しようとする方法については知りませんが(知らないことがたくさんあります)。Redis のデータベースから別のデータベースへすべてのキーをコピーする方法として、https://stackoverflow.com/questions/23222616/copy-all-keys-from-one-db-to-another-in-redis のようなアプローチが取れるようですが、直後に実施したテストでも機能しているようです。ただし、新しい Redis コンテナを作成してそれを使用するようにプレイブックを調整する方がはるかに簡単でしょう。

ありがとうございます。

さて、これらの Redis をデータベースサーバー上で実行するか、ウェブサーバー上で実行するかを判断する必要があります。

「いいね!」 3

それでは、マルチサイト設定の db_id: 2 は何を指しているのでしょうか?

「いいね!」 2

廃止された設定です:

「いいね!」 5

LOL. はい、確かに混乱しますね!

ありがとう。私は「外部リバースプロキシなしで Let’s Encrypt を使用したマルチサイト構成」というトピックに取り組んでいます。それが終わったら、他のトピックも整理します。

「いいね!」 4

その後、すぐに Unicorn を再起動してスケジュールされたタスクを再作成するようにしてください。キューにあるものはすべて失われるため、これを行う適切なタイミングを見極める必要があります。

「いいね!」 6

これは現在も正常に動作していますか?圧縮済みイメージのサイズを簡単に確認するワンライナーコマンドはありますか?

「いいね!」 1