又拍云 Redis 的改进之路
作为推出国内首创可编程 CDN 服务的专业云服务提供商,又拍云利用 CDN 边缘网络规模和性能,允许客户自定义编写规则来满足常用业务场景。而为了保证这些源数据,如边缘重定向、请求限速、自定义错误页面、访问防盗链控制、 HTTP 头部管理等,能快速同步到边缘的节点服务器,在对比了多个方案以后,又拍云于 2014 年初开始使用 Redis2.8 版本作为数据同步的解决方案。
最初的架构如下:
在继续谈 Redis 改进前,我们要先了解一下技术债。这里说的技术债指的是技术负债,通常开发人员为了加速软件开发,在应该采用最佳方案时可能进行妥协,改用短期内能加速软件开发的方案。而这种方案在未来给自己带去了额外开发负担。这种虽然眼前看起来可以得到好处,但必须在未来偿还的选择,就像债务一样,所以被叫做技术债。
而我们上面说到的这个方案就埋下了技术债的引子。在过去的几年里它虽然起到重要的作用,但架构的缺点明显,而且随着边缘服务器数量和同步数据量的增加,再加上服务器硬件的老化故障等等原因,造成了很多问题,比如如下问题:
出于安全考虑,相互 Redis 之间的通信数据都需要加密,但 Redis 本身不支持 SSL 加密。因此所有的边缘服务器都必须通过 stunnel 套接做中转服务器。然而实际工作状态下,stunnel 的性能不足,导致服务器 CPU 负载过高。
Redis 的数据主从都是长连接且尽量保持从同一源做同步,因此早期边缘服务器都是通过域名解析的方式来获取源服务器的 IP 地址。这样的好处是实施部署简单,缺点是 DNS 无法获知后端服务器的处理能力,造成每台机器上的长连接负载不均衡。而且后端服务出故障后 DNS 也无法自动处理, 即便及时对 DNS 进行了切换解析,也会因为 TTL 生效前的真空期引起数据不一样, 导致只能使用旧数据应急。
因为历史遗留原因, 边缘 Redis 版本大都是 2.x 低版本,而低版本只能通过 sync 做全量同步。因此中转服务器和主服务器的异常都会造成全网的雪崩效应,从而同步阻塞,无法快速同步元数据到边缘。
因为早期 Redis 只有主从模式可以采用,也没有实现哨兵和集群改造。所以让如今主服务器成为了单点风险,很容易造成源头上的重大故障。
因为之前妥协导致的问题和副作用,以至于我们现在必须要付出额外的时间和精力进行重构,把架构改善为最佳实现方式。
我们把改造过程分成几个步骤:
加强 SSL 的安全防护,尽可能升级到 OpenSSL 最新的稳定版本
SSL 可能是大家接触比较多的互联网安全协议之一,一般网站地址用了“https://”开头,就是采用了 SSL 安全协议。OpenSSL 是一种开放源码的 SSL 实现,用来实现网络通信的高强度加密,现在被广泛地用于各种网络应用程序中。如此重要的项目多年来始终面临着资金和人手不足的窘境,多数工作都要由为数不多的黑客和爱好者及志愿者来完成。幸好现在纳入 Linux 基金会资金资助对象,不过依然有新漏洞不断暴露,需要及时关注和跟进。
参考最新的 OpenSSL 漏洞危险等级报告:
鉴于 RC4 算法安全漏洞太多,建议编译时选择禁用。
使用最新的 stunnel 版本,优化性能,基于安全 OpenSSL 依赖库,支持 TLSv1.2+ 以上
从下图的红色框中可以看出,stunnel 在某些算法下的性能是最强的,所以在配置文件中推荐优先使用:
./configure --prefix=/opt/stunnel --with-ssl=/opt/openssl
来看一下推荐配置中的优化选项:
verify = 3
sslVersionMax = TLSv1.3
sslVersionMin = TLSv1.2
options = NO_SSLv2
options = NO_SSLv3
.......
ciphers = ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4:!DH:!DHE
可以通过亚洲诚信的网站来做 HTTPS 的可信等级检测和验证。
编译最新的 Redis-6.2.x 稳定版,功能强大丰富且无需依赖高版本的 GCC
Redis6.2 与 7.0 对比来看的话,肯定是 7.0 版本更为强大一点。Redis7.0 几乎包括了对各个方面的增量改进,其中最值得注意的是 Redis Functions、ACLv2、command introspection 和 Sharded Pub/Sub。7.0 版添加了近 50 个新命令和选项来支持这种演变并扩展 Redis 的现有功能。
但是尽管 Redis7.0 更加强大,可是综合考虑到与原来的 Redis 代码的完全兼容性,以及生产环境的稳定,我们最终选择了 Redis6.2。因为 Redis6.2 的优点也足够多,功能也很强大,而且更能满足我们生产环境的要求,比如:
多线程 IO(Threaded I/O)
众多新模块(modules)API
更好的过期循环(expire cycle)
支持 SSL
ACLs 权限控制
RESP3 协议
客户端缓存(Client side caching)
无盘复制&PSYNC2
Redis-benchmark 支持集群
Redis-cli 优化、重写 Systemd 支持
Redis 集群代理与 Redis6 一同发布(但在不同的 repo)
RDB 更快加载
SRANDMEMBER 和类似的命令具有更好的分布
STRALGO 命令
带有超时的 Redis 命令更易用
重点介绍一下 PSYNC2 的特性,这也是我们架构改进升级的重点特性之一。
在 Redis cluster 的实际生产运营中,实例的维护性重启、主实例的故障切换(如cluster failover)操作都是比较常见的(如实例升级、rename command 和释放实例内存碎片等)。而在 Redis4.0 版本前,这类维护性的处理 Redis 都会发生全量重新同步,导到性能敏感的服务有少量受损。而 PSYNC2 主要让 Redis 在从实例重启和主实例故障切换场景下,也能使用部分重新同步。
直接下载源代码编译:
# make BUILD_TLS=no
推荐配置,添加以下选项增强性能:
io-threads-do-reads yes
io-threads 8
aof-use-rdb-preamble yes
在我们的测试过程中,发现 Redis+TLS 有几个问题:
Redis 开启 TLS后,性能下降 30%。
Redis 对 OpenSSL 的强依赖性. 考虑到 OpenSSL 的过往高危漏洞不断, 如果要不断修复漏洞要重新编译 Redis,导致运维更新成本过高。
Redis 升级后, 要重新同步数据, 增加了出故障的机率或让生产停摆。
所以, 我们还是决定使用第三方程序 stunnel 来加固安全,方便升级和修复漏洞。又不影响后端连接,从而保障了 Redis 的工作连续性和稳定可靠性。
基于 APISIX+TLS 托管,使用 TCP 的哈希一致性做负载均衡来替换 DNS 的轮询,效能显著
APISIX 使用 TCP 代理, 这部分直接配置后就可以使用,和 Redis 改造关系不大,我们就直接略过,大家可以直接看一下改造后的连接数统计截图。从实际的 APISIX 的连接数可以看出负载被数量均衡地分摊到了不同的后端,而且边缘服务器重启也利用 PSYNC2 做了快速的增量同步。
使用 Redis-shake 做定制化的数据同步
在架构改进的过程中,我们也看了 redis-shake 这个工具,它是阿里云 Redis&MongoDB 团队开源的用于 Redis数据同步的工具。它支持 解析、恢复、备份、同步 四个功能。给大家主要介绍同步 sync:
恢复 restore:将 RDB 文件恢复到目的 Redis 数据库。
备份 dump:将源 Redis 的全量数据通过 RDB 文件备份起来。
解析 decode:对 RDB 文件进行读取,并以 json 格式解析存储。
同步 sync:支持源 Redis 和目的 Redis 的数据同步,支持全量和增量数据的迁移。
同步 rump:支持源 Redis 和目的 Redis 的数据同步,仅支持全量的迁移。采用 scan 和 restore 命令进行迁移,支持不同云厂商不同 Redis 版本的迁移。
我们原来有一个做过源代码修改过的 Redis,只会同步想要的空间。虽然好用,但还是需要在新代码上重新编译一个,可是原来的负责人已经找不到了。这也是很多年久失修项目的通病, 但通过 redis-shake 这样的开源工具,只要通过它简单配置一下就可以实现我们想要的功能:
- filter.db.whitelist / blacklist
- filter.key.whitelist / blacklist
- filter.command.whitelist / blacklist
现在的架构及未来的展望
在现在的架构中,我们在原来的三层架构基础上,又拆分和强化了三层架构:
DNS 层解析到 VIP,VIP 利用了 BGP/OSPF 的动态网关路由协议,对应后面一组服务器集群服务。
负载均衡层:利用 “apisix ”+ “tls1.2+ ”+ “tcp的哈希一致性连接”,把 Redis 的主从连接均衡,故障转移。
边缘 CDN 节点,利用 Redis 高版本所带来的技术红利,psync 的增量同步,加上 stunnel+tls1.2 实现了加密传输。
下一个阶段, 还要继续把数据中心的 Redis 主改造成 Redis 哨兵模式(考虑到程序代码要对哨兵模式做兼容性改造, 第一阶段先不上, 一切都为了生产环境中的稳定性)。
参考文档:
如何检查网站的 TLS 版本:https://wentao.org/post/2020-11-29-ssl-version-check/
Redis 特性之复制增强版 PSYNC2:https://www.modb.pro/db/79478
通俗易懂的 Redis 架构模式详解:https://www.cnblogs.com/mrhelloworld/p/redis-architecture.html
推荐阅读
【实操干货】做好这 16 项优化,你的 Linux 操作系统焕然一新
又拍云 Redis 的改进之路的更多相关文章
- Flink 在又拍云日志批处理中的实践
日前,由又拍云举办的大数据与 AI 技术实践|Open Talk 杭州站沙龙在杭州西溪科创园顺利举办.本次活动邀请了有赞.个推.方得智能.又拍云等公司核心技术开发者,现场分享各自领域的大数据技术经验和 ...
- 又拍云张聪:OpenResty 动态流控的几种姿势
2019 年 1 月 12 日,由又拍云.OpenResty 中国社区主办的 OpenResty × Open Talk 全国巡回沙龙·深圳站圆满结束,又拍云首席架构师张聪在活动上做了< Ope ...
- 【实战分享】又拍云 OpenResty / Nginx 服务优化实践
2018 年 11 月 17 日,由 OpenResty 主办的 OpenResty Con 2018 在杭州举行.本次 OpenResty Con 的主题涉及 OpenResty 的新开源特性.业界 ...
- 又拍云叶靖:OpenResty 在又拍云存储中的应用
2019 年 7 月 6 日,OpenResty 社区联合又拍云,举办 OpenResty × Open Talk 全国巡回沙龙·上海站,又拍云平台开发部负责人叶靖在活动上做了<OpenRest ...
- 跬步千里 —— 阿里云Redis bitfield命令加速记
link:https://developer.aliyun.com/article/757841 在一次阿里云客户问题解决中,通过给Redis添加bitfield_ro命令,解决了Redis官方bit ...
- 用StackExchange.Redis客户端连接阿里云Redis服务遇到的问题
阿里云推荐的Redis服务.NET客户端是ServiceStack.Redis,但ServiceStack.Redis不支持异步,不支持.NET Core,于是尝试使用StackExchange.Re ...
- ajax异步上传到又拍云的实例教程
作者:白狼 出处:www.manks.top/article/async_upload_to_upyun 本文版权归作者,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否 ...
- 阿里云 Redis 服务遇到的问题
ERR unknown command eval 说明: 执行当前 Web 请求期间,出现未经处理的异常.请检查堆栈跟踪信息,以了解有关该错误以及代码中导致错误的出处的详细信息. 异常详细信息: St ...
- iOS UPYUN(又拍云)使用总结
UPYUN,原来没用过,上个周用了一次,觉得蛮方便的,对于个人开发者,且没有服务器的,上传图片和文件,是个不二选择. 首先,先明白原理: 1.又拍云有一个上传空间,在这个空间里,有空间名称.密钥,其他 ...
随机推荐
- 字符串/16进制/ASCII码的转换
1 /// <字符串转16进制格式,不够自动前面补零> 2 /// 假设文本框里面填写的是:01 02 03 04 05 06 3 /// Str获取的是01 02 03 04 05 06 ...
- 『现学现忘』Git基础 — 6、Git的操作流程
目录 1.Git的基本操作流程 2.工作区.暂存区.版本库的区别 (1)工作区 (2)版本库 (3)暂存区 (4)通过新增文件理解三个区的关系 (5)说明 1.Git的基本操作流程 初始化一个本地版本 ...
- switch语法
1. js 代码 // 1. switch 语句也是多分支语句 也可以实现多选1 // 2. 语法结构 switch 转换.开关 case 小例子或者选项的意思 // switch (表达式) { / ...
- python基础练习题(题目 画菱形)
day15 --------------------------------------------------------------- 实例022:画菱形 题目 打印出如下图案(菱形):. * * ...
- Postman 正确使用姿势
前言: 请各大网友尊重本人原创知识分享,谨记本人博客:南国以南i 简介: Postman是一个接口测试工具,在做接口测试的时候,Postman相当于一个客户端,它可以模拟用户发起的各类HTTP请求,将 ...
- linux脚本执行jar包运行
以下为linux下运行jar包的脚本(只需替换jar包名称): #!/bin/bash #这里可替换为你自己的执行程序,其他代码无需更改 APP_NAME=ruoyi-admin.jar cd `di ...
- 面试突击42:synchronized和ReentrantLock有什么区别?
在 Java 中,常用的锁有两种:synchronized(内置锁)和 ReentrantLock(可重入锁),二者的功效都是相同得,但又有很多不同点,所以我们今天就来聊聊. 区别1:用法不同 syn ...
- .NET桌面程序应用WebView2组件集成网页开发4 WebView2的线程模型
系列目录 [已更新最新开发文章,点击查看详细] WebView2控件基于组件对象模型(COM),必须在单线程单元(STA)线程上运行. 线程安全 WebView2必须在使用消息泵的UI线程上创 ...
- FreeRTOS --(8)任务管理之创建任务
转载自https://blog.csdn.net/zhoutaopower/article/details/107034995 在<FreeRTOS --(7)任务管理之入门篇>文章基本分 ...
- Docker系列教程05-Docker数据卷(Data Volume)学习
引言 在Docker中,容器的数据读写默认发生在容器的存储层,当容器被删除时其上的数据将会丢失.要想实现数据的持久化,需要将数据从宿主机挂载到容器中.目前Docker提供了三种方式将数据从宿主机挂载到 ...