JAVAWEB之后端风云(码农翻身笔记)

 

数据库的危机

应用程序访问数据库需要与数据库建立连接,每一个访问都需要维持一个连接,每建立一个新的连接都需要开辟一个缓冲区(内存)用来读取以及处理数据,所以数据库能够维持的连接数总是有限的。当用户量爆发增长时,数据库的性能也就出现了瓶颈,怎么处理?

解:

  • 增加数据库服务器的内存,开辟更多的连接(治标不治本,内存的占用还是会到达瓶颈)
  • 将保存数据的机械硬盘换成SSD,提高每个连接的处理速度(SSD的成本太高,无法大规模使用)
  • 在应用程序与数据库之间增加一个中间层(缓存),根据局部性原理,将数据库常用的数据放在缓存中,应用程序先访问缓存查询,没有找到就再查数据库,同时也把查到的数据放在缓存中,以便加快下一次的访问速度。

 

上面的处理引入了新的问题:之前的应用程序与数据库是通过JDBC接口连接的,那么新增加的缓存层该怎么实现数据的访问?

解:将缓存和应用程序放在同一台主机上,缓存直接保存应用程序中的对象。

 

随着用户量的继续增大,应用程序这台主机也处理不过来,罢工了,怎么办?

解:拆分:web服务器独用一台主机,应用程序N台主机,缓存一台主机,数据库一台主机

image.png

上面的所引入的新问题:缓存和应用程序不在同一台主机上,怎样保存数据到缓存?

解:Reids(高效的键值存储数据库),将java对象转成json格式通过jedis客服端保存到redis服务器

image.png

 

随着用户量的继续增大,缓存服务器也扛不住了,怎么办?

解:多增加几台缓存服务器(质量不够,数量来凑)

image.png

上面的解引入新的问题:

  1. 这么多缓存服务器,每个 Redis 存的数据都不一样,对于应用程序来说,每次向 Redis 中存放数据的时候,到底选哪个?是存到 1 号缓存服务器,还是 2 号、 3 号?
  2. 假设已经存到了 1 号Redis,等到取数据的时候,还得去 1 号 Redis 找,要不然都找不到。
  3. 数据存储也要尽可能均匀,别让 1号、 2 号缓存服务器由于存储太多而“撑死”,而 3 号缓存因为没有数据而“饿死”。

解:

  1. 余数算法:对于用户要存储的(key,value),计算key的整数Hash值,用Hash值对缓存服务器数目求余数,对在余数号服务器进行存储。要取数的时候也用同样的方式找到那台服务器进行取数。

image.png

但是余数算法面对一个新问题时就会导致大量缓存失效:在系统运行时动态的增减缓存服务器,因为服务器的数目变了。

 

  1. 一致性Hash算法
  • 假设有一个圆,在上面映射2^32-1个点;
  • 根据服务器的IP值,用Hash函数求出一个整数值映射到圆上相应的点上;

image.png

  • 将要存储的(key,value)的key值,同样用Hash函数取整数,映射到圆上,再顺时针找到遇见的第一个服务器,就是其存储服务器;当然,取数的时候用同样的方式找到服务器

image.png

当遇到增加一台服务器时,失效的只有两台服务器之间的缓存数据;

image.png

但是这样会导致如果服务器分布不均匀,那么就会出现某些服务器负载过高的情况(key值的映射概率问题)。

解决措施:我们需要足够多的服务器来让服务器更均匀的分布在圆上(当服务器数量越多时,出现大的不均匀的概率越小),但实际上不可能有太多的服务器,并且服务器的数量也不定。所以我们可以抽象出许多虚拟服务器(将一台服务器映射出N台虚拟服务器),再把这些虚拟服务器映射到圆上。

image.png

  1. Hash槽算法
  • 假设设定16384个槽,每个服务器均匀分管部分数目的槽;

image.png

  • 将key值用CRC16算法(跟Hash函数原理一样的)产生一个整数映射到槽上,进行存储。

image.png

  • 当新增一个服务器时,将其它服务器所管理的槽各自分出一些交给新的服务器管理,以保证均匀性。
  • 当根据一个key值查找数据时,可以向任一服务器发出请求,如果没有就重定向到其它的服务器,直到查到为止(这一块涉及到redis之间的通信,也叫redis集群)

集群中的故障转移问题

当涉及到集群时,就能够对一个老问题(数据安全问题)有了比较好的解决方案。原理就是当一台服务器挂掉之后,选一台备份服务器顶上。示例如下:将16384个Hash槽由两组服务器管理(当然也可以是多组服务器),每组服务器由一个master节点N个salve节点组成,其中master节点负责处理查询请求,salve节点负责同步数据进行备份。每一个节点都是一台独立的主机,甚至主从节点如果有条件的话应该分布在不同的机房,以应对有可能整个机房全部挂掉的风险(一般是电力风险),当master节点挂掉之后,在备份组里面选一台salve节点顶上。当然这一块实现起来就涉及到Redis集群的通信问题,服务器在运行时的动态增减问题,数据的备份与故障转移等问题。

image.png

 

Nginx高可用

Nginx是负责处理http请求的web服务器,当访问量达到一定程度时,服务器挂掉怎么办?(也叫单点故障)

解:用两台服务器,一主一从,对外只提供一个IP,当主服务器挂掉后从服务器顶上,具体的实现可以用Keepalived等类似的软件。

image.png

tomcat高可用

tomcat是负责逻辑处理的应用服务器,当处理量达到一定程度时,服务器挂掉怎么办?

解:用多台服务器协同处理,为了保证负载均衡,Nginx需要将请求均匀的转发到tomcat服务器上;

引入的新问题:tomcat是需要保存服务状态的,如果一台服务器在处理用户的过程中挂掉了,那么请求就会转移到其它服务器,但是其它服务器又没有该用户的状态信息,这又该如何处理?

解:

  1. 各台应用服务器之间进行通信交流,以保证session在各台服务器时刻保持一致(通信成本太高,效率低)
  2. 把session集中保存在数据库中,每台应用服务器都能访问查询(数据库的处理速度太慢)
  3. 把session集中保存在Redis缓存中 

image.png

数据库高可用

数据库服务器是最重要的,所有用户的数据都能够永久性的在数据库中固化下来,但是在在一个分布式的环境中,保持数据的强一致性是非常难的,稍有不慎就会乱套,特别是金融数据。怎么处理这个问题?

解:数据库有个特点就是统计出来的结果,读数据的次数远远高于写数据的次数。所以可以设计一主多从的架构,一台master数据库主要负责写数据(当然也可以读数据),多台从机负责读数据;

image.png

优点:

  • 能够极大的缓解程序对X锁与S锁的争用(这块后面再深挖)
  • 能够平衡多数据库的负责均衡,提高可用性
  • 在主机挂掉之后,从机成为主机顶上

缺点:

  • 程序对数据库的访问就变得有些麻烦,怎样分离读写操作去访问不同的服务器?

 

image.png

对该缺点的解决措施:再抽象出一个中间层来处理双方产生的矛盾,如mysql proxy(这块后面深挖)

image.png

posted @ 2020-03-07 18:02  Shawn-Jarvis  阅读(116)  评论(0编辑  收藏  举报