当前位置: 首页 > news >正文

如何封装一个线程安全、可复用的 HBase 查询模板

目录

一、前言:原生 HBase 查询的痛点

(一)连接管理混乱,容易造成资源泄露

(二)查询逻辑重复,缺乏统一的模板

(三)多线程/高并发下的线程安全性隐患

(四)✍️ 总结一下

二、系统架构总览

(一)逻辑视图架构

1. BizService(业务服务层)

2. HBaseTemplate(查询执行模板)

3. HBaseConnectionFactory(连接管理器)

(二)✨ 架构设计亮点要求

三、核心实现一:基于 AtomicReference 的连接懒加载机制

(一)为什么选用 AtomicReference 持有连接?

(二)双重检查锁实现懒加载(DCL)

(三)自动重试机制,提高连接稳定性

(四)生命周期管理:@PreDestroy 优雅关闭连接

(五)HBase 配置参数统一集中管理

✅ 小结:这一层解决了什么问题?

四、核心实现二:函数式接口封装查询执行逻辑

(一)目标:让查询逻辑像“写 Lambda 一样”简单

(二)函数式接口设计:对标 Spring JdbcTemplate

(三)execute() 模板方法封装

(四)查询调用示例:像 Lambda 一样优雅

(五)支持更细粒度的扩展能力(如 Put/Delete)

五、完整案例演示:从查询封装到业务落地

(一)场景说明:根据手机号前缀模糊查找用户信息

(二)原始写法:重复 + 冗余 + 难维护

(三)优化后写法:基于模板封装

(四)支撑代码汇总(用于上下文完整性)

1. 用户实体类 UserInfo

2. HBaseTemplate 示例定义

六、异常处理与重试机制的策略设计

(一)异常类型与分类

(二)重试机制设计

(三)异常类型处理

可重试异常

不可重试异常

(四)结合重试与模板使用

七、性能优化与高可用设计:如何让查询模板更高效

(一)查询性能优化的基本原则

1. 减少不必要的 I/O 操作

2. 使用连接池减少连接创建和销毁开销

3. 异步操作与批量操作

(二)高可用性设计

1. 集群容错与负载均衡

2. 弹性扩展

3. 故障恢复与灾难恢复

(三)查询模板的优化

示例:使用缓存优化查询

(四)小结:如何提高查询模板的性能和可用性

八、总结与未来展望:从技术实现到业务落地

(一)设计总结:一个高效且健壮的 HBase 查询模板

(二)对业务的实际影响

(三)未来展望:进一步优化与发展方向

1. 高级查询优化

2. 更灵活的查询策略

3. 异常监控与自动化运维

4. 支持更多数据源和兼容性

(四)小结


干货分享,感谢您的阅读!

随着大数据时代的到来,企业在存储和处理数据时面临着越来越多的挑战。在这其中,HBase 作为一个高性能、可扩展的分布式列式数据库,在海量数据的存储和查询中发挥着重要作用。然而,尽管 HBase 具有极高的查询性能和可伸缩性,它的使用过程中依然存在一些痛点,特别是在高并发环境下,如何管理连接、优化查询、确保系统的高可用性,往往需要开发者进行额外的封装和优化。

传统的 HBase 查询方式存在诸多问题,例如连接管理复杂、查询逻辑重复、性能瓶颈等。这些问题不仅影响开发效率,还可能在业务高峰期间导致系统性能下降,甚至造成不可用的情况。因此,如何在 HBase 的基础上封装出一个既高效又易于扩展的查询模板,成为了许多企业工程师面临的实际问题。

本文将从一个高效、线程安全且可复用的 HBase 查询模板的设计与实现入手,深入探讨如何解决 HBase 查询中的常见问题,提升查询性能,并简化开发流程。通过基于 AtomicReference 的连接懒加载机制、函数式接口封装查询逻辑,以及完整的案例演示,本文将为开发者提供一个可复用的解决方案,帮助他们在复杂业务场景中高效地使用 HBase。

一、前言:原生 HBase 查询的痛点

在实际业务开发中,使用 HBase 进行数据查询时,我们往往会遇到一系列令人头疼的问题

(一)连接管理混乱,容易造成资源泄露

HBase 的连接是重量级资源,底层维护着 socket、线程池、region cache 等,如果没有统一管理,每次查询都创建新连接,很容易导致资源耗尽或者频繁报错:

Connection connection = ConnectionFactory.createConnection(config);
Table table = connection.getTable(TableName.valueOf("ns:my_table"));
Result result = table.get(new Get(Bytes.toBytes("rowKey")));
table.close();
connection.close(); // 写不写?写早了会影响别的调用?

我们常常会纠结:连接该不该关闭?在哪关闭?有没有被复用? 这些细节一旦管理不好,就可能引发连接泄露、线程堆积等问题。

(二)查询逻辑重复,缺乏统一的模板

HBase 查询语法虽然不复杂,但每次都要写重复的获取连接、构建表对象、异常处理、关闭资源,实际业务逻辑反而被掩盖在大量模板代码中。例如:

try (Connection conn = getConn(); Table table = conn.getTable(...)) {Result result = table.get(new Get(Bytes.toBytes("row")));// 业务处理
} catch (IOException e) {// 错误处理
}
  • 这段代码每个地方几乎都要复制粘贴

  • 错误处理方式不统一,日志风格不一致

  • 不利于抽象和单元测试

(三)多线程/高并发下的线程安全性隐患

如果 HBase 连接是通过某个 Bean 单例持有的,如何确保线程安全?
原生 Connection 是线程安全的,但一旦你在懒加载或共享使用上没处理好(比如用普通的 null 判断),就可能出现竞态条件:

if (connection == null) {connection = ConnectionFactory.createConnection(config); // 多线程可能重复初始化
}

高并发场景下,这样的代码就可能出现重复连接、甚至初始化失败,导致业务抖动。

(四)✍️ 总结一下

问题场景描述
连接创建重复、混乱、易泄露
查询代码冗余、不利维护和测试
多线程缺乏安全防护,存在竞态风险

为了解决这些问题,我们有必要设计并封装了一个具备以下特性的 HBase 查询模块:

  • ✅ 使用 AtomicReference 实现线程安全的连接懒加载

  • ✅ 封装模板方法,屏蔽底层连接细节

  • ✅ 自动管理资源关闭,支持 Spring 生命周期

  • ✅ 对异常处理和日志输出做了统一规范

接下来,我们将一步步拆解这个封装模块的核心设计思路和具体实现方式。

二、系统架构总览

为了实现一个线程安全、可复用、具备连接池特性的 HBase 查询模板,我们将查询模块划分为三个核心组件,每个组件职责清晰、解耦良好:

(一)逻辑视图架构

1. BizService(业务服务层)

业务层的具体服务类,只关注业务逻辑,通过模板调用来读取数据。例如:

  • 按 rowKey 查询用户得分

  • 封装 rowKey 逻辑、解析数据格式

  • 完全不关心连接获取和关闭等底层细节

这一层体现了高内聚、低耦合的原则,查询逻辑清晰、可测试。

2. HBaseTemplate(查询执行模板)

这是我们封装的核心查询执行模板,引入了函数式接口 Function<Table, T>,极大简化调用方式,并集中管理:

  • 表的打开与关闭(使用 try-with-resources)

  • 异常捕获与日志统一输出

  • 函数式执行传入的操作逻辑,灵活又强大

开发者只需关注“我要查什么表、查什么字段”,无需重复编写资源管理和异常处理代码。

3. HBaseConnectionFactory(连接管理器)

这是最底层的连接持有者,具备以下关键特性:

  • 使用 AtomicReference<Connection> 实现线程安全懒加载

  • 支持配置最大重试次数与重试间隔

  • 支持 Spring 生命周期注解 @PreDestroy,实现优雅关闭

  • 统一封装 HBase 配置参数,解耦业务层对配置细节的感知

这部分我们采取 双重检查锁(DCL)+ 原子引用,保证连接初始化只发生一次,同时具备并发安全性。

(二)✨ 架构设计亮点要求

特性说明
线程安全基于 AtomicReferencesynchronized 实现安全的懒加载
复用性Connection 和 Template 单例注入,避免重复创建资源
清晰分层业务逻辑、模板执行、连接管理各自独立,职责单一
可测试性各层通过依赖注入隔离,方便 Mock 和单元测试
可配置性连接参数、重试逻辑均可通过 Spring 配置灵活注入

三、核心实现一:基于 AtomicReference 的连接懒加载机制

在高并发、IO 敏感的微服务系统中,连接的创建与管理往往决定了系统的稳定性与性能瓶颈。为此,我们可以通过 AtomicReference<Connection> 结合双重检查加锁,构建了一个线程安全、可懒加载的 HBase 连接池。

(一)为什么选用 AtomicReference 持有连接?

Java 的 AtomicReference<T> 是一种非阻塞式的对象引用容器,具有以下优势:

  • 保证原子性操作(如 getset

  • 可与 synchronized 联合使用,减少锁粒度

  • 避免 volatile 配合双重检查锁时的指令重排问题

相比直接用 volatile ConnectionAtomicReference 更适合需要频繁读取、偶尔写入的单例资源(如连接、缓存等)。

目的:提高并发访问的安全性,避免重复创建 HBase Connection 对象。

(二)双重检查锁实现懒加载(DCL)

连接的创建使用了标准的“双重检查锁”写法:

if (connectionRef.get() == null || connectionRef.get().isClosed()) {synchronized (this) {if (connectionRef.get() == null || connectionRef.get().isClosed()) {// 创建连接逻辑...connectionRef.set(connection);}}
}

这段逻辑的重点在于:

步骤含义
外层判断避免无意义的加锁,提升并发效率
内层判断保证连接真正尚未创建,防止重复初始化
加锁粒度只在需要初始化时加锁,保证效率

(三)自动重试机制,提高连接稳定性

连接过程中可能出现网络抖动、配置错误等异常,为此我们需要引入了重试机制

for (int attempt = 1; attempt <= maxRetry; attempt++) {try {// 尝试建立连接} catch (IOException e) {// 达到最大重试次数则抛出// 否则 sleep + retry}
}

通过配置参数 apiHbaseConnectionMaxRetryapiHbaseConnectionMaxRetryDelayMillis,开发者可灵活控制重试策略,避免因一时网络抖动导致系统雪崩。

(四)生命周期管理:@PreDestroy 优雅关闭连接

为了避免应用关闭时 HBase 连接未及时释放造成资源泄露,我们使用了 Spring 的生命周期注解 @PreDestroy

@PreDestroy
public void close() {if (connection != null && !connection.isClosed()) {connection.close();}
}

确保在容器销毁时自动关闭连接,释放资源,提升系统健壮性。

(五)HBase 配置参数统一集中管理

创建连接时,所有 HBase 所需的配置都统一注入:

config.set(HBASE_ZOOKEEPER_QUORUM_KEY, zyfHbaseConfig.getHbaseZookeeperQuorum());
...
config.set(HBASE_CLIENT_CONNECTION_IMPL, AliHBaseUEClusterConnection.class.getName());

配置信息集中于 ZyfHbaseConfig 类中,做到了参数解耦配置集中化管理,更易于调试和维护。

✅ 小结:这一层解决了什么问题?

问题原始状态优化后效果
多线程连接创建可能重复创建多个连接、存在线程安全隐患原子引用 + DCL,线程安全且只创建一次连接
连接异常不可恢复一次失败即挂增加重试逻辑,提升系统容错性
Bean 销毁连接未关闭容易造成资源泄漏使用 @PreDestroy 优雅关闭
配置分散、不透明各个类硬编码配置项通过 ZyfHbaseConfig 解耦配置逻辑

四、核心实现二:函数式接口封装查询执行逻辑

完成连接池后,我们真正的目标并不是「能连上 HBase」,而是「优雅、稳定、高复用地执行查询逻辑」。这一节重点围绕我们自定义的 HBaseTemplate 展开,它解决的是 HBase 原生查询语义复杂、样板代码冗余、异常处理分散 等痛点。

(一)目标:让查询逻辑像“写 Lambda 一样”简单

对业务开发来说,其希望的是:

List<Result> results = hbaseTemplate.execute("user_table", table -> {Scan scan = new Scan();return table.getScanner(scan);
});

而不是关注:

  • 连接有没有初始化?

  • 是否线程安全?

  • 出了异常怎么办?

  • Table 用完是否关闭?

  • HBase 接口是否阻塞?

(二)函数式接口设计:对标 Spring JdbcTemplate

我们定义了一个非常简单的函数式接口:

@FunctionalInterface
public interface TableCallback<T> {T doInTable(Table table) throws Throwable;
}

这个接口的作用类似于 JDBC 中的 ConnectionCallback<T>,只不过这里操作的是 org.apache.hadoop.hbase.client.Table,它允许业务方只关心如何从 Table 中执行逻辑,而不必管理资源生命周期。

(三)execute() 模板方法封装

我们封装了如下通用模板:

public class HBaseTemplate {private final HBaseConnectionFactory connectionFactory;public HBaseTemplate(HBaseConnectionFactory connectionFactory) {this.connectionFactory = connectionFactory;}public <T> T execute(String tableName, TableCallback<T> action) {try (Table table = connectionFactory.getConnection().getTable(TableName.valueOf(tableName))) {return action.doInTable(table);} catch (Throwable e) {throw new HBaseTemplateException("Failed to execute HBase action on table: " + tableName, e);}}
}

关键点:

设计点作用
try-with-resources自动释放 HBase Table,避免资源泄漏
泛型返回值 <T>查询可返回任意类型(Result、List、Map 等)
封装异常统一异常处理,避免业务层 try-catch
解耦连接获取所有连接交由 connectionFactory 管理

(四)查询调用示例:像 Lambda 一样优雅

List<String> rowKeys = hbaseTemplate.execute("user_table", table -> {Scan scan = new Scan();try (ResultScanner scanner = table.getScanner(scan)) {List<String> keys = new ArrayList<>();for (Result result : scanner) {keys.add(Bytes.toString(result.getRow()));}return keys;}
});

这一段代码有以下特性:

  • 无样板代码:不需要手动获取连接、关闭资源、处理异常

  • 业务聚焦:只关注核心逻辑(从 result 中提取 row key)

  • 异常统一抛出:由模板封装异常处理逻辑

(五)支持更细粒度的扩展能力(如 Put/Delete)

由于封装为函数式接口,这套机制同样适用于插入、删除、批量处理等场景:

hbaseTemplate.execute("user_table", table -> {Put put = new Put(Bytes.toBytes("row1"));put.addColumn(Bytes.toBytes("cf"), Bytes.toBytes("name"), Bytes.toBytes("Alice"));table.put(put);return null;
});

开发者无需关注连接池的底层实现,无需担心 Table.close() 是否漏写,整个 API 尽可能地“隐身”,但又具备灵活性。

五、完整案例演示:从查询封装到业务落地

在这一节,我们将用一个完整的实际案例来演示如何通过 ApiHBaseConnectionFactory + ApiHBaseTemplate 两个组件,完成一次 线程安全、资源友好、逻辑聚焦的 HBase 查询

(一)场景说明:根据手机号前缀模糊查找用户信息

假设业务希望从 HBase 中的 user_info 表里,扫描所有手机号前缀为 "138" 的用户,并提取部分字段。

(二)原始写法:重复 + 冗余 + 难维护

org.apache.hadoop.conf.Configuration config = HBaseConfiguration.create();
// ... 设置一堆 config 参数(略)try (Connection conn = ConnectionFactory.createConnection(config);Table table = conn.getTable(TableName.valueOf("user_info"))) {Scan scan = new Scan();scan.setRowPrefixFilter(Bytes.toBytes("138"));try (ResultScanner scanner = table.getScanner(scan)) {for (Result result : scanner) {String userId = Bytes.toString(result.getValue(Bytes.toBytes("cf"), Bytes.toBytes("user_id")));String phone = Bytes.toString(result.getValue(Bytes.toBytes("cf"), Bytes.toBytes("phone")));// ...}}
} catch (IOException e) {// 异常处理
}

❌ 不利之处:

  • 大量样板代码(连接、关闭、异常处理)

  • ScanResultScanner 的释放顺序容易写错

  • 每次写查询都重复逻辑,极易出错

(三)优化后写法:基于模板封装

List<UserInfo> matchedUsers = hbaseTemplate.execute("user_info", table -> {Scan scan = new Scan();scan.setRowPrefixFilter(Bytes.toBytes("138"));List<UserInfo> result = new ArrayList<>();try (ResultScanner scanner = table.getScanner(scan)) {for (Result row : scanner) {String userId = Bytes.toString(row.getValue(Bytes.toBytes("cf"), Bytes.toBytes("user_id")));String phone = Bytes.toString(row.getValue(Bytes.toBytes("cf"), Bytes.toBytes("phone")));result.add(new UserInfo(userId, phone));}}return result;
});

业务层代码只需要关心三件事:

  1. 查哪个表(user_info

  2. 扫描什么前缀(138

  3. 组装什么字段(userId, phone

其余连接复用、异常封装、资源释放,全交由模板内部处理。

(四)支撑代码汇总(用于上下文完整性)

1. 用户实体类 UserInfo

public class UserInfo {private String userId;private String phone;public UserInfo(String userId, String phone) {this.userId = userId;this.phone = phone;}// getter/setter/toString 可略
}

2. HBaseTemplate 示例定义

@Component
public class HBaseTemplate {private final HBaseConnectionFactory connectionFactory;@Autowiredpublic HBaseTemplate(ApiHBaseConnectionFactory connectionFactory) {this.connectionFactory = connectionFactory;}public <T> T execute(String tableName, TableCallback<T> action) {try (Table table = connectionFactory.getConnection().getTable(TableName.valueOf(tableName))) {return action.doInTable(table);} catch (Throwable e) {throw new HBaseTemplateException("Failed to execute action on table: " + tableName, e);}}
}

六、异常处理与重试机制的策略设计

在分布式系统中,HBase 作为一个非关系型数据库,涉及到大量的网络通信、数据存储和资源管理,因此在查询过程中难免会遇到各种异常情况,例如连接超时、网络故障、节点不可用等。为了确保业务系统在遇到这些异常时能够优雅地退化,并尽量保证查询的成功率,设计一个合理的异常处理和重试机制显得尤为重要。

(一)异常类型与分类

在 HBase 查询中,我们可能会遇到以下几种常见的异常类型:

  • 连接异常:由于网络故障或 HBase 集群问题,无法建立连接。

  • 超时异常:HBase 查询请求未能在规定时间内返回结果。

  • IO 异常:由于网络不稳定或 HBase 服务器异常,导致查询失败。

  • 不可恢复异常:如配置错误、表不存在等,属于逻辑错误,一般不适合重试。

我们需要对这些异常进行分类,分别采取不同的处理策略。

(二)重试机制设计

为了保证高可用性,通常需要对可以恢复的异常进行重试处理。重试机制的设计应考虑以下几个因素:

  • 重试次数限制:重试次数过多会导致延迟过长,因此需要在系统中设置最大重试次数。

  • 重试间隔:每次重试之间应有适当的间隔,避免短时间内频繁请求导致系统负载过高。

  • 指数回退策略:对于网络不稳定等场景,可以采用指数回退策略,使重试间隔逐步增加,避免过多的并发请求同时到达 HBase。

示例代码:重试逻辑的实现

public class HBaseRetryTemplate {private final int maxRetryAttempts;private final long retryDelayMillis;private final long maxRetryDelayMillis;public HBaseRetryTemplate(int maxRetryAttempts, long retryDelayMillis, long maxRetryDelayMillis) {this.maxRetryAttempts = maxRetryAttempts;this.retryDelayMillis = retryDelayMillis;this.maxRetryDelayMillis = maxRetryDelayMillis;}public <T> T executeWithRetry(HBaseOperation<T> operation) throws IOException {int attempt = 0;long currentRetryDelay = retryDelayMillis;while (attempt < maxRetryAttempts) {attempt++;try {return operation.execute();} catch (IOException e) {// 检查是否需要重试if (shouldRetry(e)) {log.warn("HBase operation failed on attempt {}: {}. Retrying in {} ms...", attempt, e.getMessage(), currentRetryDelay);try {Thread.sleep(currentRetryDelay);} catch (InterruptedException ie) {Thread.currentThread().interrupt();throw new IOException("Thread was interrupted during retry sleep.", ie);}// 指数回退currentRetryDelay = Math.min(currentRetryDelay * 2, maxRetryDelayMillis);} else {throw e;  // 无法恢复的异常,不再重试}}}throw new IOException("Exceeded maximum retry attempts.");}private boolean shouldRetry(IOException e) {// 判断异常是否为可重试异常,如连接超时、网络错误等return e instanceof SocketTimeoutException || e instanceof ConnectException;}// 操作接口,供业务层传入具体的操作public interface HBaseOperation<T> {T execute() throws IOException;}
}

在上面的代码中,HBaseRetryTemplate 类负责执行重试逻辑。executeWithRetry 方法接受一个 HBaseOperation,这是一个函数式接口,允许业务层传入实际的操作(如 HBase 查询)。如果操作失败,系统将检查异常类型,决定是否重试,并在必要时采用指数回退策略。

(三)异常类型处理

在实现重试逻辑时,我们需要区分哪些异常是可以重试的,哪些是不可恢复的。一般来说,网络相关的异常、连接超时等可以重试,而配置错误、数据不一致等不可恢复的错误则应该立即抛出。

可重试异常
  • SocketTimeoutException:连接超时或数据传输超时

  • ConnectException:网络连接错误

不可重试异常
  • TableNotFoundException:表不存在

  • IllegalArgumentException:查询参数错误

  • HBaseIOException:由于系统配置问题导致的异常

private boolean shouldRetry(IOException e) {if (e instanceof SocketTimeoutException || e instanceof ConnectException) {return true; // 网络相关错误可重试}if (e instanceof TableNotFoundException) {log.error("Table not found: " + e.getMessage());return false; // 表不存在,不可重试}if (e instanceof IllegalArgumentException) {log.error("Invalid query parameters: " + e.getMessage());return false; // 查询参数无效,不可重试}return false;
}

(四)结合重试与模板使用

结合前面提到的 HBaseTemplateHBaseRetryTemplate,我们可以在执行查询时引入重试机制。以下是一个使用重试机制的查询示例:

List<UserInfo> matchedUsers = hbaseRetryTemplate.executeWithRetry(() -> {return hbaseTemplate.execute("user_info", table -> {Scan scan = new Scan();scan.setRowPrefixFilter(Bytes.toBytes("138"));List<UserInfo> result = new ArrayList<>();try (ResultScanner scanner = table.getScanner(scan)) {for (Result row : scanner) {String userId = Bytes.toString(row.getValue(Bytes.toBytes("cf"), Bytes.toBytes("user_id")));String phone = Bytes.toString(row.getValue(Bytes.toBytes("cf"), Bytes.toBytes("phone")));result.add(new UserInfo(userId, phone));}}return result;});
});

在这里,我们通过 HBaseRetryTemplateexecuteWithRetry 方法,确保在执行查询操作时,如果遇到临时的连接问题(如网络超时),系统会自动重试,最大重试次数和重试间隔由配置项控制。

七、性能优化与高可用设计:如何让查询模板更高效

在高并发和大规模数据环境中,HBase 查询的性能往往会成为系统瓶颈。因此,在实现查询模板时,我们不仅要关注代码的正确性,还要考虑如何优化查询性能、减少响应时间和提高系统的可用性。

(一)查询性能优化的基本原则

1. 减少不必要的 I/O 操作

HBase 查询的效率往往取决于 I/O 操作的数量。为了提高性能,我们需要确保查询只涉及必要的数据,并避免全表扫描。常见的优化方式有:

  • 使用列族过滤器:通过设置列族(ColumnFamily)过滤器,只返回必要的列,减少网络传输量。

  • 使用行键过滤:通过行键(Row Key)进行精确匹配或前缀匹配,避免扫描整个表。

  • 限制返回的行数:通过设置 Scan.setMaxResultSize 限制返回的数据量,防止查询过多数据。

2. 使用连接池减少连接创建和销毁开销

每次连接的创建和销毁都可能带来较大的性能损耗。为了优化性能,可以使用 连接池 来复用已有连接,减少频繁创建连接的开销。

// 示例:配置连接池
HBaseConnectionPool pool = new HBaseConnectionPool(config);
Connection connection = pool.getConnection();

通过连接池,可以让多个线程共享连接,避免了每次操作都需要重新建立连接的问题。对于高并发系统而言,连接池是提升性能的关键组件。

3. 异步操作与批量操作

对于大量数据的查询和写入,可以考虑 异步操作批量操作,避免单个请求的延迟导致整体性能下降。

  • 异步查询:通过使用 AsyncTable 来执行异步查询,可以避免同步阻塞,提高查询吞吐量。

  • 批量操作:对于多个插入、更新或删除操作,使用批量 API(如 PutDelete)来减少多次网络交互的开销。

// 示例:异步查询
AsyncTable<Scan> asyncTable = connection.getAsyncTable(TableName.valueOf("my_table"));
asyncTable.scan(scan).thenAccept(results -> {// 处理结果
});

(二)高可用性设计

1. 集群容错与负载均衡

为了确保系统的高可用性,HBase 集群的配置至关重要。为了避免单点故障,HBase 集群应该部署在多个节点上,并采用以下策略:

  • RegionServer 的冗余:HBase 会将数据切分成 Region,并在多个 RegionServer 上分布。RegionServer 的故障可以通过自动转移 Region 来保证服务的高可用性。

  • 负载均衡:通过合理的负载均衡策略,可以避免某些 RegionServer 过载,确保各个 RegionServer 承载均衡的负载。

HBase 会自动处理 Region 的分配和调度,但在查询时,我们也可以通过合适的请求路由策略,减少单个 RegionServer 的压力,提高集群的整体吞吐量。

2. 弹性扩展

高可用性系统需要具备弹性扩展的能力。当集群负载增加时,可以通过动态添加 RegionServer 节点来扩展 HBase 集群的处理能力。系统设计应当支持在流量增长时,平滑地增加机器资源,并确保不会因为资源不足导致服务不可用。

  • 自动化扩展:通过监控集群的负载、存储容量等,自动化地增加或减少 RegionServer 节点。

  • 动态调整配置:根据业务需求动态调整 HBase 的配置参数(如 MemStore 大小、Region 分配策略等),确保集群能够灵活应对不同的负载情况。

3. 故障恢复与灾难恢复

为了确保高可用性,HBase 集群应具备故障恢复能力。HBase 支持以下几种故障恢复机制:

  • 数据备份与恢复:定期进行 HBase 数据的备份,并在发生故障时能够快速恢复。

  • RegionServer 的自动切换:如果某个 RegionServer 节点宕机,HBase 会自动将该节点上的 Region 转移到其他正常的 RegionServer 上,确保数据不丢失且服务继续可用。

  • Zookeeper 故障转移:HBase 依赖 Zookeeper 来协调集群中的服务,确保集群的状态一致性。在 Zookeeper 出现故障时,可以通过手动或自动恢复机制快速切换到备用 Zookeeper 节点。

(三)查询模板的优化

在实现查询模板时,为了保证查询的高效性和系统的高可用性,我们需要结合前述的优化策略,设计出高效的查询模板。具体做法包括:

  • 缓存优化:使用缓存技术(如 Redis)缓存频繁查询的数据,减少对 HBase 的查询压力。特别是对于热点数据,缓存能显著减少查询响应时间。

  • 查询预热与异步查询:针对一些复杂的查询操作,可以在后台异步执行查询,并提前加载数据,减少用户请求时的延迟。

  • 合理的参数配置:在查询时,合理设置 Scan 参数(如 setBatchsetCaching 等),避免全表扫描或不必要的网络传输。

示例:使用缓存优化查询
public class HBaseCacheTemplate {private Cache<String, List<UserInfo>> cache;  // 使用缓存来存储查询结果public List<UserInfo> queryUserInfo(String prefix) throws IOException {// 先检查缓存List<UserInfo> cachedData = cache.get(prefix);if (cachedData != null) {return cachedData;}// 如果缓存没有,执行 HBase 查询List<UserInfo> result = hbaseTemplate.execute("user_info", table -> {Scan scan = new Scan();scan.setRowPrefixFilter(Bytes.toBytes(prefix));return executeScan(table, scan);});// 将查询结果放入缓存cache.put(prefix, result);return result;}private List<UserInfo> executeScan(Table table, Scan scan) throws IOException {List<UserInfo> result = new ArrayList<>();try (ResultScanner scanner = table.getScanner(scan)) {for (Result row : scanner) {String userId = Bytes.toString(row.getValue(Bytes.toBytes("cf"), Bytes.toBytes("user_id")));String phone = Bytes.toString(row.getValue(Bytes.toBytes("cf"), Bytes.toBytes("phone")));result.add(new UserInfo(userId, phone));}}return result;}
}

(四)小结:如何提高查询模板的性能和可用性

优化点效果
限制查询数据范围减少 I/O 操作,降低网络传输量
连接池复用减少连接创建销毁开销,提高响应速度
异步与批量操作提升查询吞吐量,减少单个请求的延迟
高可用设计保证系统在故障时能够快速恢复,减少停机时间
缓存优化通过缓存热点数据,减少对 HBase 的重复查询
故障恢复保证在服务不可用时能够快速恢复,提升系统的可靠性

通过这些优化,我们能够提升查询模板的性能,确保系统在高并发、大规模数据访问的场景下仍能高效运行。

八、总结与未来展望:从技术实现到业务落地

在前面的章节中,我们详细介绍了如何设计和实现一个线程安全、可复用的 HBase 查询模板。从连接池的懒加载、查询执行逻辑的封装,到性能优化和高可用性设计,我们全面探讨了构建一个高效、可扩展、可靠的 HBase 查询模板的关键要点。

(一)设计总结:一个高效且健壮的 HBase 查询模板

我们从实际需求出发,设计了一个能够在多线程环境下安全地复用连接的查询模板。整个模板的设计考虑了以下几点核心需求:

  • 线程安全性:通过使用 AtomicReference 和双重检查锁实现了懒加载的连接管理,确保在多线程环境中只有一个连接被创建和复用。

  • 性能优化:通过连接池复用、批量操作、异步查询等手段,我们有效提升了查询性能,减少了不必要的 I/O 操作和延迟。

  • 高可用性设计:在设计上引入了容错机制和自动重试机制,保证系统在高负载和故障恢复场景下能继续高效运行。

  • 查询逻辑封装:使用函数式接口封装查询逻辑,使得查询操作更加灵活,业务代码与查询实现解耦,提高了代码的可维护性。

通过这些设计,我们不仅满足了对性能的要求,也保障了系统的高可用性,使得 HBase 查询能够平稳地支持大规模业务的高并发访问。

(二)对业务的实际影响

在实际业务中,这种 HBase 查询模板的引入,使得系统能够在面对不断增长的数据量和请求量时,保持较低的延迟和较高的查询效率。尤其是在需要高并发处理和快速响应的场景下,查询模板的性能优化和高可用性设计提供了重要的保障。

  • 减少开发复杂度:通过封装查询逻辑和连接池的管理,开发人员不再需要关心 HBase 连接的管理和细节,可以更加专注于业务逻辑的开发。

  • 提升服务可用性:自动重试机制和连接池的使用大大提升了系统的容错能力,减少了因连接失败或高负载导致的服务中断。

  • 加速业务迭代:优化后的查询模板不仅提升了性能,还为业务的扩展和优化提供了便利。业务团队可以更快速地推出新功能,支持更多的查询需求。

(三)未来展望:进一步优化与发展方向

尽管我们已经实现了一个性能较好且可靠的查询模板,但随着技术的不断发展和业务需求的变化,仍然有许多潜力可以挖掘,以下是未来的一些发展方向:

1. 高级查询优化

随着数据量的不断增加,单纯的连接池复用和缓存优化可能无法满足更高的查询需求。未来可以考虑更多的 查询优化策略,如:

  • 预计算和物化视图:对于频繁查询的复杂数据,可以采用预计算的方式,将结果存储在独立的表或缓存中,减少查询时的计算压力。

  • 基于机器学习的查询优化:利用机器学习算法预测和优化查询模式,根据历史查询数据自动调整查询策略和索引。

2. 更灵活的查询策略

随着业务需求的变化,可能会出现更多种类的查询模式,未来的查询模板可以支持 更多灵活的查询策略,例如:

  • 多维度查询支持:对于具有复杂查询需求的业务,模板可以支持更加灵活的查询方式,如基于时间、地理位置、用户行为等多维度的查询。

  • 分布式查询:随着大数据量的增长,HBase 集群可能会变得更加复杂,支持跨 RegionServer 或跨集群的分布式查询可能成为未来的需求。

3. 异常监控与自动化运维

在高可用系统中,异常监控和自动化运维的能力至关重要。未来的查询模板可以与 分布式监控系统(如 Prometheus、Grafana)集成,实时监控查询性能和连接池的状态。系统出现异常时,可以自动触发警报或恢复操作。

  • 查询性能监控:监控每次查询的延迟和吞吐量,自动识别性能瓶颈。

  • 自动扩展和调整:根据系统负载,自动扩展连接池或调整查询参数,保证查询性能。

4. 支持更多数据源和兼容性

未来,随着系统需求的多样化,可能会接入不同的数据源。查询模板可以进一步扩展,支持对 多种数据源的兼容性,例如:

  • 支持多个 NoSQL 数据库:除了 HBase,还可以支持 Cassandra、MongoDB 等其他 NoSQL 数据库,统一管理多个数据源的查询操作。

  • 对不同版本 HBase 的兼容:随着 HBase 版本的更新,可能会有新的 API 和功能,查询模板应能兼容不同版本的 HBase,以便平滑过渡。

(四)小结

通过本章节的总结,我们可以看到一个完善的 HBase 查询模板不仅要关注基本的性能和高可用性,还应考虑灵活性、扩展性和长期运维的需求。从当前的实现到未来的展望,查询模板的优化和演进将是一个持续的过程,随着业务发展和技术进步,我们可以不断改进和优化查询模板,以应对越来越复杂的应用场景。

希望通过本书的介绍,读者能够掌握高效的 HBase 查询模板设计和实现技巧,并将其应用到实际的业务中,解决查询性能、连接管理和高可用性等方面的问题,最终提高整个系统的业务效率和稳定性。

相关文章:

如何封装一个线程安全、可复用的 HBase 查询模板

目录 一、前言&#xff1a;原生 HBase 查询的痛点 &#xff08;一&#xff09;连接管理混乱&#xff0c;容易造成资源泄露 &#xff08;二&#xff09;查询逻辑重复&#xff0c;缺乏统一的模板 &#xff08;三&#xff09;多线程/高并发下的线程安全性隐患 &#xff08;四…...

VLM Qwen2.5VL GRPO训练微调 EasyR1 多机多卡训练(2)

在之前博客进行了简单的训练尝试:https://www.dong-blog.fun/post/2060 在本博客,将会深入进行多机多卡训练,以及调整训练奖励函数。 之前构建了镜像: docker build . -t kevinchina/deeplearning:r1 FROM hiyouga/verl:ngc-th2.6.0-cu126-vllm0.8.4-flashinfer0.2.2-cx…...

基于建造者模式的信号量与理解建造者模式

信号量是什么&#xff1f; AI解释&#xff1a;信号量&#xff08;Semaphore&#xff09;是操作系统中用于 进程同步与互斥 的经典工具&#xff0c;由荷兰计算机科学家 Edsger Dijkstra 在 1965 年提出。它本质上是一个 非负整数变量&#xff0c;通过原子操作&#xff08;P 操作…...

笔试专题(十四)

文章目录 mari和shiny题解代码 体操队形题解代码 二叉树中的最大路径和题解代码 mari和shiny 题目链接 题解 1. 可以用多状态的线性dp 2. 细节处理&#xff1a;使用long long 存储个数 3. 空间优化&#xff1a;只需要考虑等于’s’&#xff0c;‘sh’&#xff0c;shy’的情况…...

2025年五一数学建模A题【支路车流量推测】原创论文讲解

大家好呀&#xff0c;从发布赛题一直到现在&#xff0c;总算完成了2025年五一数学建模A题【支路车流量推测】完整的成品论文。 给大家看一下目录吧&#xff1a; 摘 要&#xff1a; 一、问题重述 二&#xff0e;问题分析 2.1问题一 2.2问题二 2.3问题三 2.4问题四 2.5 …...

Linux系统:进程程序替换以及相关exec接口

本节重点 理解进程替换的相关概念与原理掌握相关程序替换接口程序替换与进程创建的区别程序替换的注意事项 一、概念与原理 进程程序替换是操作系统中实现多任务和资源复用的关键机制&#xff0c;允许进程在运行时动态加载并执行新程序。 1.1 定义 进程程序替换是指用新程…...

STM32复盘总结——芯片简介

1、stm32介绍 STM32是ST公司基于ARM Cortex-M内核开发的32位微控制器 STM32常应用在嵌入式领域&#xff0c;如智能车、无人机、机器人、无线通信、物联网、工业控制、娱乐电子产品等 STM32功能强大、性能优异、片上资源丰富、功耗低&#xff0c;是一款经典的嵌入式微控制器 目…...

安装深度环境anaconda+cuda+cudnn+pycharm+qt+MVS

下载anaconda,链接:link 默认电脑有显卡驱动,没有的话直接进NVIDIA官网:https://www.nvidia.cn/geforce/drivers/ 下载。 下载cuda 链接:https://developer.nvidia.com/cuda-toolkit-archive 下载cudnn安装包,链接:https://developer.nvidia.com/rdp/cudnn-archive 备注:…...

泰迪杯特等奖案例学习资料:基于多模态特征融合的图像文本检索系统设计

(第十二届泰迪杯数据挖掘挑战赛B题特等奖案例解析) 一、案例背景与核心挑战 1.1 应用场景与行业痛点 随着智能终端与社交媒体的普及,图像与文本数据呈现爆炸式增长,跨模态检索需求日益迫切。传统方法面临以下问题: 语义鸿沟:图像与文本的异构特征分布差异显著,导致跨模…...

进程与线程:05 内核级线程实现

内核级线程代码实现概述 这节课我们要讲内核级线程到底是怎么做出来的&#xff0c;实际上就是要深入探讨内核级线程的代码实现。 在前两节课中&#xff0c;我们学习了用户级线程和内核级线程是如何进行切换的&#xff0c;以及实现切换的核心要点。那两节课讲述的内容&#xf…...

Laravel 12 实现 API 登录令牌认证

Laravel 12 实现 API 登录令牌认证 在 Laravel 12 中实现基于令牌(Token)的 API 认证&#xff0c;可以使用 Laravel Sanctum 或 Laravel Passport。以下是两种方式的实现方法&#xff1a; 方法一&#xff1a;使用 Laravel Sanctum (轻量级 API 认证) 1. 安装 Sanctum compo…...

【Git】万字详解 Git 的原理与使用(上)

&#x1f970;&#x1f970;&#x1f970;来都来了&#xff0c;不妨点个关注叭&#xff01; &#x1f449;博客主页&#xff1a;欢迎各位大佬!&#x1f448; 文章目录 1. 初识 Git1.1 Git 是什么&#xff1f;1.2 为什么要有 Git 2. 安装 Git2.1 Linux-Ubuntu 安装 Git2.2 Windo…...

Python高级爬虫之JS逆向+安卓逆向1.7节: 面向对象

目录 引言: 1.7.1 先理解面向过程 1.7.2 再理解面向对象 1.7.3 面向对象的三大特征 1.7.4 类属性,类方法,静态方法 1.7.5 构造函数,对象属性,对象方法 1.7.6 爬虫接单实现了雪糕自由 引言: 大神薯条老师的高级爬虫+安卓逆向教程: 这套爬虫教程会系统讲解爬虫的初…...

SpringBoot基础(原理、项目搭建、yaml)

SpringBoot&#xff1a;javaweb的一个框架&#xff0c;基于Spring开发&#xff0c;SpringBoot本身并不提供Spring框架的核心特性以及扩展功能&#xff0c;只是用于快速、敏捷的开发新一代基于Spring框架的应用程序&#xff0c;它与Spring框架紧密结合用于提升Spring开发者体验的…...

MTV-SCA:基于多试向量的正弦余弦算法

3 正弦余弦算法 (SCA) 正弦余弦算法&#xff08;SCA&#xff09;是为全局优化而开发的&#xff0c;并受到两个函数&#xff0c;正弦和余弦的启发。与其他基于启发式种群的算法一样&#xff0c;SCA在问题的预设最小值和最大值边界内随机生成候选解。然后&#xff0c;通过应用方…...

STL之vector容器

vector的介绍 1.vector是可变大小数组的容器 2.像数组一样&#xff0c;采用连续的空间存储&#xff0c;也就意味着可以通过下标去访问&#xff0c;但它的大小可以动态改变 3.每次的插入都要开空间吗&#xff1f;开空间就要意味着先开临时空间&#xff0c;然后在拷贝旧的到新…...

Android学习总结之jetpack组件间的联系

在传统安卓开发中&#xff0c;UI 组件&#xff08;Activity/Fragment&#xff09;常面临三个核心问题&#xff1a; 生命周期混乱&#xff1a;手动管理 UI 与数据的绑定 / 解绑&#xff0c;易导致内存泄漏&#xff08;如 Activity 销毁后回调仍在触发&#xff09;。数据断层&am…...

linux的信号量初识

Linux下的信号量(Semaphore)深度解析 在多线程或多进程并发编程的领域中&#xff0c;确保对共享资源的安全访问和协调不同执行单元的同步至关重要。信号量&#xff08;Semaphore&#xff09;作为经典的同步原语之一&#xff0c;在 Linux 系统中扮演着核心角色。本文将深入探讨…...

【安装指南】Centos7 在 Docker 上安装 RabbitMQ4.0.x

目录 前置知识:RabbitMQ 的介绍 一、单机安装 RabbitMQ 4.0.7版本 1.1 在线拉取镜像 二、延迟插件的安装 2.1 安装延迟插件 步骤一:下载延迟插件 步骤二:将延迟插件放到插件目录 步骤三:启动延迟插件 步骤四:重启 RabbitMQ 服务 步骤五:验收成果 步骤六:手动…...

Android和iOS测试的区别有哪些?

作为移动端测试工程师,Android 和 iOS 的测试差异直接影响测试策略设计。本文从测试环境、工具链、兼容性、发布流程等维度全面解析,并附实战建议。 1. 测试环境差异 维度AndroidiOS设备碎片化高(厂商/分辨率/系统版本多样)低(仅苹果设备,版本集中)系统开放性开放(可Ro…...

spring中的@PostConstruct注解详解

基本概念 PostConstruct 是 Java EE 规范的一部分&#xff0c;后来也被纳入到 Spring 框架中。它是一个标记注解&#xff0c;用于指示一个方法应该在依赖注入完成后被自动调用。 主要特点 生命周期回调&#xff1a;PostConstruct 标记的方法会在对象初始化完成、依赖注入完成…...

大模型开发学习笔记

文章目录 大模型基础大模型的使用大模型训练的阶段大模型的特点及分类大模型的工作流程分词化(tokenization)与词表映射 大模型的应用 进阶agent的组成和概念planning规划子任务分解ReAct框架 memory记忆Tools工具\工具集的使用langchain认知框架ReAct框架plan-and-Execute计划…...

【android Framework 探究】pixel 5 内核编译

相关文章&#xff1a; 【android Framework 探究】android 13 aosp编译全记录 【android Framework 探究】android 13 aosp 全记录 - 烧录 一&#xff0c;环境 主机 -> Ubuntu 18.04.6 LTS 内存 -> 16GB 手机 -> pixel 5 代号redfin。kernel代号redbull 二&#xf…...

PowerBI实现点击空白处隐藏弹窗(详细教程)

PowerBI点击空白处隐藏弹窗 第五届PowerBI可视化大赛中亚军作品:金融企业智慧经营分析看板 有个功能挺好玩的&#xff1a;点击空白处隐藏弹窗&#xff0c;gif动图如下&#xff1a; 我们以一个案例分享下实现步骤&#xff1a; 第一步&#xff0c; 先添加一个显示按钮&#xff…...

【git】获取特定分支和所有分支

1 特定分支 1.1 克隆指定分支&#xff08;默认只下载该分支&#xff09; git clone -b <分支名> --single-branch <仓库URL> 示例&#xff08;克隆 某一个 分支&#xff09;&#xff1a; git clone -b xxxxxx --single-branch xxxxxxx -b &#xff1a;指定分支…...

Windows配置grpc

Windows配置grpc 方法一1. 使用git下载grph下载速度慢可以使用国内镜像1.1 更新子模块 2. 使用Cmake进行编译2.1 GUI编译2.2 命令行直接编译 3. 使用Visual Studio 生成解决方法 方法二1. 安装 vcpkg3.配置vckg的环境变量2. 使用 vcpkg 安装 gRPC3. 安装 Protobuf4. 配置 CMake…...

【学习笔记】深入理解Java虚拟机学习笔记——第2章 Java内存区域与内存溢出异常

第2章 Java内存区域与内存溢出异常 2.1 概述 略 2.2 运行时数据区域 2.2.1 程序计数器 线程私有&#xff0c;记录执行的字节码位置 2.2.2 Java 虚拟机栈 线程私有&#xff0c;存储一个一个的栈帧&#xff0c;通过栈帧的出入栈来控制方法执行。 -栈帧&#xff1a;对应一个…...

数字智慧方案6189丨智慧应急综合解决方案(46页PPT)(文末有下载方式)

资料解读&#xff1a;智慧应急综合解决方案 详细资料请看本解读文章的最后内容。 在当前社会环境下&#xff0c;应急管理的重要性愈发凸显。国务院发布的《“十四五” 国家应急体系规划》以及 “十四五” 智慧应急专项规划&#xff0c;明确了应急管理体系建设的方向和重点&…...

解决 3D Gaussian Splatting 中 SIBR 可视化组件报错 uv_mesh.vert 缺失问题【2025最新版!】

一、&#x1f4cc; 引言 在使用 3D Gaussian Splatting&#xff08;3DGS&#xff09;进行三维重建和可视化的过程&#xff0c;SIBR_gaussianViewer_app 是一款官方推荐的本地可视化工具&#xff0c;允许我们在 GPU 上实时浏览重建结果。然而&#xff0c;许多用户在启动该工具时…...

见多识广4:Buffer与Cache,神经网络加速器的Buffer

目录 前言传统意义上的Buffer与Cache一言以蔽之定义与主要功能BufferCache 数据存储策略二者对比 神经网络加速器的bufferInput BufferWeight BufferOutput Buffer与传统buffer的核心区别总结 前言 知识主要由Qwen和Kimi提供&#xff0c;我主要做笔记。 参考文献&#xff1a; …...

微服务中组件扫描(ComponentScan)的工作原理

微服务中组件扫描(ComponentScan)的工作原理 你的问题涉及到Spring框架中ComponentScan的工作原理以及Maven依赖管理的影响。我来解释为什么能够扫描到common模块的bean而扫描不到其他模块的bean。 根本原因 关键在于**类路径(Classpath)**的包含情况&#xff1a; Maven依赖…...

C++之类和对象基础

⾯向对象三⼤特性&#xff1a;封装、继承、多态 类和对象 一.类的定义1. 类的定义格式2.类域 二.实例化1.对象2.对象的大小 三.this指针 在 C 的世界里&#xff0c;类和对象构成了面向对象编程&#xff08;Object-Oriented Programming&#xff0c;OOP&#xff09;的核心框架&…...

【DIY小记】新手小白超频遇到黑屏问题解决分享

最近玩FPS游戏的时候&#xff0c;发现以前一顿操作超频之后的电脑&#xff0c;有一定概率会出问题。具体表现比如一种是&#xff0c;电脑显示器直接黑屏&#xff0c;所有键盘交互没有响应&#xff0c;只能直接重启电脑&#xff0c;还有一种是偶现卡顿&#xff0c;直接死机或者卡…...

虚幻引擎 IK Retargeter 编辑器界面解析

我来为您详细解释这段关于虚幻引擎IK Retargeter编辑器界面的文本&#xff0c;它描述了动画重定向系统的核心组件和工作原理。 Retarget Phases (重定向阶段) 这部分介绍了动画重定向过程中的三个关键计算阶段&#xff0c;每个阶段都可以单独启用或禁用&#xff0c;这对于调试…...

uc系统中常用命令、标准C库函数和系统调用

目录 一、常用命令 env echo $name 键值 export name unset name gcc -c xxx.c ar 命令 ar -r libxxx.a xxx1.o xxx2.o gcc -c -fpic xxx.c gcc -shared -fpic xxx1.c xxx2.c -o libxxx.so kill [-信号] PID kill -l 软链接&#xff1a;ln -s xxx yyy 硬链接&…...

OpenHarmony - 驱动使用指南,HDF驱动开发流程

OpenHarmony - HDF驱动开发流程 概述 HDF&#xff08;Hardware Driver Foundation&#xff09;驱动框架&#xff0c;为驱动开发者提供驱动框架能力&#xff0c;包括驱动加载、驱动服务管理、驱动消息机制和配置管理。并以组件化驱动模型作为核心设计思路&#xff0c;让驱动开发…...

C++负载均衡远程调用学习之UDP SERVER功能

目录 1.LARSV0.9-配置功能 2.LARSV0.10-upd-server的实现 3.LARSV0.10-udp-client的实现 1.LARSV0.9-配置功能 2.LARSV0.10-upd-server的实现 3.LARSV0.10-udp-client的实现...

word交叉引用图片、表格——只引用编号的处理方法

交叉引用图片/表格 在“引用”选项卡上的“题注”组中&#xff0c;单击“插入题注”。勾选【从题注中排除标签】。在文中插入题注。 【注 意】 这时候插入的题注只有编号项了。然后手动打上标签【TABLE】&#xff0c;并在标签和编号项之间加上【样式分隔符&#xff0c;AltCt…...

平台介绍-开放API接口-鉴权

平台的理念是一个组织内部只建一套系统。但是现实情况是&#xff0c;组织内部已经建立了很多系统&#xff0c;是不能一次性替代的&#xff0c;只能先搭起平台&#xff0c;然后逐步开始替换。这样就不可避免的存在其他系统和平台进行交互的问题。 平台为此设计了开放API接口。其…...

【Bootstrap V4系列】 学习入门教程之 组件-警告框(Alert)

Bootstrap V4 学习入门教程之 组件-警告框&#xff08;Alert&#xff09; 警告框&#xff08;Alert&#xff09;一、示例二、链接的颜色三、添加其它内容四、关闭警告框 通过 JavaScript 触发行为触发器本组件所暴露的事件 警告框&#xff08;Alert&#xff09; 通过精炼且灵活…...

【服务器通信-socket】——int socket(int domain, int type, int protocol);

#include <sys/types.h> #include <sys/socket.h> int socket(int domain, int type, int protocol); domain: AF_INET 这是大多数用来产生socket的协议&#xff0c;使用TCP或UDP来传输&#xff0c;用IPv4的地址 AF_INET6 与上面类似&#xff0c;不过是来用IPv6的地…...

洛谷P1014(Cantor 表[NOIP 1999 普及组])题解

题目大意&#xff1a;求Cantor表&#xff08;按照Z字形排列&#xff08;如第一项是1/1&#xff0c;然后是1/2&#xff0c;2/1&#xff0c;3/1&#xff0c;2/2&#xff09;&#xff09;的第N项。 那么&#xff0c;我们需要找出Cantor表的排列规律。根据题目中的Z字形描述&#x…...

【愚公系列】《Manus极简入门》012-自我认知顾问:“内在探索向导”

&#x1f31f;【技术大咖愚公搬代码&#xff1a;全栈专家的成长之路&#xff0c;你关注的宝藏博主在这里&#xff01;】&#x1f31f; &#x1f4e3;开发者圈持续输出高质量干货的"愚公精神"践行者——全网百万开发者都在追更的顶级技术博主&#xff01; &#x1f…...

密码学_加密

目录 密码学 01 密码基础进制与计量 02 加解密基操 替换 移位 编码 编码 置换 移位 加解密强度 03 对称加密算法(私钥) 工作过程 缺陷 对称加密算法列举&#xff1f; DES DES算法架构 DES分组加密公式 DES中ECB-CBC两种加密方式 3DES 由于DES密钥太短&#xf…...

w317汽车维修预约服务系统设计与实现

&#x1f64a;作者简介&#xff1a;多年一线开发工作经验&#xff0c;原创团队&#xff0c;分享技术代码帮助学生学习&#xff0c;独立完成自己的网站项目。 代码可以查看文章末尾⬇️联系方式获取&#xff0c;记得注明来意哦~&#x1f339;赠送计算机毕业设计600个选题excel文…...

云盘系统设计

需求背景 网盘面向大量C端用户 1000w用户 DAU 20% 每天10次 QPS: 1000w * 0.2 * 10 / 100k 500 峰值估计&#xff1a;500 * 5 2500 功能需求 支持上传&#xff0c;下载&#xff0c;多端共同在线编辑&#xff0c;数据冲突处理 非功能需求 1.latency 20s左右 2.可用性与…...

西电雨课堂《知识产权法》课后作业答案

目录 第 1 章 1.1 课后作业 1.2 课后作业 第 2 章 2.1 课后作业 2.2 课后作业 2.3 课后作业 2.4 课后作业 2.5 课后作业 2.6 课后作业 2.7 课后作业 2.8 课后作业 2.9 课后作业 2.10 课后作业 第 3 章 3.1 课后作业 3.2 课后作业 3.3 课后作业 3…...

通信协议记录仪-产品规格书

以下是为 ​​通信协议记录仪(ProtoLogger Pro)​​ 的​​详细产品规格书​​,覆盖 ​​技术细节、场景需求、竞品差异化​​,确保可作为产品开发、市场营销及竞品分析的核心依据。 ​​通信协议记录仪产品规格书​​ ​​产品名称​​:ProtoLogger Pro(中文名称:蹲守…...

订单系统冷热分离方案:优化性能与降低存储成本

随着时间推移&#xff0c;订单数据不断积累。在电商平台或者服务型应用中&#xff0c;订单数据是核心数据之一。然而&#xff0c;随着数据量的增长&#xff0c;如何高效存储、管理和查询这些数据成为了系统架构设计的重要问题。在大多数情况下&#xff0c;订单数据的处理不仅涉…...

数据结构学习笔记

第 1 章 绪论 【考纲内容】 &#xff08;一&#xff09;数据结构的基本概念 &#xff08;二&#xff09;算法的基本概念 算法的时间复杂度和空间复杂度 【知识框架】 【复习提示】 本章内容是数据结构概述&#xff0c;并不在考研大纲中。读者可通过对本章的学习&#xff0c;初步…...