本页面提供了有关以最优方式使用 Memorystore for Valkey 的指导。本页面还指出了需要避免的潜在问题。
内存管理最佳做法
本部分介绍了管理实例内存的策略,以便 Memorystore for Valkey 能够高效地为您的应用服务。
内存管理概念
内存用量:实例使用的内存量。您有固定的内存容量。您可以使用指标来监控内存用量。
逐出政策:Memorystore for Valkey 使用
volatile-lru
逐出政策。您可以使用 Valkey 命令(例如EXPIRE
命令)为键设置逐出。
监控实例的内存用量
如需监控 Memorystore for Valkey 实例的内存用量,建议您查看 /instance/memory/maximum_utilization
指标。如果实例的内存使用率接近 80%,并且您预计数据使用量会增加,请扩大实例的规模,以便为新数据腾出空间。
如果实例的内存用量较高,请执行以下操作来提升性能:
如果您遇到问题,请与Google Cloud 客户服务联系。
在启用集群模式的情况下扩缩分片
当您扩缩实例中的分片数量时,建议您在写入负载较低的时段进行扩缩。在高使用率期间进行扩缩可能会因复制或 slot 迁移造成内存开销而导致实例的内存不足。
如果您的 Valkey 使用场景涉及键逐出,那么缩减实例规模可能会降低缓存命中率。不过,在这种情况下,您无需担心数据丢失,因为密钥逐出是预期行为。
对于不想丢失键的 Valkey 用例,您应仅缩减到仍有足够空间来存储数据的较小实例。新的目标分片数应至少为数据所用内存的 1.5 倍。换句话说,您应预配足够的分片,以容纳当前实例中 1.5 倍的数据量。您可以使用 /instance/memory/total_used_memory
指标来查看实例中存储的数据量。
CPU 使用率最佳实践
如果发生意外的可用区中断,则由于不可用可用区中的节点丢失了容量,您的实例的 CPU 资源会减少。我们建议使用高可用性实例。每个分片使用两个副本(而不是每个分片使用一个副本)可在中断期间提供额外的 CPU 资源。此外,我们建议您管理节点 CPU 使用情况,以便节点有足够的 CPU 开销来处理因可用区意外中断而导致的容量损失所带来的额外流量。您应使用 Main Thread CPU Seconds /instance/cpu/maximum_utilization
指标监控主副本和副本的 CPU 使用情况。
根据您为每个节点预配的副本数,我们建议采用以下 /instance/cpu/maximum_utilization
CPU 使用率目标值:
- 对于每个节点有 1 个副本的实例,您应将主数据库和副本的
/instance/cpu/maximum_utilization
值设为 0.5 秒。 - 对于每个节点有 2 个副本的实例,您应将主实例的
/instance/cpu/maximum_utilization
值设为 0.9 秒,将副本的/instance/cpu/maximum_utilization
值设为 0.5 秒。
如果该指标的值超过了这些建议值,我们建议您增加实例中的分片或副本数量。
资源密集型 Valkey 命令
我们强烈建议您避免使用占用大量资源的 Valkey 命令。使用这些命令可能会导致以下性能问题:
- 延迟时间长和客户端超时
- 因增加内存用量的命令而导致的内存压力
- 节点复制和同步期间出现数据丢失,因为 Valkey 主线程被阻塞
- 健康检查、可观测性和复制资源不足
下表列出了消耗大量资源的 Valkey 命令示例,并提供了资源效率更高的替代方案。
类别 | 资源密集型命令 | 资源节约型替代方案 |
---|---|---|
针对整个键空间运行 | KEYS |
SCAN |
针对长度可变的密钥集运行 | LRANGE |
限制用于查询的范围的大小。 |
ZRANGE |
限制用于查询的范围的大小。 | |
HGETALL |
HSCAN |
|
SMEMBERS |
SSCAN |
|
阻止脚本运行 | EVAL |
确保脚本不会无限期运行。 |
EVALSHA |
确保脚本不会无限期运行。 | |
移除文件和链接 | DELETE |
UNLINK |
发布和订阅 | PUBLISH |
SPUBLISH |
SUBSCRIBE |
SSUBSCRIBE |
Valkey 客户端最佳实践
避免 Valkey 上的连接过载
为缓解连接突然涌入所造成的影响,我们建议执行以下操作:
确定最适合您的客户端连接池大小。每个客户端的合理初始大小为每个 Valkey 节点一个连接。然后,您可以进行基准比较,看看在不超出允许的最大连接数的情况下,增加连接数是否有助于提高性能。
当客户端因服务器超时而与服务器断开连接时,请使用带抖动的指数退避算法进行重试。这有助于避免多个客户端同时使服务器过载。
对于已启用集群模式的实例
当应用连接到启用了集群模式的 Memorystore for Valkey 实例时,必须使用支持集群的 Valkey 客户端。如需查看集群感知型客户端和配置示例,请参阅客户端库代码示例。客户端必须维护从哈希槽到实例中相应节点的映射,以便将请求发送到正确的节点。这样可以避免重定向造成的性能开销。
客户端映射
在以下情况下,客户端必须获取完整的 slot 列表和映射的节点:
当客户端初始化时,它必须填充初始 slot 到节点映射。
当从服务器收到
MOVED
重定向时,例如在故障切换时,当之前的主节点服务的所有 slot 都被副本接管时,或者在重新分片时,当 slot 从源主节点移动到目标主节点时。当从服务器收到
CLUSTERDOWN
错误或与特定服务器的连接持续超时时。当从服务器收到
READONLY
错误时。当主节点降级为副本时,可能会发生这种情况。此外,客户端应定期刷新拓扑,以使客户端保持预热状态,从而应对任何更改,并了解可能不会导致服务器重定向/错误的更改,例如添加新的副本节点。请注意,任何过时的连接也应作为拓扑刷新的一部分关闭,以减少在命令运行时处理失败连接的需求。
客户端发现
客户端发现通常通过向 Valkey 服务器发出 SLOTS
、NODES
或 CLUSTER SHARDS
命令来完成。我们建议使用 CLUSTER SHARDS
命令。CLUSTER SHARDS
通过提供更高效且可扩展的实例表示形式,取代了 SLOTS
命令(已弃用)。
客户端发现命令的响应大小可能会因实例大小和拓扑而异。节点较多的大型实例会生成较大的响应。因此,请务必确保执行节点拓扑发现的客户端数量不会无限增长。
这些节点拓扑刷新在 Valkey 服务器上开销很大,但对于应用可用性也很重要。因此,请务必确保每个客户端在任何给定时间只发出一个发现请求(并将结果缓存在内存中),并限制发出请求的客户端数量,以避免服务器过载。
例如,当客户端应用启动或与服务器断开连接并必须执行节点发现时,一个常见错误是,客户端应用在重试时未添加指数退避,而是发出了多次重新连接和发现请求。这可能会导致 Valkey 服务器长时间无响应,从而导致 CPU 利用率非常高。
使用发现端点进行节点发现
使用 Memorystore for Valkey 发现端点执行节点发现。发现端点具有高可用性,并且在实例中的所有节点之间实现负载平衡。此外,发现端点会尝试将节点发现请求路由到具有最新拓扑视图的节点。
对于已停用集群模式的实例
连接到已停用集群模式的实例时,您的应用必须连接到主端点才能写入实例并检索最新的写入内容。您的应用还可以连接到读取器端点,以便从副本读取数据并隔离来自主节点的流量。
持久性最佳实践
本部分介绍了有关持久性的最佳实践。
RDB 持久性
为了通过 RDB 快照备份实例获得最佳结果,您应遵循以下最佳实践:
内存管理
RDB 快照使用进程派生和“写入时复制”机制来拍摄节点数据的快照。根据对节点的写入模式,随着写入所触及的页面被复制,节点的已用内存会不断增长。在最糟糕的情况下,内存占用量可能是节点中数据大小的两倍。
为确保节点有足够的内存来完成快照,您应将 maxmemory
保持或设置为节点容量的 80%,以便预留 20% 的开销。如需了解详情,请参阅监控实例的内存用量。除了监控快照之外,此内存开销还有助于您管理工作负载,以便成功创建快照。
过时的快照
从过时快照恢复节点可能会导致应用出现性能问题,因为应用会尝试协调大量过时的密钥或对数据库的其他更改,例如架构更改。如果您担心从过时的快照中恢复,可以停用 RDB 持久性功能。重新启用持久性后,系统会在下一个预定的快照间隔时间拍摄快照。
RDB 快照对性能的影响
根据您的工作负载模式,RDB 快照可能会影响实例的性能,并会增加应用的延迟时间。如果您可以接受快照频率较低,则可以将 RDB 快照安排在低实例流量期间运行,以最大限度地降低 RDB 快照的性能影响。
例如,如果您的实例在凌晨 1 点到凌晨 4 点之间的流量较低,则可以将开始时间设置为凌晨 3 点,并将时间间隔设置为 24 小时。
如果您的系统具有恒定负载,并且需要频繁的快照,您应仔细评估性能影响,并权衡将 RDB 快照用于工作负载的好处。
如果您的实例不使用副本,请选择单可用区实例
在配置没有副本的实例时,我们建议采用单可用区架构,以提高可靠性。原因如下:
最大限度地降低中断的影响
可用区级服务中断不太可能影响您的实例。通过将所有节点放置在单个可用区内,可用区中断影响服务器的几率从 100% 降至 33%。这是因为实例所在可用区发生故障的几率为 33%,而位于不可用可用区中的节点受到影响的几率为 100%。
快速恢复
如果发生可用区级服务中断,恢复流程会更加顺畅。您可以快速在正常运行的可用区中预配新实例,并重定向应用,以尽可能减少中断。