本文引用自“孤独键客”的原创文章“支撑百万并发的数据库架构如何设计?”,内容有修订和改动,感谢原作者的技术分享。
1.jpg (7.21 KB, 下载次数: 1243)
下载附件 保存到相册
5 年前 上传
2.jpg (37.71 KB, 下载次数: 1282)
3.jpg (29.23 KB, 下载次数: 1268)
aaa.png (18.06 KB, 下载次数: 1226)
4.jpg (13.48 KB, 下载次数: 1270)
5.jpg (13.43 KB, 下载次数: 1323)
public class IdWorker { private long workerId; // 这个就是代表了机器id private long datacenterId; // 这个就是代表了机房id private long sequence; // 这个就是代表了一毫秒内生成的多个id的最新序号 public IdWorker(long workerId, long datacenterId, long sequence) { // sanity check for workerId // 这儿不就检查了一下,要求就是你传递进来的机房id和机器id不能超过32,不能小于0 if (workerId > maxWorkerId || workerId < 0) { throw new IllegalArgumentException( String.format("worker Id can't be greater than %d or less than 0",maxWorkerId)); } if (datacenterId > maxDatacenterId || datacenterId < 0) { throw new IllegalArgumentException( String.format("datacenter Id can't be greater than %d or less than 0",maxDatacenterId)); } this.workerId = workerId; this.datacenterId = datacenterId; this.sequence = sequence; } private long twepoch = 1288834974657L; private long workerIdBits = 5L; private long datacenterIdBits = 5L; // 这个是二进制运算,就是5 bit最多只能有31个数字,也就是说机器id最多只能是32以内 private long maxWorkerId = -1L ^ (-1L << workerIdBits); // 这个是一个意思,就是5 bit最多只能有31个数字,机房id最多只能是32以内 private long maxDatacenterId = -1L ^ (-1L << datacenterIdBits); private long sequenceBits = 12L; private long workerIdShift = sequenceBits; private long datacenterIdShift = sequenceBits + workerIdBits; private long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits; private long sequenceMask = -1L ^ (-1L << sequenceBits); private long lastTimestamp = -1L; public long getWorkerId(){ return workerId; } public long getDatacenterId() { return datacenterId; } public long getTimestamp() { return System.currentTimeMillis(); } // 这个是核心方法,通过调用nextId()方法,让当前这台机器上的snowflake算法程序生成一个全局唯一的id public synchronized long nextId() { // 这儿就是获取当前时间戳,单位是毫秒 long timestamp = timeGen(); if (timestamp < lastTimestamp) { System.err.printf( "clock is moving backwards. Rejecting requests until %d.", lastTimestamp); throw new RuntimeException( String.format("Clock moved backwards. Refusing to generate id for %d milliseconds", lastTimestamp - timestamp)); } // 下面是说假设在同一个毫秒内,又发送了一个请求生成一个id // 这个时候就得把seqence序号给递增1,最多就是4096 if (lastTimestamp == timestamp) { // 这个意思是说一个毫秒内最多只能有4096个数字,无论你传递多少进来, //这个位运算保证始终就是在4096这个范围内,避免你自己传递个sequence超过了4096这个范围 sequence = (sequence + 1) & sequenceMask; if (sequence == 0) { timestamp = tilNextMillis(lastTimestamp); } } else { sequence = 0; } // 这儿记录一下最近一次生成id的时间戳,单位是毫秒 lastTimestamp = timestamp; // 这儿就是最核心的二进制位运算操作,生成一个64bit的id // 先将当前时间戳左移,放到41 bit那儿;将机房id左移放到5 bit那儿;将机器id左移放到5 bit那儿;将序号放最后12 bit // 最后拼接起来成一个64 bit的二进制数字,转换成10进制就是个long型 return ((timestamp - twepoch) << timestampLeftShift) | (datacenterId << datacenterIdShift) | (workerId << workerIdShift) | sequence; } private long tilNextMillis(long lastTimestamp) { long timestamp = timeGen(); while (timestamp <= lastTimestamp) { timestamp = timeGen(); } return timestamp; } private long timeGen(){ return System.currentTimeMillis(); } //---------------测试--------------- public static void main(String[] args) { IdWorker worker = new IdWorker(1,1,1); for (int i = 0; i < 30; i++) { System.out.println(worker.nextId()); } } }
public class ToolKits { /** * “接入新访客”的服务记录id生成器。 * <p> * 注意:不同的实例,一定要配置不同的workerId或者datacenterId,否则可能生成的id是重复的。 * * workerId 相同的workerId和datacenterId在同一台机器上将生成同样的id(建议不同的实例一定要用不一样的workerId); * * datacenterId 不同的数据中心,为免生成id的重复性,应使用不一样的id。 */ private final static IdWorker NEXT_SERVICE_ID_WORKER = new IdWorker(0, 0); private final static IdWorker idWorker2 = new IdWorker(1, 0); private final static IdWorker idWorker3 = new IdWorker(0, 1); private final static IdWorker idWorker4 = new IdWorker(1, 1); /** * 为“接入新访客”功能生成一个接的会话的会话。 * * @returns 分布式环境下唯一id(数字形式) */ public static long nextServiceUniqId() { return NEXT_SERVICE_ID_WORKER.nextId(); } public static void main(String[] args) { System.out.println(ToolKits.nextServiceUniqId()); System.out.println("------------------"); System.out.println(idWorker2.nextId()); System.out.println("------------------"); System.out.println(idWorker3.nextId()); System.out.println("------------------"); System.out.println(idWorker4.nextId()); } }
6.jpg (38.22 KB, 下载次数: 1373)
来源:即时通讯网 - 即时通讯开发者社区!
轻量级开源移动端即时通讯框架。
快速入门 / 性能 / 指南 / 提问
轻量级Web端即时通讯框架。
详细介绍 / 精编源码 / 手册教程
移动端实时音视频框架。
详细介绍 / 性能测试 / 安装体验
基于MobileIMSDK的移动IM系统。
详细介绍 / 产品截图 / 安装体验
一套产品级Web端IM系统。
详细介绍 / 产品截图 / 演示视频
引用此评论
引用:Remember 发表于 2019-05-15 16:00 精彩,剩下的就是业务需要到达时的实践了
引用:lChuan 发表于 2020-12-17 17:42 数据库中间件来读写分离,但是1W的并发,10W的并发,数据库中间件mycat等 不也会造成性能瓶颈么,分库分表 ...
引用:JackJiang 发表于 2020-12-17 20:05 加缓存、搞搞读写分离
精华主题数超过100个。
连续任职达2年以上的合格正式版主
为论区做出突出贡献的开发者、版主等。
本人属:鼠
持有金钱达到500。
在线时长累积7天(即7 * 8 = 56小时)。
本人属:狗
积极发起、参与各类话题的讨论等,主题、发帖内容较有价值。
在线时长累积30天(即30 * 8 = 240小时)。
Copyright © 2014-2024 即时通讯网 - 即时通讯开发者社区 / 版本 V4.4
苏州网际时代信息科技有限公司 (苏ICP备16005070号-1)
Processed in 0.125000 second(s), 47 queries , Gzip On.