100字范文,内容丰富有趣,生活中的好帮手!
100字范文 > 分布式id黑科技完善

分布式id黑科技完善

时间:2020-09-30 07:16:29

相关推荐

分布式id黑科技完善

分布式环境下唯一id确实算个问题,今天分享的算法自己项目已经跑了两年,效率高也没出现重复情况;

直接上干货:

核心两个类:

package com.mon;import java.sql.Timestamp;import java.util.concurrent.Executors;import java.util.concurrent.ScheduledExecutorService;import java.util.concurrent.ThreadFactory;import java.util.concurrent.TimeUnit;import java.util.concurrent.atomic.AtomicLong;/*** 高并发场景下System.currentTimeMillis()的性能问题的优化*<p><p>* System.currentTimeMillis()的调用比new一个普通对象要耗时的多(具体耗时高出多少我还没测试过,有人说是100倍左右)<p>* System.currentTimeMillis()之所以慢是因为去跟系统打了一次交道<p>* 后台定时更新时钟,JVM退出时,线程自动回收<p>* 10亿:43410,206,210.72815533980582%<p>* 1亿:4699,29,162.0344827586207%<p>* 1000万:480,12,40.0%<p>* 100万:50,10,5.0%<p>*@authorlry*/public class SystemClock {private final long period; private final AtomicLong now; private SystemClock(long period) {this.period = period; this.now = new AtomicLong(System.currentTimeMillis()); scheduleClockUpdating(); }private static class InstanceHolder {public static final SystemClockINSTANCE= new SystemClock(1); }private static SystemClock instance() {return InstanceHolder.INSTANCE; }private void scheduleClockUpdating() {ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor(new ThreadFactory() {public Thread newThread(Runnable runnable) {Thread thread = new Thread(runnable, "System Clock");thread.setDaemon(true);return thread; }}); scheduler.scheduleAtFixedRate(new Runnable() {public void run() {now.set(System.currentTimeMillis()); }}, period, period, TimeUnit.MILLISECONDS); }private long currentTimeMillis() {return now.get(); }public static long now() {return instance().currentTimeMillis(); }public static String nowDate() {return new Timestamp(instance().currentTimeMillis()).toString(); }}

package com.mon;/*** 分布式高效有序ID生产黑科技(sequence)**@authorlry*/public class Sequence {private final long twepoch = 1288834974657L; private final long workerIdBits = 5L; private final long datacenterIdBits = 5L; private final long maxWorkerId = -1L ^ (-1L << workerIdBits); private final long maxDatacenterId = -1L ^ (-1L << datacenterIdBits); private final long sequenceBits = 12L; private final long workerIdShift = sequenceBits; private final long datacenterIdShift = sequenceBits + workerIdBits; private final long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits; private final long sequenceMask = -1L ^ (-1L << sequenceBits); private long workerId; private long datacenterId; private long sequence = 0L; private long lastTimestamp = -1L; /** *@paramworkerId工作机器ID *@paramdatacenterId序列号 */ public Sequence(long workerId, long datacenterId) {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; }/** * 获取下一个ID *@return*/ public synchronized long nextId() {long timestamp = timeGen();if (timestamp < lastTimestamp) {throw new RuntimeException(String.format("Clock moved backwards. Refusing to generate id for %d milliseconds", lastTimestamp - timestamp));}if (lastTimestamp == timestamp) {sequence = (sequence + 1) & sequenceMask; if (sequence == 0) {timestamp = tilNextMillis(lastTimestamp); }} else {sequence = 0L;}lastTimestamp = timestamp;return ((timestamp - twepoch) << timestampLeftShift) | (datacenterId << datacenterIdShift)| (workerId << workerIdShift) | sequence; }protected long tilNextMillis(long lastTimestamp) {long timestamp = timeGen();while (timestamp <= lastTimestamp) {timestamp = timeGen();}return timestamp; }protected long timeGen() {return SystemClock.now(); }}

private static SFSequencesequ= new SFSequence(machineId%32,0);

*** 内存方式分配全局唯一ID**@authorshuzc 总共四种方式,getNextId,getUniqueIdAsString,getNextId和数据库自增id.* 1.用户id用getNextId;如果分表按最后2 ~ 3位分即可* 2.订单id用getUniqueIdAsString,最好在这个串的前面添加某个前缀,如果想在中间添加,修改下代码;如果分表按最后2 ~* 3位分即可 3.商品id用getNextId,如果分表按最后2 ~ 3位分即可 4.进步id用getNextId,这个应该没有分表需求* 5.点赞记录的id,或者一些流水性质的,比如用户操作记录等,这些记录应该只有查询的场景,没有更新等场景;用数据库自增id,* 或者getUniqueIdAsLong,这种分表也不会利用主键的*@return*/@Service@SuppressWarnings("hiding")public class IdGenerateService {private static intMAX_TRY_TIMES= 20; private static longmachineId= calculateMachineId(); private static final SimpleDateFormatDATE_TIME_FORMAT= new SimpleDateFormat("yyyyMMddHHmmss"); private static final SimpleDateFormatSHORT_DATE_TIME_FORMAT= new SimpleDateFormat("yyMMddHHmmss"); private static final StringMACHINE_ID_FORMAT= "%1d"; private static final AtomicLongseq= new AtomicLong(0); private static long calculateMachineId() {try {for (NetworkInterface iface : Collections.list(NetworkInterface.getNetworkInterfaces())) {for (InetAddress raddr : Collections.list(iface.getInetAddresses())) {if (raddr.isSiteLocalAddress() && !raddr.isLoopbackAddress() && !(raddr instanceof Inet6Address)) {return getLocalMac(raddr);}}}} catch (SocketException e) {throw new IllegalStateException("fail to get host ip");}throw new IllegalStateException("fail to get host ip"); }private static long getLocalMac(InetAddress ia) throws SocketException {byte[] mac = NetworkInterface.getByInetAddress(ia).getHardwareAddress();int temp = 0;StringBuffer sb = new StringBuffer("");for (int i = 0; i < mac.length; i++) {if (i != 0) {sb.append("-"); }temp ^= (mac[i] & 0xff);}// 与时间异或,更有利于排除重复的可能return temp ^ (System.currentTimeMillis() % 100); }public Long getUniqueIdAsLong() {returnsequ.nextId(); }private static SFSequencesequ= new SFSequence(machineId%32,0);

for (InetAddress raddr : Collections.list(iface.getInetAddresses())) { if (raddr.isSiteLocalAddress() && !raddr.isLoopbackAddress() && !(raddr instanceof Inet6Address)) { return getLocalMac(raddr); } } } } catch (SocketException e) { throw new IllegalStateException("fail to get host ip"); } throw new IllegalStateException("fail to get host ip");}

}

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。