生产环境使用
准备好你的 Jedis 应用用于生产环境
本指南提供建议,以在你的生产环境中获得最佳可靠性和性能。
核对清单
以下核对清单中的每个项目都链接到相应建议的部分。使用核对清单图标来记录你在实施建议方面的进度。
建议
以下部分提供针对你的生产环境的建议。其中一些可能不适用于你的特定用例。
连接池
示例代码通常在开头打开一个连接,演示一个功能,然后在结尾关闭连接。然而,生产代码通常会间歇性地多次使用连接。重复打开和关闭连接会带来性能开销。
使用连接池来避免打开和关闭连接的开销,而无需编写自己的代码来缓存和重用打开的连接。参见使用连接池连接了解如何在 Jedis 中使用此技术。
客户端缓存
客户端缓存涉及将只读命令的结果存储在本地缓存中。如果稍后再次执行相同的命令,可以直接从缓存获取结果,而无需联系服务器。这提高了客户端的命令执行时间,同时减少了网络流量和服务器负载。参见使用客户端缓存连接获取更多信息和示例代码。
超时
如果在你的代码打开连接或发出命令时发生网络或服务器错误,它可能会无限期挂起。你可以通过设置套接字读写和连接超时的时长来防止这种情况发生。
要为连接设置超时,请使用带有 timeout
参数的 JedisPooled
或 JedisPool
构造函数,或使用带有 socketTimeout
和 connectionTimeout
参数的 JedisClientConfig
。(套接字超时是执行命令时允许读写数据的最长时间。连接超时是建立新连接允许的最长时间。)
HostAndPort hostAndPort = new HostAndPort("localhost", 6379);
JedisPooled jedisWithTimeout = new JedisPooled(hostAndPort,
DefaultJedisClientConfig.builder()
.socketTimeoutMillis(5000) // set timeout to 5 seconds
.connectionTimeoutMillis(5000) // set connection timeout to 5 seconds
.build(),
poolConfig
);
健康检查
如果你的代码不持续访问 Redis 服务器,那么定期(例如每隔几秒)进行“健康检查”可能很有用。你可以使用简单的 PING
命令来实现。
try (Jedis jedis = jedisPool.getResource()) {
if (! "PONG".equals(jedis.ping())) {
// Report problem.
}
}
健康检查有助于尽快检测到问题,而无需等待用户报告。
异常处理
Redis 使用命令的返回值处理许多错误,但也存在可能抛出异常的情况。在生产代码中,你应该在异常发生时进行处理。
Jedis 异常层次结构的根是 JedisException
,它实现了 RuntimeException
。因此,层次结构中的所有异常都是非检查异常。
JedisException
├── JedisDataException
│ ├── JedisRedirectionException
│ │ ├── JedisMovedDataException
│ │ └── JedisAskDataException
│ ├── AbortedTransactionException
│ ├── JedisAccessControlException
│ └── JedisNoScriptException
├── JedisClusterException
│ ├── JedisClusterOperationException
│ ├── JedisConnectionException
│ └── JedisValidationException
└── InvalidURIException
一般异常
通常,Jedis 在执行命令时可能会抛出以下异常
JedisConnectionException
- 当与 Redis 的连接丢失或意外关闭时。配置故障转移,使用 Resilience4J 和内置的 Jedis 故障转移机制自动处理此异常。JedisAccessControlException
- 当用户没有执行命令的权限或用户 ID 和/或密码不正确时。JedisDataException
- 当发送或接收到 Redis 服务器的数据出现问题时。通常,错误消息会包含有关失败命令的更多信息。JedisException
- 此异常是一个包罗万象的异常,可以针对任何其他意外错误抛出。
可能抛出 JedisException
的情况
- 使用
PING
命令进行健康检查的返回结果异常 - SHUTDOWN 期间失败
- Pub/Sub 发布命令时失败(断开连接)
- 任何未知服务器消息
- Sentinel:可以连接到 Sentinel,但主节点未被监控或所有 Sentinel 都已宕机。
- MULTI 或 DISCARD 命令失败
- Shard 命令键哈希检查失败或没有可到达的分片
- 重试期限超出/尝试次数过多(重试命令执行器)
- 连接池 - 连接池耗尽,添加空闲对象出错,将损坏的资源返回到连接池
所有 Jedis 异常都是运行时异常,并且在大多数情况下不可恢复,因此通常会向上抛出到 API 层,并捕获错误消息。
DNS 缓存和 Redis
当你连接到具有多个端点的 Redis 服务器时,例如 Redis Enterprise Active-Active,你必须禁用 JVM 的 DNS 缓存。如果服务器节点或代理失败,受影响的数据库的 IP 地址将会更改。如果启用了 DNS 缓存,你的应用程序会继续尝试使用过时的 IP 地址。
使用以下代码禁用 DNS 缓存
java.security.Security.setProperty("networkaddress.cache.ttl","0");
java.security.Security.setProperty("networkaddress.cache.negative.ttl", "0");