zoukankan      html  css  js  c++  java
  • 基于redis的分布式ID生成器

    项目地址

    https://github.com/hengyunabc/redis-id-generator

    基于redis的分布式ID生成器。

    准备

    首先,要知道redis的EVAL,EVALSHA命令:

    http://redis.readthedocs.org/en/latest/script/eval.html

    http://redis.readthedocs.org/en/latest/script/evalsha.html

    原理

    利用redis的lua脚本运行功能,在每一个节点上通过lua脚本生成唯一ID。
    生成的ID是64位的:

    • 使用41 bit来存放时间。精确到毫秒,能够使用41年。
    • 使用12 bit来存放逻辑分片ID。最大分片ID是4095
    • 使用10 bit来存放自增长ID,意味着每一个节点,每毫秒最多能够生成1024个ID

    比方GTM时间 Fri Mar 13 10:00:00 CST 2015 ,它的距1970年的毫秒数是 1426212000000,假定分片ID是53。自增长序列是4,则生成的ID是:

    5981966696448054276 = 1426212000000 << 22 + 53 << 10 + 4

    redis提供了TIME命令,能够取得redis服务器上的秒数和微秒数。因些lua脚本返回的是一个四元组。

    second, microSecond, partition, seq

    client要自己处理,生成终于ID。

    ((second * 1000 + microSecond / 1000) << (12 + 10)) + (shardId << 10) + seq;

    集群实现原理

    假定集群里有3个节点。则节点1返回的seq是:

    0, 3, 6, 9, 12 ...

    节点2返回的seq是

    1, 4, 7, 10, 13 ...

    节点3返回的seq是

    2, 5, 8, 11, 14 ...

    这样每一个节点返回的数据都是唯一的。

    单个节点部署

    下载redis-script-node1.lua,并把它load到redis上。

    cd redis-directory/
    wget https://raw.githubusercontent.com/hengyunabc/redis-id-generator/master/redis-script-node1.lua
    ./redis-cli script load "$(cat redis-script-node1.lua)" 

    获取lua脚本的sha1值,可能是:

    fce3758b2e0af6cbf8fea4d42b379cd0dc374418

    在代码里,通过EVALSHA命令,传递这个sha1值,就能够得到生成的ID。

    比方,通过命令行运行:

    ./redis-cli EVALSHA fce3758b2e0af6cbf8fea4d42b379cd0dc374418 2 test 123456789

    结果可能是:

    1) (integer) 1426238286
    2) (integer) 130532
    3) (integer) 277
    4) (integer) 4

    集群部署

    假定集群是3个节点,则分别对三个节点运行:

    ./redis-cli -host node1 -p 6379 script load "$(cat redis-script-node1.lua)" 
    ./redis-cli -host node2 -p 7379 script load "$(cat redis-script-node2.lua)" 
    ./redis-cli -host node3 -p 8379 script load "$(cat redis-script-node3.lua)" 

    性能

    redis默认配置。

    单节点,单线程:
    time:0:00:00.959
    speed:10427.52867570386
    单节点,20线程:
    time:0:00:06.710
    speed:29806.259314456034

    结论:
    - 单节点,qps约3w
    - 能够线性扩展,3个结点足以满足绝大部分的应用

    javaclient封装

    在redis-id-generator-java文件夹下。有example和benchmark代码。

    在调用时。要传入两个參数
    - tag,即为哪一类服务生成ID
    - shardId,即分片由哪个ID生成。比方一个用户的订单。则分片ID应该由userId来生成

    public class Example {
    
        public static void main(String[] args) {
            String tab = "order";
            long userId = 123456789;
    
            IdGenerator idGenerator = IdGenerator.builder()
                    .addHost("127.0.0.1", 6379, "fce3758b2e0af6cbf8fea4d42b379cd0dc374418")
    //              .addHost("127.0.0.1", 7379, "1abc55928f37176cb934fc7a65069bf32282d817")
    //              .addHost("127.0.0.1", 8379, "b056d20feb3f89483b10c81027440cbf6920f74f")
                    .build();
    
            long id = idGenerator.next(tab, userId);
    
            System.out.println("id:" + id);
            List<Long> result = IdGenerator.parseId(id);
    
            System.out.println("miliSeconds:" + result.get(0) + ", partition:"
                    + result.get(1) + ", seq:" + result.get(2));
        }
    }

    多语言client

    仅仅要支持redis evalsha命令就能够了。

    其他

    之前写的一个blog:分片(Sharding)的全局ID生成

  • 相关阅读:
    使用数组实现简单线性表功能
    解析.NET 许可证编译器 (Lc.exe) 的原理与源代码剖析
    Entity Framework with NOLOCK
    64位CentOS 6.0下搭建LAMP环境
    如何正确看待Linq的DistinctBy扩展和ForEach扩展
    jQuery最佳实践
    大话数据结构-树
    hdu2534-Score
    WKE——Webkit精简的纯C接口的浏览器
    WM_ERASEBKGND官方解释(翻译),以及Delphi里所有的使用情况(就是绘制窗口控件背景色,并阻止进一步传递消息)
  • 原文地址:https://www.cnblogs.com/jhcelue/p/7287295.html
Copyright © 2011-2022 走看看