• 【干货】整理分布式技术框架常用的算法及策略


    将一些零散的知识点进行整理, 以便加深理解,方便查阅,也希望能帮到大家。

    一、负载均衡算法

    1. 随机

    1. 完全随机

    通过系统随机函数,根据后端服务器列表的大小值来随机选择其中一台进行访问。由概率统计理论可以得知,随着调用量的增大,其实际效果越来越接近于平均分配流量到每一台后端服务器,也就是轮询的效果。

    1. 加权随机

      虽然还是采用的随机算法,但是为每台服务器根据不同的配置和负载情况来配置不同的权重,权重大的服务器获得的概率大一些,权重小的服务器获得的概率小一些。

    2. 轮询

    1. 完全轮询

      将请求按顺序轮流地分配到服务器上,它均衡地对待后端的每一台服务器,而不关心服务器实际的连接数和当前的系统负载情况。

    2. 加权轮询

      根据服务器的不同处理能力,给每个服务器分配不同的权重值,使其能够将请求顺序的按照权重分配到后端服务器上,权重越大,对应的服务器每轮所获得的请求数量越多。

    3. 平滑加权轮询

      每个服务器都有两个权重变量:

        a:weight,配置文件中指定的该服务器的权重,这个值是固定不变的;

        b:current_weight,服务器目前的权重(非固定权重)。一开始为0,之后会动态调整。

        每次当请求到来,选取服务器时,会遍历数组中所有服务器。对于每个服务器,让它的current_weight增加它的weight;同时累加所有服务器的weight,并保存为total。

        遍历完所有服务器之后,如果该服务器的current_weight是最大的,就选择这个服务器处理本次请求。最后把该服务器的current_weight减去total。

    3. 哈希(Hash)法

    先将后端服务器列表(如:按照地址IP)计算出哈希值,然后映射到HASH环上(如果服务器实例节点较少可以增加虚拟节点),当接收请求时,根据请求的信息(如请求的客户端IP、用户ID等)计算出哈希值,最后将请求信息的哈希值映射到HASH环上,按顺时针方向,确定落在哪个区间中,则选择区间的下一个服务器节点作为处理此次请求的服务器。

    4. 最小连接数(Least Connections)法

    由于后端服务器的配置不尽相同,对于请求的处理有快有慢,根据后端服务器当前的连接情况,动态地选取其中当前积压连接数最少的一台服务器来处理当前请求,尽可能地提高后端服务器的利用效率,将负载合理地分流到每一台机器。

    可参见网上文章:浅谈负载均衡算法与实现 、一致性hash算法释义

    二、限流算法

    1. 计数器(固定窗口)算法

    计数器算法是使用计数器在周期内累加访问次数,当达到设定的限流值时,触发限流策略。下一个周期开始时,进行清零,重新计数。

    2. 滑动窗口算法

    滑动窗口算法是将时间周期分为N个小周期,分别记录每个小周期内访问次数,并且根据时间滑动删除过期的小周期。

    3. 漏桶算法

    漏桶算法是访问请求到达时直接放入漏桶,如当前容量已达到上限(限流值),则进行丢弃(触发限流策略)。漏桶以固定的速率进行释放访问请求(即请求通过),直到漏桶为空。

    4. 令牌桶算法

    令牌桶算法是程序以r(r=时间周期/限流值)的速度向令牌桶中增加令牌,直到令牌桶满,请求到达时向令牌桶请求令牌,如获取到令牌则通过请求,否则触发限流策略。

    可参见网上文章:

    常用4种限流算法介绍及比较

    限流相关的算法

    三、缓存淘汰(过期)策略

    1. FIFO(First In First out)

    先进先出,淘汰最先缓存的数据,新加入的缓存数据最迟被淘汰,完全符合队列。

    2. LRU(Least recently used)

    最近最少使用,淘汰一定时期内被访问次数最少的缓存数据,以次数作为参考。

    3. LFU(Least frequently used)

    最近使用次数最少,淘汰最长时间未被使用的页面,以时间作为参考。

    4. Two queues(2Q)

    2Q算法有两个缓存队列,一个是FIFO队列,一个是LRU队列。当数据第一次访问时,2Q算法将数据缓存在FIFO队列里面,当数据第二次被访问时,则将数据从FIFO队列移到LRU队列里面,两个队列各自按照自己的方法淘汰数据。

    可参见网上文章:
    常用缓存策略
    Redis的过期策略和内存淘汰策略

    四、缓存更新策略

    1. Cache Aside

    应用在查询数据的时候,先从缓存Cache中读取数据,如果缓存中没有,则再从数据库中读取数据,得到数据库的数据之后,将这个数据也放到缓存Cache中。如果应用要更新某个数据,也是先去更新数据库中的数据,更新完成之后,则通过指令让缓存Cache中的数据失效。

    2. Read/Write Through

    应用要读数据和更新数据都直接访问缓存服务,缓存服务同步的将数据更新到数据库,在应用的眼中只有缓存服务。

    3. Write Behind

    应用要读数据和更新数据都直接访问缓存服务,缓存服务异步的将数据更新到数据库(通过异步任务)

    4. refresh-ahead

    在缓存数据过期前,能自动的刷新缓存数据(在缓存过期前剩余时间区间内【可自定义】取数据时,缓存先将之前缓存的结果返回给外部应用程序,然后异步的再从数据库去更新缓存中的值,以尽可能的保证缓存的值是最新的。如果取数据的的时候超过了缓存的过期时间,就安装read-through的方式执行)

    可参见网上文章:
    Caching漫谈--关于Cache的几个理论
    缓存服务的更新策略有哪些?

    五、分库分表方式与策略

    1. 分库分表方式

    1. 垂直分库

      为依据,按照业务归属不同,将不同的拆分到不同的中。

      结果:

      • 每个结构都不一样;
      • 每个数据也不一样,没有交集;
      • 所有并集是全量数据;
    2. 垂直分表

      字段为依据,按照字段的活跃性,将中字段拆到不同的(主表和扩展表)中。

      结果

      • 每个结构都不一样;

      • 每个数据也不一样,一般来说,每个表的字段至少有一列交集,一般是主键,用于关联数据;

      • 所有并集是全量数据;

    3. 水平分库

      字段为依据,按照一定策略(hash、range等),将一个中的数据拆分到多个中。

      结果:

      • 每个结构都一样;
      • 每个数据都不一样,没有交集;
      • 所有并集是全量数据;
    4. 水平分表

      字段为依据,按照一定策略(hash、range等),将一个中的数据拆分到多个中。

      结果:

      • 每个结构都一样;
      • 每个数据都不一样,没有交集;
      • 所有并集是全量数据;

    2. 分库分表策略

    1. hash取模

      对指定的路由key(如:id)按分表总数进行取模,得到的结果即为对应的表序号

      • 优点:订单数据可以均匀的放到那4张表中,这样此订单进行操作时,就不会有热点问题。
      • 缺点:将来的数据迁移和扩容,会很难。
    2. range范围

      按一定范围路由key(如:id,时间戳)把对应的记录存放到同一张表中,多个范围区间则存放多张表【即:每个范围区间对应一张表】

      • 优点:有利于将来的扩容,不需要做数据迁移
      • 有热点问题,在某一个时间范围内某个表的IO压力可能会非常大
    3. range+hash分组

      首先用range方案让数据落地到一个范围里面(即:分组区间)。这样以后id再变大,那以前的数据是不需要迁移的。然后在这个范围里面(即:分组区间)再根据路由key(如:id)按分表总数(注意含所有分组中的所有分表总数)进行取模,得到的结果即为对应的表序号【即:在一定范围内均匀分布数据】

      • 优点:避免热问题,扩容相对容易
      • 缺点:实现较复杂
    4. 一致性hash

      通过哈希函数,每个节点都会被分配到环上的一个位置,每个键值也会被映射到环上的一个位置。这个键值最终被放置在距离该它的位置最近的,且位置编号大于等于该值的节点上面,即放置到顺时针的下一个节点上面。

      • 优点:避免热问题,扩容相对容易

      • 缺点:实现较复杂

    ​ 可参见网上文章:

    海量数据分库分表方案(一)算法方案
    数据库怎么分库分表,垂直?水平?
    分库分表?如何做到永不迁移数据和避免热点?

  • 相关阅读:
    SpringBoot使用过滤器、拦截器、切面(AOP),及其之间的区别和执行顺序
    发送POST请求,包含文件MultipartFile参数,普通字符串参数,请求头参数
    Linux安装Mongodb(附带SpringBoot整合MongoDB项目Demo)
    博客目录
    Ubuntu+Hexo+Github搭建个人博客
    Hexo+Github搭建个人博客
    Linux设备驱动程序学习----3.模块的编译和装载
    Linux设备驱动程序学习----2.内核模块与应用程序的对比
    Linux设备驱动程序学习----1.设备驱动程序简介
    Linux设备驱动程序学习----目录
  • 原文地址:https://www.cnblogs.com/yanglang/p/13155850.html
Copyright © 2020-2023  润新知