分布式集群架构场景化解决⽅案

1 ⼀致性Hash算法

Hash算法,⽐如说在安全加密领域MD5、SHA等加密算法,在数据存储和查找⽅⾯有Hash表等, 以上 都应⽤到了Hash算法

Hash算法较多的应⽤在数据存储和查找领域,最经典的就是Hash表,它的查询效率⾮常之⾼,哈希算法如果设计的⽐较ok的话,那么Hash表的数据查询时间复杂度可以接近于O(1)

1.1 Hash算法应⽤场景

Hash算法在分布式集群架构中的应⽤场景
Hash算法在很多分布式集群产品中都有应⽤,⽐如分布式集群架构Redis、Hadoop、ElasticSearch, Mysql分库分表,Nginx负载均衡等

主要的应⽤场景归纳起来两个

  • 请求的负载均衡(⽐如nginx的ip_hash策略)
    Nginx的IP_hash策略可以在客户端ip不变的情况下,将其发出的请求始终路由到同⼀个⽬标服务 器上,
    实现会话粘滞,避免处理session共享问题
    如果使⽤哈希算法,事情就简单很多,我们可以对ip地址或者sessionid进⾏计算哈希值,哈希值与服务 器数量进⾏取模运算,得到的值就是当前请求应该被路由到的服务器编号,如此,同⼀个客户端ip发送 过来的请求就可以路由到同⼀个⽬标服务器,实现会话粘滞。

  • 分布式存储
    以分布式内存数据库Redis为例,集群中有redis1,redis2,redis3 三台Redis服务器
    那么,在进⾏数据存储时,<key1,value1>数据存储到哪个服务器当中呢?针对key进⾏hash处理 hash(key1)%3=index, 使⽤余数index锁定存储的具体服务器节点

1.2 普通Hash算法存在的问题

普通Hash算法存在⼀个问题,以ip_hash为例,
假定下载⽤户ip固定没有发⽣改变,现在tomcat3出现 了问题,down机了,服务器数量由3个变为了2个,之前所有的求模都需要重新计算。

如果在真实⽣产情况下,后台服务器很多台,客户端也有很多,那么影响是很⼤的,缩容和扩容都会存 在这样的问题,⼤量⽤户的请求会被路由到其他的⽬标服务器处理,⽤户在原来服务器中的会话都会丢 失。

1.3 ⼀致性Hash算法

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

1.4 Nginx 配置⼀致性Hash负载均衡策略

ngx_http_upstream_consistent_hash 模块是⼀个负载均衡器,使⽤⼀个内部⼀致性hash算法来选择 合适的后端节点。
该模块可以根据配置参数采取不同的⽅式将请求均匀映射到后端机器,

consistent_hash $remote_addr:可以根据客户端ip映射
consistent_hash $request_uri:根据客户端请求的uri映射
consistent_hash $args:根据客户端携带的参数进⾏映

ngx_http_upstream_consistent_hash 模块是⼀个第三⽅模块,需要我们下载安装后使⽤

1)github下载nginx⼀致性hash负载均衡模块 下载
在这里插入图片描述
2)将下载的压缩包上传到nginx服务器,并解压

3)我们已经编译安装过nginx,此时进⼊当时nginx的源码⽬录,执⾏如下命令 ./configure —add-module=/root/ngx_http_consistent_hash-master
make make install

4)Nginx就可以使⽤啦,在nginx.conf⽂件中配置

在这里插入图片描述

2 集群时钟同步问题

“集群是各个服 务器⼀起团队化作战,⼤家⼯作都不在⼀个点上,岂不乱了套!”

在这里插入图片描述

2.1 集群时钟同步配置

  • 分布式集群中各个服务器节点都可以连接互联⽹
    在这里插入图片描述
#使⽤ ntpdate ⽹络时间同步命令
ntpdate -u ntp.api.bz #从⼀个时间服务器同步时间

操作⽅式:
windows有计划任务
Linux也有定时任务,crond,可以使⽤linux的定时任务,每隔10分钟执⾏⼀次ntpdate命令

  • 分布式集群中某⼀个服务器节点可以访问互联⽹或者所有节点都不能够访问互联⽹
    在这里插入图片描述
    1)选取集群中的⼀个服务器节点A(172.17.0.17)作为时间服务器
    (整个集群时间从这台服务 器同步,⼿动设置⼀个时间)

⾸先设置好A的时间
把A配置为时间服务器(修改/etc/ntp.conf⽂件)

1、如果有 restrict default ignore,注释掉它
2、添加如下⼏⾏内容
 restrict 172.17.0.0 mask 255.255.255.0 nomodify notrap  # 放开局 域⽹同步功能,172.17.0.0是你的局域⽹⽹段
   server 127.127.1.0 # local clock    fudge 127.127.1.0 stratum 10
3、重启⽣效并配置ntpd服务开机⾃启动 service ntpd restart
   chkconfig ntpd on

集群中其他节点就可以从A服务器同步时间了

ntpdate 172.17.0.17

3 分布式ID解决⽅案

为什么需要分布式ID(分布式集群环境下的全局唯⼀ID)
在这里插入图片描述

3.1 UUID(可以⽤)

UUID 是指Universally Unique Identifier
翻译为中⽂是通⽤唯⼀识别码 产⽣重复 UUID 并造成错误的情况⾮常低,是故⼤可不必考虑此问题。

java.util.UUID.randomUUID()

3.2 SnowFlake 雪花算法(可以⽤,推荐)

雪花算法是Twitter推出的⼀个⽤于⽣成分布式ID的策略。
雪花算法是⼀个算法,基于这个算法可以⽣成ID,⽣成的ID是⼀个long型,那么在Java中⼀个long 型是8个字节,算下来是64bit,如下是使⽤雪花算法⽣成的⼀个ID的⼆进制形式示意:
在这里插入图片描述
另外,⼀切互联⽹公司也基于上述的⽅案封装了⼀些分布式ID⽣成器,⽐如滴滴的tinyid(基于数 据库实现)、百度的uidgenerator(基于SnowFlake)和美团的leaf(基于数据库和SnowFlake) 等

3.3 借助Redis的Incr命令获取全局唯⼀ID(推荐)

Redis Incr 命令将 key 中储存的数字值增⼀。如果 key 不存在,那么 key 的值会先被初始化为 0 ,然后再执⾏ INCR 操作。
<key,value> <id,>
.incr(id) 1 2 3 4
在这里插入图片描述

4 分布式调度问题

定时任务的实现⽅式有多种。早期没有定时任务框架的时候,我们会使⽤JDK中的Timer机制和多线程机 制(Runnable+线程休眠)来实现定时或者间隔⼀段时间执⾏某⼀段程序;后来有了定时任务框架,⽐ 如⼤名鼎鼎的Quartz任务调度框架,使⽤时间表达式(包括:秒、分、时、⽇、周、年)配置某⼀个任 务什么时间去执⾏

在分布式架构环境中使⽤Quartz已经不能更好 的满⾜我们需求,我们可以使⽤专业的分布式调度框架,这⾥我们推荐使⽤Elastic-job。

分布式调度:

1)运⾏在分布式集群环境下的调度任务(同⼀个定时任务程序部署多份,只应该有⼀个定时任务在执 ⾏)

2)分布式调度—>定时任务的分布式—>定时任务的拆分(即为把⼀个⼤的作业任务拆分为多个⼩的作 业任务,同时执⾏)

在这里插入图片描述
Elastic-Job是当当⽹开源的⼀个分布式调度解决⽅案,基于Quartz⼆次开发的,由两个相互独⽴的⼦项 ⽬Elastic-Job-Lite和Elastic-Job-Cloud组成。我们要学习的是 Elastic-Job-Lite,它定位为轻量级⽆中⼼ 化解决⽅案,使⽤Jar包的形式提供分布式任务的协调服务,⽽Elastic-Job-Cloud⼦项⽬需要结合Mesos 以及Docker在云环境下使⽤。

Elastic-Job的github地址:github

主要功能介绍

  • 分布式调度协调 在分布式环境中,任务能够按指定的调度策略执⾏,并且能够避免同⼀任务多实例重复执⾏

  • 丰富的调度策略 基于成熟的定时任务作业框架Quartz cron表达式执⾏定时任务

  • 弹性扩容缩容 当集群中增加某⼀个实例,它应当也能够被选举并执⾏任务;当集群减少⼀个实例 时,它所执⾏的任务能被转移到别的实例来执⾏。

  • 失效转移 某实例在任务执⾏失败后,会被转移到其他实例执⾏

  • 错过执⾏作业重触发 若因某种原因导致作业错过执⾏,⾃动记录错过执⾏的作业,并在上次作业 完成后⾃动触发。 ⽀持并⾏调度

  • ⽀持任务分⽚,任务分⽚是指将⼀个任务分为多个⼩任务项在多个实例同时执⾏。

  • 作业分⽚⼀致性 当任务被分⽚后,保证同⼀分⽚在分布式环境中仅⼀个执⾏实例。

4.1 Elastic-Job-Lite应⽤

jar包(API) + 安装zk软件

Elastic-Job依赖于Zookeeper进⾏分布式协调,所以需要安装Zookeeper软件(3.4.6版本以上),关于 Zookeeper,此处我们不做详解,在阶段三会有深度学习,我们此处需要明⽩Zookeeper的本质功能: 存储+通知。

安装Zookeeper(此处单例配置)

1)我们使⽤3.4.10版本,在linux平台解压下载的zookeeper-3.4.10.tar.gz
2)进⼊conf⽬录,cp zoo_sample.cfg zoo.cfg 3) 进⼊bin⽬录,启动zk服务
启动 ./zkServer.sh start
停⽌ ./zkServer.sh stop
查看状态 ./zkServer.sh status

Zookeeper的树形节点结构图
在这里插入图片描述
引入jar

<!-- https://mvnrepository.com/artifact/com.dangdang/elastic-job-lite-core -->
<dependency>
<groupId>com.dangdang</groupId>
<artifactId>elastic-job-lite-core</artifactId> <version>2.1.5</version>
</dependency>

4.2 Elastic-Job-Lite轻量级去中⼼化的特点

在这里插入图片描述

4.3 任务分⽚

⼀个⼤的⾮常耗时的作业Job,⽐如:⼀次要处理⼀亿的数据,那这⼀亿的数据存储在数据库中,如果 ⽤⼀个作业节点处理⼀亿数据要很久,在互联⽹领域是不太能接受的,互联⽹领域更希望机器的增加去 横向扩展处理能⼒。所以,ElasticJob可以把作业分为多个的task(每⼀个task就是⼀个任务分⽚),每 ⼀个task交给具体的⼀个机器实例去处理(⼀个机器实例是可以处理多个task的),但是具体每个task 执⾏什么逻辑由我们⾃⼰来指定。

在这里插入图片描述
Strategy策略定义这些分⽚项怎么去分配到各个机器上去,默认是平均去分,可以定制,⽐如某⼀个机 器负载 ⽐较⾼或者预配置⽐较⾼,那么就可以写策略。分⽚和作业本身是通过⼀个注册中⼼协调的,因 为在分布式环境下,状态数据肯定集中到⼀点,才可以在分布式中沟通。

在这里插入图片描述

4.4 弹性扩容

在这里插入图片描述
新增加⼀个运⾏实例app3,它会⾃动注册到注册中⼼,注册中⼼发现新的服务上线,注册中⼼会通知 ElasticJob 进⾏重新分⽚,那么总得分⽚项有多少,那么就可以搞多少个实例机器,⽐如完全可以分 1000⽚
最多就可以有多少app实例,,,,机器能成的主,完全可以分1000⽚ 那么就可以搞1000台机器⼀起执⾏作业

注意:
1)分⽚项也是⼀个JOB配置,修改配置,重新分⽚,在下⼀次定时运⾏之前会重新调⽤分⽚算法,那么 这个分⽚算法的结果就是:哪台机器运⾏哪⼀个⼀⽚,这个结果存储到zk中的,主节点会把分⽚给分好 放到注册中⼼去,然后执⾏节点从注册中⼼获取信息(执⾏节点在定时任务开启的时候获取相应的分 ⽚)。
2)如果所有的节点挂掉值剩下⼀个节点,所有分⽚都会指向剩下的⼀个节点,这也是ElasticJob的⾼可 ⽤。

5 Session共享问题

在这里插入图片描述

5.1 Session问题原因分析

出现这个问题的原因,从根本上来说是因为Http协议是⽆状态的协议。客户端和服务端在某次会话中产 ⽣的数据不会被保留下来,所以第⼆次请求服务端⽆法认识到你曾经来过, Http为什么要设计为⽆状态 协议?早期都是静态⻚⾯⽆所谓有⽆状态,后来有动态的内容更丰富,就需要有状态,出现了两种⽤于 保持Http状态的技术,那就是Cookie和Session。⽽出现上述不停让登录的问题,分析如下图:
场景:nginx默认轮询策略

在这里插入图片描述

5.2 解决Session⼀致性的⽅案

1 Nginx的 IP_Hash 策略(可以使⽤)
同⼀个客户端IP的请求都会被路由到同⼀个⽬标服务器,也叫做会话粘滞 优点:
配置简单,不⼊侵应⽤,不需要额外修改代码

缺点:

  • 服务器重启Session丢失
  • 存在单点负载⾼的⻛险
  • 单点故障问题

2 Session共享,Session集中存储(推荐)
Session的本质就是缓存,那Session数据为什么不交给专业的缓存中间件呢?⽐如Redis
在这里插入图片描述
优点:

  • 能适应各种负载均衡策略
  • 服务器重启或者宕机不会造成Session丢失 扩展能⼒强
  • 适合⼤集群数量使⽤

Spring Session使得基于Redis的Session共享应⽤起来⾮常之简单

1)引⼊Jar

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId> </dependency>
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-data-redis</artifactId> </dependency>

2)配置redis

spring.redis.database=0
spring.redis.host=127.0.0.1
spring.redis.port=6379

在这里插入图片描述

在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值