注册

原神UID300000000诞生,有人以高价购买!那么UID是怎么生成的?

原神UID有人要高价购买?


在原神的广袤世界中,每位冒险者都被赋予一个独特的身份标识——UID(User ID)。这个数字串既是你在游戏中独一无二的身-份-证明,也承载着无数冒险的记忆。然而,有一个UID格外引人注目——300000000,最近它在原神的世界中诞生,成为了众人瞩目的焦点,因为有人要以高价购买。


查阅资料我们知道,UID不同开头代表不同的含义。


UID服务
uid1、2开头官服
uid5开头B服、小米服等,国内渠道服都是5开头
uid6开头美服
uid7开头欧服
uid8开头亚服
uid9开头港澳服

首先UID是固定的9位数,也就是100000000这样的,前面的1是固定的,所有玩家开头都是这个1,然后剩下的8位数才是注册顺序。比如:100000001,这个就是开服第一位玩家,100000013,这个就是第13位注册玩家。


300000000说明官服已经有2亿用户了!!!


我们先看下UID的生成的策略吧。


系统中UID需要怎么设计呢?


什么是UID?


UID是一个系统内用户的唯一标识(Unique Identifier),唯一标识成为了数字世界中不可或缺的一部分。无论是在数据库中管理记录,还是在分布式系统中追踪实体,唯一标识都是保障数据一致性和可追溯性的关键。为了满足各种需求,各种唯一标识生成方法应运而生。


UID如何设计


UUID模式


UUID (Universally Unique Identifier),通用唯一识别码的缩写。目前UUID的产生方式有5种版本,每个版本的算法不同,应用范围也不同。其中最常见的是基于时间戳的版本(Version 1)和基于随机数的版本(Version 4)。版本1的UUID包含了时间戳和节点信息,而版本4的UUID则是纯粹的随机数生成。


•基于时间的UUID:这个一般是通过当前时间,随机数,和本地Mac地址来计算出来,可以通过 org.apache.logging.log4j.core.util包中的 UuidUtil.getTimeBasedUuid()来使用或者其他包中工具。由于使用了MAC地址,因此能够确保唯一性,但是同时也暴露了MAC地址,私密性不够好。•基于随机数UUID :这种UUID产生重复的概率是可以计算出来的,但是重复的可能性可以忽略不计,因此该版本也是被经常使用的版本。JDK中使用的就是这个版本。


Java中可通过UUID uuid = UUID.randomUUID();生成。


虽然 UUID 生成方便,本地生成没有网络消耗,但是使用起来也有一些缺点,不易于存储:UUID太长,16字节128位,通常以36长度的字符串表示,很多场景不适用。信息不安全:基于MAC地址生成UUID的算法可能会造成MAC地址泄露,暴露使用者的位置。对MySQL索引不利:如果作为数据库主键,在InnoDB引擎下,UUID的无序性可能会引起数据位置频繁变动,严重影响性能。


表ID自增


将user表的id设置为auto_increment,插入会自动生成ID,将表的主键ID作为UID.


这种方式的优势在于简单易实现,不需要引入额外的中心化服务。但也存在一些潜在的问题,比如数据库的性能瓶颈、数据量大需要分库分表等。


使用redis实现


Redis实现分布式唯一ID主要是通过提供像 INCR 和 INCRBY 这样的自增原子命令,由于Redis自身的单线程的特点所以能保证生成的 ID 肯定是唯一有序的。


但是单机存在性能瓶颈,无法满足高并发的业务需求,所以可以采用集群的方式来实现。集群的方式又会涉及到和数据库集群同样的问题,所以也需要设置分段和步长来实现。


为了避免长期自增后数字过大可以通过与当前时间戳组合起来使用,另外为了保证并发和业务多线程的问题可以采用 Redis + Lua的方式进行编码,保证安全。Redis 实现分布式全局唯一ID,它的性能比较高,生成的数据是有序的,对排序业务有利,但是同样它依赖于redis,需要系统引进redis组件,增加了系统的配置复杂性。当然现在Redis的使用性很普遍,所以如果其他业务已经引进了Redis集群,则可以考虑使用Redis来实现。


号段模式


号段模式是一种常见的分布式ID生成策略,也被称为Segment模式。该模式通过预先分配一段连续的ID范围(号段),并在每个节点上使用这个号段,以减少对全局资源的竞争,提高生成ID的性能。以下是一个简单的号段模式生成分布式ID的步骤:


1.预分配号段: 一个中心化的服务(通常是一个分布式协调服务,比如Zookeeper或etcd)负责为每个节点预分配一段连续的ID号段。这个号段可以是一段整数范围,如[1, 1000],[1001, 2000]等。2.本地取ID: 每个节点在本地维护一个当前可用的ID范围(号段)。节点在需要生成ID时,首先使用本地的号段,而不是向中心化的服务请求。这可以减少对中心化服务的压力和延迟。3.号段用尽时重新申请: 当本地的号段用尽时,节点会向中心化服务请求一个新的号段。中心化服务会为节点分配一个新的号段,并通知节点更新本地的号段范围。4.处理节点故障: 在节点发生故障或失效时,中心化服务会将未使用的号段重新分配给其他正常运行的节点,以确保所有的ID都被充分利用。5.定期刷新: 节点可能定期地或在某个条件下触发,向中心化服务查询是否有新的号段可用。这有助于节点及时获取新的号段,避免在用尽号段时的阻塞。


这种号段模式的优点在于降低了对中心化服务的依赖,减少了因为频繁请求中心化服务而产生的性能瓶颈。同时,由于每个节点都在本地维护一个号段,生成ID的效率相对较高。


需要注意的是,号段模式并不保证全局的递增性或绝对的唯一性,但在实际应用中,通过合理设置号段的大小和定期刷新机制,可以在性能和唯一性之间找到一个平衡点。


Snowflake模式


Snowflake是一个经典的号段生成算法,同时市面上存在大量的XXXflake算法.一般用作订单号。主要讲一下Snowflake的原理。


arch-z-id-3.png



  • 第1位占用1bit,其值始终是0,可看做是符号位不使用。
  • 第2位开始的41位是时间戳,41-bit位可表示2^41个数,每个数代表毫秒,那么雪花算法可用的时间年限是(1L<<41)/(1000L360024*365)=69 年的时间。
  • 中间的10-bit位可表示机器数,即2^10 = 1024台机器,但是一般情况下我们不会部署这么台机器。如果我们对IDC(互联网数据中心)有需求,还可以将 10-bit 分 5-bit 给 IDC,分5-bit给工作机器。这样就可以表示32个IDC,每个IDC下可以有32台机器,具体的划分可以根据自身需求定义。
  • 最后12-bit位是自增序列,可表示2^12 = 4096个数。

不过Snowflake需要依赖于时钟,可能受到时钟回拨的影响。同时,如果并发生成ID的速度过快,可能导致序列号用尽。


总结


在选择UID生成方法时,需要根据具体的应用场景和需求权衡其优缺点。不同的场景可能需要不同的解决方案,以满足系统的唯一性要求和性能需求。那么你觉得原神的UID是如何生成的呢?如果是你该如何设计呢?


作者:半亩方塘立身
来源:juejin.cn/post/7324633501244063782

0 个评论

要回复文章请先登录注册