slot机制 Slot 机制,大白话,就是分片机制。可以把时间或空间分成一个个槽,通过一定算法使用这些槽的机制。
有什么用? 作用是可以把数据平均分存放到某个槽空间内,比如Hash环中使用的Hash Slot。再比如数组,可以再解为是一种槽机制。 这是空间是的槽机制, 在时间维度,可以把时间分片,每隔一段时间,就是一个时间槽位。 比如:一分钟有60秒,每2秒划分一个槽位就有30个槽,那就可以执行30次; 比如:一天有86400秒,每3秒划分一个槽位就有28800个槽。
这里实现一个简单的时间槽机制,分布式场景下,通过这个机制在,去中心化的场景下,让不同的机制按照一定时间槽机制进行运作。
实现 要求 必须保证是精准的3秒间隔,中间代码处理业务逻辑的时间必须也要计算在内。 比如,执行业务逻辑使用100毫秒,那么到下一个3秒的间隔就是2900毫秒; 如果,执行业务逻辑使用500毫秒,那么到下一个3秒的间隔就是2500毫秒; 如果,执行业务逻辑使用2900毫秒,那么到下一个3秒的间隔就是100毫秒; 保证完整的3秒,不多不少。
思路 这样的话,就要记录计算所有时间:
标记当前开始时间
记录业务逻辑处理的时间
计算出下一次间隔时间
每一轮开始,就会有一个开始时间 为起点,执行的时间就是使用时间 ,将这个时间录下来,并使用开始时间减去使用时间,就得到了剩余时间 。 还需要一个标杆来确认每轮时间间隔 。
提取需要几个参数:
INTERVAL 时间间隔
current 当前时间
useTime 使用的时间
stillTime 剩余时间
INTERVAL 即是时间间隔,在逻辑上也是一个Slot。我们要做的其实就是针对这个进行操作,计算这个时间槽内的时间流逝。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 @Test public void buildInterval () throws InterruptedException { int interval = 3000 ; long nextTime; long currentSlot = 0 ; for (int i = 0 ; i < 1000 ; i++) { long current = System.currentTimeMillis(); long stillTime = interval - current % interval; System.out.println("i: " + i + ", interval: " + stillTime); Thread.sleep(stillTime); nextTime = current + stillTime; System.out.println("nextTime: " + nextTime); currentSlot = currentSlot + nextTime % interval + 1 ; System.out.println("currentSlot: " + currentSlot); System.out.println("-----------------" ); } }
结果:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 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周期内。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 public class SlotTest { private static final long BLOCK_PRODUCED_INTERVAL = 3000 ; public static long getTime (long slot) { long interval = BLOCK_PRODUCED_INTERVAL; long time = getLatestBlockHeaderTimestamp(); time = time - ((time - getGenesisBlockTime()) % interval); return time + interval * slot; } public static long getSlot (long time) { long firstSlotTime = getTime(1 ); if (time < firstSlotTime) { return 0 ; } return (time - firstSlotTime) / BLOCK_PRODUCED_INTERVAL + 1 ; } private static long getGenesisBlockTime () { return 0 ; } private static long getLatestBlockHeaderTimestamp () { return System.currentTimeMillis(); } public static void main (String[] args) { 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