架构师训练营第五周学习总结
5.1分布式缓存架构:架构原理与使用中的注意事项
缓存(cache):存储在计算机上的一个原始数据复制集,是介于数据访问着数据源之间的一种告诉存储,当需要多次读取数据的时候,可以加快数据的读取速度。缓存通常在内存中,读取速度比硬盘要快很多。
cache和buffer的区别:cache是用来在多次读取数据时加快数据的读取速度;buffer是用来提升应用程序和低速设备传输数据的效率。
无处不在的缓存:CPU缓存、操作系统缓存、数据库缓存、JVM编译缓存、CDN缓存、代理和反向代理缓存、前端缓存、应用程序缓存、分布式对象缓存。
缓存数据存储(Hash表):读取内存中的数据速度很快,但是如果使用了不合适的数据结构(例如:链表)也可能会降低访问速度。哈希表用一个数组存储key、value值,通过数组的下标计算内存地址,直接从指定的内存地址读取数据。如何得到数组的下标?简单的方法是计算key的hashcode,然后用hashcode值和数组的长度做取余运算,得到的余数就是数组的下标。哈希表的时间复杂度是O(1),速度很快。
缓存的关键指标:缓存命中率
5.2分布式缓存架构:常见的缓存实现形式
代理缓存:客户端通过代理服务器访问互联网,代理服务器属于客户端的一部分,代理服务器可以缓存资源,如果客户端访问的资源在代理服务器已经缓存,则代理服务器直接将资源返回客户端。
反向代理缓存:反向代理服务器是代理服务端的其它服务器,当客户端请求到达数据中心的时候,http反向代理拦截所有请求,当反向代理服务器缓存中没有请求的资源时才会转发给其代理的服务器,并将返回的结构缓存在自己内部,当下次有相同的请求时会将缓存中的资源直接返回给客户端。反向代理服务器可以有效降低应用服务的访问压力。
多层反向代理缓存:只要是请求资源的层前面都可以增加一个反向代理服务器
内容分发网络(CDN):托管在网络运营商机房的CDN服务器也提供反向代理服务,一般用来缓存静态资源
CDN同时配置静态文件和动态内容:AWS的CloudFront CDN接受所有静态文件和动态内容,静态资源从本地或者S3服务器上获取,动态内容将请求转发给前端服务器。
通读缓存(read-through):代理缓存、反向代理缓存和CDN缓存都是通读缓存。通读缓存服务器给客户端返回缓存资源,并在请求未命中缓存是获取实际数据。客户端连接的是通读缓存服务器而不是生产响应的原始服务器,客户端不知道原始的服务器在哪里。
旁路缓存(cache-aside):客户端先从旁路缓存中读取数据,如果未命中客户端向应用服务器请求数据,再将结果存储到旁路缓存。旁路缓存通常是一个独立的键值对存储,浏览器对象缓存和本地对象缓存是旁路缓存。
通读缓存和旁路缓存的最大区别:通读缓存不需要客户端访问应用服务器,如果通读缓存未命中,由通读缓存请求应用服务器;旁路缓存在未命中时,需要客户端自己去请求应用服务器获取资源。
本地对象缓存构建分布式集群:Jboss的缓存服务器作为一个独立的应用和应用程序部署在同一台机器上,由多台这样的机器构成集群,每台机器上的应用程序访问自己机器上的Jboss Cache,当其中一台机器上的Cache有更新时,同步更新集群中其他机器上的Cache,保证集群中每台机器上的Cache保持一致。缺点:资源浪费,每台机器上的缓存内容都一样;如果集群中的机器很多,同步更新缓存会消耗带宽。这种方式已经被淘汰。
远程分布式对象缓存:
使用独立的缓存服务器管理缓存,多个独立的缓存服务器构成一个分布式对象缓存集群,应用服务器通过RPC远程调用的方式访问缓存服务器。优点是:每台缓存服务器的缓存内容不相同,可以缓存更多的数据;集群中的服务器之间不共享任何信息Share Nothing,更容易线性伸缩;独立的缓存服务器不占用应用服务器资源。这是现在互联网常用的缓存架构。
Memcached和Redis都是远程分布式对象缓存,由每台应用服务器上的缓存客户端程序根据路由算法计算出应该从缓存集群中的哪台服务器获取或着更新缓存。缓存客户端程序的工作过程:应用程序访问缓存客户端提供的API,API调用路由算法找到集群中缓存服务器的地址,再通过通讯模块访问具体的缓存服务器。
5.3分布式缓存架构:一致性Hash算法
简单的缓存路由算法(哈希取余法)当在集群中增加一台缓存服务器时会导致原来已缓存的数据不能命中,使用一致性哈希算法可以有效解决缓存不命中的问题。
一致性hash算法:从0到2的32次方-1构成一个hash环,把每个服务器节点计算hash值,分布在hash环上,当需要获取或更新缓存时,计算key的hash值,顺时针查找距离它最近的服务器节点,从找到的服务器上读取或更新缓存。当增加增加缓存服务器时,同样计算它的hash值放在hash环上,这种算法,只会影响很少的一部分数据不能命中已有的缓存。
上面一致性hash算法存在的问题:
1.根据服务器节点计算出来的hash值不能均匀的分布在环上,造成服务器压力不均衡;
2.新增加的服务器只会影响其中的一台服务器,不能很好的分担其他服务器的压力。
改进后的一致性hash算法:将每个缓存服务器节点虚拟出150个节点,分别计算它们的hash值分布在hash环上,以便使这些虚拟节点均匀交叉的分布在hash环上,这样解决了上面节点分布不均匀的问题,当获取或更新缓存时,顺时针查找最近的虚拟节点,再通过虚拟节点找到真实的服务器。当增加一个服务器时,同样为它虚拟150个节点,均匀交叉的分布在hash环上,这样能够很好的均衡其它服务器的压力。
使用缓存的注意事项:
1.频繁修改的数据不适合使用缓存
2.没有热点的访问不适合使用缓存,当缓存的空间满,使用最近最久未使用(LRU)算法淘汰缓存
3.数据不一致与脏读,缓存中的数据会有延迟,使用缓存的地方需要接受这种延迟,对于实时数据更新时应该立即让缓存失效,或者不使用缓存
4.缓存雪崩,缓存算法或者缓存处理不当,造成缓存服务器宕机,会增加应用服务器或者数据库压力,从而导致整个系统奔溃
5.缓存预热,提前往缓存中写入数据
6.缓存穿透:频繁访问缓存中不存在的key,如果缓存处理不当,会不停的访问数据库,给数据库造成很大压力,解决的办法是把不存在的数据也缓存起来(其值为null),并设置一个很短的失效时间
5.4消息队列:
消息队列的异步架构实现写数据性能优化
消息生产者向消息队列里添加一条消息,消息消费者从消息队列里读取一条消息,处理完成后将结果返回给消息队列,消息队列通过回调通知消息生产者。
消息队列点对点模型:多个消息生产者生产消息放到消息队列,有多个消息消费者可以从消息队列中获取消息,消息队列中的消息只能被消费一次,队列中的消息只要被处理就会从消息队列中移除。
发布订阅模型:放入到消息队列中的一条消息可以被多次订阅。
消息队列的好处:
1.实现异步处理,提升处理性能,主要是写数据性能
2.更好的伸缩性,当消息队列中的消息特别多,消息消费者处理不过来的时候,可以增加消息消费者服务器,实现线性伸缩
3.削峰填谷,一个应用程序的高峰期需要更多的系统资源,而其他时候需要的资源很少,如果按高峰期的处理性能购买服务器,会造成很大资源和成本浪费。使用消息队列异步处理,在高峰期将用户请求写入消息队列,由消费消费者服务器最大的处理能力处理消息,不会高并发将这些请求发送给数据库或者其它资源敏感的服务器,从而减少并发访问量。使用消息队列可以使用比较少的资源,处理更高的并发请求。
4.失败隔离和自我修复,消息生产者不直接依赖消息消费者,所以消息消费者的系统错误可以不回传给消息生产者。
5.解耦,消息发布者和消费者没有直接联系,可以独立维护
事件驱动架构EDA
消息发布者发布消息到消息队列,消息订阅者处理消息,可以有多个订阅者对同一条消息做不同的处理。
优点:消息发布者和订阅者耦合的表面积更少
主要的MQ产品:RabbitMQ、ActiveMQ、RocketMQ、Kafka。如何选择?社区活跃度高,文档详细,资料多,百度和谷歌搜索产品名字,选结果多的
5.5负载均衡架构
用户发起的请求通过负载均衡服务器选择合适的应用服务器,负载均衡服务器将用户的高并发请求均衡的转发给集群中的应用服务器。
HTTP重定向负载均衡:客户端发送请求给负载均衡服务器,负载均衡服务器根据路由算法获取一台应用服务器的地址,写入到响应的重定向头里,客户端浏览器收到重定向响应并解析,重新把请求发送给重定向指定的IP地址(即实际的应用服务器)。缺点:用户的每次请求都要经过两次网络请求才能到达真正的应用服务器,请求效率低,浪费了宝贵的带宽;安全性差,客户端知道应用服务器地址,容易被攻击。
DNS负载均衡:域名解析服务器把同一个域名解析成不同的IP地址。现在的域名服务商都提供把一个域名解析成多个IP地址的服务。上面的重定向每次有需要重定向,而域名解析只是第一次需要解析,所以不会带来性能问题,但同样会带来安全问题。现在的大型互联网应用都使用了DNS负载均衡,这些大型互联网应用通过DNS解析出来IP地址并不是真正的应用服务器IP地址,而是这些互联网应用的负载均衡服务器地址,这些大型互联网应用使用了两级的负载均衡。
反向代理负载均衡:由反向代理服务器将客户端请求转发给不同的应用服务器,实现负载均衡。在比较小的系统中经常使用,服务器的规模几台或者十几台。缺点:效率低,性能差。客户端发起的http请求通过TCP协议到达反向代理服务器,多个TCP协议包构建成一个HTTP请求的时候,反向代理服务器才能转发,反向代理服务器需要进行应用层协议转换,才能转发。收到应用服务器响应时也需要把多个TCP协议包构建成一个HTTP响应,当请求数量很大时,应用层协议转换会带给反向代理服务器很大压力,所以反向代理负载均衡不适用于大型高并发系统。
IP负载均衡:不构建http请求,对更底层的协议进行转发,例如:通过修改IP地址实现负载均衡。客户端发起一个http请求,这个http请求可能包含多个tcp/ip协议数据包,IP负载均衡服务器收到这些数据包,根据路由算法直接修改这些数据包里的IP地址,把目标地址改成应用服务器的地址,把源地址改成自己的地址,然后请求应用服务器,由应用服务器构建http 数据包。应用服务器处理完成后返回给负载均衡服务器,负载均衡服务器根据内部的一张映射表,替换tcp/ip数据包中的目标地址为客户端地址,源地址为自己的地址,客户端收到多个tcp/id数据包后构建http响应包并处理响应。IP负载均衡由于不需要进行应用层协议转换,所以效率很高。缺点:由于http响应的数据包一般都比较大,可能会分成多个TCP/IP数据包传输,每次都需要IP负载均衡服务器处理大量的数据包,IP负载均衡服务器网卡的带宽都可能成为瓶颈,每个数据包都需要IP地址替换,cpu的压力也很大。
数据链路层负载均衡:
数据链路层在物理层的上面,在IP协议的下面,数据链路层记录每台机器网卡的MAC地址。网络通信发出请求的时候会携带目标服务器的MAC地址,通过修改MAC地址实现负载均衡。客户端发起一个请求到负载均衡服务器,负载均衡服务器收到请求后不管具体的数据,而是直接将请求中目标服务器的MAC地址由原来的负载均衡服务器MAC地址改为应用服务器MAC地址,(技巧:负载均衡服务器和应用服务器使用相同的虚拟IP地址),然后把这个数据包重新丢到网络中,目标应用服务器就会收到该请求并处理,处理完成后的相应包直接返回给客户端,而不会再经过负载均衡服务器,因为负载均衡服务器并没有修改IP地址,源地址还是客户端地址,所以应用服务器构建响应包时,会把目标地址设置为客户端地址,源地址设置成自己的地址。数据链路层负载均衡是大型网络应用最常用的方法,也是最高效的方法。
负载均衡的算法:
应用服务器集群的Session管理:
1.session复制,每个应用服务器都记录相同的session上下文,当session发生变化时,同步到集群中的其它应用服务器。性能低。
2.session绑定:使用源地址散列算法,将同一个地址的请求总是分发到同一个服务器上处理。缺点:无法实现高可用,当这台服务器宕机时,会丢失session
3.利用cookie记录session:通过http协议中的cookie存储session信息并在网络中传送。缺点cookie的容量有限,不能记录太多的信息,但仍然是一种简单高效的session管理方式,实际中也经常使用。
4.Session服务器:通过一个专门的session服务器或集群管理session,是分布式网络架构中最常用的一种方式。应用服务器不再记录session,请求分发给应用服务器后,应用服务器从session服务器中获得session信息,进行操作完成后再记录到session服务器。
无状态的应用服务,Share Nothing的架构方式是分布式架构里面最高效、最容易管理、最容易实现,在集群伸缩运维等方面都是最好的一种设计方式
评论