mirror of
https://github.com/redis/go-redis.git
synced 2025-07-29 17:41:15 +03:00
Resent client pool when sentinel switches master
This commit is contained in:
106
sentinel.go
106
sentinel.go
@ -132,7 +132,6 @@ func (c *sentinelClient) Sentinels(name string) *SliceCmd {
|
||||
}
|
||||
|
||||
type sentinelFailover struct {
|
||||
masterName string
|
||||
sentinelAddrs []string
|
||||
|
||||
opt *Options
|
||||
@ -140,8 +139,10 @@ type sentinelFailover struct {
|
||||
pool *pool.ConnPool
|
||||
poolOnce sync.Once
|
||||
|
||||
mu sync.RWMutex
|
||||
sentinel *sentinelClient
|
||||
mu sync.RWMutex
|
||||
masterName string
|
||||
_masterAddr string
|
||||
sentinel *sentinelClient
|
||||
}
|
||||
|
||||
func (d *sentinelFailover) Close() error {
|
||||
@ -168,17 +169,30 @@ func (d *sentinelFailover) MasterAddr() (string, error) {
|
||||
d.mu.Lock()
|
||||
defer d.mu.Unlock()
|
||||
|
||||
addr, err := d.masterAddr()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if d._masterAddr != addr {
|
||||
d.switchMaster(addr)
|
||||
}
|
||||
|
||||
return addr, nil
|
||||
}
|
||||
|
||||
func (d *sentinelFailover) masterAddr() (string, error) {
|
||||
// Try last working sentinel.
|
||||
if d.sentinel != nil {
|
||||
addr, err := d.sentinel.GetMasterAddrByName(d.masterName).Result()
|
||||
if err != nil {
|
||||
internal.Logf("sentinel: GetMasterAddrByName %q failed: %s", d.masterName, err)
|
||||
d._resetSentinel()
|
||||
} else {
|
||||
if err == nil {
|
||||
addr := net.JoinHostPort(addr[0], addr[1])
|
||||
internal.Logf("sentinel: %q addr is %s", d.masterName, addr)
|
||||
internal.Logf("sentinel: master=%q addr=%q", d.masterName, addr)
|
||||
return addr, nil
|
||||
}
|
||||
|
||||
internal.Logf("sentinel: GetMasterAddrByName name=%q failed: %s", d.masterName, err)
|
||||
d._resetSentinel()
|
||||
}
|
||||
|
||||
for i, sentinelAddr := range d.sentinelAddrs {
|
||||
@ -193,25 +207,36 @@ func (d *sentinelFailover) MasterAddr() (string, error) {
|
||||
PoolTimeout: d.opt.PoolTimeout,
|
||||
IdleTimeout: d.opt.IdleTimeout,
|
||||
})
|
||||
|
||||
masterAddr, err := sentinel.GetMasterAddrByName(d.masterName).Result()
|
||||
if err != nil {
|
||||
internal.Logf("sentinel: GetMasterAddrByName %q failed: %s", d.masterName, err)
|
||||
internal.Logf("sentinel: GetMasterAddrByName master=%q failed: %s", d.masterName, err)
|
||||
sentinel.Close()
|
||||
continue
|
||||
}
|
||||
|
||||
// Push working sentinel to the top.
|
||||
d.sentinelAddrs[0], d.sentinelAddrs[i] = d.sentinelAddrs[i], d.sentinelAddrs[0]
|
||||
|
||||
d.setSentinel(sentinel)
|
||||
|
||||
addr := net.JoinHostPort(masterAddr[0], masterAddr[1])
|
||||
internal.Logf("sentinel: %q addr is %s", d.masterName, addr)
|
||||
return addr, nil
|
||||
}
|
||||
|
||||
return "", errors.New("redis: all sentinels are unreachable")
|
||||
}
|
||||
|
||||
func (d *sentinelFailover) switchMaster(masterAddr string) {
|
||||
internal.Logf(
|
||||
"sentinel: new master=%q addr=%q",
|
||||
d.masterName, masterAddr,
|
||||
)
|
||||
_ = d.Pool().Filter(func(cn *pool.Conn) bool {
|
||||
return cn.RemoteAddr().String() != masterAddr
|
||||
})
|
||||
d._masterAddr = masterAddr
|
||||
}
|
||||
|
||||
func (d *sentinelFailover) setSentinel(sentinel *sentinelClient) {
|
||||
d.discoverSentinels(sentinel)
|
||||
d.sentinel = sentinel
|
||||
@ -219,25 +244,25 @@ func (d *sentinelFailover) setSentinel(sentinel *sentinelClient) {
|
||||
}
|
||||
|
||||
func (d *sentinelFailover) resetSentinel() error {
|
||||
var err error
|
||||
d.mu.Lock()
|
||||
err := d._resetSentinel()
|
||||
if d.sentinel != nil {
|
||||
err = d._resetSentinel()
|
||||
}
|
||||
d.mu.Unlock()
|
||||
return err
|
||||
}
|
||||
|
||||
func (d *sentinelFailover) _resetSentinel() error {
|
||||
var err error
|
||||
if d.sentinel != nil {
|
||||
err = d.sentinel.Close()
|
||||
d.sentinel = nil
|
||||
}
|
||||
err := d.sentinel.Close()
|
||||
d.sentinel = nil
|
||||
return err
|
||||
}
|
||||
|
||||
func (d *sentinelFailover) discoverSentinels(sentinel *sentinelClient) {
|
||||
sentinels, err := sentinel.Sentinels(d.masterName).Result()
|
||||
if err != nil {
|
||||
internal.Logf("sentinel: Sentinels %q failed: %s", d.masterName, err)
|
||||
internal.Logf("sentinel: Sentinels master=%q failed: %s", d.masterName, err)
|
||||
return
|
||||
}
|
||||
for _, sentinel := range sentinels {
|
||||
@ -248,8 +273,8 @@ func (d *sentinelFailover) discoverSentinels(sentinel *sentinelClient) {
|
||||
sentinelAddr := vals[i+1].(string)
|
||||
if !contains(d.sentinelAddrs, sentinelAddr) {
|
||||
internal.Logf(
|
||||
"sentinel: discovered new %q sentinel: %s",
|
||||
d.masterName, sentinelAddr,
|
||||
"sentinel: discovered new sentinel=%q for master=%q",
|
||||
sentinelAddr, d.masterName,
|
||||
)
|
||||
d.sentinelAddrs = append(d.sentinelAddrs, sentinelAddr)
|
||||
}
|
||||
@ -258,34 +283,6 @@ func (d *sentinelFailover) discoverSentinels(sentinel *sentinelClient) {
|
||||
}
|
||||
}
|
||||
|
||||
// closeOldConns closes connections to the old master after failover switch.
|
||||
func (d *sentinelFailover) closeOldConns(newMaster string) {
|
||||
// Good connections that should be put back to the pool. They
|
||||
// can't be put immediately, because pool.PopFree will return them
|
||||
// again on next iteration.
|
||||
cnsToPut := make([]*pool.Conn, 0)
|
||||
|
||||
for {
|
||||
cn := d.pool.PopFree()
|
||||
if cn == nil {
|
||||
break
|
||||
}
|
||||
if cn.RemoteAddr().String() != newMaster {
|
||||
internal.Logf(
|
||||
"sentinel: closing connection to the old master %s",
|
||||
cn.RemoteAddr(),
|
||||
)
|
||||
d.pool.Remove(cn)
|
||||
} else {
|
||||
cnsToPut = append(cnsToPut, cn)
|
||||
}
|
||||
}
|
||||
|
||||
for _, cn := range cnsToPut {
|
||||
d.pool.Put(cn)
|
||||
}
|
||||
}
|
||||
|
||||
func (d *sentinelFailover) listen(sentinel *sentinelClient) {
|
||||
var pubsub *PubSub
|
||||
for {
|
||||
@ -312,17 +309,16 @@ func (d *sentinelFailover) listen(sentinel *sentinelClient) {
|
||||
case "+switch-master":
|
||||
parts := strings.Split(msg.Payload, " ")
|
||||
if parts[0] != d.masterName {
|
||||
internal.Logf("sentinel: ignore new %s addr", parts[0])
|
||||
internal.Logf("sentinel: ignore addr for master=%q", parts[0])
|
||||
continue
|
||||
}
|
||||
|
||||
addr := net.JoinHostPort(parts[3], parts[4])
|
||||
internal.Logf(
|
||||
"sentinel: new %q addr is %s",
|
||||
d.masterName, addr,
|
||||
)
|
||||
|
||||
d.closeOldConns(addr)
|
||||
d.mu.Lock()
|
||||
if d._masterAddr != addr {
|
||||
d.switchMaster(addr)
|
||||
}
|
||||
d.mu.Unlock()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user