OpenResty ----lua实现的 Snowflake(雪花算法)生成器

这里使用OpenResty 实现一个支持高并发的雪花算法Id生成器。

1、准备工作

需要安装的软件

(1)OpenResty

我使用的版本是:

[root@promote snowflake]# openresty -v
nginx version: openresty/1.17.8.2

(2)需要安装 lua 5.1版本的 socket 包和bit 包

2、遇到的问题

lua 5.1 只支持32位,下面是lub 的bit库位移计算得到的结果。所以如果要在lua5.1环境下实现雪花算法只能借助其他的方式。

> print(bit.lshift(1,30))
1073741824
> print(bit.lshift(1,31))
-2147483648
> print(bit.lshift(1,32))
1

使用shell 脚本实现位移计算

文件名 id.sh

##((timestamp - twepoch) << timestampLeftShift)  | (datacenterId << datacenterIdShift)  | (workerId << workerIdShift)  | sequence
let "value= (($1 - $2) << $3) | ($4 << $5) | ($6 << $7) | $8 "
echo ${value}

 

3、lua 脚本

文件名:snowflake.lua

-- 测试代码
local _M = {}
socket = require "socket"
math = require "math"
bit = require "bit"

-- 开始时间截 (2015-01-01) 
twepoch = 1420041600000;
-- 机器id所占的位数 
workerIdBits = 5;
-- 数据标识id所占的位数 
datacenterIdBits = 5;
-- 序列在id中占的位数 
sequenceBits = 12;
-- 支持的最大机器id,结果是31 (这个移位算法可以很快的计算出几位二进制数所能表示的最大十进制数) 
maxWorkerId =  bit.lshift(1 , workerIdBits)-1;
-- 支持的最大数据标识id,结果是31 
maxDatacenterId =  bit.lshift(1 , datacenterIdBits)-1;
-- 机器ID向左移12位 
workerIdShift = sequenceBits;
-- 数据标识id向左移17位(12+5) 
datacenterIdShift = sequenceBits + workerIdBits;
-- 时间截向左移22位(5+5+12) 
timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits;
-- 生成序列的掩码,这里为4095 (0b111111111111=0xfff=4095) 
sequenceMask =   bit.lshift(1 , sequenceBits) -1;
-- 工作机器ID(0~31) 
workerId=1;
-- 数据中心ID(0~31) 
datacenterId=1;
-- 毫秒内序列(0~4095) 
sequence = 0;
-- 上次生成ID的时间截 
lastTimestamp = -1;

function  _M.SnowflakeIdWorker (workerIds, datacenterIds)
    if (workerIds > maxWorkerId or workerIds < 0) 
    then
        return -1
    end
    
    if (datacenterIds > maxDatacenterId or datacenterIds < 0)
    then
        return -1
    end     
    workerId=workerIds  
    datacenterId=datacenterIds  
end 

local function tilNextMillis(lastTimestamp)
    local timestamp = math.floor(socket.gettime() * 1000 );
    while (timestamp <= lastTimestamp) 
    do
        timestamp = math.floor(socket.gettime() * 1000 );
    end
    return timestamp;
end

function  _M.nextId ()
  local timestamp = math.floor(socket.gettime() * 1000 );
  -- 如果当前时间小于上一次ID生成的时间戳,说明系统时钟回退过这个时候应当抛出异常
  if (timestamp < lastTimestamp)
  then
    return -1
  end
  -- 如果是同一时间生成的,则进行毫秒内序列
  if (lastTimestamp == timestamp)
  then 
    sequence = bit.band((sequence + 1), sequenceMask);
    -- 毫秒内序列溢出
    if (sequence == 0)
    then
      --阻塞到下一个毫秒,获得新的时间戳
      timestamp = tilNextMillis(lastTimestamp)
    end
  else
     sequence = 0
  end
  lastTimestamp = timestamp;
  
  cmd =("sh ./id.sh " ..  timestamp  .. '\t' ..twepoch .. '\t'.. timestampLeftShift .. '\t'.. datacenterId .. '\t'.. datacenterIdShift .. '\t'.. workerId .. '\t'.. workerIdShift  .. '\t'.. sequence)
  id = os.execute(cmd)
  return id             
end 

return _M

4、简单测试

[root@promote snowflake]# lua
Lua 5.1.5  Copyright (C) 1994-2012 Lua.org, PUC-Rio
> snowflake = require "snowflake" ;
> snowflake.SnowflakeIdWorker(1,2);
> print(snowflake.nextId())
754836761179590656
0
> print(snowflake.nextId())
754836766644768768
0
> print(snowflake.nextId())
754836769094242304
0
> print(snowflake.nextId())
754836771271086080
0
> print(snowflake.nextId())
754836773481484288
0
> print(snowflake.nextId())
754836775914180608
0
> 

5、OpenResty 配置

 1、在oprenresty中引入新创建的包,首先创建目录 :/usr/local/openresty/lualib/resty/snowflake,然后并将 id.sh 和 snowflake.lua两个文件放到目录里。

2、Nginx 配置 。。。。待完善

3、简单测试 。。。。。待完善

6、高并发测试

待完善。。。。。。

 

 

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

October-

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值