本文在分布式自增序列的實現(xiàn)(一) ---分布式序號生成器基礎(chǔ)上成文集歇,因此直接上解決辦法蝌数,省去問題的討論打毛。請先閱讀分布式自增序列的實現(xiàn)(一) ---分布式序號生成器。
上一篇我們提到使用zookeeper的持久化序列node來自動生成分布式序列id嫂丙,本文將討論使用redis的INCR功能實現(xiàn)分布式自增序列的實現(xiàn)。redis是單線程的互例,它能保證生成的序列是不重復(fù)的奢入。
Redis incr功能介紹
官方文檔https://redis.io/commands/incr
Increments the number stored at key by one. If the key does not exist, it is set to 0 before performing the operation. An error is returned if the key contains a value of the wrong type or contains a string that can not be represented as integer. This operation is limited to 64 bit signed integers.
Note: this is a string operation because Redis does not have a dedicated integer type. The string stored at the key is interpreted as a base-10 64 bit signed integer to execute the operation.
Redis stores integers in their integer representation, so for string values that actually hold an integer, there is no overhead for storing the string representation of the integer.
The counter pattern is the most obvious thing you can do with Redis atomic increment operations.
可以看到最大的序列是64bit的有符號的整型, 最大值是2的63次方-1媳叨, 也就是9,223,372,036,854,775,807腥光,基本上絕大部分項目夠用了。從0開始糊秆。特別是文檔中的這句武福,"incr可以用作計數(shù)器模式,它是原子自增操作痘番。"
具體代碼實現(xiàn)
我直接使用的spring-data-redis捉片,程序基于springboot。完整代碼在這里汞舱,歡迎加星伍纫,fork。 本程序啟動時會自動連接redis, 請先配置好自己的redis服務(wù)器ip和端口等信息.
本示例代碼使用了RedisAtomicLong 昂芜,請參考官方文檔https://docs.spring.io/spring-data/redis/docs/current/api/org/springframework/data/redis/support/atomic/RedisAtomicLong.html 我們主要使用addAndGet方法莹规。
服務(wù)層代碼
package com.yq.service.impl;
import com.yq.service.RedisService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.ListOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.data.redis.support.atomic.RedisAtomicLong;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
/**
* Simple to Introduction
* className: RedisServiceImpl
*
* @author EricYang
* @version 2018/8/4 23:00
*/
@Service
@Slf4j
public class RedisServiceImpl implements RedisService {
@Autowired
private StringRedisTemplate template;
@Autowired
RedisAtomicLong redisAtomicLong;
private static final String LONG_KEY = "yqLong";
@Bean
public RedisAtomicLong getRedisAtomicLong() {
RedisAtomicLong counter = new RedisAtomicLong(LONG_KEY, template.getConnectionFactory());
return counter;
}
@Override
public String get(String key) {
ValueOperations<String, String> ops = this.template.opsForValue();
return ops.get(key);
}
@Override
public void set(String key, String value) {
ValueOperations<String, String> ops = this.template.opsForValue();
ops.set(key, value);
}
@Override
public String getHash(String key, String hashKey) {
HashOperations<String, String, String> hashOps = this.template.opsForHash();
return hashOps.get(key, hashKey);
}
@Override
public void setHash(String key, String hashKey, String value) {
HashOperations<String, String, String> hashOps = this.template.opsForHash();
hashOps.put(key, hashKey, value);
}
@Override
public long getRedisSequence() {
long sequence = 0L;
try {
if (redisAtomicLong.get() == 0) {
redisAtomicLong.getAndSet(0L);
}
sequence = redisAtomicLong.incrementAndGet();
} catch (Exception ex) {
log.error("Failed to get sequence.", ex);
}
return sequence;
}
}
controller層代碼, 供其他服務(wù)調(diào)用
@RestController
@RequestMapping("/cache")
public class RedisController {
private Logger logger = LoggerFactory.getLogger(RedisController.class);
@Autowired
RedisService redisService;
@ApiOperation(value = "獲取sequence")
@GetMapping(value = "/sequence", produces = "application/json;charset=UTF-8")
public long getSequence() {
long value = redisService.getRedisSequence();
return value;
}
。泌神。良漱。