缓存?就这?

165 阅读4分钟

性能,越来越成为当今评估开发者开发能力的高低的重要指标。通常来说,服务端与数据库打交道是比较频繁的,也是非常耗费机器资源的。 通常再这个环节容易出现性能问题。一般来说,对数据库的CRUD只要维护好Insert、update和delete操作,就不太会出现性能问题。insert一般不会有性能问题,update和delete一般会有主键,所以也不会太慢。除非索引建的太多,而数据库里的数据又太多,这三个操作才会变慢。 绝大多数情况下,select会成为拖垮系统的最后稻草。

  • 一方面,select会有很多像join、group、order、like等这样丰富的语义,这些语义是非常耗费性能的
  • 另一方面,大多数应用都是读多写少,所以加剧了慢查询的问题。
  • 分布式系统中的远程调用也会影响性能,由于网络通信存在网络开销,会导致整体的响应时间下降。为了挽救这样的性能开销,可以通过缓存来补救性能的缺失(对数据实时性要求不高时)
  • 缓存是大型系统和移动互联网中不可或缺的一部分,因为网络质量是非常能保证每时每刻都非常稳定的。前端通常会对 API加上缓存,以防网络异常导致没有数据,影响UI展示。

缓存是提高性能最好、最直接的方式,通常情况下,缓存有以下三种模式:

1. cache aside更新模式(最常用的缓存设计模式)

(查询未命中缓存)服务端先从缓存中取数据,如果没有命中缓存,则走库,查库成功,更新缓存

(查询命中缓存)服务端从缓存中取数据,取到后返回

(更新清理缓存):先把数据存到数据库中,成功后,再让缓存失效 代码需要维护两处:缓存和数据库

2. read through/write through

read through:它的套路就是再查询操作中更新缓存,如果当前内容的缓存存在,则更新缓存,再更新数据库;如果不存在,则更新缓存,再更新数据库。(更新数据库的操作由缓存代理)

write through:write through套路和read through相仿,不过是再更新数据时发生。当有数据更新的时候,如果没有缓存,则更新数据库,然后更新缓存。如果有缓存,则更新缓存,然后由缓存同步到数据库(这是同步操作)

3. write behind caching

write behind caching 与Linux操作系统内核的write back原理一样,其原理就是,再更新数据的时候,只更新缓存,不更新数据库,而我们的缓存会一步地批量更新数据库,这个设计地好处就是让数据的I/0操作很快,直接处理内存。因为异步,还可以合并对统一数据的多次操作,所以性能的提高是相当可观的。

现在很多公司都在用redis来做缓存中间件,一方面是因为redis的数据结构比较丰富,另一方面,我们不能再service内放local cache,一是每一台机器的内存不够大,二是我们的sercice有多个实例,负载均衡会把请求随机分不到不同的梳理,缓存需要在所有的service实例上都创建好,这让service有了状态,难以管理。

所以一般情况分布式项目都需要一个分布式缓存集群,这个缓存集群要保证内存足够大,网络带宽也要好,因为缓存本质上是一个内存和IO密集型的应用。

如果需要内存很大,那么你还要动用数据分片技术来把不同的缓存分布到不同的机器上,这样,可以保证集群的扩展性。

缓存的好坏要看命中率,一般命中率可以达到80%以上,就算很不错了。

另外,缓存是牺牲强一致性来提高性能的,这世上任何事情都不是免费的,所以并不是所有业务都适合缓存,这需要在设计的时候仔细调研好需求。

缓存数据的时间周期,也需要设计好,太长或太短都不可,一般缓存策略会选择LRU策略,就是将最不活跃的缓存数据清理,所谓最不活跃就是最长时间没有被访问的数据。LRU缓存系统需要早K**-**V这样的非顺序的数据结构中维护一个顺序的数据结构,并在读缓存时候,改变访问数据在这个结构中的顺位。于是LRU在读写的时候都需要加锁,因此LRU可能会导致更慢的缓存存取时间。这点值得关注。

我是littleKing,一个除了活命,还有理想的程序员~ 下期 再会~