Redian新闻
>
Redis流量镜像的实现

Redis流量镜像的实现

公众号新闻

来源 | OSCHINA 社区

作者 | KL博主

原文链接:https://my.oschina.net/klblog/blog/10115744

背景

对 Redis 场景降本增效,涉及到将部分 Redis 实例迁移到类似社区 pika 这种支持 Redis 协议的基于 SSD 磁盘存储的项目(阿里云 Tair),降低存储成本。迁移过程需要进行性能验证,除了基本的选型压测之外,还必须对每个业务场景做全指令的性能覆盖,才能确保业务迁移的性能以及指令兼容稳定性。常规的做法是需要业务开发配合在工程里进行流量双发,或者小范围流量灰度。

以上这个问题,不管哪种方式都需要投入更多的人力和时间,对降本增效本身这件事情来说,大大降低了 roi 。如果能够做到直接将原 Redis 的所有读流量重放到目标 Redis SSD 的实例,则迁移整件事件 SRE 可以完成 99% ,而且将大大缩短迁移实例的时间,所以 Redis 流量镜像这个需求就应运而生了。

tips:我们的数据迁移方案采用阿里云的 DTS ,DTS 是基于 Redis 主从复制的原理实现的,所以写流量性能在数据同步过程就可以直接验证了

调研

Google 上、Github 上逛了一圈,没有十分契合的东西,所以最后决定自研。查到的一些相关信息如下:

  • 阿里云的 SLS Redis 审计日志

阿里云的 Redis 实例支持将 Redis 的执行日志丢到 SLS(一个日志记录查询的产品) 记录,但是只有写流量的记录,达不到 Redis 读流量回放的需求。

  • pika redis-copy 工具:https://github.com/OpenAtomFoundation/pika/issues/2044

这个工具已经被 pika 项目丢弃了。目前只有文档,仓库里已经没有相关的代码了。不过本文实现也是基于和 pika 的实现原理一样的

  • istio 实现 Redis 流量镜像:https://github.com/cloudnativeto/cloudnativeto.github.io/issues/76

基于 istio 做 Redis 的镜像流量,必须接入 istio 才行,局限性太大了,而且引入一个新的 istio 组件需要做很多的稳定性测试,所以这个路线就直接否了

实现

直接接入正题,采用 Redis 的 monitor 指令来实现这个需求。

/**
* @author kl (http://kailing.pub)
* @since 2023/9/27
*/

public class RedisMonitorTest {

static final JedisPool targetRedisPool = new JedisPool("127.0.0.1", 6398);
static final JedisPool sourceRedisPool = new JedisPool("127.0.0.1", 6379);
static final Set<String> redisReadCommands = new HashSet<>(Arrays.asList(
"get", "strlen", "exists", "getbit", "getrange", "substr", "mget", "llen", "lindex",
"lrange", "sismember", "scard", "srandmember", "sinter", "sunion", "sdiff", "smembers",
"sscan", "zrange", "zrangebyscore", "zrevrangebyscore", "zrangebylex", "zrevrangebylex",
"zcount", "zlexcount", "zrevrange", "zcard", "zscore", "zrank", "zrevrank", "zscan", "hget",
"hmget", "hlen", "hstrlen", "hkeys", "hvals", "hgetall", "hexists", "hscan", "randomkey",
"keys", "scan", "dbsize", "type", "sync", "psync", "ttl", "touch", "pttl", "dump", "object",
"memory", "bitcount", "bitpos", "georadius_ro", "georadiusbymember_ro", "geohash",
"geopos", "geodist", "pfcount", "xrange", "xrevrange", "xlen", "xread", "xpending",
"xinfo", "lolwut"
));

public static void main(String[] args) {
try (Jedis jedis = sourceRedisPool.getResource()) {
jedis.monitor(new JedisMonitor() {
@Override
public void onCommand(String command) {
sendCommand(command);
}
});
}
}

public static void sendCommand(String commandStr) {
String[] parts = commandStr.split("\"");
if (parts.length < 2) {
return;
}
String cmd = parts[1];
List<String> args = new ArrayList<>();
for (int i = 3; i < parts.length; i += 2) {
args.add(parts[i]);
}
if (redisReadCommands.contains(cmd.toLowerCase())) {
ProtocolCommand command = () -> cmd.getBytes(StandardCharsets.UTF_8);

try (Jedis jedis = targetRedisPool.getResource()) {
try {
long startTime = System.currentTimeMillis();
jedis.sendCommand(command, args.toArray(new String[0]));
System.out.println(cmd + ":" + (System.currentTimeMillis() - startTime));
} catch (Exception e) {
System.err.println(cmd + e.getMessage());
}
}
}
}
}
以上是一段可以直接执行的伪代码,将 sourceRedis 的所有读流量转发到 targetRedis 执行

实现解析

上面采用的 Java 的 Redis 客户端 jedis 来开发,首先调用了 monitor 这个指令,这个指令是一个阻塞指令,会一直订阅 Redis 服务端的指令执行记录,记录的格式如下:
1695869359.747056 [0 127.0.0.1:64257] "ZRANGEBYSCORE" "delayed_tasks" "0" "1695869359805247076" "LIMIT" "0" "1"
1695869359.748040 [0 127.0.0.1:64257] "EXISTS" "asynq:{sys}:paused"
1695869359.748259 [0 127.0.0.1:64257] "EXISTS" "asynq:{sync}:paused"
1695869359.748578 [0 127.0.0.1:64257] "EXISTS" "asynq:{default}:paused"
1695869359.748916 [0 127.0.0.1:64257] "ZRANGEBYSCORE" "delayed_tasks" "0" "1695869359869190783" "LIMIT" "0" "1"
1695869359.749154 [0 127.0.0.1:64257] "ZRANGEBYSCORE" "delayed_tasks" "0" "1695869359877625076" "LIMIT" "0" "1"
1695869359.749348 [0 127.0.0.1:64257] "ZRANGEBYSCORE" "delayed_tasks" "0" "1695869359878760313" "LIMIT" "0" "1"
1695869359.749530 [0 127.0.0.1:64257] "ZRANGEBYSCORE" "delayed_tasks" "0" "1695869359882064571" "LIMIT" "0" "1"
1695869359.779048 [0 127.0.0.1:64257] "ZRANGEBYSCORE" "delayed_tasks" "0" "1695869360024586886" "LIMIT" "0" "1"
1695869359.785898 [0 127.0.0.1:64257] "ZRANGEBYSCORE" "delayed_tasks" "0" "1695869360031603858" "LIMIT" "0" "1"
1695869359.786092 [0 127.0.0.1:64257] "ZRANGEBYSCORE" "delayed_tasks" "0" "1695869360031656719" "LIMIT" "0" "1"
1695869359.786923 [0 127.0.0.1:64257] "ZRANGEBYSCORE" "delayed_tasks" "0" "1695869360031666910" "LIMIT" "0" "1"
所以我们只要解析出指令,然后发送到目标实例就好了
这里还涉及到一个问题,怎么过滤出只有读指令的记录?
我尝试过问 chatGPT ,但是他一点都不靠谱,不是少了读的指令,就是用其他写指令凑数。所以不可信。好在 Redis 服务端对每个指令都进行了打标,区分了读指令还是写指令。
所以只需要把所有的只读指令打印到控制台复制出来就解决这个问题了。

注意事项

Redis monitor 指令是一个对 Redis 性能有损的指令,官方测试会对单实例 Redis 降低 50% 左右的性能,我实际测试在 Redis 实际负载不高的情况下,这个影响可以忽略不计(特别高 QPS 的实例谨慎使用)。因为 Redis 单机 QPS 能支撑 10W 。比如线上实时 QPS 1W ,使用 monitor 的时候,QPS 和 RT 几乎没有变化。
另外需要注意,monitor 长时间运行会增加 Redis 的内存消耗,所以如果做性能验证,最好控制下时间,不要一直跑。
  • monitor 文档:https://redis.io/commands/monitor/

结语

在本篇博客中,我们探讨了 Redis 流量镜像的实现方法和其在降本增效方面的重要性。我们了解到,传统的验证方式在迁移 Redis 实例时需要大量的人力和时间投入,降低了降本增效的 ROI。为了解决这一问题,引入了 Redis 流量镜像的需求。
通过将原 Redis 的所有读流量直接重放到目标 Redis SSD 实例,我们可以高效地完成迁移实例的过程,减少了 SRE 的工作量,并显著缩短了迁移时间。这种方法不仅提高了迁移过程的效率,还降低了成本和风险,使得降本增效的目标更加可行和实现。通过采用这种方法,我们可以更高效地迁移 Redis 实例,并在降低成本、提高效率的同时保持业务的性能和稳定性。

END



中国程序员在国内为海外软件公司工作,被没收违法所得100多万



这里有最新开源资讯、软件更新、技术干货等内容

点这里 ↓↓↓ 记得 关注✔ 标星⭐ 哦


微信扫码关注该文公众号作者

戳这里提交新闻线索和高质量文章给我们。
相关阅读
Docker中容器和镜像的关系,真正的通俗易懂!爱因斯坦不知道到的是什么?黑心夫妇卷土重来?神颜女星又怀孕了?顶流女星蹭85圆脸花​流量?新流量跟配角男星撕起来了?贤妻丈夫投资又赔本了?镜像体积从1000M到10M,几招就做到部分旧版Chase Freedom用户被强制“暖心升级”成Chase Freedom Unlimited要是我在搞流量运营时,看到这篇亿级流量操盘手的分享,该有多好啊!PM闪购,20GB流量月费$32.05!新人5G速度30GB流量 月费$38!硬核观察 #1106 Amazon Linux 2023 仍然没有交付虚拟机镜像大美和二美(二十四) - 卢卡吃香了注解方式优雅的实现 Redisson 分布式锁Redmi首款曲面屏来了!Redmi Note 13 系列定档9月21日发布真假?GRE optional跟required没区别?使用 mkosi 构建 RHEL 和 RHEL UBI 镜像 | Linux 中国大规模流量下的云边端一体化流量调度体系《湖天一览楼》1部2章(3)庚子国变突发!ChatGPT Plus流量爆炸暂停注册,恢复时间未定No Pre-entry COVID Test Required数学逻辑和计算机程序代码之间的深层联系:互为镜像飞临美丽的耶路撒冷圣城Redis实战 | 使用Redis 的有序集合(Sorted Set)实现排行榜功能,和Spring Boot集成灌水:the awe effectHow a Red-Haired Chatbot Became China’s Favorite English Tutor从一千吨到巨无霸:改革开放四十五年中的茅台镜像博斯的音乐镜像廖良生院士:叠层OLED为实现高性能OLED提供新路径一个注解,优雅的实现接口幂等性!Docker实战【镜像部署】完成公司云迁移Deadly School Stampede Renews Calls For Scheduling ReformHundreds of Chinese Arrested For Cyberscams in Laos, Myanmar首个Unified Redis Release,Redis影响最深远的版本发布面试官:如何使用Dockerfile去构建自定义的Docker镜像?问倒一堆探索跨端开发的常用解决方案:条件编译的实现Troubled Singing Reality Show Accused of Mistreating Coco Lee面试官:如何使用 Dockerfile 去构建自定义的 Docker 镜像?问倒一大片。。。罗素3000指数的镜像:美国股市40年变迁
logo
联系我们隐私协议©2024 redian.news
Redian新闻
Redian.news刊载任何文章,不代表同意其说法或描述,仅为提供更多信息,也不构成任何建议。文章信息的合法性及真实性由其作者负责,与Redian.news及其运营公司无关。欢迎投稿,如发现稿件侵权,或作者不愿在本网发表文章,请版权拥有者通知本网处理。