SpringBoot与BookKeeper整合,实现金融级别的日志存储系统

BookKeeper的优势

高吞吐量和低延迟

  • 分布式架构: Apache BookKeeper采用分布式的架构设计,能够支持高并发的写入和读取操作。

  • 批量写入: 支持批量写入日志条目,显著提高写入效率。

  • 异步I/O: 使用异步I/O操作,减少等待时间,提升整体性能。

数据一致性和持久性

  • 强一致性保证: BookKeeper提供强一致性保证,确保所有写入的数据都能被正确读取。

  • 多副本复制: 数据在多个Bookies(BookKeeper节点)上进行多副本复制,防止单点故障导致的数据丢失。

  • 自动恢复: 在节点故障时,BookKeeper能够自动检测并恢复数据,确保系统的连续运行。

水平扩展能力

  • 动态扩展: 可以通过增加Bookies来扩展集群规模,适应不断增长的业务需求。

  • 负载均衡: 自动分配负载,确保各节点之间的工作负载平衡,避免热点问题。

  • 灵活性: 支持多种部署方式,包括本地部署、云部署等。

数据加密和访问控制

  • 数据加密: 支持对存储的日志数据进行加密处理,防止未授权访问。

  • 认证和授权: 提供细粒度的权限管理机制,限制不同角色的访问权限。

  • 审计日志: 记录所有对系统的访问和操作,便于追踪和审计。

记得启动ZooKeeper服务器

因为BookKeeper依赖于ZooKeeper来进行元数据管理和协调!!!

代码实操

<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.5</version><relativePath/><!-- lookup parent from repository --></parent><groupId>com.example</groupId><artifactId>bookkeeper-springboot-example</artifactId><version>0.0.1-SNAPSHOT</version><name>bookkeeper-springboot-example</name><description>Demo project for Spring Boot and Apache BookKeeper integration</description><properties><java.version>11</java.version></properties><dependencies><!-- Spring Boot Starter Web --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- Apache BookKeeper Client --><dependency><groupId>org.apache.bookkeeper</groupId><artifactId>bookkeeper-server</artifactId><version>4.18.0</version></dependency><!-- Jackson Databind for JSON processing --><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId></dependency><!-- Lombok for reducing boilerplate code --><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></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 连接字符串
bookkeeper.zk.connectString=localhost:2181
server.port=8080

配置类

package com.example.bookkeeperspringbootexample.config;import org.apache.bookkeeper.client.BookKeeper;
import org.apache.bookkeeper.client.LedgerHandle;
import org.apache.bookkeeper.conf.ClientConfiguration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;import javax.annotation.PreDestroy;
import java.io.IOException;@Configuration
publicclass BookKeeperConfig {privatestaticfinal Logger logger = LoggerFactory.getLogger(BookKeeperConfig.class);@Value("${bookkeeper.zk.connectString}")private String zkConnectString;private BookKeeper bookKeeper;private LedgerHandle ledgerHandle;/*** 初始化BookKeeper客户端** @return BookKeeper实例* @throws IOException 如果初始化失败*/@Beanpublic BookKeeper bookKeeper() throws IOException {ClientConfiguration conf = new ClientConfiguration();conf.setZkServers(zkConnectString);bookKeeper = new BookKeeper(conf);logger.info("BookKeeper客户端已初始化。");return bookKeeper;}/*** 创建一个新的Ledger** @param bookKeeper BookKeeper实例* @return LedgerHandle实例* @throws Exception 如果创建Ledger失败*/@Beanpublic LedgerHandle ledgerHandle(BookKeeper bookKeeper) throws Exception {ledgerHandle = bookKeeper.createLedger(BookKeeper.DigestType.CRC32,"password".getBytes());logger.info("Ledger已创建,ID: {}", ledgerHandle.getId());return ledgerHandle;}/*** 关闭BookKeeper客户端和Ledger*/@PreDestroypublic void shutdown() throws InterruptedException, BookKeeper.BKException {if (ledgerHandle != null) {ledgerHandle.close();logger.info("Ledger已关闭。");}if (bookKeeper != null) {bookKeeper.close();logger.info("BookKeeper客户端已关闭。");}}}

交易的数据模型

package com.example.bookkeeperspringbootexample.model;import lombok.Data;import java.time.LocalDateTime;/*** 表示交易的数据模型*/
@Data
public class Transaction {private Long transactionId; // 交易IDprivate Double amount;      // 交易金额private LocalDateTime timestamp; // 时间戳
}

服务类

package com.example.bookkeeperspringbootexample.service;import com.example.bookkeeperspringbootexample.model.Transaction;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.bookkeeper.client.BKException;
import org.apache.bookkeeper.client.LedgerHandle;
import org.apache.bookkeeper.proto.BookieProtocol;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import java.io.IOException;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;@Service
publicclass BookKeeperService {privatestaticfinal Logger logger = LoggerFactory.getLogger(BookKeeperService.class);@Autowiredprivate LedgerHandle ledgerHandle;@Autowiredprivate ObjectMapper objectMapper;/*** 异步添加交易到BookKeeper** @param transaction 交易对象* @return CompletableFuture<Long> 包含新条目的entryId*/public CompletableFuture<Long> addTransaction(Transaction transaction) {try {byte[] logData = objectMapper.writeValueAsBytes(transaction); // 将交易对象转换为字节数组return CompletableFuture.supplyAsync(() -> {try {long entryId = ledgerHandle.addEntry(logData); // 将字节数组添加到Ledgerlogger.info("已添加交易,entryId: {}", entryId);return entryId;} catch (BKException | InterruptedException e) {thrownew RuntimeException(e);}});} catch (IOException e) {thrownew RuntimeException(e);}}/*** 异步从BookKeeper读取交易** @param entryId 条目ID* @return CompletableFuture<Transaction> 包含读取的交易对象*/public CompletableFuture<Transaction> readTransaction(long entryId) {return CompletableFuture.supplyAsync(() -> {try {LedgerSequence seq = ledgerHandle.readEntries(entryId, entryId); // 读取指定entryId的条目if (seq.hasMoreElements()) {LedgerEntry entry = seq.nextElement(); // 获取条目byte[] data = entry.getEntryBytes(); // 获取条目的字节数组logger.info("已读取交易,entryId: {}", entryId);return objectMapper.readValue(data, Transaction.class); // 将字节数组转换为交易对象}thrownew IllegalArgumentException("未找到ID为 " + entryId + " 的交易");} catch (BKException | InterruptedException | ExecutionException | IOException e) {thrownew RuntimeException(e);}});}}

Controller

package com.example.bookkeeperspringbootexample.controller;import com.example.bookkeeperspringbootexample.model.Transaction;
import com.example.bookkeeperspringbootexample.service.BookKeeperService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;import java.util.concurrent.CompletableFuture;@RestController
@RequestMapping("/transactions")
publicclass TransactionController {@Autowiredprivate BookKeeperService bookKeeperService;/*** 添加新的交易** @param transaction 交易对象* @return ResponseEntity<Long> 包含新条目的entryId*/@PostMapping("/")public ResponseEntity<Long> addTransaction(@RequestBody Transaction transaction) {CompletableFuture<Long> futureEntryId = bookKeeperService.addTransaction(transaction); // 异步添加交易try {Long entryId = futureEntryId.get(); // 获取结果return ResponseEntity.ok(entryId); // 返回成功的HTTP响应} catch (InterruptedException | ExecutionException e) {Thread.currentThread().interrupt(); // 中断线程return ResponseEntity.internalServerError().build(); // 返回内部服务器错误}}/*** 根据entryId读取交易** @param entryId 条目ID* @return ResponseEntity<Transaction> 包含读取的交易对象*/@GetMapping("/{entryId}")public ResponseEntity<Transaction> getTransaction(@PathVariable long entryId) {CompletableFuture<Transaction> futureTransaction = bookKeeperService.readTransaction(entryId); // 异步读取交易try {Transaction transaction = futureTransaction.get(); // 获取结果return ResponseEntity.ok(transaction); // 返回成功的HTTP响应} catch (InterruptedException | ExecutionException e) {Thread.currentThread().interrupt(); // 中断线程return ResponseEntity.notFound().build(); // 返回未找到资源}}}

Application

package com.example.bookkeeperspringbootexample;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication
public class BookKeeperSpringBootExampleApplication {public static void main(String[] args) {SpringApplication.run(BookKeeperSpringBootExampleApplication.class, args);}}

测试

添加交易

curl -X POST http://localhost:8080/transactions/ \
-H "Content-Type: application/json" \
-d '{"transactionId": 1, "amount": 100.50, "timestamp": "2025-03-19T21:36:06"}'

Respons:

1

读取交易

curl -X GET http://localhost:8080/transactions/1

Respons:

{"transactionId":1,"amount":100.5,"timestamp":"2025-03-19T21:36:06"}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/78523.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Bug】 [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed

当你在进行深度学习相关操作时&#xff0c;若因缺少本地的 CA 证书而无法下载资源&#xff0c;下面为你介绍几种解决办法&#xff1a; 方法一&#xff1a;更新 CA 证书 在大多数 Linux 发行版中&#xff0c;你可以使用包管理器来更新 CA 证书。例如&#xff0c;在基于 Debian…

Vue3中AbortController取消请求的用法详解

在 Vue3 中&#xff0c;AbortController 用于取消 fetch 请求&#xff0c;避免组件卸载后仍执行异步操作导致的潜在问题&#xff08;如内存泄漏或更新已销毁组件的状态&#xff09;。以下是详细用法和最佳实践&#xff1a; 一、基本用法 创建 AbortController 实例 在组件 setu…

【刷题Day26】Linux命令、分段分页和中断(浅)

说下你常用的 Linux 命令&#xff1f; 文件与目录操作&#xff1a; ls&#xff1a;列出当前目录的文件和子目录&#xff0c;常用参数如-l&#xff08;详细信息&#xff09;、-a&#xff08;包括隐藏文件&#xff09;cd&#xff1a;切换目录&#xff0c;用于在文件系统中导航m…

Spring Boot 参考文档导航手册

&#x1f4da; Spring Boot 参考文档导航手册 &#x1f5fa;️ ✨ 新手入门 &#x1f476; 1️⃣ &#x1f4d6; 基础入门&#xff1a;概述文档 | 环境要求 | 安装指南 2️⃣ &#x1f527; 实操教程&#xff1a;上篇 | 下篇 3️⃣ &#x1f680; 示例运行&#xff1a;基础篇 …

卷积神经网络(CNN)详细教程

卷积神经网络&#xff08;CNN&#xff09;详细教程 一、引言 卷积神经网络&#xff08;Convolutional Neural Networks, CNN&#xff09;是一种深度学习模型&#xff0c;广泛应用于图像识别、视频分析、自然语言处理等领域。CNN通过模拟人类视觉系统的层次结构&#xff0c;能够…

解决SSLError: [SSL: DECRYPTION_FAILED_OR_BAD_RECORD_MAC] decryption faile的问题

问题描述&#xff1a; 在pip安装第三方库时&#xff0c;出现SSL的问题。 传输层安全性协议&#xff08;TLS&#xff09;及其前身安全套接层&#xff08;SSL&#xff09;是现在的 HTTPS 协议中的一种安全协议&#xff0c;目的是为互联网通信提供安全及数据完整性保障。而较新版…

SpringBoot程序的创建以及特点,配置文件,LogBack记录日志,配置过滤器、拦截器、全局异常

目录 一、创建一个SpringBoot程序 二、SpringBoot的特点 ①主要特点 ②其他特点 ③热部署 启动热部署 关闭热部署 三、SpringBoot的配置文件 ①SpringBoot三种配置文件的格式&#xff08;以设置端口号为例&#xff09;&#xff1a; ②配置文件的优先级 ③常见配置项 1…

i18n-ai-translate开源程序,可以使用DeepSeek等模型将您的 i18nJSON翻译成任何语言

一、软件介绍 文末提供程序和源码下载 i18n-ai-translate开源程序使用 DeepSeek等模型可以将您的 i18n JSON 翻译成任何语言。 无缝翻译本地化文件。支持嵌套翻译文件的目录。需要i18next样式的JSON 文件&#xff08;文末一并提供下载&#xff09;。 二、模式 CSV 模式 三个…

Flask + ajax上传文件(一)--单文件上传

一、概述 本教程将教你如何使用Flask后端和AJAX前端实现文件上传功能,包含完整的代码实现和详细解释。 二、环境准备 1. 所需工具和库 Python 3.xFlask框架jQuery库Bootstrap(可选,用于美化界面)2. 安装Flask pip install flask三、项目结构 upload_project/ ├── a…

如何在 Postman 中,自动获取 Token 并将其赋值到环境变量

在 Postman 中&#xff0c;你可以通过 预请求脚本&#xff08;Pre-request Script&#xff09; 和 测试脚本&#xff08;Tests&#xff09; 实现自动获取 Token 并将其赋值到环境变量&#xff0c;下面是完整的操作步骤&#xff1a; ✅ 一、创建获取 Token 的请求 通常这个请求…

北斗导航 | 基于Transformer+LSTM+激光雷达的接收机自主完好性监测算法研究

基于Transformer+LSTM+激光雷达的接收机自主完好性监测算法研究 接收机自主完好性监测(RAIM)是保障全球导航卫星系统(GNSS)定位可靠性的核心技术。传统RAIM算法依赖最小二乘残差法,存在故障漏检、对复杂环境适应性差等问题。结合Transformer、LSTM与激光雷达的多模态融合…

基于Python爬虫的豆瓣电影信息爬取(可以根据选择电影编号得到需要的电影信息)

# 豆瓣电影信息爬虫(展示效果如下图所示:) 这是一个功能强大的豆瓣电影信息爬虫程序,可以获取豆瓣电影 Top 250 的详细信息。 ## 功能特点 - 自动爬取豆瓣电影 Top 250 的所有电影信息 - 支持分页获取,每页 25 部电影,共 10 页 - 获取每部电影的详细信息,包括: - 标题…

Ubuntu22.04/24.04 P104-100 安装驱动和 CUDA Toolkit

硬件环境 使用一块技嘉 B85m-DS3H 安装 P104-100, CPU是带集成显卡的i5-4690. 先在BIOS中设置好显示设备优先使用集成显卡(IGX). 然后安装P104-100开机. 登入Ubuntu 后查看硬件信息, 检查P104-100是否已经被检测到 # PCI设备 lspci -v | grep -i nvidia lspci | grep NVIDIA …

东南亚与中东小游戏市场出海调研报告

东南亚与中东小游戏市场出海调研报告 目标市场筛选与概况 (The Gaming Market in Southeast Asia (SEA) | Allcorrect)图:2018–2027年东南亚主要国家游戏市场收入(亿美元)趋势。到2024年东南亚游戏市场规模预计将接近300亿美元 (2024年东南亚手游市场怎么样? - 快出海问…

力扣4-最长公共前缀

一.题目 编写一个函数来查找字符串数组中的最长公共前缀。 如果不存在公共前缀&#xff0c;返回空字符串 ""。 示例 1&#xff1a; 输入&#xff1a;strs ["flower","flow","flight"] 输出&#xff1a;"fl"示例 2&…

设计模式和单一原则笔记

单一原则&#xff1a;方法 对象 策略模式&#xff1a;方法实现 // 策略接口&#xff08;单一职责&#xff1a;定义计算规范&#xff09; public interface PriceStrategy {boolean match(String type); // 职责1&#xff1a;判断是否适用该策略double calculate(double pric…

常见正则表达式整理与Java使用正则表达式的例子

一、常见正则表达式整理 1. 基础验证类 邮箱地址 ^[a-zA-Z0-9._%-][a-zA-Z0-9.-]\\.[a-zA-Z]{2,}$ &#xff08;匹配如 userexample.com&#xff09;手机号 ^1[3-9]\\\\d{9}$ &#xff08;匹配国内11位手机号&#xff0c;如 13812345678&#xff09;中文字符 ^[\u4e00-\u9fa5…

vue2 项目的 vscode 插件整理

Folder Selector 当项目文件很多时&#xff0c;查找一个文件&#xff0c;可能需要在资源管理器中不断的滚动再打开文件夹查找文件&#xff0c;很麻烦&#xff0c;这个可以增加一个面板通过右键文件夹选择 然后在面板中查看文件 Reveal Button 文件中跳转到另一个文件时&#…

使用 Node、Express 和 MongoDB 构建一个项目工程

本文将详细介绍如何使用 Node.js Express MongoDB 构建一个完整的 RESTful API 后端项目&#xff0c;涵盖&#xff1a; 项目初始化 Express 服务器搭建 MongoDB 数据库连接 REST API 设计&#xff08;CRUD 操作&#xff09; 错误处理与中间件 源码结构与完整代码 部署建…

如何实现Spring Boot应用程序的安全性:全面指南

在现代 Web 开发中&#xff0c;安全性是 Spring Boot 应用程序的核心需求&#xff0c;尤其是在微服务、云原生和公开 API 场景中。Spring Boot 结合 Spring Security 提供了一套强大的工具&#xff0c;用于保护应用程序免受常见威胁&#xff0c;如未经授权的访问、数据泄露、跨…