写点什么

week5 技术选型(一) 学习总结

用户头像
杨斌
关注
发布于: 2020 年 11 月 22 日

第 5 周 技术选型(一)

5.1 分布式缓存架构:架构原理与使用中的注意事项

什么是缓存

  • 缓存:存储在计算机上的一个原始数据复制集,以便于访问 –(维基百科)

  • 缓存是介于数据访问者和数据源之间的一种高速存储,当数据需要多次读取的时候,用 于加快读取的速度。

  • 缓存( Cache )和缓冲 (Buffer )的分别?

 

 无处不在的缓存

  • CPU 缓存 

  • 操作系统缓存 

  • 数据库缓存 

  • JVM 编译缓存

  • CDN 缓存 

  • 代理与

  • 反向代理缓存 

  • 前端缓存 

  • 应用程序缓存 

  • 分布式对象缓存

 

 缓存数据存储(Hash 表)



缓存的关键指标

  • 缓存命中率

  • 缓存是否有效依赖于能多少次重用同一个缓存响应业务请求,这个度量指标被称作缓存命中 率

  • 如果查询一个缓存,十次查询九次能够得到正确结果,那么它的命中率是 90%

影响缓存命中率的主要指标

  •  缓存键集合大小

  • 缓存中的每个对象使用缓存键进行 识别,定位一个对象的唯一方式就是对缓存键执行精 确匹配。例如,如果想为每个商品缓 存在线商品信息,你需要使用商品 ID 作为缓存键。 换句话说,缓存键空间是你的应用能 够生成的所有键的数量。从统计数字上看,应用生 成的唯一键越多,重用的机会越小。例 如,如果想基于客户 IP 地址缓存天气数据,则 可能有多达 40 亿个键(这是所有可能的 IP 地址的数量)。如果要基于客户来源国家缓存 天气数据,则可能仅需几百个缓存键(世界上所有国家的数量)。一定要想办法减少可能的 缓存键数量。键数量越少,缓存的效率越高。

  •  缓存可使用内存空间

  • 缓存可使用内存空间直接决定了缓存对象的平均大小和缓存对象数量。因为缓存通常存 储在内存中,缓存对象可用空间受到严格限制且 相对昂贵。如果想缓存更多的对象,就 需要先删除老的对象,再添加新的对象。替换(清除)对象会降低缓存命中率,因为缓存对 象被删除后,将来的请求就无法命中了。物理上能缓存的对象越多,缓存命中率就越高。

  • 缓存对象生存时间

  • 缓存对象生存时间称为 TTL( Time To Live )。在某些场景中,例如,缓存天气预报数 据 15 分钟没问题。在这个场景下, 你可以设置缓存对象预定义 TTL 为 15 分钟。在其 他场景中,你可能不能冒险使用过于陈旧的数据。例如,在一个电子商务系统中,店铺 管理员可能在任何时刻修改商品价格,如果这些价格需要准确地展示在整个网站中。在 这个场景下,你需要在每次商品价格修改时让缓存失效。简单讲,对象缓存的时间越长, 缓存对象被重用的可能性就越高。

 

5.2 分布式缓存架构:常见的缓存实现形式

代理缓存



反向代理服务



多层反向代理缓存



内容分发网络(CDN)



CDN 同时配置静态文件和动态内容



 通读缓存(read-through)

  • 代理缓存,反向代理缓存,CDN 缓存都是通读缓存。

  • 通读缓存给客户端返回缓存资源,并在请求未命中缓存时获取实际数据。 

  • 客户端连接的是通读缓存而不是生成响应的原始服务器。



 旁路缓存(cache-aside)

  • 对象缓存是一种旁路缓存,旁路缓存通常是一个独立的键值对(key-value)存储。

  • 应用代码通常会询问对象缓存需要的对象是否存在,如果存在,它会获取并使用缓存 的对象,如果不存在或已过期, 应用会连接主数据源来组装对象,并将其保存回对象 缓存中以便将来使用



 浏览器对象缓存 

// 在WebStorage中缓存对象的JavaScript代码var preferences = {/* data object to be stored */}; localStorage.setItem('preferences', JSON.stringify(preferences));

// 访问缓存对象的JavaScript代码var cachedData = localStorage.getItem('preferences');var preferences = JSON.parse(cachedData);
复制代码

 

 本地对象缓存

• 对象直接缓存在应用程序内存中 。

• 对象存储在共享内存,同一台机器的多个进程可以访问它们。 • 缓存服务器作为独立应用和应用程序部署在同一个服务器上。

 

本地对象缓存构建分布式集群



远程分布式对象缓存  



Memcached 分布式对象缓存

//PHP客户端访问Memcached集群 $m = new Memcached(); //添加服务器集群 $cache->addServers(array(array('cache1.example.com', 11211),array('cache2.example.com', 11211), array('cache3.example.com', 11211)));//写缓存,失效时间5分钟 $m->set('userCount', 123, 600);
复制代码



 Memcached 分布式缓存访问模型



5.3 分布式缓存架构:一致性 Hash 算法

分布式对象的缓存的一致性 hash 算法 



一致性 Hash 节点扩容



基于虚拟节点的一致性 Hash 算法

 


各种介质访问延迟



技术栈各个层次的缓存



缓存为什么能显著提升性能

  • 缓存数据通常来自内存,比磁盘上的数据有更快的访问速度

  • 缓存存储数据的最终结果形态,不需要中间计算,减少 CPU 资源的消耗

  • 缓存降低数据库、磁盘、网络的负载压力,这些 I/O 设备获取更好的响应特性

缓存是系统性能优化的大杀器

  • 技术简单

  • 性能提升显著

  • 应用场景多

 

合理使用缓存

使用缓存对提高系统性能有很多好处,但是不合理的使用缓存可能非但不能提高系统的性能,还会称为系统的累赘,甚至风险。实践中,缓存滥用的情景屡见不鲜——过分依赖缓存、不合适的数据访问特性等

 

频繁修改的数据:

这种数据如果缓存起来,由于频繁修改,应用还来不及读取就已经时效或更新,徒增系统负担。一般说来,数据的读写比在 2:1 以上,缓存才有意义。

没有热点的访问:

缓存使用内存为存储,内存资源贵而且有限,不能将所有数据都缓存起来,如果应用系统访问数据没有热点,不遵循二八定律,既大部分数据访问不是集中在小部分数据上,那么缓存就没有意义,因为大部分数据还没有被再次访问就已经被挤出缓存了。

LRU 算法(下图)



数据不一致与脏读:

一般会对存储的数据设置时效时间,一旦超过失效时间,就要从数据库中重新加载。因此应用要容忍一定时间的数据不一致,如卖家已经编辑了商品属性,到那时需要过一段时间才能被买家看到。在互联网应用中,这种延迟通常是可以接受的,但是具体应用仍需谨慎对待。还有集中策略是数据更新时立即更新缓存,不过也会带来系统开销和事务不一致性的问题。因此数据更新时通知缓存失效,删除该缓存数据,是一种更加稳妥的做法。

 

计算机科学中只有三件事情最困难:缓存失效,命名事务,计数错误——Phil Karlton

 

缓存雪崩:

缓存是为了提高数据读取性能的,缓存数据丢失或者缓存不可用不会影响到 应用程序的处——它可以从数据库直接获取数据。但是随着业务的发展,缓存会承担大 部分的数据访问压力,数据库已经习惯了有缓存的日子,所以当缓存服务崩溃的时候, 数据库会因为完全不能承受如此大的压力而宕机,进而导致整个网站不可用。这种情况, 被称作缓存雪崩,发生这种故障,甚至不能简单的重启缓存服务器和数据库服务器来恢 复网站访问。

 

缓存预热:

缓存中存放的是热点数据,热点数据又是缓存系统利用 LRU(最近最久未用) 算法对不断访问的数据筛选淘汰出来的,这个过程需要花费较长的时间,在这段时间, 系统的性能和数据库负载都不太好,那么最好在缓存系统启动的时候就把热点数据加载 好,这个缓存预加载手段叫做缓存预热(warm up)。对于一些元数据如城市地名列表、 类目信息,可以启动时加载数据库中全部数据到缓存进行预热。

 

缓存穿透:

如果不恰当的业务、或者恶意攻击持续高并发的请求某个不存在的数据,因 为缓存没有保存该数据,所有的请求都会落到数据库上,会对数据库造成很大的压力, 甚至崩溃。一个简单的对策是将不存在的数据也缓存起来(其 value 值为 null),并设 定一个较短的失效时间。

 

Redis VS Memcached

  • Redis 支持复杂的数据结构

  • Redis 支持多路复用异步 I/O 高性能 

  • Redis 支持主从复制高可用

  • Redis 原生集群与 share nothing 集群模式

 


Redis 集群

  • Redis 集群预分好 16384 个桶,当需要在 Redis 集群中放置一个 key-value 时,根据 CRC16(key) mod 16384 的值,决定将一个 key 放到哪个桶中。

  • redis-cluster 把所有的物理节点映射到[0- 16383]slot 上(不一定是平均分配), cluster 负责维护 slot 与服务器的映射关系。

  • 客户端与 Redis 节点直连,客户端不需要连 接集群所有节点,连接集群中任何一个可用 节点即可。

  • 所有的 Redis 节点彼此互联。



5.4 消息队列:如何避免系统故障传递

同步调用 VS 异步调用

同步调用



多个耗时操作同步调用



异步调用



有回调的异步调用



多次异步调用,不阻塞应用线程



消息队列构建异步架构

  • 消息生产者

  • 消息队列

  • 消息消费者

 

点对点模型



发布调用模型



消息队列的好处

实现异步处理,提升处理性能



更好的伸缩性



消峰填谷



消息队列的好处

失败隔离和自我修复

  • 因为发布者不直接依赖消费者,所以消息系统可以将消费者系统错误与生产者系统组件 隔离。

  • 生产者和消费者互相不受对方失败影响。

  • 这意味着任意时刻,我们都可以对后端服务器执行维护和发布操作。我们可以重启、添 加或删除服务 器而不影响生产者可用性,这样简化了部署和服务器管理的难度。

解偶



事件驱动架构 EDA



下面 2 幅图对比




 主要 MQ 产品比较

  • RabbitMQ 的主要特点是性能好,社区活跃,但是 RabbitMQ 用 Erlang 开发,对不熟悉 Erlang 的同学而言不便于二次开发和维护。(49M)

  • ActiveMQ 影响比较广泛,可以跨平台,使用 Java 开发,对 Java 比较友好。(27M)

  • RocketMQ 是阿里推出的一个开源产品,也是使用 Java 开发,性能比较好,可靠性也 比较高。(35M)

  • Kafka ,LinkedIn 出品的,Scala 开发,专门针对分布式场景进行了优化,因此分布 式的伸缩性会比较好。(63M)

 

5.5 负载均衡架构:如何用十行代码写一个负载均衡服务器?

负载均衡架构



HTTP 重定向负载均衡



缺点:两次请求,安全问题(容易被攻击);性能比较差。实际中不常用。

 

DNS 负载均衡



缺点:也存在安全问题。

大型互联网应用:两层 DNS 负载均衡

反向代理负载均衡



IP 负载均衡



原因:修改 ip 地址,处理 tcp/ip 数据包。

缺点:带宽

 

数据链路层负载均衡



不修改 ip 地址,修改 mac 地址;原地址不变,响应的内容不经过负载均衡服务器

 

负载君恨算法

  • 轮询:所有请求被依次分发到每个应用服务器上,适合于所有服务器硬件都相同的场 景。

  • 加权轮询:根据应用服务器硬件性能的情况,在轮询的基础上,按照配置的权重将请 求分发到每个服务器,高性能的服务器分配更多请求。

  • 随机:请求被随机分配到各个应用服务器,在许多场合下,这种方案都很简单实用, 因为好的随机数本身就很均衡。如果应用服务器硬件配置不同,也可以很容易的使用 加权随机算法。

  • 最少连接:记录每个应用服务器正在处理的连接数(请求数),将新到的请求分发到 最少连接的服务器上,应该说,这是最符合负载均衡定义的算法。

  • 源地址散列:根据请求来源的 IP 地址进行 Hash 计算,得到应用服务器,该算法可以保 证同一个来源的请求总在同一个服务器上处理,实现会话粘滞。

 

应用服务器集群的 Session 管理

应用服务器的高可用架构设计主要基于服务无状态这一特性,但是事实上,业务总是有 状态的,在交易类的电子商务网站,需要有购物车记录用户的购买信息,用户每次购买 请求都是向购物车中增加商品;在社交类的网站中,需要记录用户的当前登录状态、最 新发布的消息等以便及时将这些信息通知给他的好友。Web 应用中将这些状态信息称作 会话(Session),单机情况下,Session 可交给 Web 容器管理,在使用负载均衡的集 群环境中,Session 管理主要有以下几种手段。

Session 复制



确定:消耗资源严重,网络,磁盘

Session 绑定



也很少使用

利用 cookie 记录 session



简单,高效、能够满足互联网需求

Session 服务器



互联网最常见的管理方式

 

5.6 第五周课后练习

作业一(2 选 1):

  1. 用你熟悉的编程语言实现一致性 hash 算法。

  2. 编写测试用例测试这个算法,测试 100 万 KV 数据,10 个服务器节点的情况下,计算这些 KV 数据在服务器上分布数量的标准差,以评估算法的存储负载不均衡性。

作业二:

根据当周学习情况,完成一篇学习总结


用户头像

杨斌

关注

还未添加个人签名 2020.03.17 加入

还未添加个人简介

评论

发布
暂无评论
week5 技术选型(一) 学习总结