Java 中間件Kafka 分區(qū)策略(自定義分區(qū)器實(shí)現(xiàn)負(fù)載均衡)
在現(xiàn)代分布式系統(tǒng)架構(gòu)中,Apache Kafka 作為高性能、高吞吐量的分布式消息中間件,已經(jīng)成為構(gòu)建實(shí)時(shí)數(shù)據(jù)管道和流式處理應(yīng)用的核心組件。Kafka 的分區(qū)(Partition)機(jī)制是其能夠?qū)崿F(xiàn)水平擴(kuò)展、并行處理以及高可用性的關(guān)鍵設(shè)計(jì)之一。而分區(qū)策略(Partitioning Strategy)——即決定每條消息應(yīng)被寫入哪個(gè)分區(qū)的邏輯——則直接影響著 Kafka 集群的負(fù)載均衡、吞吐性能和數(shù)據(jù)局部性。
本文將深入探討 Kafka 的分區(qū)機(jī)制,重點(diǎn)講解如何通過自定義分區(qū)器(Custom Partitioner)來實(shí)現(xiàn)更精細(xì)、更高效的負(fù)載均衡策略。我們將從基礎(chǔ)概念出發(fā),逐步過渡到實(shí)戰(zhàn)編碼,并結(jié)合實(shí)際場(chǎng)景分析不同策略的優(yōu)劣。文章包含完整的 Java 代碼示例、可運(yùn)行的配置說明,以及使用 Mermaid 繪制的架構(gòu)圖,幫助你全面掌握這一核心技能。
1. Kafka 分區(qū)機(jī)制基礎(chǔ) ??
1.1 什么是分區(qū)?
Kafka 的 Topic(主題)被劃分為多個(gè) Partition(分區(qū))。每個(gè)分區(qū)是一個(gè)有序、不可變的消息序列,存儲(chǔ)在 Kafka 集群的一個(gè)或多個(gè) Broker 上。分區(qū)是 Kafka 并行處理的基本單位:
- 生產(chǎn)者可以同時(shí)向多個(gè)分區(qū)寫入消息;
- 消費(fèi)者可以組成 Consumer Group,每個(gè)分區(qū)只能被組內(nèi)的一個(gè)消費(fèi)者消費(fèi),從而實(shí)現(xiàn)并行消費(fèi);
- 分區(qū)支持副本機(jī)制(Replication),提高容錯(cuò)能力。

上圖展示了
user-events主題被劃分為 3 個(gè)分區(qū),分別分布在不同的 Broker 上。
1.2 默認(rèn)分區(qū)策略
Kafka 提供了默認(rèn)的分區(qū)選擇邏輯,由 DefaultPartitioner 實(shí)現(xiàn)。其規(guī)則如下:
- 如果指定了
partition字段(顯式指定分區(qū)編號(hào))→ 直接使用該分區(qū); - 如果未指定分區(qū)但提供了
key→ 使用murmur2哈希算法對(duì) key 進(jìn)行哈希,然后對(duì)分區(qū)數(shù)取模,確保相同 key 的消息總是進(jìn)入同一分區(qū)(保證順序性); - 如果既無分區(qū)也無 key → 使用輪詢(Round-Robin)策略,均勻分配到所有可用分區(qū)。
這種策略在大多數(shù)場(chǎng)景下表現(xiàn)良好,但在某些特定業(yè)務(wù)需求下可能不夠靈活。例如:
- 某些 key 的消息量遠(yuǎn)大于其他 key,導(dǎo)致“熱點(diǎn)分區(qū)”;
- 需要根據(jù)消息內(nèi)容(如用戶 ID、地區(qū)、設(shè)備類型)進(jìn)行智能路由;
- 需要避開某些負(fù)載過高的分區(qū)以實(shí)現(xiàn)動(dòng)態(tài)負(fù)載均衡。
此時(shí),自定義分區(qū)器就成為必要手段。
2. 為什么需要自定義分區(qū)器???
雖然默認(rèn)分區(qū)器簡(jiǎn)單高效,但它無法滿足所有業(yè)務(wù)場(chǎng)景。以下是一些典型需求場(chǎng)景:
場(chǎng)景一:避免熱點(diǎn)分區(qū) ??
假設(shè)你的系統(tǒng)中有一個(gè) VIP 用戶(如 user_id=1001)產(chǎn)生了大量日志,而其他用戶流量正常。使用默認(rèn)分區(qū)器時(shí),所有 user_id=1001 的消息都會(huì)進(jìn)入同一個(gè)分區(qū),導(dǎo)致該分區(qū)所在的 Broker 負(fù)載飆升,而其他分區(qū)閑置。
這種“數(shù)據(jù)傾斜”問題會(huì)嚴(yán)重限制系統(tǒng)的整體吞吐能力。
場(chǎng)景二:按業(yè)務(wù)維度分片 ???
你希望將來自不同地區(qū)的用戶數(shù)據(jù)寫入不同的分區(qū),以便后續(xù)按地區(qū)進(jìn)行獨(dú)立處理(如區(qū)域化分析、合規(guī)存儲(chǔ)等)。例如:
- 華北用戶 → 分區(qū) 0
- 華東用戶 → 分區(qū) 1
- 華南用戶 → 分區(qū) 2
默認(rèn)分區(qū)器無法實(shí)現(xiàn)這種語義化路由。
場(chǎng)景三:動(dòng)態(tài)負(fù)載感知 ??
在集群運(yùn)行過程中,某些 Broker 可能因硬件故障或網(wǎng)絡(luò)問題導(dǎo)致負(fù)載升高。理想情況下,分區(qū)器應(yīng)能感知這些狀態(tài),將新消息路由到負(fù)載較低的分區(qū)。
雖然 Kafka 本身不提供實(shí)時(shí)負(fù)載指標(biāo),但你可以結(jié)合外部監(jiān)控系統(tǒng)(如 Prometheus + JMX)實(shí)現(xiàn)智能路由。
3. Kafka 分區(qū)器接口詳解 ???
Kafka 允許用戶通過實(shí)現(xiàn) org.apache.kafka.clients.producer.Partitioner 接口來自定義分區(qū)邏輯。該接口定義如下:
public interface Partitioner extends Configurable, Closeable {
int partition(String topic, Object key, byte[] keyBytes,
Object value, byte[] valueBytes, Cluster cluster);
void close();
void configure(Map<String, ?> configs);
}核心方法說明:
partition(...):核心方法,返回消息應(yīng)寫入的分區(qū)索引(從 0 開始)。topic:目標(biāo)主題名稱;key/keyBytes:消息的 key(對(duì)象或字節(jié)數(shù)組);value/valueBytes:消息的 value;cluster:當(dāng)前 Kafka 集群的元數(shù)據(jù),包含所有 Topic、Partition、Broker 信息。
configure(...):初始化時(shí)調(diào)用,可用于讀取配置參數(shù);close():關(guān)閉資源,如線程池、連接等。
?? 注意:
partition()方法必須是線程安全的,因?yàn)樯a(chǎn)者內(nèi)部會(huì)多線程調(diào)用它。
4. 實(shí)戰(zhàn):實(shí)現(xiàn)一個(gè)簡(jiǎn)單的自定義分區(qū)器 ??
我們先從一個(gè)最簡(jiǎn)單的例子開始:基于用戶 ID 的哈希分區(qū)器,但增加對(duì) VIP 用戶的特殊處理。
4.1 項(xiàng)目依賴
確保你的 Maven 項(xiàng)目包含 Kafka 客戶端依賴(以 Kafka 3.x 為例):
<dependency>
<groupId>org.apache.kafka</groupId>
<artifactId>kafka-clients</artifactId>
<version>3.6.0</version>
</dependency>4.2 自定義分區(qū)器代碼
import org.apache.kafka.clients.producer.Partitioner;
import org.apache.kafka.common.Cluster;
import org.apache.kafka.common.PartitionInfo;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public class UserIdPartitioner implements Partitioner {
// VIP 用戶列表(可從配置或數(shù)據(jù)庫(kù)加載)
private static final Set<String> VIP_USERS = Set.of("1001", "2005", "9999");
// 緩存 VIP 用戶的專屬分區(qū),避免頻繁計(jì)算
private final Map<String, Integer> vipPartitionCache = new ConcurrentHashMap<>();
@Override
public void configure(Map<String, ?> configs) {
// 可在此處讀取自定義配置,如 VIP 列表、分區(qū)偏移量等
System.out.println("UserIdPartitioner configured.");
}
@Override
public int partition(String topic, Object key, byte[] keyBytes,
Object value, byte[] valueBytes, Cluster cluster) {
// 獲取該 topic 的所有分區(qū)信息
List<PartitionInfo> partitions = cluster.partitionsForTopic(topic);
int numPartitions = partitions.size();
if (key == null) {
// 無 key 時(shí),使用輪詢(簡(jiǎn)化版)
return Math.abs(key.hashCode()) % numPartitions;
}
String userId = key.toString();
if (VIP_USERS.contains(userId)) {
// VIP 用戶:固定分配到前 N 個(gè)分區(qū)(例如前 2 個(gè))
// 為每個(gè) VIP 用戶分配唯一分區(qū),避免沖突
return vipPartitionCache.computeIfAbsent(userId, k -> {
int index = VIP_USERS.stream().toList().indexOf(k);
return index % Math.min(2, numPartitions); // 最多使用 2 個(gè)分區(qū)
});
} else {
// 普通用戶:使用標(biāo)準(zhǔn)哈希
return Math.abs(userId.hashCode()) % numPartitions;
}
}
@Override
public void close() {
vipPartitionCache.clear();
System.out.println("UserIdPartitioner closed.");
}
}4.3 配置生產(chǎn)者使用自定義分區(qū)器
Properties props = new Properties();
props.put("bootstrap.servers", "localhost:9092");
props.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer");
props.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer");
// 關(guān)鍵配置:指定自定義分區(qū)器
props.put("partitioner.class", "com.example.UserIdPartitioner");
KafkaProducer<String, String> producer = new KafkaProducer<>(props);
// 發(fā)送消息
producer.send(new ProducerRecord<>("user-events", "1001", "VIP login"));
producer.send(new ProducerRecord<>("user-events", "5001", "Normal user action"));? 運(yùn)行后,
user_id=1001的消息將始終進(jìn)入分區(qū) 0 或 1(取決于 VIP 列表順序),而普通用戶按哈希分布。
5. 高級(jí)自定義分區(qū)器:實(shí)現(xiàn)動(dòng)態(tài)負(fù)載均衡 ??
前面的例子解決了熱點(diǎn)問題,但仍是靜態(tài)策略。現(xiàn)在我們嘗試實(shí)現(xiàn)一個(gè)基于分區(qū)當(dāng)前負(fù)載的動(dòng)態(tài)分區(qū)器。
5.1 思路設(shè)計(jì)
由于 Kafka 客戶端無法直接獲取分區(qū)的實(shí)時(shí)負(fù)載(如消息速率、磁盤 IO),我們需要借助外部系統(tǒng)。一種可行方案是:
- 使用 JMX 指標(biāo)(如
kafka.log:type=LogFlushStats,name=LogFlushRateAndTimeMs)監(jiān)控各分區(qū)寫入速率; - 通過 Prometheus + JMX Exporter 暴露指標(biāo);
- 在分區(qū)器中定期拉取這些指標(biāo),選擇負(fù)載最低的分區(qū)。
?? 參考:Kafka Monitoring with Prometheus(官方指南)
5.2 簡(jiǎn)化版:基于分區(qū)消息計(jì)數(shù)的模擬負(fù)載
為便于演示,我們假設(shè)“負(fù)載”等于該分區(qū)已接收的消息數(shù)量(實(shí)際中不可行,僅用于示例)。
public class LoadAwarePartitioner implements Partitioner {
private final Map<Integer, Long> partitionLoad = new ConcurrentHashMap<>();
private final Random random = new Random();
@Override
public void configure(Map<String, ?> configs) {}
@Override
public int partition(String topic, Object key, byte[] keyBytes,
Object value, byte[] valueBytes, Cluster cluster) {
List<PartitionInfo> partitions = cluster.partitionsForTopic(topic);
int numPartitions = partitions.size();
if (key == null) {
// 無 key:選擇負(fù)載最低的分區(qū)
return findLeastLoadedPartition(numPartitions);
}
// 有 key:仍需保證相同 key 進(jìn)同一分區(qū)(順序性)
// 但我們可以記錄該分區(qū)的負(fù)載
int targetPartition = Math.abs(key.hashCode()) % numPartitions;
updateLoad(targetPartition);
return targetPartition;
}
private int findLeastLoadedPartition(int numPartitions) {
long minLoad = Long.MAX_VALUE;
int bestPartition = 0;
for (int i = 0; i < numPartitions; i++) {
long load = partitionLoad.getOrDefault(i, 0L);
if (load < minLoad) {
minLoad = load;
bestPartition = i;
}
}
// 更新負(fù)載(模擬)
updateLoad(bestPartition);
return bestPartition;
}
private void updateLoad(int partition) {
partitionLoad.compute(partition, (k, v) -> (v == null) ? 1L : v + 1);
}
@Override
public void close() {
partitionLoad.clear();
}
}?? 注意:此實(shí)現(xiàn)僅用于教學(xué)!真實(shí)系統(tǒng)中,
partitionLoad應(yīng)從外部監(jiān)控系統(tǒng)獲取,且需考慮線程安全、緩存過期等問題。
6. 分區(qū)策略與消息順序性的權(quán)衡 ??
在設(shè)計(jì)自定義分區(qū)器時(shí),必須明確一個(gè)核心原則:
Kafka 僅保證單個(gè)分區(qū)內(nèi)的消息順序性,不保證跨分區(qū)的全局順序。
因此,如果你的業(yè)務(wù)要求“同一用戶的所有操作必須嚴(yán)格按序處理”,那么所有該用戶的消息必須進(jìn)入同一分區(qū)。此時(shí),分區(qū)器必須基于用戶 ID(或其他唯一標(biāo)識(shí))進(jìn)行確定性路由。
錯(cuò)誤示例:破壞順序性
// ? 錯(cuò)誤!相同 key 可能進(jìn)入不同分區(qū)
public int partition(...) {
if (isVip(key)) {
return random.nextInt(numPartitions); // 隨機(jī)分配 VIP
}
return hash(key) % numPartitions;
}上述代碼會(huì)導(dǎo)致 VIP 用戶的消息亂序,可能引發(fā)狀態(tài)不一致問題(如“先扣款后下單”變成“先下單后扣款”)。
正確做法:保留 key 的確定性
// ? 正確:相同 key 始終進(jìn)入同一分區(qū)
public int partition(...) {
if (isVip(key)) {
// 所有 VIP 用戶進(jìn)入分區(qū) 0
return 0;
}
return hash(key) % numPartitions;
}即使 VIP 用戶集中在一個(gè)分區(qū),也保證了其內(nèi)部順序。
7. 性能考量與最佳實(shí)踐 ??
自定義分區(qū)器雖強(qiáng)大,但也需注意性能影響:
7.1 避免復(fù)雜計(jì)算
partition() 方法在每次發(fā)送消息時(shí)都會(huì)被調(diào)用,因此必須高效。避免:
- 數(shù)據(jù)庫(kù)查詢;
- 網(wǎng)絡(luò)請(qǐng)求;
- 復(fù)雜正則匹配;
- 未緩存的反射調(diào)用。
? 建議:
- 預(yù)加載配置到內(nèi)存;
- 使用緩存(如
ConcurrentHashMap); - 優(yōu)先使用
keyBytes而非反序列化key。
7.2 線程安全
分區(qū)器實(shí)例會(huì)被多個(gè)生產(chǎn)者線程共享,所有狀態(tài)變量必須線程安全。
// ? 使用 ConcurrentHashMap private final Map<String, Integer> cache = new ConcurrentHashMap<>(); // ? 非線程安全 private Map<String, Integer> cache = new HashMap<>();
7.3 分區(qū)數(shù)量變化的處理
當(dāng) Topic 的分區(qū)數(shù)增加時(shí),原有 key 的分區(qū)映射可能改變,導(dǎo)致:
- 消息不再進(jìn)入原分區(qū);
- 消費(fèi)者可能重復(fù)消費(fèi)或丟失消息。
?? Kafka 官方建議:分區(qū)數(shù)一旦設(shè)定,盡量不要減少。增加分區(qū)需謹(jǐn)慎評(píng)估。
7.4 測(cè)試你的分區(qū)器
編寫單元測(cè)試驗(yàn)證分區(qū)邏輯:
@Test
public void testVipUserRouting() {
UserIdPartitioner partitioner = new UserIdPartitioner();
partitioner.configure(Collections.emptyMap());
Cluster cluster = mockClusterWithPartitions(4); // 模擬 4 分區(qū)集群
int p1 = partitioner.partition("test", "1001", null, null, null, cluster);
int p2 = partitioner.partition("test", "1001", null, null, null, cluster);
assertEquals(p1, p2); // 同一 VIP 應(yīng)進(jìn)入同一分區(qū)
assertTrue(p1 < 2); // 且應(yīng)在前 2 個(gè)分區(qū)
}8. 實(shí)際案例:電商訂單系統(tǒng)的分區(qū)策略 ??
假設(shè)你正在構(gòu)建一個(gè)電商系統(tǒng),訂單消息包含:
{
"order_id": "O12345",
"user_id": "U789",
"region": "CN-EAST",
"amount": 299.99
}業(yè)務(wù)需求:
- 同一用戶的訂單必須按序處理(防止超賣);
- 華東地區(qū)訂單量大,需更多分區(qū)處理;
- 避免單個(gè)分區(qū)成為瓶頸。
解決方案:
- Key 設(shè)計(jì):使用
user_id作為消息 key; - 自定義分區(qū)器:根據(jù)
region和user_id聯(lián)合路由。
public class RegionAwareOrderPartitioner implements Partitioner {
private static final Map<String, Integer> REGION_PARTITION_OFFSET = Map.of(
"CN-EAST", 0,
"CN-NORTH", 2,
"CN-SOUTH", 4
);
private static final int PARTITIONS_PER_REGION = 2;
@Override
public int partition(String topic, Object key, byte[] keyBytes,
Object value, byte[] valueBytes, Cluster cluster) {
// 假設(shè) value 是 JSON 字符串
String jsonValue = (String) value;
String region = extractRegionFromJson(jsonValue); // 解析 region
int basePartition = REGION_PARTITION_OFFSET.getOrDefault(region, 0);
int totalPartitions = cluster.partitionsForTopic(topic).size();
// 計(jì)算該 region 的可用分區(qū)范圍
int start = basePartition;
int end = Math.min(basePartition + PARTITIONS_PER_REGION, totalPartitions);
if (start >= totalPartitions) {
// fallback to default
return Math.abs(key.hashCode()) % totalPartitions;
}
// 在 region 內(nèi)部按 user_id 哈希
int userHash = Math.abs(key.hashCode());
int regionPartition = start + (userHash % (end - start));
return regionPartition;
}
private String extractRegionFromJson(String json) {
// 簡(jiǎn)化:實(shí)際應(yīng)使用 JSON 解析庫(kù)
int start = json.indexOf("\"region\":\"") + 11;
int end = json.indexOf("\"", start);
return json.substring(start, end);
}
@Override
public void configure(Map<String, ?> configs) {}
@Override
public void close() {}
}分區(qū)布局示意:
渲染錯(cuò)誤: Mermaid 渲染失敗: Parsing failed: unexpected character: ->“<- at offset: 29, skipped 6 characters. unexpected character: ->:<- at offset: 36, skipped 1 characters. unexpected character: ->“<- at offset: 44, skipped 6 characters. unexpected character: ->:<- at offset: 51, skipped 1 characters. unexpected character: ->“<- at offset: 59, skipped 6 characters. unexpected character: ->:<- at offset: 66, skipped 1 characters. Expecting token of type 'EOF' but found `2`. Expecting token of type 'EOF' but found `2`. Expecting token of type 'EOF' but found `2`.
通過這種方式,華東的高流量被隔離在分區(qū) 0-1,不會(huì)影響其他區(qū)域;同時(shí)同一用戶的消息仍在同一分區(qū)內(nèi),保證順序。
9. 常見陷阱與調(diào)試技巧 ???♂?
9.1 分區(qū)器未生效?
檢查以下幾點(diǎn):
partitioner.class配置是否正確(全限定類名);- 類是否在 classpath 中;
- 是否不小心指定了
ProducerRecord的partition參數(shù)(會(huì)覆蓋分區(qū)器)。
9.2 消息分布不均?
使用 Kafka 自帶工具查看分區(qū)偏移量:
kafka-run-class.sh kafka.tools.GetOffsetShell \ --broker-list localhost:9092 \ --topic user-events
輸出示例:
user-events:0:15000 user-events:1:5000 user-events:2:5000
分區(qū) 0 明顯偏高,可能存在熱點(diǎn) key。
9.3 如何監(jiān)控分區(qū)器性能?
- 在
partition()方法中添加微基準(zhǔn)測(cè)試(如System.nanoTime()); - 使用 APM 工具(如 SkyWalking、Pinpoint)追蹤生產(chǎn)者調(diào)用鏈;
- 日志記錄關(guān)鍵決策(如“VIP user routed to partition 0”)。
10. 擴(kuò)展閱讀與資源 ??
- Apache Kafka 官方文檔 - Partitioning
- 官方對(duì)分區(qū)器的詳細(xì)說明,包括配置參數(shù)和行為定義。
- Kafka: The Definitive Guide
- 由 Confluent 團(tuán)隊(duì)編寫的權(quán)威指南,第 3 章深入講解分區(qū)與復(fù)制機(jī)制。
- Understanding Kafka Partitioning
- Baeldung 的高質(zhì)量教程,包含代碼示例和圖解。
結(jié)語 ??
Kafka 的分區(qū)策略是連接業(yè)務(wù)邏輯與底層基礎(chǔ)設(shè)施的關(guān)鍵橋梁。通過自定義分區(qū)器,我們不僅能解決默認(rèn)策略的局限性,還能實(shí)現(xiàn)精細(xì)化的流量調(diào)度、熱點(diǎn)隔離和區(qū)域化處理。然而,強(qiáng)大的能力也伴隨著責(zé)任——必須謹(jǐn)慎權(quán)衡順序性、負(fù)載均衡與系統(tǒng)復(fù)雜度。
在實(shí)際項(xiàng)目中,建議:
- 先用默認(rèn)分區(qū)器,僅在出現(xiàn)性能瓶頸或業(yè)務(wù)需求時(shí)才自定義;
- 充分測(cè)試分區(qū)邏輯,尤其是邊界條件和并發(fā)場(chǎng)景;
- 監(jiān)控分區(qū)分布,及時(shí)發(fā)現(xiàn)數(shù)據(jù)傾斜;
- 保持簡(jiǎn)單,避免過度工程化。
希望本文能為你在 Kafka 分區(qū)策略的設(shè)計(jì)與實(shí)現(xiàn)上提供清晰的思路和實(shí)用的代碼參考。Happy coding! ??
到此這篇關(guān)于Java 中間件Kafka 分區(qū)策略(自定義分區(qū)器實(shí)現(xiàn)負(fù)載均衡)的文章就介紹到這了,更多相關(guān)Java Kafka 分區(qū)策略內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
使用?Spring?Boot?Admin?監(jiān)控應(yīng)用狀態(tài)的詳細(xì)過程
這篇文章主要介紹了使用?Spring?Boot?Admin?監(jiān)控應(yīng)用狀態(tài),該模塊采集應(yīng)用的內(nèi)部信息,并暴露給外部的模塊,支持?HTTP?和?JMX,并可以與一些第三方監(jiān)控系統(tǒng)(如?Prometheus)整合,需要的朋友可以參考下2022-09-09
SpringBoot用JdbcTemplates訪問Mysql實(shí)例代碼
本篇文章主要介紹了SpringBoot用JdbcTemplates訪問Mysql實(shí)例代碼,非常具有實(shí)用價(jià)值,需要的朋友可以參考下2017-05-05
Springboot MongoDB實(shí)現(xiàn)自增序列的項(xiàng)目實(shí)踐
在某些特定的業(yè)務(wù)場(chǎng)景下,會(huì)需要使用自增的序列來維護(hù)數(shù)據(jù),本文主要介紹了Springboot MongoDB實(shí)現(xiàn)自增序列的項(xiàng)目實(shí)踐,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-07-07
Java MD5加密工具類的方法(支持多參數(shù)輸入)
在實(shí)際開發(fā)過程中,MD5加密是一種常見的數(shù)據(jù)安全處理手段,常用于密碼存儲(chǔ)、數(shù)據(jù)完整性校驗(yàn)等場(chǎng)景,這篇文章主要介紹了Java MD5加密工具類(支持多參數(shù)輸入),需要的朋友可以參考下2024-05-05
SpringCloud與Consul集成實(shí)現(xiàn)負(fù)載均衡功能
負(fù)載均衡基本概念有:實(shí)服務(wù)、實(shí)服務(wù)組、虛服務(wù)、調(diào)度算法、持續(xù)性等,其常用應(yīng)用場(chǎng)景主要是服務(wù)器負(fù)載均衡,鏈路負(fù)載均衡。這篇文章主要介紹了SpringCloud與Consul集成實(shí)現(xiàn)負(fù)載均衡 ,需要的朋友可以參考下2018-09-09
Java?LocalTime的常用時(shí)間操作總結(jié)
日常開發(fā)中,?我們會(huì)經(jīng)常遇到時(shí)間的運(yùn)算,?操作,?格式化等,?這篇文章主要為大家詳細(xì)介紹了LocalTime的常用時(shí)間操作,感興趣的小伙伴可以了解一下2023-11-11

