正文
本系列的最后一篇,现在草草地把这个系列结束了,期待日后对内容的丰富。
扩容
垂直扩容(纵向扩展)
提高单个服务(服务器、数据库)自身能力
但会增大单个服务中其他软件设施的依赖与管理、服务内部复杂度
水平扩容(横向扩展)
增加更多服务成员
但会增加网络、数据库IO开销、管理多个服务器的难度
对数据库的扩容方案
确定业务类型
-
读操作多:采用垂直扩容方案(redis、CDN)。采用水平扩容没有太大的意义,因为性能的瓶颈不在写操作,所以不需要实时去完成,用更多的服务器来分担压力性价比太低。所以针对单个系统去强化它的读性能就可以了
-
写操作多:采用水平扩容方案(HBase、增加服务器、数据库)。也可以考虑垂直扩容提升单个数据库的性能,但会发现资金与硬盘的IO能力是有限的,所以需要增加更多数据库来分担写的压力。
缓存
应用需要支撑大量并发量,但数据库的性能有限,所以使用缓存来减少数据库压力与提高访问性能
特征
-
命中率 = 命中数 / (命中数 + 没有命中数)
-
最大空间:缓存最大空间
-
清空策略:FIFO/LFU/LRU/过期时间/随机
FIFO:最先进入缓存的数据,在缓存空间不足时被清除,为了保证最新数据可用
LFU(Least Frequently Used):最近最不常用,基于访问次数,去除命中次数最少的元素 LRU(Least Recently Used):最近最少使用,基于访问时间,在被访问过的元素中去除最久未使用的元素
其实编程时候写的成员变量、静态变量、常亮也被看做缓存
高并发缓存问题
缓存一致性
全量、增量同步
根据业务需求决定分布式锁
缓存并发
当大量请求访问同一个没有被缓存的数据的时候,会发送大量请求给数据库,导致数据库压力过大,还会导致一致性问题,所以解决方式就是在缓存获取的时候加上针对单个数据的锁,直到缓存被重建成功得到最新数据
缓存击穿/穿透
查询一个数据库中不存在的数据,比如商品详情,查询一个不存在的ID,每次都会访问DB,如果有人恶意破坏,很可能直接对DB造成过大地压力。
解决方案:当通过某一个key去查询数据的时候,如果对应在数据库中的数据都不存在,我们将此key对应的value设置为一个默认的值。
缓存失效
在高并发的环境下,如果此时key对应的缓存失效,此时有多个进程就会去同时去查询DB,然后再去同时设置缓存。这个时候如果这个key是系统中的热点key或者同时失效的数量比较多时,DB访问量会瞬间增大,造成过大的压力。
解决方案:
-
将系统中key的缓存失效时间均匀地错开
-
当我们通过key去查询数据时,首先查询缓存,如果此时缓存中查询不到,就通过分布式锁进行加锁
热点key
缓存中的某些Key(可能对应用与某个促销商品)对应的value存储在集群中一台机器,使得所有流量涌向同一机器,成为系统的瓶颈,该问题的挑战在于它无法通过增加机器容量来解决。
解决方案:
-
客户端热点key缓存:将热点key对应value并缓存在客户端本地,并且设置一个失效时间。
-
将热点key分散为多个子key,然后存储到缓存集群的不同机器上,这些子key对应的value都和热点key是一样的。
消息队列
消息队列是为了解决
生产和消费的速度不一致
导致的问题,有以下好处: