原文:http://tlzl0526-gmail-com.iteye.com/blog/2378853
在一些高並發的場景中,比如秒殺,搶票,搶購這些場景,都存在對核心資源,商品庫存的爭奪,控制不好,庫存數量可能被減少到負數,出現超賣的情況,或者 產生唯一的一個遞增ID,由於web應用部署在多個機器上,簡單的同步加鎖是無法實現的,給數據庫加鎖的話,對於高並發,1000/s的並發,數據庫可能由行鎖變成表鎖,性能下降會厲害。那相對而言,redis的分布式鎖,相對而言,是個很好的選擇,redis官方推薦使用的Redisson就提供了分布式鎖和相關服務。
下面介紹下如何使用Redisson。
- <dependency>
- <groupId>org.redisson</groupId>
- <artifactId>redisson</artifactId>
- <version>2.7.0</version>
- </dependency>
使用redisson,最好采用redis 2.6.0以上版本,因為redosson一些后台命令采用eval的命令
- import org.redisson.Redisson;
- import org.redisson.api.RAtomicLong;
- import org.redisson.config.Config;
- public class RedissonManager {
- private static final String RAtomicName = "genId_";
- private static Config config = new Config();
- private static Redisson redisson = null;
- public static void init(String key,String value){
- try {
- /* config.useClusterServers() //這是用的集群server
- .setScanInterval(2000) //設置集群狀態掃描時間
- .setMasterConnectionPoolSize(10000) //設置連接數
- .setSlaveConnectionPoolSize(10000)
- .addNodeAddress("127.0.0.1:6379");*/
- if(key==null || "".equals(key)){
- key=RAtomicName;
- }
- config.useSingleServer().setAddress("127.0.0.1:6379");
- redisson = (Redisson) Redisson.create(config);
- //清空自增的ID數字
- RAtomicLong atomicLong = redisson.getAtomicLong(key);
- long pValue=1;
- if(value!=null && !"".equals(value)){
- pValue = Long.parseLong(value);
- }
- atomicLong.set(pValue);
- }catch (Exception e){
- e.printStackTrace();
- }
- }
- public static Redisson getRedisson(){
- return redisson;
- }
- /** 獲取redis中的原子ID */
- public static Long nextID(){
- RAtomicLong atomicLong = getRedisson().getAtomicLong(RAtomicName);
- //原子性的獲取下一個ID,遞增1
- atomicLong.incrementAndGet();
- return atomicLong.get();
- }
- }
加鎖和釋放鎖的方法,設置超時
- public class DistributedRedisLock {
- private static Redisson redisson = RedissonManager.getRedisson();
- private static final String LOCK_TITLE = "redisLock_";
- public static boolean acquire(String lockName){
- String key = LOCK_TITLE + lockName;
- RLock mylock = redisson.getLock(key);
- mylock.lock(2, TimeUnit.MINUTES); //lock提供帶timeout參數,timeout結束強制解鎖,防止死鎖
- System.err.println("======lock======"+Thread.currentThread().getName());
- return true;
- }
- public static void release(String lockName){
- String key = LOCK_TITLE + lockName;
- RLock mylock = redisson.getLock(key);
- mylock.unlock();
- System.err.println("======unlock======"+Thread.currentThread().getName());
- }
- }
在web端,controller中
- @RequestMapping("/redder")
- @ResponseBody
- public String redder() throws IOException{
- String key = "test123";
- DistributedRedisLock.acquire(key);
- Long result = RedissonManager.nextID();
- DistributedRedisLock.release(key);
- return ""+result;
- }
程序首先要設置 RedissonManager.init("",""); 進行初始化,這樣的目的主要是可以根據實際情況,設置對應的信息,設置遞增的初始值。
目前用jmeter的測試,1000的並發,確保ID設置為1001