免费php企业网站,苏州网站建设多少钱,建设行业门户网站需要什么条件,网站建设与维护工作做一个积极的人编码、改bug、提升自己我有一个乐园#xff0c;面向编程#xff0c;春暖花开#xff01;一#xff1a;前言我在实际环境中遇到了这样一种问题#xff0c;分布式生成id的问题#xff01;因为业务逻辑的问题#xff0c;我有个生成id的方法#xff0c;是根据…做一个积极的人编码、改bug、提升自己我有一个乐园面向编程春暖花开一前言我在实际环境中遇到了这样一种问题分布式生成id的问题因为业务逻辑的问题我有个生成id的方法是根据业务标识id 当做唯一的值 而uuid是递增生成的从1开始一直递增那么在同一台机器上运行代码加上同步方法(synchronized)这个生成id的方法就是ok但是因为业务扩展或者说为了安全项目运行在两台机器上此时单个的同步方法(synchronized或者Lock)就不能防止id的重复了要解决上面的这个问题其他有如下解决办法 (1)每台机器生产Id的代码keyid 可以在前加上机器编号区分key id --- 机器唯一编号 key id (2)使用数据库行锁(单个数据库的是时候如何是分布式数据库也会出现问题)在需要插入id的表加上行锁防止数据重复导致程序异常 (3)使用分布式锁二分布式锁简介网上有很多的讲解分布式锁的文章但是细细分析很多的代码还是有很多的问题的如下代码片段摘自博文https://my.oschina.net/91jason/blog/517996?p1http://blog.csdn.net/u010359884/article/details/50310387public void lock(long timeout) { long nano System.nanoTime(); timeout * 1000000; final Random r new Random(); try { while ((System.nanoTime() - nano) timeout) { if (redisTemplate.getConnectionFactory().getConnection().setNX(key.getBytes(), LOCKED.getBytes())) { redisTemplate.expire(key, EXPIRE, TimeUnit.SECONDS); locked true; logger.debug(add RedisLock[ key ].); break; } Thread.sleep(3, r.nextInt(500)); } } catch (Exception e) { } }上面的代码博主也说了如果长时间获取不到就会获取锁失败相当于没加锁这里还有可能发生其他问题(1)并发情况expire主动释放锁的时候可能释放的是别人的锁(不懂请自行查询相关资料)(2)Redis服务挂掉锁失败相当于没加锁最好使用主从哨兵提高 高可用注使用的时候要注意上面问题还有一种摘自博文 http://www.cnblogs.com/0201zcr/p/5942748.html 这个博问分析的 while (timeout 0) { long expires System.currentTimeMillis() expireMsecs 1; String expiresStr String.valueOf(expires); //锁到期时间 if (this.setNX(lockKey, expiresStr)) { // lock acquired locked true; return true; } String currentValueStr this.get(lockKey); //redis里的时间 if (currentValueStr ! null Long.parseLong(currentValueStr) System.currentTimeMillis()) { //判断是否为空不为空的情况下如果被其他线程设置了值则第二个条件判断是过不去的 // lock is expired String oldValueStr this.getSet(lockKey, expiresStr); //获取上一个锁到期时间并设置现在的锁到期时间 //只有一个线程才能获取上一个线上的设置时间因为jedis.getSet是同步的 if (oldValueStr ! null oldValueStr.equals(currentValueStr)) { //防止误删(覆盖因为key是相同的)了他人的锁——这里达不到效果这里值会被覆盖但是因为什么相差了很少的时间所以可以接受 //[分布式的情况下]:如过这个时候多个线程恰好都到了这里但是只有一个线程的设置值和当前值相同他才有权利获取锁 // lock acquired locked true; return true; } } timeout - DEFAULT_ACQUIRY_RESOLUTION_MILLIS; /* 延迟100 毫秒, 这里使用随机时间可能会好一点,可以防止饥饿进程的出现,即,当同时到达多个进程, 只会有一个进程获得锁,其他的都用同样的频率进行尝试,后面有来了一些进行,也以同样的频率申请锁,这将可能导致前面来的锁得不到满足. 使用随机的等待时间可以一定程度上保证公平性 */ Thread.sleep(DEFAULT_ACQUIRY_RESOLUTION_MILLIS); }这个相比第一个完善了误删除key的问题但是要合理的设置超时时间 (要了解具体加锁的业务)否则的话也会使锁失效。三Redisson分布式锁的介绍和简单的使用Redisson的介绍可以到https://github.com/redisson/redisson/wiki/1.-%E6%A6%82%E8%BF%B0 这里去了解我这里说一下使用时候要注意的问题1文档里面说明了支持Redis 2.8以上版本支持Java1.6以上版本。根据自己的环境选择合适的版本22.8.1的redisson 需要使用 netty的jar包 否则报错Hopper: java.lang.NoClassDefFoundError: io/netty/channel/EventLoopGroup。32.8.1的redisson需要jackson 2.5版本否则报错bjectMapper.addMixIn method not fond。我写了一个简单的例子自己也做了一下测试使用的Redis主从哨兵模式 demo的目录结构具体的源码我放到github上面,地址https://github.com/dufyun/learn-tech-collection/tree/master/redissondemo注这里一定要先安装Redis服务如果没有安装Redis服务请参考这篇http://blog.csdn.net/u010648555/article/details/69944668 如果Redis服务安装到服务器上面请修改代码中的Redis地址和端口否则运行不起了!运行这个类UUidGeneratorLockTest就可以看到效果测试结果我也在readme.txt进行了总结如果在测试和学习的过程中有疑问可以随时和我联系也可以加左侧的群或者QQ互相探讨谢谢四总结这个时代信息爆炸各种技术博文之间互相参考真正的问题可能没有暴露出来真正好的文章还是需要鉴别的(我自己也会参考一些文章但是我都会进行一些自己验证一个是为准确性一个加深自己的对知识的认识)我也要反思自己之前也写过一些博文也是遇到问题了去网上搜一些解决方案很多方案确实是理论上可以解决当前遇到的问题当时去深究就会发现很多的不完整性多思考多测试让代码能够更加高效、健壮和安全五参考博文Redis实现分布式锁全局锁—Redis客户端Redisson中分布式锁RLock实现 分布式锁的几种实现方式谢谢你的阅读如果您觉得这篇博文对你有帮助请点赞或者喜欢让更多的人看到祝你每天开心愉快不管做什么只要坚持下去就会看到不一样在路上不卑不亢!愿你我在人生的路上能都变成最好的自己能够成为一个独挡一面的人© 每天都在变得更好的阿飞云