使用REDIS的INCREMENT方法生成自增主键,并发量每秒一万
使用REDIS的INCREMENT方法生成自增主键,并发量每秒一万
·
redis是单线程的,他提供了一个单线程的自增方法increment供我们使用。
现在有一个业务需求,id需要自增生成,且生成速度要求一秒一千以上。废话不多说,直接上代码
public class IncrIdUtils { private final String REDIS_KEY_TASK_ID = "AUTO_TASK_ID"; private final String REDIS_KEY_PRO_INS_ID = "AUTO_PRO_INS_ID"; @Resource private RedisUtils redisUtils; @Value("${task.id.last}") private Long taskIdLast = 900000000000L; @Value("${pro.ins.id.last}") private Long proInsIdLast = 900000000000L; /** * 生成一个长度为12的纯数字字符串作为任务id,规则如下 * 1.以9开头 * 2.后11位数字从1开始自增 * * @return 如:"900000000001" */ public String getTaskId() { String taskIdRedis; long incr = redisUtils.incr(REDIS_KEY_TASK_ID, 1); taskIdRedis = String.valueOf(incr + taskIdLast); return taskIdRedis; } } 下面是测试代码
@Resource IncrIdUtils incrIdUtils;
public Response testTaskIdCreate(@ApiParam(name = "num", value = "生成数量", required = true) @RequestParam("num") Integer num) throws InterruptedException { long start = System.currentTimeMillis(); Map<String, Integer> dataMap = new ConcurrentHashMap<>(); ExecutorService executorService = Executors.newFixedThreadPool(100); for (int i = 0; i < num; i++) { executorService.submit(() -> { String taskId = ""; taskId = incrIdUtils.getTaskId(); System.out.println(taskId); dataMap.put(taskId, 1); }); } executorService.shutdown(); while (true) { if (executorService.isTerminated()) { Map<String, Integer> resultMap = new HashMap<>(); resultMap.put("map", dataMap.size()); resultMap.put("time", (int) (System.currentTimeMillis() - start)); return Response.success(resultMap); } } }
运行代码测试,并发量可以达到每秒一万以上,并且生成的id不会重复,搞定 开发过程中遇到的坑:注意在测试的时候一定不能用hashmap,hashmap是线程不安全的,因为一开始用了hashmap,老师出现数量对不上的情况,换了concurrenthashmap马上好了 用过的其他方法: 在代码中进行自增运算,然后写入的时候用cas算法校验。 这种方法效率低,增加了redis的读写次数,并且单纯的cas算法并没有保证线程安全,还容易导致内存溢出。再加上synchronized代码锁之后,效率更低,每秒只能生成150个左右。 换成lock锁之后效率更低,只有每秒100个左右。频繁的加锁释放锁也是很浪费时间
更多推荐
已为社区贡献4条内容
所有评论(0)