点击上方蓝字关注我们!
这事情还得从两天前说起...话说迭代上了个接口,该接口横跨多个应用服务,链路如下图所示:
问题来了:通过skywalking,我们的监控到dev环境的该接口偶尔请求耗时很长,且抛异常了:
接口503的报错原因查明:
1、外部系统D应用接口响应慢,导致上游C服务的接口超时;
2、上游服务C最终做了降级处理,返回了空串内容给B服务;
3、B服务最终抛了NPE,导致最终接口500;
因此我们也定下了解决目标:
1、提供多级缓存来实现API加速优化
2、降级服务处理要做好一点,确保缓存一致性
基于Redis和Cos的二级缓存
API优化方案涉及了COS和Redis。
Redis自然不用过多介绍,这是缓存的主流中间件;基于内存的访问可以大大提高数据读取效率,这里也主要用于数据缓存。
COS对象存储(Cloud Object Storage,COS)是腾讯云提供的一种存储海量文件的分布式存储服务,具有高扩展性、低成本、可靠安全等优点;这里也是用于数据缓存。
基于Redis和Cos的二级缓存,如下图所示:
- Redis:提供基于内存的数据存储
- Cos:提供基于云的对象存储
- 远端数据源:跨集群的数据提供方
API优化方案
基于Redis和Cos的二级缓存,API的优化方案如下:
【1】优化后的读API流程图:
(1)优先从redis读
(2)redis读不到,从cos读,写入redis
(3)cos读不到,从sca读
(4)写入redis、写入cos
【2】我们在Redis和Cos的缓存数据预处理上,采用了“存量预热”+“增量缓存”的策略:
(1)存量预热:目标存储到COS
(2)增量缓存:参考【1】优化后的读API流程图
FAQ
Q1:有些同学问,为什么只有增量缓存时,数据才写入Redis呢;存量预热为什么没有写入Redis?
A1:从缓存穿透的角度看:只有主动读取API访问到的,该数据下次被访问的概率会更高,因此可以写入Redis,以使得下次访问获得更快的性能。虽然提前写入Redis存量预热的数据,在访问量不大的情况下,会造成大量的缓存浪费;Redis是非常宝贵的资源,虽然性能高但是价格昂贵,非必要不过渡使用它。
从缓存击穿的角度看:预热写入Redis的数据,都会配置EXPIRE生存时间,在高并发的情况下,同一批缓存有大概率一起过期失效,这将导致所有请求打到第三方系统D服务上。严重情况下,甚至出现缓存雪崩,导致下游服务过载重启,影响服务SLA。
Q2:存量预热的数据,在迁移数据过程中,会有什么风险呢?
A2:好问题,参考下面的“DB告警和监控”这Part。
Q3:COS的使用手册有吗?
A3:参考文档(https://cloud.tencent.com/document/product/436/6222)
Q4:COS的收费贵不?
A4:降本增效的背景下,我们开发资源很多时候受限于成本预算,下面我给出一部分的计费价格,大伙参考使用(1TB的存储大小)。
Q5:COS的QPS是多少?
A5:使用了云服务商的产品,自然要进行性能评估了,我参考了文档的内容,其实每个存储桶的读QPS是可以达到30000的,应该是可以满足大部分业务需求(https://cloud.tencent.com/document/product/436/14518)
其实,cos存储成本并不高的,实际上的花费主要都是在流量上。
Q6:COS的读取比第三方系统的API读取快很多吗?
A6:是的,COS的读取在腾讯云内部会更加有网络保障;而第三方API接入相对来说,系统稳定性更加不可控。从最后的实现比对来看,COS读取大都在200ms左右完成,大大优于第三方API的性能表现。
DB告警和监控
在存量数据预热的过程里,我们选择业务低峰期执行迁移任务。
不出意外的出现了意外,云数据库很快给出了告警:CPU使用率超过了80%(虽然不会对线上业务造成影响,但着实惊出一身冷汗)。
这里给出几点启示:
(1)批量同步数据,千万要记住多线程执行小任务(减少出错概率互相影响)
(2)留下足够的时间间隔,让CPU任务使用率在多线程下摊分,降低CPU瞬时负载
总结
以上是我们的一次API优化总结,最后还是给出2点提示:
- 数据预热过程可能很慢,我们其实可以跟产品,一起沟通下,能否可以按小项目维度去进行灰度功能(让预热数据及时跟上灰度范围)
- 迁移过程会产生非常大的DB查询,建议业务低峰期执行预热操作
往期推荐
《源码系列》
《JDK之Object 类》
《JDK之BigDecimal 类》
《JDK之String 类》
《JDK之Lambda表达式》
《Spring源码:Event事件发布与监听》
《互联网技术峰会》
《ArchSummit:从珍爱微服务框架看架构演进》
《ArchSummit_2022_全球架构峰会》
《2021年深圳ArchSummit全球架构师峰会》
《降本30%,酷家乐海量数据冷热分离设计与实践》
《经典书籍》
《Java并发编程实战:第1章 多线程安全性与风险》
《Java并发编程实战:第2章 影响线程安全性的原子性和加锁机制》
《Java并发编程实战:第3章 助于线程安全的三剑客:final & volatile & 线程封闭》
《服务端技术栈》
《Docker 核心设计理念》
《Kafka原理总结》
《HTTP的前世今生》
《如何进行一次高质量CR》
《一时重构一时爽,一直重构一直爽》
《一文带你看懂:亿级大表垂直拆分的工程实践》
《设计模式》
《设计模式之六大设计原则》
《设计模式之创建型(1):单例模式》
《设计模式之创建型(2):工厂方法模式》
《设计模式之创建型(3):原型模式》
《设计模式之创建型(4):建造者模式》
《设计模式之创建型(5):抽象工厂设计模式》
《设计模式之结构型(1):代理类设计模式》