暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

技术创想 | Atome实用主义性能优化盘点 - 缓存篇

领创集团Advance Group 2022-01-12
454

目录

1 背景
   1.1 何为“实用主义”
   1.2 性能优化考量指标
2 几个非常好用的优化模式汇总
   2.1 最简单内存、Redis做缓存
   2.2 内存+Redis混合缓存
   2.3 内存+MQ混合缓存
3 总结

背景介绍

1.1 何为“实用主义”

很多工程师都有想要优化千亿数据,百亿并发量的心。可是,在真实职业生涯当中不得不受制于公司发展的阶段、系统业务的类型和自己负责的模块的限制而无法接触到真正极致的性能优化问题。
但是,一个好的工程师仍然能站在公司和业务的角度,为系统量身打造一套最适合的性能优化方案,为业务创造最大的价值。“实用主义”的关键也正是在此,尊重业务需求,不追求极致的性能,而追求极致的“性价比”。
同时,在笔者的经验中,负责的大部分系统均是Read远远大于Write的,同时系统的瓶颈也出现在业务层面的Read,只需要优化应用层面的处理逻辑即可得到大幅优化。所以本文主要讨论的重点在于围绕缓存的各种性能优化方法

1.2 性能优化考量指标

适用场景
技术方案没有“银弹”,不同的优化方案适合不同的业务场景,我们需要根据实际情况选择适合场景的优化方案。
基于缓存的优化的前提是建立在对资源请求的不均匀,如80%的请求在20%的资源上。如果请求是均匀分布或随机的,那么缓存的优化将失去作用。
实时性
实时性是缓存方案的重要考量指标,实时性的要求通常来自于实际业务和服务需求。一般来说,缓存的设置要做到“让下游看/感觉不出来此处有缓存”。
可伸缩性(Scalability)
由于现在的微服务架构大多都有负载均衡和多副本设置,可伸缩性主要表现在想要服务提升整体性能,只需要提供更多的副本即可,服务性能和副本数量呈线性关系。
这里要注意一下,大多数简单的CRUD服务均为不可伸缩的,随着访问量的增大,数据库会变成整个系统的瓶颈。
缓存命中率(Hit Rate)
对于基于缓存的优化方案来说,缓存的命中率至关重要。根据Amdahl's law,一个系统的Hit Rate通常决定了系统能支持的最大吞吐量,因为未命中的请求会占用绝大多数的计算和网络资源。
实现复杂性
实现复杂度即实现成本,往往决定着在繁重的业务需求压力下,我们是否还有力气将优化工作落地。
瓶颈是什么?
在设计方案和实现过程中,时刻都要对整体方案进行重新审视,任何一个微小的设计不合理都可能为系统创造一个新的瓶颈。我们要时刻记得系统的瓶颈在哪,并根据实际的业务场景估算瓶颈是否可能到来。

几个非常好用的优化模式汇总

Atome 的系统为分层的微服务架构,其中每个服务有可能包含MySQL等数据库存储、服务之间接口调用、缓存访问、业务复杂计算等不同的逻辑。服务也会有很多副本(replica),每个副本是一个独立的Java/Golang 服务。
从性能角度分析,瓶颈一般出现在数据访问而非业务计算的场景。在一个正常的业务中,数据访问性能一般为

内存

Redis

(或类似缓存服务)

MySQL

(或类似关系型数据库)

内部接口

(同一集群)

读取速度

极快

相当于读取变量,基本不会成为瓶颈

比Redis慢

取决于接口性能和网络开销。大多数情况比MySQL慢

常见瓶颈

硬件资源

网络带宽,尤其是单个entry较大的情况

CPU(数据反序列化)

网络带宽

MySQL 硬件资源

连接池数量

网络带宽

CPU (数据反序列化)

依赖接口的性能

下面介绍几种在我们实践中较为常用且简单的优化模式,在实践中可以达到事半功倍的效果。

2.1 最简单内存、Redis做缓存

此模式为最简单的缓存方案,有很多非常方便的工具都可以在代码改动极少的情况下实现这种缓存实现,例如cacheManager,Guava,go-cache等,甚至有些动手能力强的同学在短时间内就能手敲一个简单的cache类出来。
在选用此缓存实现之前,一定要考虑好业务层面是否可以接受这样的方案。在一些简单的业务场景下,这种缓存结构已经能达到一个很高效的优化结果。另外在实时性要求高的场所,可以根据需求缩短缓存的失效时间,在高并发的场景下,即使是1秒的内存cache,性能也比无cache要高好几个量级。
那么该选用内存还是Redis呢?主要有下面几个考量点
  1. 内存无论是吞吐量还是对CPU、网络的负担都会更小

  2. 在使用多replica+内存的方案中,由于不同replica缓存过期时间不一致会有每次请求结果不一致的情况。

  3. Redis更适合entry数量比较多的场景,内存更适合单个entry比较大的场景

指标

评估(内存)

评估(Redis)

适用场景

对于数据的实时性要求不是很高的情况

实时性

非实时,由于没有缓存的更新策略。

由于不同副本缓存数据的时间不一致会有请求结果不确定的情况。

由于每次都访问redis,不会出现请求结果不确定的情况。

可伸缩性

可伸缩

一定程度可伸缩,受制于Redis网络带宽

缓存命中率

和缓存的失效有关。通常情况下命中率高,只有在缓存失效的时候才会不命中。

实现复杂度

很低

但一些工程师会写出容易“缓存雪崩”的代码

可能存在的瓶颈

可能由于数据量 (条数)太大,造成缓存频繁进行淘汰,造成缓存命中率低的情况

使用Redis存储较大单条数据的缓存,在数据被频繁访问时可能会面临网络带宽不足的情况

2.2 内存+Redis混合缓存

此混合缓存方案为将内存和Redis的不同特性相结合,从而得到一个能同时发挥内存和Redis强项的缓存方案。核心思想,是将数据使用内存进行缓存,使用redis来校验数据的实时性

此方法有如下的优点:

  1. 不会出现前文提到的多replica+内存方案中“请求结果不一致”情况。

  2. Redis只处理简单的checksum的存储和查询。避免了在处理单个entry较大的缓存时,可能出现网络瓶颈问题。

  3. 可做缓存的更新淘汰,只需要在数据更新时将Redis内的checksum删除。

指标

评估

适用场景

单个缓存entry数据较大

实时性

亚秒

可伸缩性

可伸缩

缓存命中率

和缓存的失效有关。通常情况下命中率高,只有在缓存失效的时候才会不命中。

实现复杂度

中等

”数据更新时将Redis内的checksum删除“,如果实现的不合理可能会破坏系统层级结构

可能存在的瓶颈

数据写入频繁使得缓存过期频繁

每次访问数据时都需要计算Checksum,如果算法选用不好有可能造成CPU性能问题

2.3 内存+MQ混合缓存

此方法是一个基于内存作为主要介质的cache系统,MQ主要解决数据更新时候的实时性问题。和之前使用Redis Checksum解决实时性问题的方法相比,主要优点在于:

  1. 缓存(内存)的数据能保证是最新的

  2. 每次访问的时候,不需要进行访问网络

  3. 系统结构较为合理,能很好的解决“数据更新”和“缓存失效”可能存在的耦合,中间仅有消息队列通信,是典型的“高内聚低耦合”的设计理念。

指标

评估

适用场景

单个缓存entry数据较大

实时性

亚秒

可伸缩性

可伸缩

缓存命中率

和缓存的失效有关。通常情况下命中率高,只有在缓存失效的时候才会不命中。

实现复杂度

中等

“数据更新时将Redis内的checksum删除”,如果实现的不合理可能会破坏系统层级结构

可能存在的瓶颈

数据写入频繁使得缓存过期频繁


总结

对于不同系统的优化多种多样,除了从应用层切入之外,还可以从系统另外的层次切入,得到不同的优化方案,例如网络、数据库甚至机器硬件,每个方面都是一门大学问。伴随着业务的发展,需要优化的系统以及优化目标也会随时变化,但无论如何,系统优化的指导理论和设计思路都是万变不离其宗的,这些东西也是我们真正需要学习和掌握的核心能力。


关于领创集团
(Advance Intelligence Group)
领创集团成立于2016年,致力于通过科技创新的本地化应用,改造和重塑金融和零售行业,以多元化的业务布局打造一个服务于消费者、企业和商户的生态圈。集团旗下包含企业业务和消费者业务两大板块,企业业务包含ADVANCE.AI和Ginee,分别为银行、金融、金融科技、零售和电商行业客户提供基于AI技术的数字身份验证、风险管理产品和全渠道电商服务解决方案;消费者业务Atome Financial包括亚洲最大的先享后付平台Atome和数字信贷服务。2021年9月,领创集团宣布完成超4亿美元D轮融资,融资完成后领创集团估值已超20亿美元,成为新加坡最大的独立科技创业公司之一。
往期回顾
BREAK AWAY





技术创想 | Python 事件循环及协程原理

技术创想 | GitOps 系列之 Flux 实践篇


   Reactor 编程之旅


   

文章转载自领创集团Advance Group,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论