diff --git a/sentinel/sentinel.go b/sentinel/sentinel.go index 22e844a..acf109b 100644 --- a/sentinel/sentinel.go +++ b/sentinel/sentinel.go @@ -3,7 +3,9 @@ package sentinel import ( "errors" "fmt" + "log" "net" + "os" "strings" "sync" "time" @@ -54,6 +56,19 @@ import ( // }, // } // } + +type Config struct { + Debug bool `toml:"debug"` //调试开关(会在日志打印REDIS语句) + Username string `toml:"username"` //REDIS连接用户名 + Password string `toml:"password"` //REDIS连接用户密码 + MasterName string `toml:"mastername"` //REDIS主名称(一个哨兵集群可管理多个REDIS主从结构) + Sentinels string `toml:"sentinels"` //哨兵节点列表,逗号分隔,一般配置三个 + Wait bool `toml:"wait"` + MaxIdle int `toml:"max_idle"` + MaxActive int `toml:"max_active"` + IdleTimeout int `toml:"idle_timeout"` +} + type Sentinel struct { // Addrs is a slice with known Sentinel addresses. Addrs []string @@ -78,6 +93,60 @@ type Sentinel struct { addr string } +func NewPool(cfg Config) *redis.Pool { + var ( + masterName = cfg.MasterName + masterPassword = cfg.Password + sntnl = &Sentinel{ + Addrs: strings.Split(cfg.Sentinels, ","), + MasterName: masterName, + Dial: func(addr string) (redis.Conn, error) { + timeout := 1000 * time.Millisecond + c, err := redis.DialTimeout("tcp", addr, timeout, timeout, timeout) + if err != nil { + return nil, err + } + return c, nil + }, + } + ) + + return &redis.Pool{ + MaxIdle: cfg.MaxIdle, + MaxActive: cfg.MaxActive, + Wait: cfg.Wait, + IdleTimeout: time.Duration(cfg.IdleTimeout) * time.Second, + Dial: func() (redis.Conn, error) { + masterAddr, err := sntnl.MasterAddr() + if err != nil { + return nil, err + } + + c, err := redis.Dial("tcp", masterAddr) + if err != nil { + return nil, err + } + + okstr, err := redis.String(c.Do("AUTH", masterPassword)) + if err != nil { + return nil, fmt.Errorf("redis master AUTH failed: <%s>", err.Error()) + } else if okstr != "OK" { + return nil, fmt.Errorf("redis master AUTH failed: <%s>", okstr) + } + + if !TestRole(c, "master") { + c.Close() + return nil, fmt.Errorf("%s is not redis master", masterAddr) + } + + if cfg.Debug { + c = redis.NewLoggingConn(c, log.New(os.Stdout, "XXXXXXX", log.LstdFlags), "coreredis") + } + return c, nil + }, + } +} + // NoSentinelsAvailable is returned when all sentinels in the list are exhausted // (or none configured), and contains the last error returned by Dial (which // may be nil)