Loading [MathJax]/jax/input/TeX/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >【我在拉勾训练营学技术】分布式问题解决方案整理

【我在拉勾训练营学技术】分布式问题解决方案整理

作者头像
程序员爱酸奶
发布于 2021-07-20 08:51:07
发布于 2021-07-20 08:51:07
51700
代码可运行
举报
文章被收录于专栏:程序员爱酸奶程序员爱酸奶
运行总次数:0
代码可运行

前言

文章内容输出来源:拉勾教育Java高薪训练营;

在面试的时候,尝尝会被问到分布式一些相关的问题,比如如何确保在分布式环境下 session 一致,分布式 ID 等等。我在拉勾训练营学习的时候,刚好老师有讲到,我就整理下来了。

一致性Hash 算法

image-20200703104027902

解决hash 冲突的方法:

开放寻址法:1放进去了,6再来的时候,向前或者向后找空闲位置存放,不好的地⽅,如果数组⻓度定

义好了⽐如10,⻓度不能扩展,来了11个数据,不管Hash冲突不冲突,肯定存不下这么多数据

拉链法:数据⻓度定义好了,怎么存储更多内容呢,算好Hash值,在数组元素存储位置放了⼀个链表.也就是出现重读的,我们就通过链表存储起来,也叫链地址法。hashmap 就是采用在这种结构哒。

hash 算法应用场景

nginx 的负载均衡

我们知道 nginx 实现负载均衡有三种方式。轮寻、设置权重、配置 ip_hash 。‘’

其中配置 ip_hash 就使用到了 hash 算法。Nginx的 IP_hash策略可以在客户端ip不变的情况下,将其发出的请求始终路由到同⼀个⽬标服务器上,实现会话粘滞,避免处理session共享问题 。对ip地址或者sessionid进⾏计算哈希值,哈希值与服务器数量进⾏取模运算,得到的值就是当前请求应该被路由到的服务器编号,如此,同⼀个客户端ip发送过来的请求就可以路由到同⼀个⽬标服务器,实现会话粘滞。

分布式存储

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

普通hash 简单实现

我们写一个普通hash 的简单实现。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制

public class GeneralHash {


    public static void main(String[] args) {


        // 定义客户端IP
        String[] clients = new String[]{
                "192.168.1.61",
                "192.168.1.48",
                "192.168.1.44",
                "192.168.1.42",
                "192.168.1.43",
                "192.168.1.73",
                "192.168.1.83",
                "192.168.1.23"};


        //服务器数量
        int count =5;


        for (String client : clients) {
            int hash = Math.abs(client.hashCode());
            int index=hash%count;
            System.out.println("IP 为:"+client+ "服务器编号为:"+index);
        }
    }
}

结果:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
IP :192.168.1.61服务器编号为:2
IP :192.168.1.48服务器编号为:2
IP :192.168.1.44服务器编号为:3
IP :192.168.1.42服务器编号为:1
IP :192.168.1.43服务器编号为:2
IP :192.168.1.73服务器编号为:0
IP :192.168.1.83服务器编号为:1
IP :192.168.1.23服务器编号为:0

普通 hash 算法存在的问题

比如上面的 ip_hash 是利用取模运算,但是如果出现一个服务宕机或者出现扩容和缩容的情况,就会导致重新hash .那么原来的会话就会丢失。

一致性 hash 算法

首先有一条一条直线。为 0 到 2 的 32 次方 -1。然后将首尾相连,形成一个闭环,也就是 hash 环。

image-20200703132632412

如下图所示:我们的服务器节点散落在这个环上。当请求的 ip 通过一致性 hash 可以找到离他最近的节点,从而进行访问。

当出现服务宕机,或者缩容时。只会影响部分的 IP 进行重新指向。

同理,增加服务器的时候,也只会影响部分 IP 重新指定。

demo 实现

我们使用 代码来实现一个一致性 hash 算法 借助 SortedMap 的 tailMap(K fromKey)获取一个子集。其所有对象的 key 的值大于等于 fromKey 。然后 firstKey() 获取最小 key

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制

/**
 * 无虚拟节点
 */
public class ConsistentHashNoVirtual {


    public static void main(String[] args) {


        //step 1:将服务器的节点存到 hash 环中。

        // 定义服务器节点
        String[] servers = new String[]{
                "192.168.1.10",
                "192.168.1.30",
                "192.168.1.50",
                "192.168.1.70",
                "192.168.1.90",
                "192.168.2.10",
                "192.168.1.30",
                "192.168.2.80"};

        //定义一个hash 环
        SortedMap<Integer, String> hashServerMap = new TreeMap<>();

        for (String server : servers) {
            int hash = Math.abs(server.hashCode());
            hashServerMap.put(hash,server);
        }


        //step 2:将客户端的IP映射到 hash 环中。

        String[] clients = new String[]{
                "10.168.1.10",
                "10.168.2.10",
                "10.168.3.10",
                "10.168.4.10",
                "10.168.5.10",
                "10.168.6.10",
                "10.168.7.10",
                "192.168.1.40",
                "192.168.1.60",
                "192.168.1.80",
                "192.168.2.00",
                "192.168.2.30",
                "192.168.2.50",
                "192.168.3.50",
                "192.168.4.50",
                "192.168.2.90"};


        for (String client : clients) {
            //step3 针对客户端,找到能够处理当前客户端请求的服务器(哈希环上顺时针最近)
            // 根据客户端ip的哈希值去找出哪一个服务器节点能够处理()
            int clienthash = Math.abs(client.hashCode());

            //tailMap(K fromKey)获取一个子集。其所有对象的 key 的值大于等于 fromKey
            SortedMap<Integer, String> tailMap = hashServerMap.tailMap(clienthash);
            Integer firstKey = hashServerMap.firstKey();
            if(!tailMap.isEmpty()){
                firstKey = tailMap.firstKey();
            }
            System.out.println("客户端:" + client + " 被路由到服务器:" + hashServerMap.get(firstKey));
        }
    }
}

结果:

问题

从上面的结果来看,这种会存在一问题,也就是可能出现数据倾斜。⼀致性哈希算法在服务节点太少时,容易因为节点分部不均匀⽽造成数据倾斜问题。例如系统中只有两台服务器,其环分布如下,节点2只能负责⾮常⼩的⼀段,⼤量的客户端请求落在了节点1上,这就是数据(请求)倾斜问题。

解决方案

一致性hash 算法引入了虚拟节点机制。为每个服务节点计算多个hash,每个hash 放置一个服务器几点,称为虚拟节点。

具体做法可以在服务器ip或主机名的后⾯增加编号来实现。⽐如,可以为每台服务器计算三个虚拟节点,于是可以分别计算 “节点1的ip#1”、“节点1的ip#2”、“节点1的ip#3”、“节点2的ip#1”、“节点2的ip#2”、“节点2的ip#3”的哈希值,于是形成六个虚拟节点,当客户端被路由到虚拟节点的时候其实是被路由到该虚拟节点所对应的真实节点

demo 实现

我们在上面代码的基础上增加,虚拟节点。这里的 rehash 算法需要实际调整,我这里只是随便写的。

image-20200703164212953

就在原来的基础上加了这部分代码,我们再运行看下。可以看到原来后面这部分就重新分配了。

集群时钟同步问题

当我们的服务部署在多台服务器时,如果这些服务器的时间不一致必定会导致各种问题。

所以需要保证集群所在的服务器时间保持一致。

可以联网

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#使⽤ ntpdate ⽹络时间同步命令
ntpdate -u ntp.api.bz #从⼀个时间服务器同步时间

不能联网

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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

分布式 ID 解决方案

image-20200703171349839

解决方法:

  • UUID 使用uuid 最为主键,每次都会随机生成保证不一样。
  • 独⽴数据库的⾃增ID
  • SnowFlake 雪花算法

雪花算法是⼀个算法,基于这个算法可以⽣成ID,⽣成的ID是⼀个long型,那么在Java中⼀个long 型是8个字节,算下来是64bit,如下是使⽤雪花算法⽣成的⼀个ID的⼆进制形式示意

image-20200703173115718

  • 借助Redis的Incr命令获取全局唯⼀ID

分布式调度问题

什么是分布式调度

  • 运⾏在分布式集群环境下的调度任务(同⼀个定时任务程序部署多份,只应该有⼀个定时任务在执⾏)
  • 分布式调度—>定时任务的分布式—>定时任务的拆分(即为把⼀个⼤的作业任务拆分为多个⼩的作业任务,同时执⾏)

定时任务与消息队列的区别

共同点:

  • 异步处理。⽐如注册、下单事件
  • 应⽤解耦。不管定时任务作业还是MQ都可以作为两个应⽤之间的⻮轮实现应⽤解耦,这个⻮轮可以中转数据,当然单体服务不需要考虑这些,服务拆分的时候往往都会考虑
  • 流量削峰。双⼗⼀的时候,任务作业和MQ都可以⽤来扛流量,后端系统根据服务能⼒定时处理订单或者从MQ抓取订单抓取到⼀个订单到来事件的话触发处理,对于前端⽤户来说看到的结果是已经下单成功了,下单是不受任何影响的

不同点:

定时任务作业是时间驱动,⽽MQ是事件驱动;

时间驱动是不可代替的,⽐如⾦融系统每⽇的利息结算,不是说利息来⼀条(利息到来事件)就算⼀下,⽽往往是通过定时任务批量计算;所以,定时任务作业更倾向于批处理,MQ倾向于逐条处理;

分布式调度框架 Elastic-Job

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

Elastic-Job的github地址:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
https://github.com/elasticjob

主要功能介绍

  • 分布式调度协调。在分布式环境中,任务能够按指定的调度策略执⾏,并且能够避免同⼀任务多实例重复执⾏
  • 丰富的调度策略 基于成熟的定时任务作业框架Quartz cron表达式执⾏定时任务
  • 弹性扩容缩容 当集群中增加某⼀个实例,它应当也能够被选举并执⾏任务;当集群减少⼀个实例时,它所执⾏的任务能被转移到别的实例来执⾏。
  • 失效转移 某实例在任务执⾏失败后,会被转移到其他实例执⾏错过执⾏作业重触发 若因某种原因导致作业错过执⾏,⾃动记录错过执⾏的作业,并在上次作业完成后⾃动触发。
  • ⽀持并⾏调度 ⽀持任务分⽚,任务分⽚是指将⼀个任务分为多个⼩任务项在多个实例同时执⾏。
  • 作业分⽚⼀致性 当任务被分⽚后,保证同⼀分⽚在分布式环境中仅⼀个执⾏实例。

引用

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<!-- 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>

Session 共享问题

session 丢失问题

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

解决 Session ⼀致性的⽅案

Nginx的 IP_Hash 策略(可以使⽤)

同⼀个客户端IP的请求都会被路由到同⼀个⽬标服务器,也叫做会话粘滞

优点:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
  配置简单,不⼊侵应⽤,不需要额外修改代码

缺点:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
服务器重启Session丢失
存在单点负载⾼的⻛险
单点故障问题

Session复制(不推荐)

多个tomcat之间通过修改配置⽂件,达到Session之间的复制

image-20200705163259385

优点:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
不⼊侵应⽤
便于服务器⽔平扩展
能适应各种负载均衡策略
服务器重启或者宕机不会造成Session丢失

缺点:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
性能低
内存消耗
不能存储太多数据,否则数据越多越影响性能
延迟性

Session共享,Session集中存储(推荐)

image-20200705163354860

优点:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
能适应各种负载均衡策略
服务器重启或者宕机不会造成Session丢失
扩展能⼒强
适合⼤集群数量使⽤

缺点:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
对应⽤有⼊侵,引⼊了和Redis的交互代码

总结

这些问题都是面试会别问到的高频问题,所以赶紧 get 吧

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-06-20,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 程序员爱酸奶 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
分布式ID解决方案
在面试的时候,尝尝会被问到分布式一些相关的问题,比如如何确保在分布式环境下 session 一致,分布式 ID 等等。我在拉勾训练营学习的时候,刚好老师有讲到,我就整理下来了。
程序员爱酸奶
2023/11/16
2240
分布式ID解决方案
分布式任务调度框架技术选型
很多业务场景需要我们某一特定的时刻去做某件任务,定时任务解决的就是这种业务场景。一般来说,系统可以使用消息传递代替部分定时任务,两者有很多相似之处,可以相互替换场景。如,上面发货成功发短信通知客户的业务场景,我们可以在发货成功后发送MQ消息到队列,然后去消费mq消息,发送短信。
lyb-geek
2019/10/10
5.6K0
分布式任务调度框架技术选型
分布式任务调度的解决方案
随着系统规模的发展,定时任务数量日益增多,任务也变得越来越复杂,尤其是在分布式环境下,存在多个业务系统,每个业务系统都有定时任务的需求,如果都在自身系统中调度,一方面增加业务系统的复杂度,另一方面也不方便管理,因此需要有一个任务平台对分散的任务进行统一管理调度,基于目前的情况,任务平台需要支持以下几个方面:
慕容千语
2021/07/20
1.4K0
分布式定时任务调度框架选型
任何工具的使用都要结合自身的业务场景,脱落业务场景谈技术选型就是耍流氓。 考虑私有云场景业务量一般,高并发场景很少遇到,同一时间也不会有超大量定时任务同时需要执行,所以考虑自研也未尝不可。 目前自研最急需解决的问题并不是高并发,而是如何避免任务被重复执行; 场景就变成了:
BUG弄潮儿
2021/09/10
3.2K0
分布式定时任务调度框架选型
【分布式详解】一致性算法、全局唯一ID、分布式锁、分布式事务、 分布式缓存、分布式任务、分布式会话
分布式系统通过副本控制协议,使得从系统外部读取系统内部各个副本的数据在一定的约束条件下相同,称之为副本一致性(consistency)。副本一致性是针对分布式系统而言的,不是针对某一个副本而言。
奥耶可乐冰
2024/01/11
1.1K0
【分布式详解】一致性算法、全局唯一ID、分布式锁、分布式事务、 分布式缓存、分布式任务、分布式会话
分布式session的几种解决方案,你中意哪种?
我发现了一个商城,我还没有登录,就可以往购物车中添加商品,加了好几件后,我准备付款,需要我先去登录,登录完之后付款。
Java旅途
2021/05/10
3440
分布式session的几种解决方案,你中意哪种?
分布式定时任务调度系统技术选型
原文链接:https://blog.csdn.net/guyue35/article/details/84883408
业余草
2019/10/22
3.6K0
分布式定时任务调度系统技术选型
几种主流的分布式定时任务
自从JDK1.5之后,提供了ScheduledExecutorService代替TimerTask来执行定时任务,提供了不错的可靠性。
用户4283147
2022/10/27
5150
几种主流的分布式定时任务
Redis分布式篇
Redis 本身的 QPS 已经很高了,但是如果在一些并发量非常高的情况下,性能还是 会受到影响。这个时候我们希望有更多的 Redis 服务来完成工作
编程之心
2021/07/14
4410
lagou 爪哇 2-2 分布式集群架构场景化解决⽅案 笔记
数据表A(ID),A的数据量很⼤的情况下,我们会进⾏分表操作,A(ID)表拆分成了A1表 (ID)+A2表(ID),需要⼀种在分布式集群架构中能够产⽣全局唯⼀ID的⽅案
acc8226
2022/05/17
3390
lagou 爪哇 2-2 分布式集群架构场景化解决⽅案 笔记
分布式定时任务调度框架之elastic-job简介
1.elastic-job是什么? elastic-job是当当内部应用框架ddframe中dd-job的作业模块中分离出来的分布式弹性作业框架。 2. 什么是作业调度(定时任务)? 作业即定时任务。
lyb-geek
2018/07/26
3.5K0
分布式定时任务调度框架之elastic-job简介
探寻繁杂定时任务的解决方案:分布式任务调度系统
导语:本文我们从架构和技术实现上来为大家讲解腾讯云分布式任务调度系统TCT(Tencent Cloud Task)如何实现任务调度的精准实时、稳定高效,以及任务的切分和编排。(编辑:中间件小Q妹)
腾讯云中间件团队
2021/03/24
2K0
探寻繁杂定时任务的解决方案:分布式任务调度系统
Elastic-Job2.1.5源码-基于Zookeeper分布式锁实现选举作业主节点原理
大家好,本文给大家介绍一下Elastic-Job 基于Zookeeper分布式锁实现选举作业主节点原理,本文主要介绍Elastic-Job如何使用Zookeeper分布式锁进行选举作业主节点,分布式锁的原理和注意事项。
宋小生
2022/12/14
5830
Elastic-Job2.1.5源码-基于Zookeeper分布式锁实现选举作业主节点原理
几种主流的分布式定时任务,你知道哪些?
点击上方“芋道源码”,选择“设为星标” 管她前浪,还是后浪? 能浪的浪,才是好浪! 每天 10:33 更新文章,每天掉亿点点头发... 源码精品专栏 原创 | Java 2021 超神之路,很肝~ 中文详细注释的开源项目 RPC 框架 Dubbo 源码解析 网络应用框架 Netty 源码解析 消息中间件 RocketMQ 源码解析 数据库中间件 Sharding-JDBC 和 MyCAT 源码解析 作业调度中间件 Elastic-Job 源码解析 分布式事务中间件 TCC-Transaction
芋道源码
2022/03/04
5K0
zk分布式任务管理
在我们的系统开发过程 中不可避免的会使用到定时任务的功能,而当我们在生产环境部署的服务超过1台时,就需要考虑任务调度的问题,防止两台或多台服务器上执行同一个任务,这个问题今天咱们就用zookeeper来解决。
写代码的猿
2019/05/07
1.4K0
zk分布式任务管理
分布式定时任务原理
在quartz的集群解决方案里有张表scheduler_locks,quartz采用了悲观锁的方式对triggers表进行行加锁,以保证任务同步的正确性。一旦某一个节点上面的线程获取了该锁,那么这个Job就会在这台机器上被执行,同时这个锁就会被这台机器占用。同时另外一台机器也会想要触发这个任务,但是锁已经被占用了,就只能等待,直到这个锁被释放
用户4283147
2022/10/27
5970
分布式定时任务原理
看完这篇文章,还敢说自己不会分布式任务调度?
以上场景就是任务调度所需要解决的问题,任务调度是为了自动完成特定任务,在约定的特定时刻去执行任务的过程。
上分如喝水
2021/08/16
1.2K0
看完这篇文章,还敢说自己不会分布式任务调度?
分布式定时任务,你了解多少?基于Quartz实现分布式任务解决方案!
后台定时任务系统在应用平台中的重要性不言而喻,特别是互联网电商、金融等行业更是离不开定时任务。在任务数量不多、执行频率不高时,单台服务器完全能够满足。但是随着业务逐渐增加,定时任务系统必须具备高可用和水平扩展的能力,单台服务器已经不能满足需求。因此需要把定时任务系统部署到集群中,实现分布式定时任务系统集群。
章为忠学架构
2023/10/06
8.5K0
分布式定时任务,你了解多少?基于Quartz实现分布式任务解决方案!
几种主流的分布式定时任务,你知道哪些?
单点定时任务 JDK原生 自从JDK1.5之后,提供了ScheduledExecutorService代替TimerTask来执行定时任务,提供了不错的可靠性。 public class SomeScheduledExecutorService {     public static void main(String[] args) {         // 创建任务队列,共 10 个线程         ScheduledExecutorService scheduledExecutorService =
程序猿DD
2022/04/18
3510
几种主流的分布式定时任务,你知道哪些?
专访当当网张亮:深度解读分布式作业调度框架elastic-job
【编者按】互联网从诞生到现在,网站的规模不断扩大,存储和处理的数据量也远远超出了人们的想象,又随着对信息实时性、多媒体需求大幅增长的现象,互联网架构面临越来越大的挑战。CSDN致力于解决这一问题,在刚刚结束的 SDCC 2015中国软件开发者大会上,特举办了架构专场( 上午报报道、 下午报道),以及《程序员》电子刊10月B开设了 架构专题。在接下来也将继续深耕架构师、服务于开发者,推出更多的大牛访谈、知名互联网公司架构实践、技术公开课等,敬请期待。 日前,笔者采访了当当网架构师、当当技术委员会成员张亮,在本
CSDN技术头条
2018/02/11
1.2K0
专访当当网张亮:深度解读分布式作业调度框架elastic-job
推荐阅读
相关推荐
分布式ID解决方案
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验