唯一ID的生成

  下面列举几种常见的唯一ID生成方案,需要满足两大核心需求:1.全局唯一  2趋势有序

   1. 用数据库的auto_increment(自增ID)来生成,每次通过写入数据库一条记录,利用数据库ID自增的特性获取唯一,有序的ID。

     优点:使用数据库原有的功能,相对简单;能够保证唯一;能够保证递增性;ID之间的步长是固定且可以自定义的

     缺点:可用性难以保证,当生成ID的那台服务器宕机,系统就玩不转了;由于写入是单点的,所以扩展性差,性能上限取决于数据库的写性能。

   2. 用UUID

     优点:简单方便;全球唯一,在遇见数据迁移、合并或者变更时可以从容应对;

     缺点:没有递增性;UUID是很长的字符串,作为主键对存储空间有一定要求,查询效率也较低。

   3. 使用Redis生成ID,主要利用Redis是单线程的,所以也可以用来生成唯一ID。当使用的是Redis集群的时候,比如集群中有5台Redis,初始化每台Redis的值为1,2,3,4,5,设置步长为5,并且确定一个不随机的负载均衡策略,能够保证有序,唯一。

     优点:不依赖数据库,灵活,且性能相对于数据库有一定提高;使用Redis集群策略还能排除单点故障问题;ID天然有序

     缺点:如果系统中没有Redis,还需要引入新的组件;编码和配置工作量大

   4. 使用Twitter的snowflake算法;其核心思想是一个64位long型ID,使用41bit作为毫秒数,10bit作为机器的ID(5个bit是数据中心,5个bit的机器ID),12bit作为毫秒内的流水号(意味着每个节点在每毫秒可以产生 4096 个 ID),最后还有一个符号位,永远是0。可以根据自身需求进行一定的修改。

    优点:不依赖数据库,灵活方便,性能优于数据库;ID按照时间在单机上是递增的

    缺点:单机上递增,但是当分布式环境下每台机器的时钟不可能完全同步,有时并不能做做全局递增。

   5. 使用zookeeper生成唯一ID,主要通过znode数据版本来生成序列号,可以生成32为和64为的数据版本号。很少使用,因为是多步调用API,并发情况下还需要考虑分布式锁,不是很理想。

   6. MongoDB的ObjectID,和snowflake算法类似。4字节Unix时间戳,3字节机器编码,2字节进程编码,3字节随机数

 

1 单表分表策略

  a.当数据比较大的时候,对数据进行分表操作,首先要确定需要将数据平均分配到多少张表中,也就是:表容量。

   这里假设有100张表进行存储,则我们在进行存储数据的时候,首先对用户ID进行取模操作,根据 user_id % 100获取对应的表进行存储查询操作.

          user_id % 100 = 0  user_id % 100 = 1 user_id % 100 = 2  

2 分表分库策略 

  a.

    1、中间变量 = user_id%(库数量*每个库的表数量);
    2、库序号 = 取整(中间变量/每个库的表数量);
    3、表序号 = 中间变量%每个库的表数量;

    例如:数据库有256 个,每一个库中有1024个数据表,用户的user_id=262145,按照上述的路由策略,可得:  

    1、中间变量 = 262145%(256*1024)= 1;
    2、库序号 = 取整(1/1024)= 0;
    3、表序号 = 1%1024 = 1;

    这样的话,对于user_id=262145,将被路由到第0个数据库的第1个表中