写点什么

为什么总是需要无意义的 ID ?(二)

  • 2019-12-27
  • 本文字数:2139 字

    阅读完需:约 7 分钟

为什么总是需要无意义的 ID ?(二)

唯一性

消息队列往往需要对外保证服务质量,可能需要提供包括最多一次、最少一次和正好一次在内的服务质量,由于网络可能存在超时等不确定性,当我们想要实现正好一次时,就一定需要一种机制能够在接收方识别发送方发出的重复消息,在这时就需要使用唯一的标识符来解决这个问题:



我们在之前的系列文章 为什么 TCP 建立连接需要三次握手 提到的 TCP 连接中的序列号也是一个唯一的标识符,它能够帮助我们判断对数据进行去重,保证应用层的协议不会收到异常的数据包,这些场景都需要用到标识符的唯一性,唯一性为我们带来的就是精确识别对象的能力。


在与网络相关的场景下,使用唯一 ID 的例子非常普遍,假如我们想通过支付宝或者微信的 API 向其他人发起一笔转账,如果这次请求发生了超时,那么我的这笔转账请求到底有没有被处理呢?



当前的节点对于这笔转账请求的结果是不知道的,如果这时重新请求可能会发生二次转账这类严重的问题,但是如果不重新请求,转账可能没有生效,这时如果我们引入一个无意义的 ID 来帮助接收方识别请求的唯一性就能很好地解决这个问题:


  1. 如果接收方已经成功处理 ID 对应的请求,那么就直接返回;

  2. 如果接收方没有处理 ID 对应的请求,就正常进行处理;


为了保证请求的唯一性,根据业务对于唯一性要求的强弱,我们需要在接收方对 ID 进行存储,可以在内存中,也可以在数据库中,最重要的是唯一的 ID 为接收方提供了判断重复的重要依据。


除了在不稳定的网络中,数据库也包含 ID 标识符这一概念,我们在数据库中往往叫做主键,它在一般情况下都是一个递增的唯一整数,绝大多数的表都会使用 ID 作为表的主键来保证数据的唯一性,当我们想要对数据进行增删改查等操作时,使用主键 ID 查询数据也是性能最优并且最不容易出现问题的做法。

无意义

无意义的意思其实就是 ID 中不应该包含任何与具体场景或者业务相关的内容,包含这些内容并不是不可以,只是一旦出现这些内容,要么 ID 重复的可能性会增加,这很可能对我们的业务逻辑造成比较严重的影响,以我们的身份证号为例,它的 18 位数字(或符号)大多都是有意义的。



这 18 位数字中的前 6 位表示的是地区,也就是省份、城市和区县,随后的 8 位表示的是出生年月日,接下来的 3 位才同时表示 ID 和性别,最后 1 位用于做校验码防止出现身份证号输错的情况。用上述图中的黄色部分中有一半的数字是用来表示出生的男性,另一半表示出生的女性,所以如果同一个地区的同一天,同时出生了 501 位男性或者女性就会导致潜在的重复问题。


上面谈到的问题其实也是我们在各种业务场景中经常能够遇到的问题,18 位的数字中真正用于表示序列的 ID 其实只有 1000 的一半,如果 18 位数都是无意义的,那它们可以表示 10 亿亿个人,但是一旦在 ID 中引入了业务上的具体信息,就增加了冲突的可能性。


业务记录上主键的长度往往都是固定的,大多数业务的主键都会使用整数,它的上限一般就是 2^64,如果这些位数都用来表示记录的 ID,那么在有生之年基本上是不可能被使用完的,但是一旦我们将业务信息加入 ID,就会让原本无意义的 ID 变得有意义从而影响它的唯一性。


另一个比较类似的例子其实是分布式的 ID 生成器,Snowflake 算法会为 64 个比特的整数赋予不同的信息:


范围长度作用
0-01不使用
1-4141毫秒级时间戳
42-465数据中心标识符
47-515机器标识符
52-6312序列号


从这个设计来看,我们的假设其实是一台机器上一毫秒最多只能生成 4096 个 ID,一旦超过了这个这个数量就有可能导致 ID 冲突或者乱序,从而失去其唯一性;这个算法中涉及的时间戳、数据中心标识符、机器标识符都没有办法解决唯一性的问题,哪怕这三者完全相等,最终还是有冲突的可能,我们仍然需要使用无其他意义的序列号来保证 ID 的唯一。

总结

其实不难看出,使用无意义 ID 的主要目的就是利用它的唯一性保证对象的标识符不会发生冲突,无意义 ID 的唯一作用就是保证唯一性,这能帮助我们避免业务字段可能存在潜在冲突的可能,这也提示我们想要使用联合字段构成主键时一定要深思熟虑。


如果我们想要在具有唯一性的标识符中加入业务信息,一定要注意这可能会减少用于保证唯一性的『空间』,当然对于一个足够大的空间来说,这其实并没有什么问题;但是类型为 int64 的 ID 中加入业务数据还是需要仔细思考可扩展性以及预留的信息是否足够业务的发展。


到最后,我们还是来看一些比较开放的相关问题,有兴趣的读者可以仔细思考一下下面的问题:


  • 软件工程还有哪些场景利用了 ID 的唯一性?

  • 在日常生活中除了身份证号之外,还有哪些 ID 也有比较高的冲突可能性?


如果对文章中的内容有疑问或者想要了解更多软件工程上一些设计决策背后的原因,可以在博客下面留言,作者会及时回复本文相关的疑问并选择其中合适的主题作为后续的内容。

相关文章


本文转载自 Draveness 技术博客。


原文链接:https://draveness.me/whys-the-design-meaningless-identifier


2019-12-27 11:33914

评论

发布
暂无评论
发现更多内容

记录一次TiDB v5.2.3迁移到v6.1.0的过程

TiDB 社区干货传送门

迁移 实践案例

聊聊Mybatis的类型转换的别名管理

急需上岸的小谢

11月月更

java培训学习过程中需要什么方法?

小谷哥

阿里云与信通院邀您参与云原生安全用户调研

阿里巴巴云原生

阿里云 云原生

java培训程序员失业后的发展方向

小谷哥

宜昌市委书记王立调研数字经济发展并莅临升哲科技

SENSORO

进腾讯了!全靠着这两份近千页的Redis+Netty技术笔记

小小怪下士

Java redis 程序员 面试 Netty

新鲜出炉|基于深度学习的运维日志领域新进展

云智慧AIOps社区

人工智能 深度学习 日志分析 日志管理 运维管理

多点DMALL × Apache Kyuubi:构建统一SQL Proxy探索实践

网易数帆

hadoop spark 开源 Apache Kyuubi

Python(文件操作)

浅辄

Python 文件 11月月更

linux高可用软件有哪些?重点推荐哪款?

行云管家

高可用 双机热备

小间距LED显示屏既是机遇也是挑战

Dylan

LED显示屏 全彩LED显示屏 led显示屏厂家

前端培训学习,就业前景怎么样

小谷哥

大数据培训学习方法有哪些

小谷哥

记一次TiDB数据库Insert语句执行报错的处理过程

TiDB 社区干货传送门

自制操作系统日记(8):变量显示

操作系统

InterruptedException异常会对并发编程产生哪些影响?

冰河

并发编程 多线程 高并发 协程 异步编程

从零开始学Java系列之Java是什么?它到底是个啥?

千锋IT教育

不会还有人不知道,面试靠这1700道java面试八股文题库就能杀进大厂吧

程序知音

Java java面试 java架构 后端技术 Java面试八股文

Python太难懂?火山引擎数智平台这款产品可以了解一下

字节跳动数据平台

Python 大数据 数据分析

我从外包辞职了,10000小时后,走进字节跳动拿了offer

钟奕礼

Java java面试 java编程 程序员‘

先到先得!阿里淘系内传322页Java并发编程核心讲义学习笔记

钟奕礼

Java java面试 java编程 程序员 java

六年三次架构迭代,OceanBase 单机分布式一体化会是大势所趋吗?

OceanBase 数据库

数据库 oceanbase

商业智能BI工具如何选择?公司方面需学习具体方法

流量猫猫头

大数据

瓴羊Quick BI工具,为数据分析人员带来帮助

流量猫猫头

大数据

ThreadPool的线程开启、线程等待、线程池的设置、定时功能

C++后台开发

线程 线程池 后端开发 C++开发 ThreadPool

如何通过前端培训成为合格的程序员

小谷哥

Spring Boot 3.0 正式发布,这份升级指南必须码住

程序知音

Java spring 微服务 springboot 后端技术

OceanBase 4.0 解读:分布式查询性能提升,我们是如何思考的?

OceanBase 数据库

数据库 oceanbase

高性能数据访问中间件 OBProxy(六):一文讲透数据路由

OceanBase 数据库

oceanbase

又一巅峰神作!14年工作经验大咖出品“JVM&G1 GC深入学习手册”

钟奕礼

Java java面试 java编程 程序员‘

为什么总是需要无意义的 ID ?(二)_文化 & 方法_Draveness_InfoQ精选文章