redis-哨兵模式配置整理

redis-哨兵模式配置整理

  • 哨兵模式概述
  • 核心架构组成
    • [1. 哨兵节点 (Sentinel)](#1. 哨兵节点 (Sentinel))
    • [2. 数据节点](#2. 数据节点)
  • 哨兵工作机制详解
    • [1. 监控机制](#1. 监控机制)
  • 故障转移详细流程
    • [1. 故障发现阶段](#1. 故障发现阶段)
  • 配置详解
    • [1. 基本哨兵配置(通常位于/etc/redis/sentinel.conf)](#1. 基本哨兵配置(通常位于/etc/redis/sentinel.conf))
    • [2. 关键参数说明](#2. 关键参数说明)
  • [启动 Sentinel 监控有几种方式](#启动 Sentinel 监控有几种方式)
    • [1. 使用 redis-sentinel 命令启动](#1. 使用 redis-sentinel 命令启动)
    • [2. 使用 redis-server 命令启动](#2. 使用 redis-server 命令启动)
    • [3. 完整的启动脚本示例](#3. 完整的启动脚本示例)
    • [4. 验证哨兵状态](#4. 验证哨兵状态)
    • [5. 停止哨兵服务](#5. 停止哨兵服务)
  • 业务中连接方式
    • [1. 自动发现机制](#1. 自动发现机制)
    • [2. 连接状态管理](#2. 连接状态管理)
  • 部署最佳实践
    • [1. 哨兵节点部署方案](#1. 哨兵节点部署方案)
    • [2. 一种可行的网络拓扑方式](#2. 一种可行的网络拓扑方式)
  • 故障场景分析
    • [1. 主节点故障](#1. 主节点故障)
    • [2. 网络分区场景](#2. 网络分区场景)
  • 监控与运维
    • [1. 关键监控指标](#1. 关键监控指标)
    • [2. 日常运维命令](#2. 日常运维命令)
  • 优缺点分析
  • [Redis Sentinel 自动发现机制的 Lua 实现](#Redis Sentinel 自动发现机制的 Lua 实现)
    • [完整的 Lua 实现方案](#完整的 Lua 实现方案)
      • [1. 核心 Sentinel 发现类](#1. 核心 Sentinel 发现类)
      • [2. 连接池管理](#2. 连接池管理)
      • [3. 使用示例和配置](#3. 使用示例和配置)
      • [4. 应用层封装](#4. 应用层封装)
      • [5. 故障转移处理增强](#5. 故障转移处理增强)
    • 核心特性说明
  • 另一种基于skyent框架实现示例

哨兵模式概述

Redis 哨兵(Sentinel)是 Redis 官方提供的高可用性解决方案,用于管理 Redis主从架构,实现自动故障检测和故障转移

核心架构组成

1. 哨兵节点 (Sentinel)

bash 复制代码
# 哨兵节点配置示例
port 26379
sentinel monitor mymaster 127.0.0.1 6379 2
sentinel down-after-milliseconds mymaster 5000
sentinel failover-timeout mymaster 60000
sentinel parallel-syncs mymaster 1

2. 数据节点

  • 主节点 (Master):处理写操作和读操作
  • 从节点 (Slave):复制主节点数据,处理读操作

哨兵工作机制详解

1. 监控机制

  1. 可以配置N个哨兵节点只需要监控主节点 - 哨兵会自动发现主节点下的所有从节点
  2. 例如可以在同一机器上启动多个哨兵 - 使用不同端口即可(26379、26380、26381),但线上不建议,因为一旦机器挂掉则对应的监控哨兵都会挂掉
  3. 配置方式 - 每个哨兵配置文件都指向同一个主节点即可

故障转移详细流程

1. 故障发现阶段

配置详解

1. 基本哨兵配置(通常位于/etc/redis/sentinel.conf)

bash 复制代码
# sentinel.conf
port 26379
daemonize yes
pidfile /var/run/redis-sentinel.pid # 每个哨兵用不同的pid文件
logfile "/var/log/redis/sentinel.log" # 每个哨兵用不同的日志文件

# 监控配置
sentinel monitor mymaster 192.168.1.100 6379 2 
sentinel down-after-milliseconds mymaster 5000
sentinel failover-timeout mymaster 60000
sentinel parallel-syncs mymaster 1

# 密码认证(如有)
sentinel auth-pass mymaster MyPassword

其中:

mymaster是给主节点起的名字,2表示至少需要2个哨兵同意才能判断主节点客观下线。例如有三个哨兵,所以通常设置为2(多数原则)

重要提醒:
1. 关键问题 :注意添加的sentinel_XXX.conf,不可以出现相同的 sentinel myid 会导致哨兵无法相互识别
2. 自动生成内容 :哨兵启动后会自动在配置文件中添加运行时信息,不要手动修改这些内容
3. 启动顺序 :先启动Redis主从,再启动哨兵
4. 等待时间:给哨兵足够的时间进行相互发现(30-60秒)

如果出现因为myid相同知道哨兵节点无法互相识别,将对应配置中的最后一部分删掉,然后重新启动既可以:从 "# Generated by CONFIG REWRITE" 开始到文件末尾的所有内容

2. 关键参数说明

参数 默认值 说明
down-after-milliseconds 30000 主观下线判定时间
failover-timeout 180000 故障转移超时时间
parallel-syncs 1 同时同步的从节点数
quorum 2 客观下线所需票数

启动 Sentinel 监控有几种方式

1. 使用 redis-sentinel 命令启动

bash 复制代码
# 分别启动三个哨兵
redis-sentinel /path/to/sentinel1.conf
redis-sentinel /path/to/sentinel2.conf
redis-sentinel /path/to/sentinel3.conf

2. 使用 redis-server 命令启动

bash 复制代码
# 也可以使用 redis-server 命令
redis-server /path/to/sentinel1.conf --sentinel
redis-server /path/to/sentinel2.conf --sentinel
redis-server /path/to/sentinel3.conf --sentinel

# 后台启动
redis-server /path/to/sentinel1.conf --sentinel --daemonize yes

3. 完整的启动脚本示例

bash 复制代码
#!/bin/bash

SENTINEL_CONF_DIR="/etc/redis/sentinel"
SENTINEL_PORTS=(26379 26380 26381)

for port in "${SENTINEL_PORTS[@]}"; do
    config_file="${SENTINEL_CONF_DIR}/sentinel-${port}.conf"
    echo "启动哨兵端口: $port, 配置文件: $config_file"
    redis-sentinel $config_file --daemonize yes
done

echo "所有哨兵节点启动完成"

4. 验证哨兵状态

bash 复制代码
# 连接哨兵查看信息
redis-cli -p 26379
127.0.0.1:26379> info sentinel

# 或者查看主节点信息
127.0.0.1:26379> sentinel masters
127.0.0.1:26379> sentinel slaves mymaster  # 查看从节点
127.0.0.1:26379> sentinel sentinels mymaster  # 查看其他哨兵

5. 停止哨兵服务

bash 复制代码
# 查看进程
ps aux | grep redis-sentinel

# 优雅停止
redis-cli -p 26379 shutdown
redis-cli -p 26380 shutdown
redis-cli -p 26381 shutdown

重要提醒

  1. 确保配置文件路径正确
  2. 每个哨兵使用不同的端口和pid文件
  3. 检查防火墙规则,确保哨兵节点之间可以通信
  4. 查看日志文件确认启动是否成功

启动后,哨兵会自动相互发现并组成哨兵集群来监控你的Redis主从架构,可以进入到对应的哨兵端口,使用info sentinel查看sentinels=X, 其中X为哨兵集群中的哨兵数量

业务中连接方式

1. 自动发现机制

java 复制代码
// Java客户端示例
Set<String> sentinels = new HashSet<>();
sentinels.add("192.168.1.10:26379");
sentinels.add("192.168.1.11:26379");
sentinels.add("192.168.1.12:26379");

JedisSentinelPool pool = new JedisSentinelPool("mymaster", sentinels);
try (Jedis jedis = pool.getResource()) {
    jedis.set("key", "value");
}

2. 连接状态管理

部署最佳实践

1. 哨兵节点部署方案

bash 复制代码
# 推荐部署奇数个哨兵节点
节点分布:
- 哨兵1: 192.168.1.10:26379
- 哨兵2: 192.168.1.11:26379  
- 哨兵3: 192.168.1.12:26379

# 数据节点
- 主节点: 192.168.1.100:6379
- 从节点1: 192.168.1.101:6379
- 从节点2: 192.168.1.102:6379

2. 一种可行的网络拓扑方式

故障场景分析

1. 主节点故障

bash 复制代码
# 故障转移日志示例
1. +sdown master mymaster 192.168.1.100 6379
2. +odown master mymaster 192.168.1.100 6379
3. +vote-for-leader sentinel1 1
4. +elected-leader master mymaster
5. +failover-state-select-slave master mymaster
6. +selected-slave slave 192.168.1.101:6379
7. +failover-state-send-slaveof-noone
8. +failover-state-wait-promotion
9. +promoted-slave slave 192.168.1.101:6379
10. +failover-state-reconf-slaves
11. +switch-master mymaster 192.168.1.100 6379 192.168.1.101 6379

2. 网络分区场景

监控与运维

1. 关键监控指标

bash 复制代码
# 查看哨兵状态
redis-cli -p 26379 info sentinel

# 监控指标
sentinel_masters:1
sentinel_tilt:0
sentinel_running_scripts:0
sentinel_scripts_queue_length:0
sentinel_simulate_failure_flags:0

2. 日常运维命令

bash 复制代码
# 查看主节点信息
redis-cli -p 26379 sentinel get-master-addr-by-name mymaster

# 手动故障转移
redis-cli -p 26379 sentinel failover mymaster

# 查看从节点信息
redis-cli -p 26379 sentinel slaves mymaster

# 添加监控
redis-cli -p 26379 sentinel monitor newmaster 192.168.1.200 6379 2

优缺点分析

优点 ✅
1. 自动故障转移 :无需人工干预
2. 配置中心 :客户端自动发现主节点
3. 监控完备 :全面的节点健康检查
4. 官方支持:Redis 官方维护,稳定性高

缺点 ❌
1. 写操作单点 :主节点仍然是写瓶颈
2. 数据一致性 :异步复制可能导致数据丢失
3. 配置复杂 :需要正确配置多个参数
4. 资源消耗:需要额外的哨兵节点

Redis Sentinel 自动发现机制的 Lua 实现

完整的 Lua 实现方案

1. 核心 Sentinel 发现类

lua 复制代码
local redis = require("resty.redis")
local cjson = require("cjson")

local RedisSentinel = {}
RedisSentinel.__index = RedisSentinel

function RedisSentinel.new(sentinels, master_name, options)
    local self = setmetatable({}, RedisSentinel)
    self.sentinel_hosts = sentinels or {}
    self.master_name = master_name or "mymaster"
    self.options = options or {}
    self.current_master = nil
    self.sentinel_timeout = self.options.timeout or 1000  -- 毫秒
    self.retry_count = self.options.retry_count or 3
    self.connection_pool = {}
    return self
end

-- 从 Sentinel 获取当前主节点信息
function RedisSentinel:get_master_from_sentinel(sentinel_host)
    local red = redis:new()
    red:set_timeout(self.sentinel_timeout)
    
    local ok, err = red:connect(sentinel_host.host, sentinel_host.port)
    if not ok then
        return nil, "Failed to connect to sentinel: " .. err
    end
    
    -- 如果配置了密码
    if sentinel_host.password then
        local auth_ok, auth_err = red:auth(sentinel_host.password)
        if not auth_ok then
            red:close()
            return nil, "Sentinel auth failed: " .. auth_err
        end
    end
    
    -- 查询主节点信息
    local res, err = red:command("sentinel", "get-master-addr-by-name", self.master_name)
    if not res or type(res) ~= "table" or #res < 2 then
        red:close()
        return nil, "Failed to get master from sentinel: " .. (err or "invalid response")
    end
    
    red:close()
    
    return {
        host = res[1],
        port = tonumber(res[2])
    }
end

-- 自动发现主节点(轮询所有 Sentinel)
function RedisSentinel:discover_master()
    for i = 1, self.retry_count do
        for _, sentinel in ipairs(self.sentinel_hosts) do
            local master, err = self:get_master_from_sentinel(sentinel)
            if master then
                -- 验证主节点是否可用
                local is_alive, valid_err = self:validate_master(master)
                if is_alive then
                    self.current_master = master
                    return master
                else
                    ngx.log(ngx.WARN, "Master validation failed: ", valid_err)
                end
            else
                ngx.log(ngx.WARN, "Sentinel ", sentinel.host, ":", sentinel.port, " failed: ", err)
            end
        end
        
        -- 所有 Sentinel 都失败,等待后重试
        if i < self.retry_count then
            ngx.sleep(0.1)  -- 等待 100ms 后重试
        end
    end
    
    return nil, "All sentinels failed after " .. self.retry_count .. " retries"
end

-- 验证主节点是否可用
function RedisSentinel:validate_master(master)
    local red = redis:new()
    red:set_timeout(1000)  -- 1秒超时
    
    local ok, err = red:connect(master.host, master.port)
    if not ok then
        return false, "Connect failed: " .. err
    end
    
    -- 如果配置了密码
    if self.options.password then
        local auth_ok, auth_err = red:auth(self.options.password)
        if not auth_ok then
            red:close()
            return false, "Auth failed: " .. auth_err
        end
    end
    
    -- 执行 PING 命令验证
    local pong, ping_err = red:ping()
    if not pong then
        red:close()
        return false, "Ping failed: " .. ping_err
    end
    
    red:close()
    return true
end

-- 获取当前主节点连接
function RedisSentinel:get_master_connection()
    -- 如果当前主节点为空或需要刷新,则重新发现
    if not self.current_master then
        local master, err = self:discover_master()
        if not master then
            return nil, err
        end
    end
    
    -- 创建到主节点的连接
    local red = redis:new()
    red:set_timeout(self.options.redis_timeout or 5000)
    
    local ok, err = red:connect(self.current_master.host, self.current_master.port)
    if not ok then
        -- 连接失败,可能是故障转移,重新发现
        local master, discover_err = self:discover_master()
        if not master then
            return nil, "Reconnect failed and rediscovery also failed: " .. discover_err
        end
        
        -- 使用新发现的主节点重连
        ok, err = red:connect(master.host, master.port)
        if not ok then
            return nil, "Reconnect with new master failed: " .. err
        end
    end
    
    -- 认证
    if self.options.password then
        local auth_ok, auth_err = red:auth(self.options.password)
        if not auth_ok then
            red:close()
            return nil, "Redis auth failed: " .. auth_err
        end
    end
    
    -- 选择数据库
    if self.options.database then
        local select_ok, select_err = red:select(self.options.database)
        if not select_ok then
            red:close()
            return nil, "Select database failed: " .. select_err
        end
    end
    
    return red
end

-- 获取从节点列表
function RedisSentinel:get_slaves()
    for _, sentinel in ipairs(self.sentinel_hosts) do
        local red = redis:new()
        red:set_timeout(self.sentinel_timeout)
        
        local ok, err = red:connect(sentinel.host, sentinel.port)
        if ok then
            if sentinel.password then
                red:auth(sentinel.password)
            end
            
            local slaves, err = red:command("sentinel", "slaves", self.master_name)
            red:close()
            
            if slaves and type(slaves) == "table" then
                local slave_list = {}
                for _, slave_info in ipairs(slaves) do
                    if type(slave_info) == "table" then
                        local slave = {}
                        for i = 1, #slave_info, 2 do
                            if slave_info[i] == "ip" then
                                slave.host = slave_info[i+1]
                            elseif slave_info[i] == "port" then
                                slave.port = tonumber(slave_info[i+1])
                            elseif slave_info[i] == "flags" then
                                slave.flags = slave_info[i+1]
                            end
                        end
                        -- 只包含正常运行的从节点
                        if not slave.flags or not slave.flags:find("s_down") then
                            table.insert(slave_list, slave)
                        end
                    end
                end
                return slave_list
            end
        end
    end
    
    return nil, "Failed to get slaves from all sentinels"
end

-- 获取只读连接的从节点
function RedisSentinel:get_slave_connection()
    local slaves, err = self:get_slaves()
    if not slaves then
        return nil, err
    end
    
    -- 随机选择一个从节点(负载均衡)
    if #slaves > 0 then
        local slave = slaves[math.random(1, #slaves)]
        
        local red = redis:new()
        red:set_timeout(self.options.redis_timeout or 5000)
        
        local ok, err = red:connect(slave.host, slave.port)
        if ok then
            -- 认证和数据库选择
            if self.options.password then
                red:auth(self.options.password)
            end
            if self.options.database then
                red:select(self.options.database)
            end
            return red
        end
    end
    
    return nil, "No available slaves"
end

return RedisSentinel

2. 连接池管理

lua 复制代码
local RedisConnectionPool = {}
RedisConnectionPool.__index = RedisConnectionPool

function RedisConnectionPool.new(sentinel, pool_size)
    local self = setmetatable({}, RedisConnectionPool)
    self.sentinel = sentinel
    self.pool_size = pool_size or 10
    self.master_pool = {}
    self.slave_pool = {}
    return self
end

function RedisConnectionPool:get_master_connection()
    -- 尝试从连接池获取
    for i = #self.master_pool, 1, -1 do
        local conn = table.remove(self.master_pool, i)
        if conn and self:is_connection_alive(conn) then
            return conn
        end
    end
    
    -- 连接池为空或连接无效,创建新连接
    return self.sentinel:get_master_connection()
end

function RedisConnectionPool:get_slave_connection()
    -- 尝试从连接池获取
    for i = #self.slave_pool, 1, -1 do
        local conn = table.remove(self.slave_pool, i)
        if conn and self:is_connection_alive(conn) then
            return conn
        end
    end
    
    -- 连接池为空或连接无效,创建新连接
    return self.sentinel:get_slave_connection()
end

function RedisConnectionPool:release_master_connection(conn)
    if conn and #self.master_pool < self.pool_size then
        table.insert(self.master_pool, conn)
    else
        if conn then
            conn:close()
        end
    end
end

function RedisConnectionPool:release_slave_connection(conn)
    if conn and #self.slave_pool < self.pool_size then
        table.insert(self.slave_pool, conn)
    else
        if conn then
            conn:close()
        end
    end
end

function RedisConnectionPool:is_connection_alive(conn)
    local ok, err = conn:ping()
    return ok and true or false
end

function RedisConnectionPool:close_all()
    for _, conn in ipairs(self.master_pool) do
        conn:close()
    end
    for _, conn in ipairs(self.slave_pool) do
        conn:close()
    end
    self.master_pool = {}
    self.slave_pool = {}
end

3. 使用示例和配置

lua 复制代码
-- config.lua
local config = {
    sentinels = {
        { host = "192.168.1.10", port = 26379 },
        { host = "192.168.1.11", port = 26379 },
        { host = "192.168.1.12", port = 26379 }
    },
    master_name = "mymaster",
    options = {
        password = "your_password",
        database = 0,
        timeout = 1000,
        retry_count = 3,
        redis_timeout = 5000
    }
}

return config

4. 应用层封装

lua 复制代码
-- app_redis.lua
local RedisSentinel = require("redis_sentinel")
local RedisConnectionPool = require("redis_connection_pool")
local config = require("config")

local _M = {}
_M._VERSION = "1.0"

local sentinel = RedisSentinel.new(
    config.sentinels,
    config.master_name,
    config.options
)

local connection_pool = RedisConnectionPool.new(sentinel, 20)

-- 执行写操作(主节点)
function _M:execute_write(command, ...)
    local conn, err = connection_pool:get_master_connection()
    if not conn then
        return nil, err
    end
    
    local ok, result = pcall(function()
        return conn[command](conn, ...)
    end)
    
    -- 释放连接回连接池
    connection_pool:release_master_connection(conn)
    
    if not ok then
        return nil, result
    end
    
    return result
end

-- 执行读操作(从节点)
function _M:execute_read(command, ...)
    local conn, err = connection_pool:get_slave_connection()
    if not conn then
        -- 从节点失败,降级到主节点
        conn, err = connection_pool:get_master_connection()
        if not conn then
            return nil, err
        end
    end
    
    local ok, result = pcall(function()
        return conn[command](conn, ...)
    end)
    
    -- 释放连接回连接池
    if conn then
        connection_pool:release_slave_connection(conn)
    end
    
    if not ok then
        return nil, result
    end
    
    return result
end

-- 批量操作
function _M:execute_pipeline(commands, use_slave)
    local conn, err
    if use_slave then
        conn, err = connection_pool:get_slave_connection()
        if not conn then
            conn, err = connection_pool:get_master_connection()
        end
    else
        conn, err = connection_pool:get_master_connection()
    end
    
    if not conn then
        return nil, err
    end
    
    -- 开始管道
    conn:init_pipeline()
    
    for _, cmd in ipairs(commands) do
        local command = cmd.command
        local args = cmd.args or {}
        conn[command](conn, unpack(args))
    end
    
    local results, err = conn:commit_pipeline()
    
    -- 释放连接
    if use_slave then
        connection_pool:release_slave_connection(conn)
    else
        connection_pool:release_master_connection(conn)
    end
    
    if not results then
        return nil, err
    end
    
    return results
end

-- 强制刷新主节点信息
function _M:refresh_master_info()
    return sentinel:discover_master()
end

-- 获取当前主节点信息
function _M:get_current_master()
    return sentinel.current_master
end

-- 健康检查
function _M:health_check()
    local master_conn, err = connection_pool:get_master_connection()
    if not master_conn then
        return false, "Master connection failed: " .. (err or "unknown")
    end
    
    local ok, ping_err = master_conn:ping()
    connection_pool:release_master_connection(master_conn)
    
    if not ok then
        return false, "Master ping failed: " .. (ping_err or "unknown")
    end
    
    return true, "Healthy"
end

return _M

5. 故障转移处理增强

lua 复制代码
-- failover_handler.lua
local _M = {}

function _M:handle_failover(sentinel, old_master, new_master)
    ngx.log(ngx.INFO, "Failover detected: ", 
            old_master.host, ":", old_master.port, " -> ",
            new_master.host, ":", new_master.port)
    
    -- 清理连接池中旧的连接
    if connection_pool then
        connection_pool:close_all()
    end
    
    -- 发送通知(可选)
    self:send_failover_notification(old_master, new_master)
    
    -- 更新应用状态
    self:update_application_state(new_master)
end

function _M:send_failover_notification(old_master, new_master)
    -- 实现通知逻辑,如发送邮件、短信、Webhook等
    local message = string.format(
        "Redis failover occurred: %s:%d -> %s:%d",
        old_master.host, old_master.port,
        new_master.host, new_master.port
    )
    
    -- 示例:记录到日志文件
    ngx.log(ngx.WARN, message)
end

function _M:update_application_state(new_master)
    -- 更新应用配置或状态
    -- 例如:刷新本地缓存、更新配置中心等
end

return _M

核心特性说明

1. 自动故障检测

  • 连接失败时自动重试其他 Sentinel
  • 验证主节点可用性
  • 支持故障转移后的自动重连

2. 负载均衡

  • 从节点读操作的随机选择
  • 连接池管理减少连接开销
  • 支持读写分离

3. 容错机制

  • 多 Sentinel 节点轮询
  • 从节点失败时降级到主节点
  • 连接池健康检查

4. 性能优化

  • 连接复用减少开销
  • 异步操作支持
  • 合理的超时和重试配置

另一种基于skyent框架实现示例

lua 复制代码
local skynet = require "skynet"
local redis = require "skynet.db.redis"
local cjson = require "cjson"
local cfgmgr = require "cfgmgr"

local redis_db

---从哨兵那里获取真正的master ,返回ip 端口
local function get_master_info(sentinel_cfg)
    for _, conn in ipairs(sentinel_cfg.hosts) do
        local ret, db = pcall(redis.connect, conn)
        if ret and db then
            local ret = db:sentinel("get-master-addr-by-name", sentinel_cfg.master )
            db:disconnect()
            return ret[1], ret[2]
        end
    end
end

---根据配置去找有效的redis连接
local function get_available_redis()
    local sentinel_cfg = cfgmgr.get_redis_sentinel_cfg()
    local conn = {}

    --有哨兵配置就走哨兵配置
    if sentinel_cfg and #sentinel_cfg.hosts > 0 then
        conn = sentinel_cfg.redis_conn  or {}
        conn.host, conn.port = get_master_info(sentinel_cfg)
        ERROR("get_available_redis form sentinel", conn)
        if not conn.host then
            return
        end
    else
        conn = cfgmgr.get_redis_cfg()
        ERROR("get_available_redis form common redis", conn)
    end

    local ret, db = pcall(redis.connect, conn)
    if ret and db then
        ERROR("get_available_redis success!!", conn)
        return db
    end
end

local function redis_conn_timer()    
    if not redis_db then
        redis_db = get_available_redis()
    else
        local result = redis_db:ping()
        -- DEBUG("[init][ping] result=", result)
        if not result then
            redis_db = nil
        end
    end
    local update_time = 100
    if not redis_db then
        ERROR("[init] redis connect error!please check!")
    else
        update_time = 1000
    end
    skynet.timeout(update_time, redis_conn_timer)
end

function init()
    DEBUG("[init] Start init redis service ...")
    cjson.encode_sparse_array(true, 1, 1)

    redis_conn_timer()
    DEBUG("[init] connect to reids server success, Init server service success!")
end

function response.do_cmd(cmd, key,...)
    --DEBUG("[redis do cmd]:",cmd,key, ...)
    local result = nil
    if redis_db then
        result = redis_db[cmd](redis_db, key,...)
    else
        ERROR("[redis do cmd] ERROR ", cmd,key, ...)
    end    
    return result
end
相关推荐
云边有个稻草人23 分钟前
KingbaseES 数据库赋能:时序数据库国产化替代的硬实力范本
数据库·时序数据库·国产数据库·金仓·kingbasees sql
MC丶科6 小时前
【SpringBoot常见报错与解决方案】中文乱码?Spring Boot 统一解决前后端中文乱码问题(含 Postman 测试)!别再百度“加 UTF-8”了!
spring boot·后端·postman
今晚务必早点睡7 小时前
微服务改数据库密码后服务仍能访问?一次“看似异常、实则常见”的生产现象全解析
数据库·微服务·oracle
老师我太想进步了20269 小时前
cmd连接MySQL及相关查询
数据库·mysql
浩瀚地学10 小时前
【Java】JDK8的一些新特性
java·开发语言·经验分享·笔记·学习
JeffDingAI10 小时前
【Datawhale学习笔记】深入大模型架构
笔记·学习
暖阳之下10 小时前
学习周报三十一
学习
a不是橘子10 小时前
03在Ubuntu中验证PV操作
笔记·ubuntu·操作系统·虚拟机·os·pv操作
tangyal11 小时前
渗透笔记1
笔记·网络安全·渗透
XXOOXRT11 小时前
基于SpringBoot的加法计算器
java·spring boot·后端·html5