Nextcloudをロードバランシング

たいへん遅いマシンで動いているNextcloudの負荷を少しでも分散したいシリーズ。今回はロードバランシング。バックエンドのサーバは1台だけで、まったくロードバランスできてないけどロードバランス構成をとりたい。やりたいからやる。という話です。

ちゃんと書こうと思ってたけど、書いてみたら何をやったか結構忘れてて、後から読んだらわけがわからなそうな備忘録ができました。いつものことだ。

分散には成功したので、バックエンドのサーバは今後その気になれば増やせるけど、全体的な狙いはどちらかと言うと、なんでもやらせすぎな家サーバの負荷分散です。

ちょっと前に、dbサーバにWindowsマシンを投入しましたが、今回は、非力だけど家サーバよりは強いCPUを持ちSSDも積んだLinuxマシンを投入してウェブサーバとし、こいつにNextcloud本体の負荷(php-fpm)を丸投げします。

目標

以下の形を目指しました。

構成図
  • 新サーバはUbuntu22.04ltsのノート。CPUはCeleron 1000Mと、これまたどんくさいCPUを積んでますが、FreeBSDマシンよりは高速でメモリが8GB、SSDが1TBあるのでNextcloudしか動かさなければ軽そう。
  • ロードバランサはFreeBSD 13の家サーバ。CPUがAthron Neo N36Lの10年以上前のマシンですが、メモリは16GBでディスクは20TBくらい積んでる(ZFS)。これまでのNextcloudサーバそのもので、今後もルータでありファイルサーバでありトラブル時の代替サーバです。

やったこと

  1. 新サーバでテストインスタンスが動くとこまで持っていく。
    • phpモジュール等のインストールや設定が済んでないと引っ越しもできないため、 一番簡単な条件出しとして、実際に /var/www/nextcloud-test にサラからインストールして動かす。 
    • Nextcloudのインストールはこれの通りに普通にやる:

      Installation and server configuration — Nextcloud latest Administration Manual latest documentation

    • nginxはhttpのみに設定する(listenを443→80に)
    • phpは22.04の標準の8.1がNextcloud未対応ということで使えず、8.0を

      How to Install PHP 8.0 on Ubuntu 22.04 LTS - LinuxCapable

      に書いてあるとおりにしてインストール。
    • phpまわりのモジュールのインストールや設定はいろいろあるけど、まあドキュメントのとおりにやれば大丈夫。 
      • ただしメモリキャッシュは複数のNextcloudを動かすのに備え、APCuに加えRedisも使って分散キャッシュやファイルロックができるようにしておく。Redisはこれまでのサーバで動いてるのでこれを使う。
      • (ちなみにデータキャッシュはウェブサーバが1台だけならAPCuの内部キャッシュだけでよい。Redisが動いているのは、元サーバのNextcloudインストール時にドキュメントに書いてあるものを闇雲に全部動かしたため。同様の経緯でmemcachedも動かしたが、こちらはまったく不要なので今回止めた。)
      • php-fpmだけでなく、コマンドラインから使うoccなどがメモリキャッシュを使えるように(しないとエラーが出る)、/etc/php/8.0/mods-available/apcu.iniでapcまわりの設定をしておく。
  2. ロードバランサでのSSLアンロード & HTTP変換実験
    • これまでのサーバにはSSLアンロードとRedisサーバを担当してもらう。
    • httpのロードバランサ(リバースプロキシ)にはHAProxyとかあるけど、nginxのみの簡単な設定で行ける
    • 参考ドキュメント:

      How To Set Up Nginx Load Balancing with SSL Termination | DigitalOcean

    • このドキュメントはけっこう長いけど、それはSSLを動かすところやウェブサーバがロードバランサとしか通信しないようにするところなどに紙幅を割いているから。
    • ウチでは元のサーバでSSL自体は動いていたし、後背はイントラネットでロードバランサ=ウェブサーバ間のセキュリティはあまり考える気がないため、骨の骨の設定である "Virtual Host File And Upstream Module" という項の内容しか多分やってない。
      • これは本質的にはnginx.confで2箇所設定するだけ:
      • upstream mywebapp1 {
            server 10.130.227.11;
            server 10.130.227.22;
        }
      • server {
            listen 80;
            server_name example.com www.example.com;
        	
            location / {
                proxy_pass http://mywebapp1;
                proxy_set_header Host $host;
                proxy_set_header X-Real-IP $remote_addr;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                proxy_set_header X-Forwarded-Proto $scheme;
            }
        }
      • upstreamはserverに前置して設定する。
      • upstreamで設定した名前(この例ではmywebapp1)を server 内の location / のproxy_pass に渡す。
      • mywebappをhttp://でアクセスするのがキモ。たったこれだけとは!
    • Let's Encryptのワイルドカードな証明書を使っているので、既存インスタンスのホスト名をnextcloud、新サーバにリダイレクトするホスト名をnextcloud2として設定した
      • server項を書き足して既存のNextcloudインスタンスと分けて
      • upstreamとhttpで通信する
  3. 新サーバで旧サーバの環境をNFSマウントしてテスト。FreeBSDUbuntuhttpdを担うユーザーのデフォルトのUID/GIDが違ってて面倒だったが、Ubuntu側でFreeBSDと同じ80:80にして解決。これで解決してくれるUbuntuはすごく楽。もうそれなりに動く。
  4. 新サーバで旧サーバの環境をrsync(80GBに5、6時間かかった。Joplinの細かいファイル群が重い)で丸コピーしてテスト。ちゃんと動く。あとは、テストインスタンス側のconfig/config.phpのoverwrite関係だけが「設定」の「概要」にある「セキュリティ&セットアップ警告」に引っかかる状態。
  5. 旧サーバを止めてrsyncし直して(今度は4分しかかからず)切り替え。overwrite関連は、Reverse proxy — Nextcloud latest Administration Manual latest documentation の最後のとこにあるExampleとにらめっこして設定したので、「セキュリティ&セットアップ警告」も「すべてのチェックに合格しました。」となる。よしよし。
  6. すっかり安定して動いてると思ってたら、スマホアプリから写真がアップロードできず、さんざん悩んだ。 request entity too large とか言ってくる。
    • これはロードバランサのnginxでclient_max_body_size 512M; を入れてなかったため
    • ロードバランサはただ投げるだけかと思っていたら、デフォルトの制限などは効いてくるのでした。
    • 何が起きてるのかまったくわからなかったが、NextCloudで413エラーが表示される問題【Nginx】 というページで納得。
    • 手を抜いて安心してた場所でひどい目にあうのはいつものことだね…。

ともあれ完成です。あとはこれを丸コピーすれば複数のインスタンスで動かすことも可能。

感想

むちゃくちゃ速くなりました!…相対的には。

絶対的にはまだ微妙な性能です。Talkアプリをタップしてからチャンネル一覧が出るまで、たっぷり5秒かかる。以前は12秒くらいかかってたので人間的なスピードになったけど、まだ満足とは言い難い。

分散によって実験しやすくなったので、今後もいろいろ投入してみたい。

今後やりたいこと

これやりたい。

  • 新サーバが止まる時には元サーバを上げておきたい
  • 元サーバのNextcloudは普段は止めておくが、nginxの設定をいじるだけで動かせる状態にはしておきたい
  • というわけで、新旧サーバでファイルの同期は取っておく必要がある

から。

旧サーバのNextcloudインスタンスは新サーバにNFSマウントしてあり、そのままローカルファイルシステム同様にアクセス可能なため、同期そのものはrsyncで容易に取れるわけです。

Nextcloudの構成はwebサーバ、ストレージ、データベースから成る。ウェブサーバは今回設定し、データベースはdbサーバをそのまま使うので、あとはファイルの同期だけ取れば、すぐに復旧できる。

NFSのキャッシュを頑張るとか、Union FSを使うとか考えたんだけど、realtime rsyncでぐぐったら出てきたlsyncdが便利そう。lsyncdはディレクトリに変更があったら即座にrsyncを走らせて同期をとってくれるやつです。

ちょっと今週はもう時間がないけど、次はこれを入れようと思います。