前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >时间轮 slot 机制实现

时间轮 slot 机制实现

作者头像
潇洒
发布2023-10-23 14:29:32
2110
发布2023-10-23 14:29:32
举报
文章被收录于专栏:石头岛

slot机制

Slot 机制,大白话,就是分片机制。可以把时间或空间分成一个个槽,通过一定算法使用这些槽的机制。

有什么用?

作用是可以把数据平均分存放到某个槽空间内,比如Hash环中使用的Hash Slot。再比如数组,可以再解为是一种槽机制。 这是空间是的槽机制, 在时间维度,可以把时间分片,每隔一段时间,就是一个时间槽位。 比如:一分钟有60秒,每2秒划分一个槽位就有30个槽,那就可以执行30次; 比如:一天有86400秒,每3秒划分一个槽位就有28800个槽。

这里实现一个简单的时间槽机制,分布式场景下,通过这个机制在,去中心化的场景下,让不同的机制按照一定时间槽机制进行运作。

实现

要求 必须保证是精准的3秒间隔,中间代码处理业务逻辑的时间必须也要计算在内。 比如,执行业务逻辑使用100毫秒,那么到下一个3秒的间隔就是2900毫秒; 如果,执行业务逻辑使用500毫秒,那么到下一个3秒的间隔就是2500毫秒; 如果,执行业务逻辑使用2900毫秒,那么到下一个3秒的间隔就是100毫秒; 保证完整的3秒,不多不少。

思路 这样的话,就要记录计算所有时间:

  1. 标记当前开始时间
  2. 记录业务逻辑处理的时间
  3. 计算出下一次间隔时间

每一轮开始,就会有一个开始时间为起点,执行的时间就是使用时间,将这个时间录下来,并使用开始时间减去使用时间,就得到了剩余时间。 还需要一个标杆来确认每轮时间间隔

提取需要几个参数:

  1. INTERVAL 时间间隔
  2. current 当前时间
  3. useTime 使用的时间
  4. stillTime 剩余时间

INTERVAL 即是时间间隔,在逻辑上也是一个Slot。我们要做的其实就是针对这个进行操作,计算这个时间槽内的时间流逝。

代码语言:javascript
复制
@Test
public void buildInterval() throws InterruptedException {
  int interval = 3000;
  long nextTime;
  long currentSlot = 0;
  for (int i = 0; i < 1000; i++) {
    // 获取当前时间,逻辑上是当前slot内的起始时间
    long current = System.currentTimeMillis();
    // do something
    
    // 计算出当前 slot 的剩余时间
    long stillTime = interval - current % interval;
    System.out.println("i: " + i + ", interval: " + stillTime);
    Thread.sleep(stillTime);

    // 获得下一个 slot 的时间
    nextTime = current + stillTime;
    System.out.println("nextTime: " + nextTime);
    currentSlot = currentSlot + nextTime % interval + 1;
    System.out.println("currentSlot: " + currentSlot);
    System.out.println("-----------------");
  }
}

结果:

代码语言:javascript
复制
i: 0, interval: 2272
nextTime: 1647172716000
currentSlot: 1
-----------------
i: 1, interval: 2999
nextTime: 1647172719000
currentSlot: 2
-----------------
i: 2, interval: 2994
nextTime: 1647172722000
currentSlot: 3
-----------------
i: 3, interval: 2997
nextTime: 1647172725000
currentSlot: 4
-----------------
i: 4, interval: 2995
nextTime: 1647172728000
currentSlot: 5
-----------------
i: 5, interval: 2999
nextTime: 1647172731000
currentSlot: 6
-----------------
i: 6, interval: 2995
nextTime: 1647172734000
currentSlot: 7
-----------------
i: 7, interval: 2999
nextTime: 1647172737000
currentSlot: 8
-----------------

现在可以完整复现出一个完美情况下的Slot机制,可以看到每个时间戳之间的差距刚好是3000毫秒。 这里还有问题,如果超时了怎么办?分布式环境下,如何保证多个节点之间的时间是同步的?

getSlot 方法

把上面封装成一个可以操作的方法,用来在获得和判断下一个slot的位置。产块前,需要先判断是否进入了下一个slot周期。当前时间必须大于 LatestBlockHeaderTimestamp,等于也不行说明还在当前slot周期内。

代码语言:javascript
复制
/**
 * @author liukai
 */
public class SlotTest {

  private static final long BLOCK_PRODUCED_INTERVAL = 3000;

  // 算出下一个 slot 的时间点

  /**
   * 算出下一个 slot 时间点
   *     slot机制调定每3秒为了个slot,一天有86000 秒,则一天有 86400 / 3 = 28800(slot)
   *     00: 00
   *     00: 03
   *     00: 06
   *     00: 09
   *     00: 12
   *     ...
   *     以此类推
   *     该方法算出上一个区块的时间,到下一个slot的精确slot是在什么位置
   * @param slot
   * @return
   */
  public static long getTime(long slot) {
    long interval = BLOCK_PRODUCED_INTERVAL;
    // 最后一块高度的时间戳
    long time = getLatestBlockHeaderTimestamp();
    // 算出一个不带余数,整数如: 1600000123 计处后得到余数:123;
    // 1600000123 - 123 = 1600000000
    time = time - ((time - getGenesisBlockTime()) % interval);
    return time + interval * slot;
  }

  public static long getSlot(long time) {
    long firstSlotTime = getTime(1);
    // 只有当前时间大于 产块时间,说明已经进入下一个slot,等于都不行
    if (time < firstSlotTime) {
      return 0;
    }
    return (time - firstSlotTime) / BLOCK_PRODUCED_INTERVAL + 1;
  }

  private static long getGenesisBlockTime() {
    return 0;
  }

  /**
   * 获得区块头时间戳
   *  实际场景中,这个是间一定比当前时间戳 System.currentTimeMillis() 早大概0-3000毫秒
   * @return
   */
  // 在线时间戳转换工具 https://tool.lu/timestamp/
  private static long getLatestBlockHeaderTimestamp() {
    return System.currentTimeMillis();
//    return 1652849462102L; //2022-04-26 14:57:09
//    return 1650956726000L; //2022-04-26 15:05:26
  }

  public static void main(String[] args) {
//    测试数据1:时间和 LatestBlockHeaderTimestamp 相等
//    long current = System.currentTimeMillis();

//    测试数据2:current > LatestBlockHeaderTimestamp
//    long current = System.currentTimeMillis() + 1000;

//    测试数据3:
    long current = System.currentTimeMillis() + 3000;
    long time3000 = getTime(1);
    long time6000 = getTime(2);

    System.out.println("当前时间:" + current);
    System.out.println("下一个slot 时间点:" + time3000);
    System.out.println("下一个时间间格6000:" + time6000);
    long slot = getSlot(current + 50);
    System.out.println(slot);
    if (slot == 0) {
      System.out.println("NOT_TIME_YET");
    } else {
      System.out.println("PRODUCT slot: " + slot);
    }
  }
}

结果:

当前时间:1652857261155 下一个时间间格3000:1652857260000 下一个时间间格6000:1652857263000 1 PRODUCT slot: 1

模拟多节点Slot

不同机器,不同网络环境,非中心化节点之间Slot场景

TODO

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022-03-24,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

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

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • slot机制
    • 有什么用?
    • 实现
    • getSlot 方法
    • 模拟多节点Slot
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档