Week 05 学习总结
本周主要学习了分布式缓存、消息队列、负载均衡以及一部分分布式数据库的知识(分布式数据库下周还要继续讲的)。
1 分布式缓存架构
1.1 缓存概述
缓存:存储在计算机上的一个原始数据复制集,以便于访问(维基百科的说明)
缓存是介于数据访问者和数据源之间的一种高速存储,当数据需要多次读取的时候,用
于加快读取的速度。(缓存就是一个多次读取的高速存储)
缓存无所不在,只要需要对数据进行多次读取时,都可以用缓存:
-CPU缓存
-操作系统缓存
-数据库缓存
-JVM编译缓存
-CDN缓存
-代理与反向代理缓存
-应用程序缓存
-分布式对象缓存
缓存的底层数据存储是Hash表,而Hash表本质上是一个数组:
缓存为什么能显著提升性能:
缓存数据通常来自内存,比磁盘上的数据有更快的访问速度。
缓存存储数据的最终结果形态,不需要中间计算,减少CPU资源的消耗。
缓存降低数据库、磁盘、网络的负载压力,使这些I/O设备获得更好的响应特性。
而且正因为缓存技术简单、性能提升显著且应用场景多,使缓存成为了系统性能优化的大杀器哦。
注意:
1.不要缓存频繁修改的数据:
对于频繁修改的数据如果缓存起来,由于频繁修改,应用还来不及读取就已失效
或更新,徒增系统负担。一般说来,数据的读写比在2:1以上,缓存才有意义!
2.不要缓存没有热点的访问:
没有热点的访问:缓存使用内存作为存储,内存资源宝贵而有限,不能将所有数据都缓存起来,如果应用系统访问数据没有热点,不遵循二八定律,即大部分数据访问不是集中在小部分数据上,那么缓存就没有意义,因为大部分数据还没有被再次访问就已经被挤出缓存了。
3.使用LRU算法可使缓存“知道”哪些是热点数据。
1.2 缓存Cache和缓冲Buffer的分别
缓存(cache):把常用数据存储到可以快速获取的区域(缓存区),以备重复利用,提高效率。
例如:从内存中读取数据时,先将常用的数据存放到缓存区,硬盘直接从缓存区读取。
缓冲(buffer):在数据流转过程中,不同层次数据速度不一致时,利用缓冲区来缓解上下层之间速度问题,增加速度。
例如:将数据写入到内存时,先写入缓冲区,内存则直接从缓冲区中读取写入,减少IO次数,增加速度,降低对磁盘的损耗
1.3 缓存的关键指标
缓存命中率:
指缓存是否有效依赖于能多少次重用同个缓存响应业务请求,这个度量指标被称作缓存命中率。如果查询一个缓存,十次查询九次能够得到正确结果,那么它的命中率是90%。
影响缓存命中率的主要指标:
●缓存键集合大小:
缓存中的每个对象使用缓存键进行识别,定位一个对象的唯一 方 式就是对缓存键执行精确匹配。
例如,如果想为每个商品缓存在线商品信息,你需要使用商品ID作为缓存键。
换句话说,缓存键空间是你的应用能够生成的所有键的数量。
从统计数字上看,应用生成的唯一键越多,重用的机会越小。例如,如果想基于客户IP地址缓存天气数据,则可能有多达40亿个键(这是所有可能的IP地址的数量)。如果要基于客户来源国家缓存天气数据,则可能仅需几百个缓存键(世界上所有国家的数量)。一定要想办法减少可能的缓存键数量。
键数量越少,缓存的效率越高。
●缓存可使用内存空间:
缓存可使用内存空间直接决定了缓存对象的平均大小和缓存对象数量。因为缓存通常存储在内存中,缓存对象可用空间受到严格限制且相对昂贵。如果想缓存更多的对象,
就需要先删除老的对象,再添加新的对象。替换(清除)对象会降低缓存命中率,因为缓存对象被删除后,将来的请求就无法命中了。
物理上能缓存的对象越多,缓存命中率就越高。
●缓存对象生存时间:
缓存对象生存时间称为TTL ( Time ToLive )。在某些场景中,例如,缓存天气预报
数据15分钟没问题。在这个场景下,你可以设置缓存对象预定义TTL为15分钟。在
其他场景中,你可能不能冒险使用过于陈旧的数据。
例如,在个电子商务系统中 ,店铺管理员可能在任何时刻修改商品价格,如果这些价格需要准确地展示在整个网站中。在这个场景下, 你需要在每次商品价格修改时让缓存失效。
简单讲,对象缓存的时间越长,缓存对象被重用的可能性就越高。
1.4 代理缓存与反向代理缓存
●代理缓存:
●反向代理缓存:
●多层反向代理缓存:
1.5 内容分发网络(CDN)
CDN(Content Delivery Network),即内容分发网络。
各地部署多套静态存储服务,本质上是空间换时间。
自动选择最近的节点内容,不存在再请求原始服务器。
适合存储更新很少的静态内容,文件更新慢。
CDN同时配置静态文件和动态内容:
1.6 什么是通读缓存(read-through)
代理缓存,反向代理缓存,CDN缓存都是通读缓存。
通读缓存给客户端返回缓存资源,并在请求未命中缓存时获取实际数据。
客户端连接的是通读缓存而不是生成响应的原始服务器。
1.7 什么是旁路缓存(cache-aside)
对象缓存是一种旁路缓存,旁路缓存通常是一个独立的键值对( key-value )存储。
应用代码通常会询问对象缓存需要的对象是否存在,如果存在,它会获取并使用缓
存的对象,如果不存在或E过期,应用会连接主数据源来组装对象,并将其保存回
对象缓存中以便将来使用。
1.8 浏览器对象缓存
1.9 本地对象缓存
-将对象直接缓存在应用程序内存中。
-将对象存储在共享内存,同一台机器的多个进程可以访问它们。
-将缓存服务器作为独立应用和应用程序部署在同一个服务器上。
1.10 远程分布式对象缓存
分布式对象缓存中的每台缓存服务器之间是互不感知的,他们共同组成一个集群对外提供服务。
Memcached分布式对象缓存:
Memcached分布式缓存访问模型:
1.11 一致性Hash算法
使用余数Hash选择缓存服务器时,当改变缓存服务器的数量后,会造成缓存大量失效的问题。
一致性哈希算法是分布式系统中常用的算法。
一致性哈希算法解决了普通余数Hash算法伸缩性差的问题,可以保证在上线、下线服务器的情况下尽量有多的请求命中原来路由到的服务器。
分布式对象缓存的一致性hash算法:
一致性哈希的基本原理就是在一个hash环上(如范围0-2^32-1)计算服务器节点的hash值,如果一个object要寻找应该路由的服务器节点,则计算其hash值,并在环上顺时针查找离它最近的节点。
虚拟节点的一致性Hash算法:
为了分布得更均匀,通过使用虚拟节点的方式,每个节点计算出n个hash值,均匀地放在hash环上这样数据就能比较均匀地分布到每个节点。
1.12 各种介质数据访问延迟
1.13 技术栈各个层次的缓存
1.14 与缓存相关的问题
数据不一致和脏读:
一般会对缓存的数据设置失效时间,一旦超过失效时间,就要从数据库中重新加载。因此应用要容忍一定时间的数据不一致。比如卖家已经编辑了商品属性,但是需要过一段时间才能被买家看到。
在互联网应用中,这种延迟通常是可以接受的,但是具体应用仍需慎重对待。
还有一种策略是数据更新时立即更新缓存,不过也会带来更多系统开销和事务一致性的问题,因此数据更新时通知缓存失效,删除该缓存数据,是一种更加稳妥的做法。
缓存雪崩:
缓存是为了提高数据读取性能的,缓存数据丢失或者缓存不可用不会影响到应用程序的处--它可以从数据库直接获取数据。
但是随着业务的发展,缓存会承担大部分的数据访问压力,数据库已经习惯了有缓存的日子,所以当缓存服务崩溃的时候,数据库会因为完全不能承受如此大的压力而宕机,进而导致整个网站不可用。
这种情况,被称作缓存雪崩,发生这种故障,甚至不能简单的重启缓存服务器和数据库服务器来恢复网站访问。
缓存穿透:
如果不恰当的业务、或者恶意攻击持续高并发的请求某个不存在的数据,因为缓存没有保存该数据,所有的请求都会落到数据库上,会对数据库造成很大的压力,甚至崩溃。
一个简单的对策是将不存在的数据也缓存起来(其value值为null), 并设定一个较短的失效时间。
缓存预热:
缓存预热:缓存中存放的是热点数据,热点数据又是缓存系统利用LRU (最近最久未
用)算法对不断访问的数据筛选淘汰出来的,这个过程需要花费较长的时间,在这段时
间,系统的性能和数据库负载都不太好,那么最好在缓存系统启动的时候就把热点数据
加载好,这个缓存预加载手段叫做缓存预热( warm up )。对于一-些元数据如城市地名
列表、类目信息,可以启动时加载数据库中全部数据到缓存进行预热。
2 消息队列与异步架构
2.1 同步调用与异步调用
-同步调用:
同步调用是一种阻塞式调用,一段代码调用另一端代码时,必须等待这段代码执行结束并返回结果后,代码才能继续执行下去。
-异步调用:
异步调用是一种非阻塞式调用,一段异步代码还未执行完,可以继续执行下一段代码逻辑,当代码执行完以后,通过回调函数返回继续执行相应的逻辑,而不耽误其他代码的执行。
无回调的异步调用:
有回调的异步调用:
2.2 消息队列构建异步调用架构
-点对点模型:
-发布订阅模型:
使用消息队列的好处:
1.实现异步处理,提升处理性能:
2.更好的伸缩性:
3.削峰填谷:
4.失败隔离和自我修复:
因为发布者不直接依赖消费者,所以消息系统可以将消费者系统错误与生产者系统组件隔离。生产者和消费者互相不受对方失败影响。
这意味着任意时刻,我们都可以对后端服务器执行维护和发布操作。我们可以重启、添加或删除服务器而不影响生产者可用性,这样简化了部署和服务器管理的难度。
5.解耦:
2.3 事件驱动架构EDA
EDA 是一种侧重于以生成/消费为基础的异步通信的架构模式。这主要对照于传统的基于线程的同步系统。
EDA 是一种以事件 (event)为核心,提供事件产生,路由,消费已经结果回调等机制的架构模式。
传统面向接口编程是以接口为媒介,实现调用接口者和接口实现者之间的解耦,但是这种解耦程度不是很高,如果接口发生变化,双方代码都需要变动,而事件驱动则是调用者和被调用者互相不知道对方,两者只和中间消息队列耦合。
事件驱动有以下特征:
1.生产者producer发生实时事件
2.推送通知
3.生产者发射即完成fire-and -orget
4.消费者consumer立即响应
5.事件与命令是有区别的
2.4 主要MQ产品比较
RabbitMQ:主要特点是性能好,社区活跃,但是RabbitMQ 用Erlang开发,对不熟悉Erlang的同学而言不便于二次开发和维护。
ActiveMQ:影响比较广泛,可以跨平台,使用Java开发,对Java比较友好。
RocketMQ:阿里推出的一个开源产品,也是使用Java开发,性能比较好,可靠性也比较高。
Kafka:LinkedIn 出品的,Scala 开发,专针对分布式场景进行了优化,因此分布式的伸缩性会比较好。
3 负载均衡
3.1 负载均衡概述
负载均衡,英文名称为Load Balance,其含义就是指将负载(工作任务)进行平衡、分摊到多个操作单元上进行运行,例如FTP服务器、Web服务器、企业核心应用服务器和其它主要任务服务器等,从而协同完成工作任务。
负载均衡构建在原有网络结构之上,它提供了一种透明且廉价有效的方法扩展服务器和网络设备的带宽、加强网络数据处理能力、增加吞吐量、提高网络的可用性和灵活性。
3.2 负载均衡技术
3.2.1 HTTP重定向负载均衡
3.2.2 DNS负载均衡
3.2.3 反向代理负载均衡
3.2.4 IP负载均衡
3.2.5 数据链路层负载均衡
3.3 负载均衡算法
1.轮询:
所有请求被依次分发到每个应用服务器上,适合于所有服务器硬件都相同的场
景。
2.加权轮询:
根据应用服务器硬件性能的情况,在轮询的基础上,按照配置的权重将请
求分发到每个服务器,高性能的服务器分配更多请求。
3.随机:
请求被随机分配到各个应用服务器,在许多场合下,这种方案都很简单实用,
因为好的随机数本身就很均衡。如果应用服务器硬件配置不同,也可以很容易的使用
加权随机算法。
4.最少连接:
记录每个应用服务器正在处理的连接数(请求数) ,将新到的请求分发到
最少连接的服务器上,应该说,这是最符合负载均衡定义的算法。
5.源地址散列:
根据请求来源的IP地址进行Hash计算,得到应用服务器,该算法可以保
证同一个来源的请求总在同一个服务器上处理,实现会话粘滞。
3.4 应用服务器集群的Session管理
应用服务器的高可用架构设计主要基于服务无状态这一特性,但是事实上,业务总是有
状态的,在交易类的电子商务网站,需要有购物车记录用户的购买信息,用户每次购买
请求都是向购物车中增加商品;在社交类的网站中,需要记录用户的当前登录状态、最
新发布的消息等以便及时将这些信息通知给他的好友。
Web应用中将这些状态信息称作会话(Session) ,单机情况下,Session 可交给Web容器管理,在使用负载均衡的集群环境中,Session 管理主要有以下几种手段:
3.4.1 Session复制
3.4.2 Session绑定
3.4.3 利用Cookie记录Session
3.4.4 Session服务器
4 分布式数据库(上)
4.1 MySQL主从复制
MySQL 主从复制是指数据可以从一个MySQL数据库服务器主节点复制到一个或多个从节点。
MySQL 默认采用异步复制方式,这样从节点不用一直访问主服务器来更新自己的数据,数据的更新可以在远程连接上进行,从节点可以复制主数据库中的所有数据库或者特定的数据库,或者特定的表。
为什么需要主从复制?
1、在业务复杂的系统中,使用主从复制实现读写分离;让主库负责写,从库负责读,这样,即使主库出现了锁表的情景,通过读从库也可以保证业务的正常运作。
2、做数据的热备
3、架构的扩展。业务量越来越大,I/O访问频率过高,单机无法满足,此时做多库的存储,降低磁盘I/O访问的频率,提高单个机器的I/O性能。
4.2 MySQL一主多从复制
一主多从复制的优点:
-分摊负载
-专机专用
-便于冷备
-高可用
4.3 MySQL主主复制实现高可用
-MySQL主主失效恢复:
-MySQL主主失效的维护过程:
-MySQL复制注意事项:
主主复制的两个数据库不能并发写入。
复制只是增加了数据的读并发处理能力,没有增加写并发能力和存储能力。
更新表结构会导致巨大的同步延迟。
评论