使用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个左右。频繁的加锁释放锁也是很浪费时间

 


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM