架构的演进(缓存穿透/穿刺/雪崩/倾斜)

先修概念:

  • 高可用:

系统保持正常运行时间的百分比。即系统中部分节点失效时,其他节点能够接替它继续提供服务,则可认为系统具有高可用性。

计算机系统的可用性用 “平均无故障时间”(MTTF)来度量,即计算机系统平均能够正常运行多长时间,才发生一次故障。系统的可用性越高,“平均无故障时间” 越长。可维护性用 “平均维修时间”(MTTR)来度量,即系统发生故障后维修和重新恢复正常运行平均花费的时间。系统的可维护性越好,“平均维修时间” 越短。

计算机系统的可用性定义为:MTTF/(MTTF+MTTR) * 100%。

  • 集群:

集群(cluster)就是一组计算机,它们作为一个整体向用户提供一组网络资源。这些单个的计算机系统就是集群的节点(node)。如 Zookeeper 中的 Master 和 Slave 分别部署在多台服务器上,共同组成一个整体提供集中配置服务。

高可用性集群(HA cluster)是指如单系统一样地运行并支持(计算机)持续正常运行的一个主机群。

  • 分布式:

系统中的多个模块在不同服务器上部署,即可称为分布式系统,如 Tomcat 和数据库分别部署在不同的服务器上,或两个相同功能的 Tomcat 分别部署在不同服务器上。

在常见的集群中,客户端往往能够连接任意一个节点获得服务,并且当集群中一个节点掉线时,其他节点往往能够自动的接替它继续提供服务,这时候说明集群具有高可用性。

  • 负载均衡:

请求发送到系统时,通过某些方式把请求均匀分发到多个节点上,使系统中每个节点能够均匀的处理请求负载,则可认为系统是负载均衡的。

  • 正向代理和反向代理:

系统内部要访问外部网络时,统一通过一个代理服务器把请求转发出去,在外部网络看来就是代理服务器发起的访问,此时代理服务器实现的是正向代理;当外部请求进入系统时,代理服务器把该请求转发到系统中的某台服务器上,对外部请求来说,与之交互的只有代理服务器,此时代理服务器实现的是反向代理。

简单来说,正向代理是代理服务器代替系统内部来访问外部网络的过程,反向代理是外部请求访问系统时通过代理服务器转发到内部服务器的过程。

  • DNS:

网域名称系统(DNS,Domain Name System,将域名和IP地址相互映射的一个分布式数据库)是因特网的一项核心服务,它作为可以将域名和IP地址相互映射的一个分布式数据库,能够使人更方便地访问互联网,而不用去记住能够被机器直接读取的IP地址数串。

 

垂直架构:

  • 第一代:

网络条件:拨号猫时代:56kb --> 7KB/s

项目:非常简单,基本上都是文本内容 --> 基本上几个 Servlet 就搞定了,东西非常简单,访问量很低,有时候会出现无法访问的情况,但是无所谓。

  • 第二代:

网络条件:ADSL:1-8M/s,图片,动画,渣渣像素的视频出现了,网站内容变多,用户开始变多。

第一个问题:Tomcat 不能无限制接收请求。

解决方案:加服务器。

第二个问题:如何将不同的请求分配到不同的服务器。(一个域名对应多个IP(DNS),一个IP对应多个服务器。X)

解决方案:负载均衡(轮询/随机)/ 反向代理 / 路由。

第三个问题:第一次请求在 服务器1 完成登录,创建了 Session 和 Cookie,第二次请求被派发到 服务器2 ,再次登录后客户端 JSESSIONID 被覆盖,但再次请求被派发到 服务器3 , JSESSIONID 再次被覆盖,再一次请求被派发到 服务器1 时,因为 JSESSIONID 的不对应,仍然不会被服务器认为是登录状态。

解决方案:将相同的来访者固定分到同一台服务器(负载均衡的 Hash 算法)。

第四个问题:来访者固定被分到的一台服务器宕机了。

解决方案:服务器向其他服务器发送请求,同步 Session。

第五个问题:因为服务器存储空间的有限,服务器越多服务器集群应用效率越低。(第 n 个服务器还没处理请求存储空间就被其他服务器的 Session 占满了)。

解决方案:Session 共享不可行。做数据共享时优先使用第三方服务器(Redis:妙级20万请求量)。即所有服务器创建一个 Session 往 Redis 中存储一个,每次处理请求时,先查 Redis 里面是否存在,不存在就创建,存在就读出。

至此初步实现了服务器集群环境的搭建,其中 负载均衡 的服务器可以用 LVS (主从备份)做,还会存在 监听服务器(同一个IP) 确保服务器集群稳定。

  • 第三代:

网络继续发展,用户越来越多,服务器越来越多 。

作为bug的生产者之程序猿,每天要造无数的bug,以及添加无数的功能,开始使用MVC,新加的功能放到其他的服务器 ,这样子新功能出现了问题只需要维护对应的服务器就可以了,如果出现了bug,需要将这个功能对应的服务器集群重新部署。但是在之前,我们将大量的功能写在了一起,导致任意一个功能出现问题后需要将其他功能都要部署重启(功能之间的关联),速度特别慢,所以我们开始想能不能拆分功能。

公司大了之后会有很多不同的部门,每个部门都有自己的系统,也有可能会出现系统之间需要相互调用的情况。

  • 分布式架构:

随着项目的增大,代码越来越多,服务器越来越多,维护成为一个大问题,为了降低运维的压力,我们对项目进行拆分,按照功能、业务等方式进行拆分,将整个项目拆分为不同的小项目。

如 注册登录集群+订单集群+用户信息集群,在此基础上 继续把前后端分开,即 “前后端分离”,前端做静态资源加载,后端做数据的填入(服务:JS请求的后端代码),后端 Controller 和 Service 可以做进一步拆分。

RPC:(Remote Procedure Call)远程过程调用。Controller 想调哪个 Service 就调哪个 Service,此时两者都已是集群式。

问题:缺少服务治理,最终会出现混乱的情况,不知道谁调用了谁。被调用着停止服务,下线时,无法查找调用者。

服务器的增删问题:被调用的服务增加或者删除了服务器的情况下如何保证稳定。

解决方案:Redis 存储被调用的服务器集群的信息,用 负载均衡+IP(数据库中存储的) 的方式实现调度记录。但是某台服务器宕机时,人为修改必定出现人工延迟的情况。此时需要动态感知。

动态感知:长链接实现,需要一个注册中心(平台),服务器和平台保持长链接,调用时通过平台查找,宕机时平台第一时间即可感知并做出调整。

注册中心:zookeeper(+Dubbo)、eureka

  • 服务治理:

dubbo+zk 的方式实现,dubbo内置了服务治理功能(服务降级等),包含监控平台,查看使用情况。

  • 微服务:

springcloud家族。微服务仍然是分布式的范畴,只是将上面的服务拆的更小了。

  • 数据库:

分布式中的数据库也是采用集群模式设计的,此时摒弃了外键,并使用一些冗余数据达到减少数据库操作关联关系的目的,最终实现 SQL 多为单表操作,即空间换时间。

并且为短时期的用户请求爆发性增长加大量服务器是不合理的,会采用在数据库服务器之前加 Redis 集群的方式过滤数据库操作。

 

Redis缓存问题:

分布式结构中使用 Redis 过滤 SQL 操作的一系列问题。

  • 缓存穿透:

查询没有的数据,每次都查数据库,但是数据库中那条数据不存在,最终实现恶意攻击。

解决方案:数据项:主键自增,自定义值。排除 “<0 和 >主键最大值” 的 SQL;将所有主键存在 Redis 中做比对。

  • 缓存穿刺(击穿):

条件:高并发访问高热度数据。因为是同一条,同一部分热点数据。秒杀,明星出轨。。。

解决方案:分布式锁(synchronized是单JVM的),锁 Redis 集群。

  • 缓存雪崩:

大量的缓存数据在极短的时间内到期,导致大量 SQL 涌向数据库。

解决方案:缓存有效期设置为区间:1000s -- 4600s;一个小时拉长了缓存数据可能到期的时间,从而降低了极短时间内的缓存数据到期问题。

  • 缓存倾斜:

条件:高并发访问高热读数据。明星结婚事件。。。

解决方案:1、在 Redis 集群的基础之上为每一台 Redis 服务器搭主从结构(读写分离式等)。

2、将 SQL 分配到不同的服务器,通过改写 key 的方式:zly --> zly:1;zly:2;zly:3......

  • 缓存穿透解决方案:

  • 缓存穿刺解决方案:

  • 缓存倾斜解决方案:

  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值