写点什么

架构师训练营第一期 - 第五周学习总结

发布于: 2020 年 10 月 26 日

使用缓存处理是计算机系统性能优化的重要手段,在互联网应用系统中使用缓存主要是保存用户需要多次读取的数据,也就是满足降低用户响应延迟获得良好体验的需求。缓存在计算机系统中是无处不在的,比如 CUP 使用的 L1\L2\L3 缓存、操作系统内核进行数据读写时使用内存缓存、数据库进行数据读写时也会使用内存缓存。这是因为计算处理的速度远远高于读取数据的速度导致了计算和数据失配,从而导致整个计算过程时间长性能低。

在互联网应用系统中也使用了很多缓存处理的手段来提高用户的请求响应,比如:CDN 缓存、反向代理缓存、前端缓存及应用程序缓存等等。缓存通常是使用 hash 表数据结构来存储数据,因为缓存的目的是能够快速查询获取到数据,需要查询速度尽可能地快,而 hash 表地查询速度是 O(1)能很好的满足需求。hash 表通过将 key 进行 hashcode 计算,然后根据 hashcode 计算出 hash 表的索引地址就可以快速定位数据存储的位置。衡量缓存使用好不好的关键指标是缓存命中率:从缓存中查找到的次数/从缓存中查找的次数。影响缓存命中率的因素主要有:缓存键集合的大小、缓存可使用的内存空间、缓存对象的生存时间。一般来讲缓存是使用内存的,而内存的空间大小是有限的,如果缓存键越多能够放到缓存的对象就越少,缓存命中率就会越低,如果缓存能够使用的内存空间越大能够缓存的对象就越多,缓存命中率就会越高,当缓存中存放不下更多缓存对象时就需要删除旧的对象在增加新的对象进行替换,进行缓存对象替换会降低缓存命中率。

缓存的类型分为:通读缓存和旁路缓存,通读缓存和旁路缓存的最大区别是客户端应用程序连接的时候是不是直接连接最终的数据源,通读缓存是客户端连接的是缓存服务器并由其代理客户端请求,旁路缓存是要客户端直接连接服务端获取数据并将数据写入到缓存中。代理缓存、反向代理缓存、内容分发网络 CDN 都是通读缓存,而应用程序中常用的对象缓存(浏览器对象缓存、本地对象缓存、分布式对象缓存)是旁路缓存。现在的大型互联网应用中一般都是会结合使用通读缓存和旁路缓存,使用 CDN 和反向代理来缓存大量的网页静态数据,使用分布式对象缓存比如 redis 来进行应用数据缓存以减少数据库的数据访问压力。

分布式对象缓存的路由算法一般是采用一致性 hash 算法:先构造一个长为 2^32 的整数环,时钟 12 点位置为 0,按顺时针方向递增,临近 12 点的左侧位置为 2^32-1,根据节点的 Hash 值将 Node(服务器)分配到环的对应位置上,然后计算需要查询数据的键值 KEY 的哈希值,然后在哈希环上顺时针查询离这个 KEY 最近的服务器节点完成映射。服务器删除节点或者有节点宕机时,比如要删除节点 Node3,只会影响该节点与上一个节点(Node2)之间的对象,这部分对象将被调整映射到下一个节点 Node4,而其他对象的映射关系都无需调整。服务器增加节点时,比如要在 Node2 和 Node3 之间增加节点 NodeN,只会影响新增节点(NodeN)与上一个节点(Node2)之间的对象,这部分对象调整映射到新增节点 NodeN,其他对象的映射关系都无需调整。一致性哈希算法在服务节点太少时,容易因为节点分部不均匀而造成数据倾斜问题。解决这个问题的办法是使用虚拟节点,将一个服务器节点虚拟成若干个虚拟节点,将虚拟节点放到环上。

缓存实现技术简单,对系统的性能提升显著。但是不合理的使用缓存可能非但不能提高系统的性能,还会成为系统的累赘,甚至风险。频繁修改的数据及没有热点的访问这两种场景是不适合使用缓存的。缓存设计时需要注意避免“缓存雪崩”问题,因为缓存是为了避免数据库的读取负载压力,而一旦

缓存出现问题,大量的数据请求将直接访问数据库而致使数据库崩溃进而整个系统崩溃。缓存服务启动时可以使用“缓存预热”提前将热点数据通过人为收到写入到缓存中,避免缓存数据需要通过 LRU 算法进行长时间的选择来自动产生。

如果说使用缓存解决了系统的数据读取性能优化,那消息队列就是用来解决系统的数据写入性能优化的。消息队列通过异步处理机制设计解耦了程序开发,程序的生产者独立开发程序把消息写到消息队列中就可以了,而程序的消费者也独立开发程序从消息队列中读取消息就可以了。这样解耦后的程序是独立部署独立运行的,前端程序不必再等待耗时的后端程序处理完成并返回响应后才能进行后续的处理而提升了系统处理性能,另外可以指针对耗时的后端处理程序进行扩容处理,扩容更加容易。除了这些之外,因为生产者不直接依赖消费者,所以消息队列可以使生产者和消费者互相不受对方失败的影响;这意味着任意时刻我们都可以对后端服务器执行维护和发布操作,从而达到失败隔离、自我修复的目的。

使用消息队列还可以进行削峰填谷:如果应用服务器按最高峰的并发请求进行部署,那可能要部署正常需求的几倍几十倍的服务器,而最高峰可能仅仅只持续几秒钟,但是如果不增加这些服务器,高峰期的这些请求过来又会把一些负载压力大的应用服务器压垮(比如数据库),进而整个系统都会崩溃。使用消息队列来解决这个问题,将消息都写入到消息队列,消费者按自己的处理能力去消息队列获取数据进行处理,处理不过来的先堆积在消息队列中,直到将消息队列中的消息处理完。


现在的大型互联网系统都是使用分布式架构来满足系统的高并发处理请求,在分布式架构中使用负载均衡技术来将并发请求均匀的路由分发给相关的应用服务器集群中的单台服务器进行处理是必不可少的部分。当前的互联网系统架构中一般使用两级负载均衡架构:在数据中心之外利用 DNS 的 A 记录机制实现负载均衡,在数据中心内部再部署一层负载均衡服务器集群。DNS 解析得到的是负载均衡服务器的地址,每一台负载均衡服务器再负责负载均衡一个小的应用服务器集群,很多台负载均衡服务器的集群组合成一个大的应用服务器集群。内部负载均衡可以使用反向代理负载均衡、IP 负载均衡和链路层负载均衡。反向代理负载均衡在实践中是比较常见的,但通常是应用在比较小的应用系统中(几台十几台应用服务器集群),主要由于是效率比较低性能比较差,因为它代理的是 http 请求,而应用层的 http 协议是比较厚重的。在大的应用系统中通常是使用基于更低层网络协议进行请求的转发的负载均衡技术:IP 负载均衡和链路层负载均衡,如果一个请求包对应一两个响应包可以使用 IP 负载均衡,但是如果一个请求包需要返回几百几千个响应包则需要使用链路层负载均衡,避免负载均衡服务器的网卡带宽瓶颈。


用户头像

还未添加个人签名 2019.01.15 加入

还未添加个人简介

评论

发布
暂无评论
架构师训练营第一期 - 第五周学习总结