외부 Redis 연결 오류

커뮤니티 여러분 안녕하세요,

저희는 Kubernetes 환경에서 Discourse를 운영 중입니다. 외부 Redis와 외부 PostgreSQL을 사용하면서 Discourse 컨테이너 이미지를 기반으로 배포(deployment)를 실행하고 있습니다.
Redis HA를 관리하기 위해 Sentinel로 관리되는 StatefulSet 내에 3개의 노드를 배포했습니다. 또한, Discourse와 Redis 사이에 다음과 같은 설정의 HAProxy 배포를 추가했습니다:

global
      log stdout format raw local0
      maxconn 102400
      maxsessrate 500
      maxconnrate 2000
      maxsslrate 2000

    resolvers mydns
      parse-resolv-conf
      hold valid 5s
      accepted_payload_size 8192

    defaults
      log global
      mode tcp
      timeout client 2h
      timeout connect 360s
      timeout server 2h
      default-server init-addr none
      retries 3

    frontend stats
        bind *:1024
        mode http
        http-request use-service prometheus-exporter if { path /metrics }
        stats enable
        stats uri /stats
        stats refresh 10s

    listen redis_master
      bind *:6379
      mode tcp

      option tcp-check
      tcp-check connect
      tcp-check send AUTH\ XXXXXXXXXXX\r\n
      tcp-check expect string +OK
      tcp-check send PING\r\n
      tcp-check expect string +PONG
      tcp-check send info\ replication\r\n
      tcp-check expect string role:master
      tcp-check send QUIT\r\n
      tcp-check expect string +OK
      server redis_node_0 discoursev2-redis-node-0.discoursev2-redis-headless.discoursev2.svc.cluster.local:6379 resolvers mydns check inter 1s fall 1 rise 1
      server redis_node_1 discoursev2-redis-node-1.discoursev2-redis-headless.discoursev2.svc.cluster.local:6379 resolvers mydns check inter 1s fall 1 rise 1
      server redis_node_2 discoursev2-redis-node-2.discoursev2-redis-headless.discoursev2.svc.cluster.local:6379 resolvers mydns check inter 1s fall 1 rise 1

    listen redis_slave
      bind *:6380
      mode tcp
      option tcp-check
      tcp-check connect
      tcp-check send AUTH\ cUvNwwd4ujTbqshTbYjeTTrX8tDlKAcYvvAUOGuk\r\n
      tcp-check expect string +OK
      tcp-check send PING\r\n
      tcp-check expect string +PONG
      tcp-check send QUIT\r\n
      tcp-check expect string +OK
      server redis_node_0 discoursev2-redis-node-0.discoursev2-redis-headless.discoursev2.svc.cluster.local:6379 resolvers mydns check inter 1s fall 1 rise 1
      server redis_node_1 discoursev2-redis-node-1.discoursev2-redis-headless.discoursev2.svc.cluster.local:6379 resolvers mydns check inter 1s fall 1 rise 1
      server redis_node_2 discoursev2-redis-node-2.discoursev2-redis-headless.discoursev2.svc.cluster.local:6379 resolvers mydns check inter 1s fall 1 rise 1

저희가 겪는 문제는 Discourse 배포에 롤아웃(rollout)을 수행할 때마다 Unicorn 스레드가 Redis에 연결하지 못한다는 것입니다. 연결을 재시도하며, 시간이 좀 지나면 결국 모든 스레드가 연결됩니다. 로그에서 확인되는 몇 가지 오류는 다음과 같습니다:

/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/redis-4.8.1/lib/redis/client.rb:398:in `rescue in establish_connection'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/unicorn-6.1.0/lib/unicorn/http_server.rb:684:in `init_worker_process'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/unicorn-6.1.0/lib/unicorn/http_server.rb:547:in `spawn_missing_workers'
config/unicorn.conf.rb:299:in `block in reload'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/unicorn-6.1.0/lib/unicorn/http_server.rb:721:in `worker_loop'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/redis-4.8.1/lib/redis/client.rb:379:in `establish_connection'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/redis-4.8.1/lib/redis/client.rb:115:in `block in connect'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/redis-4.8.1/lib/redis/client.rb:295:in `reconnect'
/var/www/discourse/lib/discourse.rb:906:in `after_fork'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/unicorn-6.1.0/bin/unicorn:128:in `<top (required)>'
/var/www/discourse/vendor/bundle/ruby/3.3.0/bin/unicorn:25:in `<main>'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/redis-4.8.1/lib/redis/client.rb:344:in `with_reconnect'
E, [2024-07-24T15:42:22.524194 #531] ERROR -- : Error connecting to Redis on discoursev2-haproxy.discoursev2.svc.cluster.local:6379 (Socket::ResolutionError) (Redis::CannotConnectError)
/var/www/discourse/lib/discourse_redis.rb:217:in `reconnect'
/var/www/discourse/vendor/bundle/ruby/3.3.0/bin/unicorn:25:in `load'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/redis-4.8.1/lib/redis/client.rb:114:in `connect'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/unicorn-6.1.0/lib/unicorn/http_server.rb:143:in `start'
I, [2024-07-24T15:42:23.499254 #422]  INFO -- : Loading Sidekiq in process id 422
2024-07-24 15:42:23 +0000: Starting Prometheus global reporter pid: 439
Booting Sidekiq 6.5.12 with Sidekiq::RedisConnection::RedisAdapter options {:host=>"discoursev2-haproxy.discoursev2.svc.cluster.local", :port=>6379, :password=>"REDACTED", :namespace=>"sidekiq"}
E, [2024-07-24T15:42:23.530765 #810] ERROR -- : Error connecting to Redis on discoursev2-haproxy.discoursev2.svc.cluster.local:6379 (Socket::ResolutionError) (Redis::CannotConnectError)
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/redis-4.8.1/lib/redis/client.rb:398:in `rescue in establish_connection'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/redis-4.8.1/lib/redis/client.rb:115:in `block in connect'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/unicorn-6.1.0/lib/unicorn/http_server.rb:684:in `init_worker_process'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/unicorn-6.1.0/lib/unicorn/http_server.rb:547:in `spawn_missing_workers'
/var/www/discourse/vendor/bundle/ruby/3.3.0/bin/unicorn:25:in `<main>'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/redis-4.8.1/lib/redis/client.rb:344:in `with_reconnect'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/redis-4.8.1/lib/redis/client.rb:295:in `reconnect'
config/unicorn.conf.rb:299:in `block in reload'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/redis-4.8.1/lib/redis/client.rb:379:in `establish_connection'
/var/www/discourse/lib/discourse.rb:906:in `after_fork'
/var/www/discourse/vendor/bundle/ruby/3.3.0/bin/unicorn:25:in `load'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/unicorn-6.1.0/bin/unicorn:128:in `<top (required)>'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/redis-4.8.1/lib/redis/client.rb:114:in `connect'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/unicorn-6.1.0/lib/unicorn/http_server.rb:721:in `worker_loop'
/var/www/discourse/lib/discourse_redis.rb:217:in `reconnect'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/unicorn-6.1.0/lib/unicorn/http_server.rb:143:in `start'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/unicorn-6.1.0/lib/unicorn/http_server.rb:143:in `start'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/redis-4.8.1/lib/redis/client.rb:344:in `with_reconnect'
config/unicorn.conf.rb:299:in `block in reload'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/redis-4.8.1/lib/redis/client.rb:398:in `rescue in establish_connection'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/redis-4.8.1/lib/redis/client.rb:379:in `establish_connection'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/redis-4.8.1/lib/redis/client.rb:295:in `reconnect'
/var/www/discourse/lib/discourse_redis.rb:217:in `reconnect'
E, [2024-07-24T15:42:24.540440 #887] ERROR -- : Error connecting to Redis on discoursev2-haproxy.discoursev2.svc.cluster.local:6379 (Socket::ResolutionError) (Redis::CannotConnectError)

HAProxy를 제거하고 Redis 마스터 노드에 직접 연결하도록 설정하여 테스트해 보았지만, 동일한 문제를 관찰했습니다. 또한, Discourse와 Redis 사이의 Istio 게이트웨이를 비활성화했습니다. 이 두 시나리오 모두에서 시간이 좀 지나면 모든 Unicorn 스레드가 Redis에 연결을 확립할 수 있었습니다.

이 문제에 대해 조언을 주실 수 있는 분이 있을까요? Redis에 특별한 설정이 필요한가요? 현재 저희의 설정은 다음과 같습니다:

appendonly yes
appendfsync no
aof-rewrite-incremental-fsync yes
save ""

마지막으로, 다음 사항에 대해 알고 싶습니다:

  1. Redis를 HA 모드로 구성하는 권장 방법은 무엇인가요? 저희가 아는 바로는 Redis 클러스터는 지원되지 않습니다.
  2. 단일 Redis 노드 구성을 사용하는 경우, Redis가 몇 초간 손실되면 어떤 결과가 발생합니까? Redis가 상태 없는(stateless) 구성으로 변경되어 재시작할 때마다 모든 정보를 잃게 될 경우, Discourse가 콘텐츠를 다시 채워 넣(replicate)을 할까요?

미리 감사드립니다.

커뮤니티 여러분 안녕하세요,

Kubernetes 환경에서의 Discourse 설정과 관련하여, 배포 롤아웃 시 Unicorn 스레드와 Redis 사이의 연결 문제와 관련해 이전 게시글에 이어서 말씀드리고자 합니다. HAProxy 제거 및 Istio 게이트웨이 비활성화를 포함한 다양한 구성을 시도해 보았지만, 문제가 여전히 지속되고 있습니다.

이 문제를 해결하기 위한 가이드나 권장 사항을 제공해 주시면 감사하겠습니다. 구체적으로 다음과 같은 사항에 대해 알고 싶습니다:

  1. 우리의 설정을 지원하기 위해 Redis에 특별한 구성이 필요한가요?
  2. Redis Cluster가 지원되지 않는 점을 고려할 때, Redis의 높은 가용성(High Availability)을 보장하기 위한 권장 접근 방식은 무엇인가요?
  3. 단일 Redis 노드 구성을 선택할 경우, 짧은 시간의 Redis 장애가 어떤 영향을 미치나요? 모든 데이터가 재시작 시 손실되는 무상태(stateless) Redis 환경에서 Discourse가 데이터를 다시 채워 넣(replicate)을 수 있나요?

이 문제를 해결하기 위해 계속 노력하고 있는 중이므로, 여러분의 통찰력이 매우 소중합니다.

미리 도움을 주셔서 감사합니다.