解决PHP连接Redis报read error on connection错误

项目将Redis短连接改为长连接后,出现read error on connection异常。原因是PHP的default_socket_timeout配置项默认60s,超时未使用连接会抛异常。文中给出三种解决方案,包括修改php.ini、程序中设置、使用Redis的option,无超时时间设置为 -1 而非 0。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

背景

项目由于并发很高,所以将之前连接redis使用短连接改成了长连接,结果导致出现了抛出了read error on connection

出现原因

php有一个配置项default_socket_timeout表示一个socket连接的超时时间,默认是60s,而phpredis这个扩展的底层连接redis是使用的socket,所以当一个连接在60秒内没有被使用的时候,下次连接就会抛出这个异常。

解决方案

方案1 修改php.ini(不推荐)

在php.ini中设置default_socket_timeout = -1,然后重启php-fpm

方案2 程序中设置

使用ini_set函数
ini_set('default_socket_timeout', -1); // 不超时

方案3 使用redis的option

在连接redis时setOption
$this->redis->setOption(Redis::OPT_READ_TIMEOUT, -1);

注意设置没有超时时间都要设置成-1 而不是0

参考文章:

https://github.com/phpredis/phpredis/pull/260

<think>好的,我需要解决用户的问题:如何使用Python代码通过Redis哨兵实现读写分离。用户希望得到具体的操作方法和示例代码。 首先,我得回忆一下Redis哨兵的基本原理。哨兵模式用于监控主从节点,实现自动故障转移。主节点处理写操作,从节点处理读操作,这样可以分担主节点的压力,实现读写分离。 接下来,用户提到使用Pythonredis-py库。我记得redis-py确实支持哨兵模式,需要创建Sentinel对象,然后通过它获取主节点和从节点的连接。主节点用于写操作,从节点用于读操作。 然后,我需要确保代码示例的正确性。比如,配置哨兵地址时,应该是一个包含多个哨兵地址的列表。然后创建Sentinel实例,指定服务名称'mymaster',并设置密码参数,因为引用中提到有些配置需要密码。比如引用[2]和引用[3]中提到了密码的使用,所以在示例代码中需要包含password参数。 另外,读写分离的具体实现是通过分别调用master_for和slave_for方法来获取主节点和从节点的连接。写操作使用master,读操作使用slave。需要注意,从节点可能有多个,slave_for默认会选择一个,可以通过slave_rw参数指定是否允许写,但这里应该设置为只读。 还要处理可能的异常,比如连接失败或者主节点切换的情况。redis-py的Sentinel会自动处理故障转移,但在代码中可能需要重试机制或者捕获异常。不过用户可能只需要基本示例,所以暂时不涉及高级错误处理。 然后,根据引用[3]中的配置示例,设置replicaof和masterauth,所以在代码中连接时需要提供密码,这需要在Sentinel初始化时传递password参数,以及在获取master和slave时使用。 最后,确保代码中的注释清晰,解释每个步骤的作用,比如配置哨兵地址、创建哨兵对象、获取主从连接,以及读写操作示例。这样用户能够理解每行代码的目的。 总结步骤: 1. 导入redis库 2. 配置哨兵地址列表 3. 创建Sentinel对象,传入哨兵地址和密码 4. 使用master_for获取主节点连接(写) 5. 使用slave_for获取从节点连接(读) 6. 示例写操作和读操作 7. 异常处理建议 检查引用内容是否符合,比如引用[1]中的示例代码使用了哨兵配置,但没有处理密码。而引用[2]和[3]提到了密码参数,所以需要在代码中添加password='your_password',确保与实际配置一致。 可能还需要提醒用户替换示例中的密码、哨兵地址和服务名称,以及注意事项,比如哨兵的高可用配置,读写分离的负载均衡可能需要更多设置,或者使用连接池优化性能。这部分可以作为扩展说明。 现在,将这些整理成一个清晰的步骤和代码示例,确保符合用户的要求,并且语法正确,使用中文回答,结构清晰。</think>以下是如何使用Python通过Redis哨兵实现读写分离的完整实现方法及示例代码: ### 一、实现步骤 1. **配置哨兵连接参数** - 需要至少两个哨兵实例地址 - 指定Redis服务名称(默认`mymaster`) - 设置认证密码(如启用) 2. **创建哨兵对象** ```python from redis.sentinel import Sentinel sentinel = Sentinel(sentinels=[('sentinel1.ip', 26379), ('sentinel2.ip', 26379)], socket_timeout=0.5, password='your_sentinel_password') ``` 3. **获取读写连接** ```python # 主节点(写操作) master = sentinel.master_for('mymaster', password='your_redis_password') # 从节点(读操作) slave = sentinel.slave_for('mymaster', password='your_redis_password') ``` ### 二、完整示例代码 ```python import redis from redis.sentinel import Sentinel # 哨兵配置(至少配置两个哨兵节点) SENTINELS = [ ('192.168.1.100', 26379), ('192.168.1.101', 26379), ('192.168.1.102', 26379) ] SERVICE_NAME = 'mymaster' REDIS_PASSWORD = 'your_redis_password' # 主从节点密码 SENTINEL_PASSWORD = 'your_sentinel_password' # 哨兵节点密码 # 创建哨兵连接 sentinel = Sentinel( sentinels=SENTINELS, socket_timeout=0.5, password=SENTINEL_PASSWORD # 如果哨兵有密码需要配置 ) # 获取主节点连接(写操作) master = sentinel.master_for( SERVICE_NAME, password=REDIS_PASSWORD, db=0, socket_timeout=1 ) # 获取从节点连接(读操作) slave = sentinel.slave_for( SERVICE_NAME, password=REDIS_PASSWORD, db=0, socket_timeout=1 ) # 写操作示例 try: master.set('cache_key', 'value', ex=60) print("写入成功") except redis.exceptions.ConnectionError as e: print(f"主节点写入失败: {str(e)}") # 读操作示例 try: value = slave.get('cache_key') print(f"读取到数据: {value.decode()}") except redis.exceptions.ConnectionError as e: print(f"从节点读取失败: {str(e)}") ``` ### 三、关键配置说明 1. **读写分离机制**:哨兵自动监控主从状态,`master_for`始终返回当前主节点,`slave_for`随机选择可用从节点[^3] 2. **密码配置**:需同时配置哨兵认证密码和Redis节点密码(如果启用) 3. **连接参数**: - `socket_timeout`:建议设置为0.5-1秒 - `db`:指定数据库编号 - `decode_responses=True`:可自动解码返回字符串 ### 四、增强功能实现 ```python # 自动故障转移重试装饰器 def auto_retry(func): def wrapper(*args, **kwargs): for _ in range(3): try: return func(*args, **kwargs) except redis.exceptions.ConnectionError: print("节点故障,尝试重新连接...") time.sleep(0.5) raise Exception("所有节点不可用") return wrapper # 带自动重试的读取操作 @auto_retry def safe_read(key): return slave.get(key) # 带自动重试的写入操作 @auto_retry def safe_write(key, value): return master.set(key, value) ``` ### 五、注意事项 1. **哨兵数量**:生产环境建议至少3个哨兵节点[^2] 2. **连接池配置**:推荐使用连接池提升性能 ```python from redis.connection import ConnectionPool pool = ConnectionPool.from_options( max_connections=10, socket_timeout=1, retry_on_timeout=True ) master = sentinel.master_for(..., connection_pool=pool) ``` 3. **读写策略**:严格分离写操作到主节点,避免在从节点执行写命令[^4]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值