Redission和Zookeeper分別實現分散式鎖

2022年08月20日10:49:04 科技 1195

redission和zookeeper分別實現分散式鎖(windows)

1、Redission實現分散式事務

1.1 前提準備

  • 下載好nginx(windows版本)
  • 下載好Jmeter(模仿高並發)
  • 下載好redis(windows版)

1.2 代碼

  • pom文件
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.7.2</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <groupId>cn.lanqiao</groupId>
    <artifactId>arcdemo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>arcdemo</name>
    <description>arcdemo</description>


    <properties>
        <java.version>8</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>Spring-boot-starter-data-redis</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.session</groupId>
            <artifactId>spring-session-data-redis</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!-- redisson -->
        <dependency>
            <groupId>org.redisson</groupId>
            <artifactId>Redisson-spring-boot-starter</artifactId>
            <version>3.17.5</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>
  • 配置文件
  • 因為實現分散式事務,所以一會再啟動一個9000埠的該項目
# 應用名稱
spring.application.name=arcdemo
# 應用服務 WEB 訪問埠
server.port=8000


# Redis資料庫索引(默認為0)
spring.redis.database=0
# Redis伺服器地址
spring.redis.host=127.0.0.1
# Redis伺服器連接埠
spring.redis.port=6379
# Redis伺服器連接密碼(默認為空)
spring.redis.password=
# 連接池最大連接數(使用負值表示沒有限制)
spring.redis.jedis.pool.max-active=20
# 連接池最大阻塞等待時間(使用負值表示沒有限制)
spring.redis.jedis.pool.max-wait=-1
# 連接池中的最大空閑連接
spring.redis.jedis.pool.max-idle=10
# 連接池中的最小空閑連接
spring.redis.jedis.pool.min-idle=0
# 連接超時時間(毫秒)
spring.redis.timeout=1000
  • 在主啟動類注入Redisson
package com.example;

import org.redisson.Redisson;
import org.redisson.config.Config;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession;

@SpringBootApplication
@EnableRedisHttpSession
public class ArcdemoApplication {
 

    public static void main(String[] args) {
 
        SpringApplication.run(ArcdemoApplication.class, args);
    }
    @Bean
    public Redisson redission() {
 
        Config config = new Config();
        config.useSingleServer().setAddress("redis://localhost:6379").setDatabase(0);
        return (Redisson) Redisson.create(config);
    }

}
  • controller類
package com.example.controller;

import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.recipes.locks.InterProcessMutex;
import org.apache.curator.retry.RetryNTimes;
import org.redisson.Redisson;
import org.redisson.api.RLock;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.HttpRequest;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.util.concurrent.TimeUnit;

/**
 * @Author Devere19
 * @Date 2022/8/17 10:41
 * @Version 1.0
 */
@RestController
public class BiSheController {
 

    // private static final String ZK_ADDRESS = "127.0.0.1:2181";
    //
    // private static final String ZK_LOCK_PATH = "/zkLock";
    //
    // static CuratorFramework client = null;
    //
    // static {
 
    //     //連接zk
    //     client = CuratorFrameworkFactory.newClient(ZK_ADDRESS,
    //             new RetryNTimes(10, 5000));
    //     client.start();
    // }

    // 分散式鎖
    @Autowired
    private Redisson redisson;

    @Resource
    private StringRedisTemplate StringRedisTemplate;


    @GetMapping("/login")
    public String login(String username, HttpSession session, HttpServletRequest request) {
 
        session.setAttribute("username", username);
        return username + ",埠" + request.getLocalPort();
    }

    @GetMapping("/getUser")
    public String getUser(HttpSession session, HttpServletRequest request) {
 
        String username = (String) session.getAttribute("username");
        return session.getId() + "," + username + ",埠" + request.getLocalPort();
    }

    @PostMapping("/checkTeacher")
    public String checkteacher(String teacherName) {
 
        // SpringBoot操作Redis
        String lockKey = "lockKey";
        RLock redissonLock = null;
        String num = "";
        try {
 
            redissonLock = redisson.getLock("lockKey");//加鎖
            redissonLock.tryLock(30, TimeUnit.SECONDS);//超時時間:每間隔10秒(1/3)
            num = stringRedisTemplate.opsForValue().get(teacherName);
            int n = Integer.parseInt(num);

            if (n > 0) {
 
                n = n - 1;
                stringRedisTemplate.opsForValue().set("lkz", n + "");
                //正常選擇老師
                System.out.println("當前名額:" + n);
            } else {
 
                return "名額已滿";
            }
        } catch (InterruptedException e) {
 
            e.printStackTrace();
        } finally {
 
            redissonLock.unlock();//釋放鎖
        }
        return num;
    }
    // @PostMapping("/checkTeacher")
    // public String checkteacher(String teacherName) {
 
    //     InterProcessMutex lock = new InterProcessMutex(client, ZK_LOCK_PATH);
    //     String num = "";
    //     try {
 
    //         if (lock.acquire(6000, TimeUnit.SECONDS)) {
 
    //             // System.out.println("拿到了鎖");
    //             //業務邏輯
    //             num = stringRedisTemplate.opsForValue().get(teacherName);
    //             int n = Integer.parseInt(num);
    //             if (n > 0) {
 
    //                 n = n - 1;
    //                 stringRedisTemplate.opsForValue().set("lkz", n + "");
    //                 //正常選擇老師
    //                 System.out.println("當前名額:" + n);
    //             } else {
 
    //                 return "名額已滿";
    //             }
    //             // System.out.println("任務完畢,該釋放鎖了");
    //         }
    //     } catch (Exception e) {
 
    //         System.out.println("業務異常");
    //         e.printStackTrace();
    //     }finally {
 
    //         try {
 
    //             lock.release();
    //         } catch (Exception e) {
 
    //             System.out.println("釋放鎖異常");
    //             e.printStackTrace();
    //         }
    //     }
    //     return num;
    // }
}
  • redis需要有對應的key
set lkz 6

Redission和Zookeeper分別實現分散式鎖 - 天天要聞

1.3 啟動項目

  • 第一步:啟動redis,並且給lkz賦值
  • 第二步:啟動nginx,nginx需要做配置,指向本地的8000和9000埠
upstream testdev{
            server   127.0.0.1:8000 weight=1;
            server   127.0.0.1:9000 weight=1;
   }

    server {
        listen       80;
        server_name  localhost;

        #charset koi8-r;

        #access_log  logs/host.access.log  main;

        location / {
            root   html;
            index  index.html index.htm;
            proxy_pass http://testdev;
            proxy_redirect default;
        }
  • 第三步:idea中啟動8000埠,並且再修改配置文件埠,再啟動9000埠

Redission和Zookeeper分別實現分散式鎖 - 天天要聞

點擊這個,然後修改9000即可同時啟動8000和9000埠

  • 第三步:啟動Jmeter,發請求

Redission和Zookeeper分別實現分散式鎖 - 天天要聞

Redission和Zookeeper分別實現分散式鎖 - 天天要聞

1.4 結果

Redission的結果自行查看,博主偷懶了在下面的zookeeper實現分散式鎖的結果才截圖了。

2、Zookeeper實現分散式鎖

2.1 前提準備

  • 下載好nginx(windows版本)
  • 下載好Jmeter(模仿高並發)
  • 下載好redis(windows版)
  • 下載好zookeeper(windows版本)和ZooInspector(可視化工具,也可以不下載)

2.2 代碼

  • pom文件
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.7.2</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <groupId>cn.lanqiao</groupId>
    <artifactId>arcdemo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>arcdemo</name>
    <description>arcdemo</description>


    <properties>
        <java.version>8</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.session</groupId>
            <artifactId>spring-session-data-redis</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!-- redisson -->
        <dependency>
            <groupId>org.redisson</groupId>
            <artifactId>redisson-spring-boot-starter</artifactId>
            <version>3.17.5</version>
        </dependency>
    <!--    zookeeper和curator-->
        <dependency>
            <groupId>org.apache.zookeeper</groupId>
            <artifactId>zookeeper</artifactId>
            <version>3.5.7</version>
        </dependency>
        <dependency>
            <groupId>org.apache.curator</groupId>
            <artifactId>curator-framework</artifactId>
            <version>4.3.0</version>
        </dependency>
        <dependency>
            <groupId>org.apache.curator</groupId>
            <artifactId>curator-recipes</artifactId>
            <version>4.3.0</version>
        </dependency>
        <dependency>
            <groupId>org.apache.curator</groupId>
            <artifactId>curator-client</artifactId>
            <version>4.3.0</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>
  • controller
package com.example.controller;

import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.recipes.locks.InterProcessMutex;
import org.apache.curator.retry.RetryNTimes;
import org.redisson.Redisson;
import org.redisson.api.RLock;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.HttpRequest;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.util.concurrent.TimeUnit;

/**
 * @Author Devere19
 * @Date 2022/8/17 10:41
 * @Version 1.0
 */
@RestController
public class BiSheController {
 

    private static final String ZK_ADDRESS = "127.0.0.1:2181";

    private static final String ZK_LOCK_PATH = "/zkLock";

    static CuratorFramework client = null;

    static {
 
        //連接zk
        client = CuratorFrameworkFactory.newClient(ZK_ADDRESS,
                new RetryNTimes(10, 5000));
        client.start();
    }

    // 分散式鎖
    // @Autowired
    // private Redisson redisson;

    @Resource
    private StringRedisTemplate stringRedisTemplate;


    @GetMapping("/login")
    public String login(String username, HttpSession session, HttpServletRequest request) {
 
        session.setAttribute("username", username);
        return username + ",埠" + request.getLocalPort();
    }

    @GetMapping("/getUser")
    public String getUser(HttpSession session, HttpServletRequest request) {
 
        String username = (String) session.getAttribute("username");
        return session.getId() + "," + username + ",埠" + request.getLocalPort();
    }

    // @PostMapping("/checkTeacher")
    // public String checkteacher(String teacherName) {
 
    //     // SpringBoot操作Redis
    //     String lockKey = "lockKey";
    //     RLock redissonLock = null;
    //     String num = "";
    //     try {
 
    //         redissonLock = redisson.getLock("lockKey");//加鎖
    //         redissonLock.tryLock(30, TimeUnit.SECONDS);//超時時間:每間隔10秒(1/3)
    //         num = stringRedisTemplate.opsForValue().get(teacherName);
    //         int n = Integer.parseInt(num);
    //
    //         if (n > 0) {
 
    //             n = n - 1;
    //             stringRedisTemplate.opsForValue().set("lkz", n + "");
    //             //正常選擇老師
    //             System.out.println("當前名額:" + n);
    //         } else {
 
    //             return "名額已滿";
    //         }
    //     } catch (InterruptedException e) {
 
    //         e.printStackTrace();
    //     } finally {
 
    //         redissonLock.unlock();//釋放鎖
    //     }
    //     return num;
    // }
    @PostMapping("/checkTeacher")
    public String checkteacher(String teacherName) {
 
        InterProcessMutex lock = new InterProcessMutex(client, ZK_LOCK_PATH);
        String num = "";
        try {
 
            if (lock.acquire(6000, TimeUnit.SECONDS)) {
 
                // System.out.println("拿到了鎖");
                //業務邏輯
                num = stringRedisTemplate.opsForValue().get(teacherName);
                int n = Integer.parseInt(num);
                if (n > 0) {
 
                    n = n - 1;
                    stringRedisTemplate.opsForValue().set("lkz", n + "");
                    //正常選擇老師
                    System.out.println("當前名額:" + n);
                } else {
 
                    return "名額已滿";
                }
                // System.out.println("任務完畢,該釋放鎖了");
            }
        } catch (Exception e) {
 
            System.out.println("業務異常");
            e.printStackTrace();
        }finally {
 
            try {
 
                lock.release();
            } catch (Exception e) {
 
                System.out.println("釋放鎖異常");
                e.printStackTrace();
            }
        }
        return num;
    }
}

2.3 啟動項目

  • 第一步:啟動redis,並且給lkz賦值
  • 第二步:啟動nginx,nginx需要做配置,指向本地的8000和9000埠
upstream testdev{
            server   127.0.0.1:8000 weight=1;
            server   127.0.0.1:9000 weight=1;
   }

    server {
        listen       80;
        server_name  localhost;

        #charset koi8-r;

        #access_log  logs/host.access.log  main;

        location / {
            root   html;
            index  index.html index.htm;
            proxy_pass http://testdev;
            proxy_redirect default;
        }
  • 第三步:idea中啟動8000埠,並且再修改配置文件埠,再啟動9000埠

Redission和Zookeeper分別實現分散式鎖 - 天天要聞

點擊這個,然後修改9000即可同時啟動8000和9000埠

  • 第三步:啟動zookeeper,並且啟動ZooInspector可視化工具
  • 第四步:啟動Jmeter,發請求

Redission和Zookeeper分別實現分散式鎖 - 天天要聞

Redission和Zookeeper分別實現分散式鎖 - 天天要聞

2.4 結果

Redission和Zookeeper分別實現分散式鎖 - 天天要聞

Redission和Zookeeper分別實現分散式鎖 - 天天要聞

看到控制台的輸出,可以看出來分散式鎖起作用了,並且可以觀看ZooInspector進行查看

Redission和Zookeeper分別實現分散式鎖 - 天天要聞

因為這裡採用的是有序臨時鎖,所以請求發完之後就刪除了鎖。必須在發起請求的一瞬間去刷新,才可能看到排好序的鎖。

3、 案例源碼地址

https://github.com/Guoleyuan/arcdemo

科技分類資訊推薦

清華專家破百年陳規!滬上論壇曝電力革新,陳磊構想太敢了 - 天天要聞

清華專家破百年陳規!滬上論壇曝電力革新,陳磊構想太敢了

聽說了嗎?清華大學的專家居然說要徹底打破電力系統運行了上百年的規矩!就在上海那場新能源論壇上,陳磊研究員拋出個重磅觀點 —— 以後用電不用再看頻率臉色,有功功率想咋調就咋調!這事兒要是真能成,咱們家裡的空調、電動車充電可就再也不會因為電網不
消費活力釋放,上海零售商業形態向「文商旅體展」融合演進 - 天天要聞

消費活力釋放,上海零售商業形態向「文商旅體展」融合演進

2025年二季度,在上海市政府經濟刺激方案推動下,上海商業市場消費活力逐步釋放,但零售物業租賃指標的復甦態勢仍顯平緩。核心商圈平均租金為1877元/平方米/月,平均出租率為94.71%,整體表現與去年同期持平,其中徐家匯、陸家嘴等商圈憑藉成熟商業生態,表現相對突出。但與非核心商圈相比,從存量、新增供應、凈吸納量等指...
OPPO K13 Turbo 系列真機曝光,7 月 21 日發布 - 天天要聞

OPPO K13 Turbo 系列真機曝光,7 月 21 日發布

IT之家 7 月 11 日消息,博主 @i冰宇宙 今日分享了一款帶保密殼的新機真機圖,配備 RGB 燈效以及主動散熱風扇,預計為剛剛官宣的 OPPO K13 Turbo 系列。IT之家注意到,OPPO K13 Turbo 系列將於 7 月 21 日發布,在 GeekBench 6.3.0 中單核成績為 2156 分,多核成績為 6652 分,預計搭載高通驍龍
醒醒吧!CEO猛吹AI寫95%代碼,績效考核卻還在拼程序員手速? - 天天要聞

醒醒吧!CEO猛吹AI寫95%代碼,績效考核卻還在拼程序員手速?

編譯 | Tina在 AI 工具席捲開發圈之後,一批技術老兵的工作方式悄然發生變化。Superhuman (原生 AI 郵件應用)工程負責人 Loic Houssier 正是這場轉型的親歷者之一。這位出身數學背景、擁有密碼學工程經驗的 VP,曾帶領團隊經歷了從大型 B2C 到核心底層架構的複雜挑戰。而當 ChatGPT、Claude Code 等工具走進日常
從領先到落後:英特爾正經歷「寒冬」 - 天天要聞

從領先到落後:英特爾正經歷「寒冬」

【環球網科技綜合報道】7月11日,據外媒報道,英特爾首席執行官陳立武近日在發表內部講話時直言英特爾已不再是領先晶元製造商,甚至不在前十。其市值如今僅約1000億美元,與18個月前相比大幅縮水,而英偉達市值卻一度突破4萬億美元,形成鮮明對比。「二三十年前,我們確實是行業領導者。可如今的世界已經變了,我們已不在全...