成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

SpringBoot與Curator整合,實現票務預訂系統

開發
Curator Recipes 是 Curator 提供的一組高級功能模塊,其中包括了實現分布式鎖所需的工具。特別是InterProcessMutex類,它是基于 ZooKeeper 實現的一個可重入的分布式互斥鎖。

在票務預訂系統中,多個服務實例需要競爭性地處理票務預訂請求,以確保每個座位只被預訂一次。為了滿足這個基本的要求,我們決定使用 Apache Curator 實現一個分布式鎖來控制對票務資源的訪問。

一、我們為什么選擇Curator?

1. 簡化ZooKeeper的使用

Apache Curator 是一個高級的 Java 客戶端庫,專門用于簡化對 ZooKeeper 的操作。它提供了許多實用的功能和抽象,使得我們更容易地與 ZooKeeper 進行交互,而無需處理底層的復雜細節。

  • 自動重試機制:Curator 提供了多種重試策略(如指數退避),確保在連接中斷時能夠自動重試。
  • 路徑管理:Curator 自動處理節點的創建、刪除等操作,簡化了路徑管理的工作。
  • 事件監聽:Curator 提供了更簡潔的事件監聽接口,方便處理各種 ZooKeeper 事件。

2. 強大的分布式鎖實現

Curator Recipes 是 Curator 提供的一組高級功能模塊,其中包括了實現分布式鎖所需的工具。特別是InterProcessMutex類,它是基于 ZooKeeper 實現的一個可重入的分布式互斥鎖。

  • 可重入性:InterProcessMutex 支持線程級別的可重入性,確保同一個線程多次獲取鎖不會導致死鎖。
  • 公平性:InterProcessMutex 默認是公平鎖,確保按照請求順序依次獲取鎖。
  • 靈活性:可以通過配置不同的參數來滿足不同的需求,例如超時時間、重試次數等。

二、哪些公司使用了Curator?

  • 歐洲核子研究組織(CERN)使用 Curator 來管理其高性能計算環境中的協調任務。
  • Uber 使用 Curator 來實現其微服務架構中的服務發現和協調。
  • Twitter 使用 Curator 來管理其微服務架構中的配置和服務協調。
  • eBay 使用 Curator 來管理其分布式系統的配置和服務協調。
  • LinkedIn 使用 Curator 來實現集群管理和協調任務調度。
  • Airbnb 使用 Curator 來處理其基礎設施中的各種協調任務。
  • Yahoo! 使用 Curator 來管理其大規模分布式系統的配置和服務發現。
  • Facebook 使用 Curator 來管理其分布式系統的配置和服務協調。

三、代碼實操

<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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.example</groupId>
    <artifactId>ticket-booking-system</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>Ticket Booking System</name>
    <description>A simple example of using Apache Curator for distributed locking in a Spring Boot application</description>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.7.5</version>
        <relativePath/><!-- lookup parent from repository -->
    </parent>

    <properties>
        <java.version>11</java.version>
        <curator.version>5.3.0</curator.version>
    </properties>

    <dependencies>
        <!-- Spring Boot Starter Web -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!-- Apache Curator Framework -->
        <dependency>
            <groupId>org.apache.curator</groupId>
            <artifactId>curator-framework</artifactId>
            <version>${curator.version}</version>
        </dependency>

        <!-- Apache Curator Recipes (for InterProcessMutex) -->
        <dependency>
            <groupId>org.apache.curator</groupId>
            <artifactId>curator-recipes</artifactId>
            <version>${curator.version}</version>
        </dependency>

        <!-- SLF4J Logging -->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
        </dependency>

        <!-- Test Dependencies -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

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

四、application.properties

zookeeper.connect-string=localhost:2181
server.port=8080
initial.tickets=100

五、配置 Curator 客戶端

package com.example.ticketbooking.config;

import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class CuratorConfig {

    @Value("${zookeeper.connect-string}")
    private String zookeeperConnectString;

    /**
     * 配置并返回一個 CuratorFramework 實例,用于連接 ZooKeeper。
     * 使用指數退避重試策略(ExponentialBackoffRetry)來處理連接失敗的情況。
     *
     * @return 初始化并啟動的 CuratorFramework 實例
     */
    @Bean(initMethod = "start", destroyMethod = "close")
    public CuratorFramework curatorFramework() {
        return CuratorFrameworkFactory.newClient(zookeeperConnectString,
                new ExponentialBackoffRetry(1000, 3));
    }
}

六、Service

package com.example.ticketbooking.service;

import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.recipes.locks.InterProcessMutex;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.TimeUnit;

@Service
public class BookingService {

    private static final Logger logger = LoggerFactory.getLogger(BookingService.class);

    @Autowired
    private CuratorFramework client;

    @Value("${initial.tickets}")
    private int initialTickets;

    private static final String TICKETS_PATH = "/tickets";

    /**
     * 在服務啟動時初始化票數。
     * 如果 ZooKeeper 中不存在 /tickets 節點,則創建該節點并設置初始票數。
     *
     * @throws Exception 如果操作過程中發生異常
     */
    @PostConstruct
    public void initializeTickets() throws Exception {
        if (client.checkExists().forPath(TICKETS_PATH) == null) {
            client.create().creatingParentsIfNeeded()
                    .forPath(TICKETS_PATH, String.valueOf(initialTickets).getBytes(StandardCharsets.UTF_8));
        }
    }

    /**
     * 獲取當前可用的票數。
     *
     * @return 當前可用的票數
     * @throws Exception 如果操作過程中發生異常
     */
    public synchronized int getCurrentTickets() throws Exception {
        byte[] data = client.getData().forPath(TICKETS_PATH);
        return Integer.parseInt(new String(data, StandardCharsets.UTF_8));
    }

    /**
     * 嘗試預訂指定數量的票。
     * 使用分布式鎖確保同一時間只有一個實例能夠更新票數。
     *
     * @param quantity 需要預訂的票數
     * @return 如果預訂成功則返回 true,否則返回 false
     * @throws Exception 如果操作過程中發生異常
     */
    public boolean bookTicket(int quantity) throws Exception {
        InterProcessMutex lock = new InterProcessMutex(client, "/locks/ticket-booking");

        try {
            // 嘗試在 10 秒內獲取鎖
            if (lock.acquire(10, TimeUnit.SECONDS)) {
                try {
                    int currentTickets = getCurrentTickets();
                    if (currentTickets >= quantity) {
                        int newTickets = currentTickets - quantity;
                        client.setData().forPath(TICKETS_PATH, String.valueOf(newTickets).getBytes(StandardCharsets.UTF_8));
                        logger.info("Booked {} tickets. Remaining: {}", quantity, newTickets);
                        returntrue;
                    } else {
                        logger.warn("Insufficient tickets. Current: {}, Requested: {}", currentTickets, quantity);
                        returnfalse;
                    }
                } finally {
                    // 確保釋放鎖
                    lock.release();
                }
            } else {
                logger.warn("Failed to acquire lock for booking tickets.");
                returnfalse;
            }
        } catch (Exception e) {
            logger.error("Error booking tickets", e);
            throw e;
        }
    }
}

七、Controller

package com.example.ticketbooking.controller;

import com.example.ticketbooking.service.BookingService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class BookingController {

    private static final Logger logger = LoggerFactory.getLogger(BookingController.class);

    @Autowired
    private BookingService bookingService;

    /**
     * 獲取當前可用的票數。
     *
     * @return 當前可用的票數
     */
    @GetMapping("/get-tickets")
    public String getTickets() {
        try {
            int currentTickets = bookingService.getCurrentTickets();
            return"Current Tickets Available: " + currentTickets;
        } catch (Exception e) {
            logger.error("Error getting ticket count", e);
            return"An error occurred while getting ticket count";
        }
    }

    /**
     * 處理預訂票務的請求。
     * 使用分布式鎖確保同一時間只有一個實例能夠處理預訂請求。
     *
     * @param quantity 需要預訂的票數
     * @return 預訂結果
     */
    @GetMapping("/book-ticket")
    public String bookTicket(@RequestParam int quantity) {
        try {
            boolean success = bookingService.bookTicket(quantity);
            if (success) {
                return"Successfully booked " + quantity + " tickets";
            } else {
                return"Failed to book " + quantity + " tickets";
            }
        } catch (Exception e) {
            logger.error("Error booking tickets", e);
            return"An error occurred while booking tickets";
        }
    }
}

八、Application

package com.example.ticketbooking;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class TicketBookingApplication {

    public static void main(String[] args) {
        SpringApplication.run(TicketBookingApplication.class, args);
    }
}

九、測試

確保 ZooKeeper 服務器正在運行。

1. 終端 1

(1) 獲取當前票數:

curl http://localhost:8080/get-tickets

Respons:

Current Tickets Available: 100

(2) 預訂 10 張票:

curl http://localhost:8080/book-ticket?quantity=10

Respons:

Successfully booked 10 tickets

(3) 再次獲取當前票數:

curl http://localhost:8080/get-tickets

Respons:

Current Tickets Available: 90

2. 終端 2

(1) 在 Terminal 1 正在處理預訂請求的同時,在 Terminal 2 中嘗試預訂 10 張票:

curl http://localhost:8080/book-ticket?quantity=10

Respons:

Successfully booked 10 tickets

(2) 再次獲取當前票數:

curl http://localhost:8080/get-tickets

Respons:

Current Tickets Available: 80

3. 嘗試預訂超過剩余票數

(1) 嘗試預訂超過剩余票數的情況:

curl http://localhost:8080/book-ticket?quantity=100

Respons:

Failed to book 100 tickets

(2) 再次獲取當前票數:

curl http://localhost:8080/get-tickets

Respons:

Current Tickets Available: 80

責任編輯:趙寧寧 來源: Java知識日歷
相關推薦

2025-02-28 08:40:28

ZooKeeperSpringBoot計費系統

2025-04-08 08:50:37

SpringCamel系統

2025-05-09 08:34:57

RSocketSpringBoot聊天系統

2025-03-31 08:43:34

SpringTika優化

2025-03-03 07:30:00

SpringBootJGraphT網絡建模

2025-05-06 08:40:21

SpringPostGIS系統

2025-06-03 02:10:00

SpringInfluxDB數據

2025-03-11 09:28:34

2025-04-21 03:00:00

2025-02-26 09:24:54

SpringMySQLMyBatis

2025-03-26 01:55:00

Spring協議物聯網

2025-03-20 08:57:54

Spring日志存儲系統

2025-04-25 08:34:52

2025-04-01 08:38:41

2025-05-16 08:55:58

2025-04-14 01:00:00

Calcite電商系統MySQL

2025-03-21 08:55:36

SpringOpenFeignAPI

2025-04-18 08:54:30

2020-04-23 15:08:41

SpringBootMyCatJava

2025-05-23 08:37:26

點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 一区二区中文字幕 | 精品国产一区二区三区久久 | 91精品国产综合久久久久久蜜臀 | 久久99精品久久久久久 | 中文字幕一区二区三区乱码图片 | 日韩精品1区2区3区 国产精品国产成人国产三级 | 亚洲精品中文字幕av | 久久大全 | 日韩成人| 一区二区三区国产好 | 日韩欧美黄色 | 欧美久久久久 | 一级片av | 午夜视频一区二区三区 | 最新国产精品 | 精品国产18久久久久久二百 | 亚洲成人免费在线 | 国产在线视频在线观看 | 国产高清精品一区二区三区 | 中文字幕欧美一区 | 国产精品无码久久久久 | 国内久久 | 一级毛片网 | 久草网站 | 99精品国产一区二区青青牛奶 | 精品日韩一区 | 色欧美片视频在线观看 | 精品国产欧美一区二区 | 成人自拍视频网站 | 免费黄色录像视频 | 欧美日韩国产精品一区 | 全部免费毛片在线播放网站 | 91视视频在线观看入口直接观看 | 久在线| 国产精品a久久久久 | 特黄毛片视频 | 久久99精品久久久久久 | 盗摄精品av一区二区三区 | 久久一视频| 欧美激情精品久久久久久变态 | 国产黄色在线观看 |