Skip to content

Commit

Permalink
Prevent connections to replica on replica restart (#57)
Browse files Browse the repository at this point in the history
There is a brief period of time during a Redis replica restart when
HAProxy can send writes to it; causing the following error:

```
READONLY You can't write against a read only replica.
```

This is because HAProxy (< 3.1.0) always treats newly detected backends
as immediately UP - ready to serve traffic - UNTIL they failed their
checks. HAProxy v3.1.0 adds the ability to configure a backend's initial
state - init-state - and how/when it HAProxy determines that the backend
is ready to receive traffic.

This changes the HAProxy configuration so that a new Redis node is
disqualified from client receiving traffic until HAProxy determines that
the node is indeed a "master" node.

This also updates the default operator's HAProxy image accordingly to
receive the `init-state` HAProxy configuration option.

References:

- haproxy/haproxy#51
-
haproxy/haproxy@50322df
  • Loading branch information
indiebrain authored Dec 4, 2024
1 parent 1c0d2ec commit 83e73dc
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 44 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ Also check this project's [releases](https://github.com/powerhome/redis-operator

## Unreleased

### Changed

- **BREAKING** [HAProxy: avoid sending traffic to replicas on failover](https://github.com/powerhome/redis-operator/pull/57/). RedisFailovers using `haproxy:` must now use a HAProxy image of v3.1.0 or greater. The operator now uses HAProxy v3.1.0 by default.

## [v3.1.0] - 2024-09-05

- [Automatically recreate StatefulSet after volume expansion](https://github.com/powerhome/redis-operator/pull/55)
Expand Down
2 changes: 1 addition & 1 deletion api/redisfailover/v1/defaults.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ const (
defaultSentinelExporterImage = "leominov/redis_sentinel_exporter:1.7.1"
defaultExporterImage = "quay.io/oliver006/redis_exporter:v1.57.0"
defaultImage = "redis:7.2.4-alpine"
defaultHAProxyImage = "haproxy:2.9.6"
defaultHAProxyImage = "haproxy:3.1.0"
defaultRedisPort = 6379
)

Expand Down
87 changes: 44 additions & 43 deletions operator/redisfailover/service/generator.go
Original file line number Diff line number Diff line change
Expand Up @@ -134,49 +134,50 @@ func generateHAProxyRedisMasterConfigmap(rf *redisfailoverv1.RedisFailover, labe
labels = util.MergeLabels(labels, generateSelectorLabels("haproxy", rf.Name), generateRedisMasterRoleLabel())

port := rf.Spec.Redis.Port
haproxyCfg := fmt.Sprintf(`global
daemon
maxconn 5000
defaults
mode tcp
timeout connect 5000ms
timeout client 50000ms
timeout server 50000ms
timeout check 5000ms
frontend http
bind :8080
default_backend stats
backend stats
mode http
stats enable
stats uri /
stats refresh 1s
stats show-legends
stats admin if TRUE
resolvers k8s
parse-resolv-conf
hold other 10s
hold refused 10s
hold nx 10
hold timeout 10s
hold valid 10s
hold obsolete 10s
frontend redis-master
bind *:%d
default_backend redis-master
backend redis-master
mode tcp
balance first
option tcp-check
tcp-check send info\ replication\r\n
tcp-check expect string role:master
server-template redis %d _redis._tcp.%s.%s.svc.cluster.local:%d check inter 1s resolvers k8s init-addr none
haproxyCfg := fmt.Sprintf(`
global
daemon
maxconn 5000
defaults
mode tcp
timeout connect 5000ms
timeout client 50000ms
timeout server 50000ms
timeout check 5000ms
frontend http
bind :8080
default_backend stats
backend stats
mode http
stats enable
stats uri /
stats refresh 1s
stats show-legends
stats admin if TRUE
resolvers k8s
parse-resolv-conf
hold other 10s
hold refused 10s
hold nx 10
hold timeout 10s
hold valid 10s
hold obsolete 10s
frontend redis-master
bind *:%d
default_backend redis-master
backend redis-master
mode tcp
balance first
option tcp-check
tcp-check send info\ replication\r\n
tcp-check expect string role:master
server-template redis %d _redis._tcp.%s.%s.svc.cluster.local:%d check inter 1s resolvers k8s init-addr none init-state down
`, port, rf.Spec.Redis.Replicas, redisName, namespace, port)

if rf.Spec.Haproxy.CustomConfig != "" {
Expand Down

0 comments on commit 83e73dc

Please sign in to comment.