通过读写分离缓解热点Key问题

为缓解热点Key带来大量读请求的影响,您可以启用读写分离功能并增加只读节点,系统能够将读请求分散至各个节点。这将降低主节点的压力,并提升系统的整体吞吐量和稳定性。

功能概述

读写分离架构的所有只读节点通过异步复制主节点的数据(最终一致性),整体数据同步延迟低。这意味着在部分写入量较大的情况下,可能会发生数据同步延迟,此时应用程序能够容忍稍旧的数据。例如下述场景:

  • 缓存数据:网址首页的HTML缓存等,更新频率低。

  • 游戏排行榜:小时级别排行榜,其轻微的更新延迟对用户影响并不显著。

  • 天气预报数据:用户频繁查询天气,数据则按照预定时间进行更新。

增加只读节点的直接作用

  • 分担主节点负载:主节点仅负责100%写请求、1/N的读请求(N为总节点数,例如1个主节点、3个只读节点,即N4)。这降低了主节点的CPU压力、网络压力,以及连接开销。

  • 提高系统吞吐量:每个只读节点可独立处理读请求,整体读性能呈线性扩展。在理想情况下,增加N个只读节点可提升N倍读性能。

  • 降低响应延迟:将读请求分散到多个节点后,可减少单个请求的排队等待时间。

不仅支持为标准(主从)架构开启读写分离,也支持为集群架构开启读写分离,可为集群的每个数据分片节点增加对应的只读节点,具体架构信息请参见读写分离功能

如何开启

前提条件:

  • 部署模式为云原生

  • 实例为Redis开源版Tair(企业版)内存型、持久内存型。

  • 实例规格为1 GB及以上。

  • 实例类型为高可用。

开启方法:在实例详情页中,单击左侧导航栏的节点管理,并打开读写分离开关。具体操作请参见开启读写分离

客户端连接

单可用区实例

通常情况下,读写分离架构实例仍提供一个连接地址,实例将通过Proxy组件实现路由分发。您无需修改代码,开箱即用,更多信息请参见客户端程序连接教程

双可用区实例

在双可用区、读写分离架构实例,实例将分别提供主、备可用区连接地址。其中备可用区连接地址仅用于读请求,可实现就近访问,缩短读请求延迟。

例如实例为杭州I(主可用区)、杭州J(备可用区)。

  • 位于杭州I的客户端(ECS实例)可以连接实例的主可用区地址,并执行读写操作。代码如下:

    import redis.clients.jedis.Jedis;
    import redis.clients.jedis.JedisPool;
    import redis.clients.jedis.JedisPoolConfig;
    
    public class MasterReadWrite {
        public static void main(String[] args) {
            JedisPoolConfig config = new JedisPoolConfig();
            config.setMaxIdle(200);
            config.setMaxTotal(300);
            config.setTestOnBorrow(false);
            config.setTestOnReturn(false);
    
            // 配置主可用区连接地址、端口、账号密码信息。
            String host = "r-bp1vtq8tnrquy****pd.redis.rds.aliyuncs.com";
            int port = 6379;
            String password = "default:Passw***2";
        
            JedisPool pool = new JedisPool(config, host, port, 3000, password);
            Jedis jedis = null;
            try {
                jedis = pool.getResource();
                // 执行相关操作,示例如下。
                jedis.set("foo", "bar");
                System.out.println(jedis.get("foo"));
            }
            catch (Exception e) {
                // 超时或其他异常处理。
                e.printStackTrace();
            }
            finally {
                if (jedis != null) {
                    jedis.close();
                }
            }
            pool.destroy();    // 当应用退出,需销毁资源时,调用此方法。此方法会断开连接、释放资源。
        }
    }
  • 位于杭州J的客户端(ECS实例)可以连接实例的备可用区地址,并仅执行读操作(如需执行写操作,仍需连接主可用区地址)。代码如下:

    import redis.clients.jedis.Jedis;
    import redis.clients.jedis.JedisPool;
    import redis.clients.jedis.JedisPoolConfig;
    
    public class ReplicaRead {
        public static void main(String[] args) {
            JedisPoolConfig config = new JedisPoolConfig();
            config.setMaxIdle(200);
            config.setMaxTotal(300);
            config.setTestOnBorrow(false);
            config.setTestOnReturn(false);
    
            // 配置备可用区连接地址、端口、账号密码信息。
            String host = "r-bp1vtq8tnrquy****pd.redis.rds.aliyuncs.com";
            int port = 6379;
            String password = "default:Passw***2";
    
            JedisPool pool = new JedisPool(config, host, port, 3000, password);
            Jedis jedis = null;
            try {
                jedis = pool.getResource();
                // 执行相关操作,示例如下。
                System.out.println(jedis.get("foo"));
            }
            catch (JedisDataException e) {
                // 捕获写操作异常(如果误操作执行了写操作)。
                e.getMessage();
            }
            catch (Exception e) {
                // 超时或其他异常处理。
                e.printStackTrace();
            }
            finally {
                if (jedis != null) {
                    jedis.close();
                }
            }
            pool.destroy();    // 当应用退出,需销毁资源时,调用此方法。此方法会断开连接、释放资源。
        }
    }