zoukankan      html  css  js  c++  java
  • 游戏服务器架构系列

    为什么要生成分布式ID?

    在复杂分布式系统中,往往需要对大量的数据和消息进行唯一标识。例如在游戏中,游戏数据日渐增长,对数据分库分表后需要有一个唯一ID来标识一条数据或消息,数据库的自增ID显然不能满足需求,那业务系统对ID号的要求有哪些呢?

    1)全局唯一性:不能出现重复的ID号,既然是唯一标识,这是最基本的要求。

    2)趋势递增:在MySQL InnoDB引擎中使用的是聚集索引,由于多数RDBMS使用B-tree的数据结构来存储索引数据,在主键的选择上面我们应该尽量使用有序的主键保证写入性能。

    3)单调递增:保证下一个ID一定大于上一个ID,例如事务版本号、IM增量消息、排序等特殊需求。

    4)信息安全:如果ID是连续的,恶意用户的扒取工作就非常容易做了,直接按照顺序下载指定URL即可;如果是订单号就更危险了,竞对可以直接知道我们一天的单量。所以在一些应用场景下,会需要ID无规则、不规则。

    1、UUID

    使用网卡地址、时间戳和随机数进行生成唯一ID,Java中就自带生成UUID的方法。

    优点:本地即可生成,不需要网络开销

    缺点:字符串占用内存,不自增,对数据库索引不友好,MySQL官方推荐不要使用

    2、snowflake算法

    1位:保留位不用。二进制中最高位为1的都是负数,但是我们生成的id一般都使用整数,所以这个最高位固定是0

    41位:用来记录时间戳(毫秒),41位可以表示2^41−1个数字,(2^41−1)/(1000∗60∗60∗24∗365)=69年

    10位:用来记录工作机器id

    12位:序列号,用来记录同毫秒内产生的不同id

    优点:存在自增趋势,只占用64位

    缺点:强依赖机器时钟

    3、Flicker公司的解决方案

    使用MySQL的auto_increment自增特性来生成唯一ID。

    创建优惠券表:

    CREATE TABLE Discount (
    id bigint(20) unsigned NOT NULL auto_increment,
    stub char(1) NOT NULL default '',
    PRIMARY KEY (id),
    UNIQUE KEY stub (stub)
    ) ENGINE=InnoDB
    

    获取ID: 在一个事务中执行如下sql,replace和insert语句区别主要是replace在插入数据的时候,如果数据存在(通过主键和唯一索引来查找)则先删除,然后再进行插入。

    START TRANSACTION;
        REPLACE INTO Tickets64 (stub) VALUES ('a');
        SELECT LAST_INSERT_ID();
    COMMIT;
    

    上面这种方法只在单台MySQL上生成ID,从高可用角度考虑,接下来就要解决单点故障问题:可以启用两台数据库服务器来生成ID,通过区分auto_increment的起始值和步长来生成奇偶数的ID。

    DiscountServer1  // 优惠券服务1
    auto-increment-increment = 2 // 自增值
    auto-increment-offset = 1 // 起始值
     
    DiscountServer2 // 优惠券服务2
    auto-increment-increment = 2 // 自增
    auto-increment-offset = 2 // 起始值
    

    优点:充分借助数据库的自增ID机制,提供高可靠性,生成的ID有序。

    缺点:强依赖数据库,占用两个独立的MySQL实例,有些浪费资源,成本较高,而且增删MySQL实例很复杂。

    4、MongoDB的ObjectId

    MongoDB中我们经常会接触到一个自动生成的字段:”_id”,类型为ObjectId。上面方法中用到了MySQL数据库时,主键都是设置成自增的。但在分布式环境下,这种方法就不可行了,会产生冲突。为此,MongoDB采用了一个称之为ObjectId的类型来做主键。ObjectId是一个12字节的 BSON 类型字符串。

    4字节:UNIX时间戳 
    3字节:表示运行MongoDB的机器 
    2字节:表示生成此_id的进程 
    3字节:由一个随机数开始的计数器生成的值 
    

    前9个字节保证了同一秒不同机器不同进程产生的ObjectId的唯一性。后三个字节是一个自动增加的计数器(一个mongod进程需要一个全局的计数器),保证同一秒的ObjectId是唯一的。同一秒钟最多允许每个进程拥有(256^3 = 16777216)个不同的ObjectId。

    优点:算法实现思路和snowflake类似,但是相比更消耗空间

  • 相关阅读:
    [译]《Sphinx权威指南》
    sphinx 配置文件全解析
    利用 crontab 來做 Linux 固定排程
    http协议中用于上传多个文件的 multipart 字段
    Python 代码覆盖率统计工具 coverage.py
    Disruptor 基础篇
    NPM:常用命令的生命周期脚本
    十大经典排序算法(动图演示)【转】
    TypeScript Jest 调试
    NPM: 日常开发环境配置
  • 原文地址:https://www.cnblogs.com/cnsec/p/13406979.html
Copyright © 2011-2022 走看看