kafka學習筆記(三、消費者Consumer使用教程——使用實例及及核心流程源碼講解)

在這里插入圖片描述


1.核心概念與架構

1.1.消費者與消費者組

Kafka消費者是訂閱主題(Topic)并拉取消息的客戶端實例,其核心邏輯通過KafkaConsumer類實現。消費者組(Consumer Group)是由多個邏輯關聯的消費者組成的集合

  1. 核心規則
  • 同一分區獨占性: 一個分區(Partition)只能被同一消費者組內的一個消費者消費,但不同消費者組可同時消費同一分區,實現廣播模式。

  • 負載均衡與容錯: 通過動態分區分配(Rebalance)實現消費者增減時的負載均衡,支持水平擴展和容錯恢復。

  1. 消息投遞模式
  • 點對點模式: 所有消費者屬于同一組,消息被均勻分配給組內消費者,每條消息僅被消費一次。

  • 發布/訂閱模式: 消費者屬于不同組,消息廣播到所有組,每個組獨立消費全量數據。

消費者與消費者組的這種模式可以讓整體的消費能力具備橫向伸縮性,可以增加或減少消費者的個數來提高或降低整體的消費能力。注:消費者個數不能大于分區數。

1.2.核心類與組件

類名作用
KafkaConsumer消費者入口類,封裝所有消費邏輯(線程不安全,需單線程操作)
ConsumerNetworkClient網絡通信層,管理與 Broker 的 TCP 連接和請求發送/接收
Fetcher消息拉取核心邏輯,處理消息批次、反序列化、異常重試
SubscriptionState維護訂閱狀態(主題、分區分配、消費偏移量等)
ConsumerCoordinator消費者協調器,負責消費者組管理、心跳發送、分區再平衡(Rebalance)
Deserializer反序列化器接口,將字節數組轉換為 Java 對象

2.基礎消費者示例

import org.apache.kafka.clients.consumer.*;
import org.apache.kafka.common.TopicPartition;
import org.apache.kafka.common.serialization.StringDeserializer;
import java.time.Duration;
import java.util.Collections;
import java.util.Properties;public class BasicKafkaConsumer {public static void main(String[] args) {// 1. 配置消費者屬性Properties props = new Properties();props.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, "localhost:9092");props.put(ConsumerConfig.GROUP_ID_CONFIG, "test-group"); // 消費者組IDprops.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class.getName());props.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class.getName());props.put(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, "earliest"); // 當無提交offset時,從最早的消息開始props.put(ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG, "true"); // 自動提交偏移量props.put(ConsumerConfig.AUTO_COMMIT_INTERVAL_MS_CONFIG, "1000"); // 每秒自動提交// 2. 創建消費者實例try (KafkaConsumer<String, String> consumer = new KafkaConsumer<>(props)) {// 3. 訂閱主題(支持多個主題和正則表達式)consumer.subscribe(Collections.singletonList("test-topic"));// 4. 持續拉取消息while (true) {// poll()參數為等待時間(毫秒),返回消息集合ConsumerRecords<String, String> records = consumer.poll(Duration.ofMillis(100));for (ConsumerRecord<String, String> record : records) {// 處理消息System.out.printf("Received message: topic=%s, partition=%d, offset=%d, key=%s, value=%s%n",record.topic(),record.partition(),record.offset(),record.key(),record.value());}}}}
}

3.源碼及核心功能解析

3.1.訂閱主題和分區

3.1.1. 訂閱主題

在上面#2中的代碼實例中的注釋2中,使用subscribe()方法訂閱了一個主題。消費者通過 subscribe() 方法訂閱一個或多個主題,Kafka會自動將主題的分區分配給消費者組內的各個消費者。這是最常見的消費方式,適用于動態分區分配場景。

核心特點:

  • 自動負載均衡: 消費者組內的消費者會分攤主題的分區(例如:3個分區被2個消費者分配為2+1)。
  • 支持分區再平衡(Rebalance): 當消費者加入或離開組時,Kafka會自動重新分配分區。
  • 依賴消費者組(Group ID): 通過 group.id 標識消費者組,同一組的消費者共享分區。

代碼實例:

// 訂閱單個主題
consumer.subscribe(Collections.singletonList("test-topic"));// 訂閱多個主題
consumer.subscribe(Arrays.asList("topic1", "topic2"));// 使用正則表達式訂閱(匹配所有以 "logs-" 開頭的主題)
consumer.subscribe(Pattern.compile("logs-.*"));

適用場景:

  • 需要動態擴展消費者數量(水平擴展)。
  • 分區數量固定或動態變化時(如新增分區)。
  • 消費者需要自動故障恢復(如某個消費者宕機,其他消費者接管分區)。

分區分配策略:
通過 partition.assignment.strategy 配置:

  • RangeAssignor(默認): 按范圍分配分區(可能導致不均衡)。

  • RoundRobinAssignor: 輪詢分配分區(更均衡)。

  • StickyAssignor: 盡量保持分配粘性,減少Rebalance時的分區變動。

3.1.2.直接訂閱分區

消費者通過 assign() 方法直接指定要消費的分區,繞過消費者組管理,需手動管理分區偏移量。

核心特點:

  • 無消費者組協調: 不依賴 group.id,消費者獨立運行。
  • 完全手動控制: 需自行指定分區和起始偏移量。
  • 不支持自動再平衡: 分區增減或消費者故障時需手動處理。

代碼示例:

// 分配指定主題的特定分區
TopicPartition partition0 = new TopicPartition("test-topic", 0);
TopicPartition partition1 = new TopicPartition("test-topic", 1);
consumer.assign(Arrays.asList(partition0, partition1));// 指定從某個offset開始消費
consumer.seek(partition0, 100); // 從offset=100開始
consumer.seekToBeginning(Collections.singleton(partition1)); // 從最早開始
consumer.seekToEnd(Collections.singleton(partition1)); // 從最新開始

適用場景:

  • 需要精確控制消費特定分區(如按業務邏輯分區)。
  • 消費者組管理不適用時(如單消費者消費所有分區)。
  • 測試或調試場景下手動控制消費位置。

3.1.3.取消訂閱

適用KafkaConsumer中的unsubscribe()方法來取消主題和分區的訂閱。
代碼實例:

consumer.unsubscribe()

如果將subscribe(Collection)assign(Collection)中的集合參數設置為空集合,那么作用與unsubscribe()等同。

3.2.消息拉取

poll() 方法是消息消費的核心入口,其內部實現涉及 網絡通信消息批量拉取分區狀態管理反序列化位移提交 等多個關鍵步驟。以下從源碼層面逐層解析 poll() 方法的完整流程:

3.2.1.poll()方法源碼解析

// KafkaConsumer.poll() 方法定義
public ConsumerRecords<K, V> poll(Duration timeout) {// 1. 檢查線程安全性(確保單線程調用)acquireAndEnsureOpen();try {// 2. 記錄開始時間(用于超時控制)long startMs = time.milliseconds();long remainingMs = timeout.toMillis();// 3. 主循環:處理消息拉取、心跳、Rebalance 等do {// 3.1 發送心跳(維持消費者組活性)coordinator.poll(timeRemaining(remainingMs, startMs));// 3.2 拉取消息(核心邏輯在 Fetcher 中)Map<TopicPartition, List<ConsumerRecord<K, V>>> records = fetcher.fetchedRecords();if (!records.isEmpty()) {// 3.3 返回拉取到的消息(退出循環)return new ConsumerRecords<>(records);}// 3.4 計算剩余等待時間remainingMs = timeRemaining(remainingMs, startMs);} while (remainingMs > 0);return ConsumerRecords.empty();} finally {release();}
}

3.2.2.核心子流程解析

  1. 發送心跳(coordinator.poll()
    消費者通過 ConsumerCoordinator 維持與 GroupCoordinator 的心跳,確保消費者組活性。

    關鍵源碼路徑:
    ConsumerCoordinator.poll()pollHeartbeat()sendHeartbeatRequest()

    // ConsumerCoordinator.poll() 核心邏輯
    public void poll(long timeoutMs) {// 1. 處理未完成的異步請求(如心跳、JoinGroup 等)client.poll(timeoutMs, time.milliseconds(), new PollCondition() {@Overridepublic boolean shouldBlock() {return !coordinatorUnknown(); // 是否等待響應}});// 2. 檢查是否需要觸發 Rebalanceif (needRejoin()) {joinGroupIfNeeded(); // 觸發 Rebalance}// 3. 周期性發送心跳pollHeartbeat(time.milliseconds());
    }
    

    心跳機制:

    • 心跳間隔:heartbeat.interval.ms 控制(默認 3 秒)。

    • 會話超時:session.timeout.ms 控制(默認 10 秒)。若超時未心跳,消費者被踢出組。

  2. 消息拉取(fetcher.fetchedRecords()
    Fetcher 負責從 Broker 拉取消息并解析。其內部維護一個 completedFetches 隊列緩存已拉取但未處理的消息批次。

    源碼路徑:
    Fetcher.fetchedRecords()parseCompletedFetches()parseRecord()deserializeRecord()

    // Fetcher.fetchedRecords() 核心邏輯
    public Map<TopicPartition, List<ConsumerRecord<K, V>>> fetchedRecords() {Map<TopicPartition, List<ConsumerRecord<K, V>>> drainedRecords = new HashMap<>();int recordsRemaining = maxPollRecords; // 單次 poll 最大記錄數(默認 500)// 1. 遍歷已完成的拉取請求(completedFetches)while (recordsRemaining > 0 && !completedFetches.isEmpty()) {CompletedFetch completedFetch = completedFetches.peek();// 2. 解析消息批次(MemoryRecords → RecordBatch)MemoryRecords records = completedFetch.records();for (RecordBatch batch : records.batches()) {// 3. 遍歷批次內的每條消息for (Record record : batch) {// 4. 反序列化消息(調用 Deserializer)K key = keyDeserializer.deserialize(record.topic(), record.key());V value = valueDeserializer.deserialize(record.topic(), record.value());// 5. 構建 ConsumerRecordConsumerRecord<K, V> consumerRecord = new ConsumerRecord<>(record.topic(),record.partition(),record.offset(),record.timestamp(),TimestampType.forCode(record.timestampType()),record.serializedKeySize(),record.serializedValueSize(),key,value,record.headers(),record.leaderEpoch());// 6. 按分區緩存消息drainedRecords.computeIfAbsent(partition, p -> new ArrayList<>()).add(consumerRecord);recordsRemaining--;}}completedFetches.poll();}return drainedRecords;
    }
    

    關鍵設計:

    • 批量拉取: Kafka 按批次(RecordBatch)拉取消息,減少網絡開銷。
    • 零拷貝優化: MemoryRecords 直接操作 ByteBuffer,避免內存復制。
    • 反序列化延遲: 反序列化在消息實際被消費時進行(而非拉取時)。
  3. 位移提交(maybeAutoCommitOffsetsAsync()
    若啟用自動提交(enable.auto.commit=true),消費者會在 poll() 后異步提交位移。

    源碼路徑:
    KafkaConsumer.maybeAutoCommitOffsetsAsync()commitOffsetsAsync()

    // KafkaConsumer 自動提交邏輯
    private void maybeAutoCommitOffsetsAsync() {if (autoCommitEnabled) {// 1. 計算距離上次提交的時間間隔long now = time.milliseconds();if (now - lastAutoCommitTime >= autoCommitIntervalMs) {// 2. 提交所有分區的位移commitOffsetsAsync(subscriptions.allConsumed());lastAutoCommitTime = now;}}
    }// 異步提交位移
    private void commitOffsetsAsync(final Map<TopicPartition, OffsetAndMetadata> offsets) {coordinator.commitOffsetsAsync(offsets, new OffsetCommitCallback() {@Overridepublic void onComplete(Map<TopicPartition, OffsetAndMetadata> offsets, Exception exception) {if (exception != null) {log.error("Async auto-commit failed", exception);}}});
    }
    

    自動提交配置:

    • 提交間隔:auto.commit.interval.ms 控制(默認 5 秒)。

    • 提交內容: 提交所有已消費分區的 offset + 1(確保至少一次語義)。

3.2.3.網絡通信

所有網絡請求(拉取消息、心跳、位移提交)由 ConsumerNetworkClient 管理,其核心機制為 異步請求-響應模型

  1. 請求發送

    // ConsumerNetworkClient.send() 方法
    public RequestFuture<ClientResponse> send(Node node,AbstractRequest.Builder<?> requestBuilder,long timeoutMs
    ) {// 1. 構建請求對象long now = time.milliseconds();ClientRequest clientRequest = client.newClientRequest(node.idString(),requestBuilder,now,true,timeoutMs,null);// 2. 將請求加入隊列(非阻塞)unsent.put(node, clientRequest);return clientRequest.future();
    }
    
  2. 響應處理

    // ConsumerNetworkClient.poll() 方法
    public void poll(long timeout, long now, PollCondition pollCondition) {// 1. 發送所有未完成的請求sendAllRequests();// 2. 輪詢網絡通道(Selector),接收響應client.poll(timeout, now, new PollCondition() {@Overridepublic boolean shouldBlock() {return pollCondition.shouldBlock() || hasPendingRequests();}});// 3. 處理已完成的響應handleCompletedSends();handleCompletedReceives();handleDisconnections();handleConnections();handleTimedOutRequests();
    }
    

    關鍵機制:

    • 請求隊列: unsent 緩存待發送的請求。

    • 響應回調: 每個請求關聯一個 RequestFuture ,在響應到達時觸發回調。

3.3.反序列化

3.3.1.核心接口

Kafka 的反序列化通過 org.apache.kafka.common.serialization.Deserializer 接口實現,所有反序列化器必須實現該接口。

接口定義:

public interface Deserializer<T> extends Closeable {// 配置反序列化器(從消費者配置中讀取參數)void configure(Map<String, ?> configs, boolean isKey);// 核心反序列化方法T deserialize(String topic, byte[] data);// 反序列化方法(帶Headers)default T deserialize(String topic, Headers headers, byte[] data) {return deserialize(topic, data);}// 關閉資源@Overridevoid close();
}

3.3.2.源碼級執行流程

  1. 消費者初始化階段
    當創建 KafkaConsumer 時,會通過 ConsumerConfig 加載配置,并初始化 key.deserializervalue.deserializer

    關鍵源碼路徑:
    KafkaConsumer#initialize()ConsumerConfig#getConfiguredInstance()

    // 源碼片段:ConsumerConfig.java
    public static <T> T getConfiguredInstance(String key, Class<T> t) {String className = getString(key);try {Class<?> c = Class.forName(className, true, Utils.getContextOrKafkaClassLoader());return Utils.newInstance(c, t); // 反射創建實例} catch (ClassNotFoundException e) {// 處理異常...}
    }// KafkaConsumer 構造函數中初始化反序列化器
    this.keyDeserializer = config.getConfiguredInstance(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, Deserializer.class);
    this.valueDeserializer = config.getConfiguredInstance(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, Deserializer.class);// 調用 configure() 方法
    Map<String, Object> configs = config.originals();
    this.keyDeserializer.configure(configs, true);   // 標記為 key 反序列化器
    this.valueDeserializer.configure(configs, false); // 標記為 value 反序列化器
  2. 消息拉取與反序列化
    當調用 poll() 方法拉取消息后,Kafka 會遍歷每條消息,使用反序列化器將字節數組轉換為 Java 對象。

    關鍵源碼路徑:
    KafkaConsumer#poll()Fetcher#parseRecord()ConsumerRecord#toRecord()

    // 源碼片段:ConsumerRecord.java
    public static <K, V> ConsumerRecord<K, V> toRecord(/* 參數省略 */) {// 反序列化 KeyK key = keyDeserializer != null ? keyDeserializer.deserialize(topic, headers, keyBytes) : null;// 反序列化 ValueV value = valueDeserializer != null ? valueDeserializer.deserialize(topic, headers, valueBytes) : null;return new ConsumerRecord<>(topic, partition, offset, timestamp, timestampType,key, value, headers, leaderEpoch);
    }
  3. 線程安全與生命周期

    • 線程安全: 每個 KafkaConsumer 實例持有獨立的反序列化器實例,因此反序列化器無需考慮線程安全。

    • 生命周期: 反序列化器的 close() 方法在消費者關閉時被調用。

3.3.3.自定義反序列化器實現

  1. 實現 Deserializer 接口
    假設需要反序列化 JSON 數據:
    public class JsonDeserializer<T> implements Deserializer<T> {private ObjectMapper objectMapper = new ObjectMapper();private Class<T> targetType;@Overridepublic void configure(Map<String, ?> configs, boolean isKey) {// 從配置中獲取目標類型(如 User.class)String configKey = isKey ? "key.type" : "value.type";String typeName = (String) configs.get(configKey);try {this.targetType = (Class<T>) Class.forName(typeName);} catch (ClassNotFoundException e) {throw new KafkaException("Class not found: " + typeName, e);}}@Overridepublic T deserialize(String topic, byte[] data) {if (data == null) return null;try {return objectMapper.readValue(data, targetType);} catch (IOException e) {throw new SerializationException("Error deserializing JSON", e);}}@Overridepublic void close() {// 清理資源(可選)}
    }
    
  2. 消費者配置
    props.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, JsonDeserializer.class.getName());
    props.put("value.type", "com.example.User"); // 自定義參數傳遞
    

3.4.消費者攔截器

Kafka 支持通過 ConsumerInterceptor 攔截消息處理流程:

public interface ConsumerInterceptor<K, V> extends Configurable {// 在消息返回給用戶前攔截ConsumerRecords<K, V> onConsume(ConsumerRecords<K, V> records);// 在位移提交前攔截void onCommit(Map<TopicPartition, OffsetAndMetadata> offsets);
}
  • KafkaConsumer會在poll()方法返回之前調用攔截器的onConsume()方法來對消息進行定制化處理。
  • KafkaConsumer會在提交完消費者位移之后調用攔截器的onCommit(),可以使用和這個方法來記錄跟蹤所提交的位移信息。

消費者也有連接鏈的概念,跟生產者一樣也是按照inerceptor.classes參數配置連接鏈的執行順序。

配置方式:

props.put(ConsumerConfig.INTERCEPTOR_CLASSES_CONFIG, "com.example.MyConsumerInterceptor");

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/81891.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/81891.shtml
英文地址,請注明出處:http://en.pswp.cn/web/81891.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

《java創世手記》---java基礎篇(下)

《Java 創世手記 - 基礎篇&#xff08;下&#xff09;》 第五章&#xff1a;契約與規范 —— 接口 (Interfaces) 與抽象類 (Abstract Classes) 造物主&#xff0c;在你日益繁榮的世界里&#xff0c;你發現僅僅依靠“繼承”來構建“物種體系”有時會遇到一些限制。比如&#x…

氣鎮閥是什么?

01、閥門介紹&#xff1a; 油封機械真空泵的壓縮室上開一小孔&#xff0c;并裝上調節閥&#xff0c;當打開閥并調節入氣量&#xff0c;轉子轉到某一位置&#xff0c;空氣就通過此孔摻入壓縮室以降低壓縮比&#xff0c;從而使大部分蒸汽不致凝結而和摻入的氣體一起被排除泵外起此…

計算機一次取數過程分析

計算機一次取數過程分析 1 取址過程 CPU由運算器和控制器組成&#xff0c;其中控制器中的程序計數器(PC)保存的是下一條指令的虛擬地址&#xff0c;經過內存管理單元(MMU)&#xff0c;將虛擬地址轉換為物理地址&#xff0c;之后交給主存地址寄存器(MAR)&#xff0c;從主存中取…

從equals思考對“正念”的認知

正念 很多人聊正念&#xff0c;每個人有自己的解說&#xff0c;我聽到最符合邏輯的一個說法&#xff1a;正念就是對抗慣性。 如果嘗試過打坐或者冥想&#xff0c;就有一個說法叫正觀&#xff0c;什么意義呢&#xff1f;就是說感受自己的呼吸&#xff0c;自己的心跳&#xff0c…

信息安全管理與評估2025山東卷

需要其他賽題解析的可聯系博主

【leetcode】02.07. 鏈表相交

鏈表相交 題目代碼1. 計算兩個鏈表的長度2. 雙指針 題目 02.07. 鏈表相交 給你兩個單鏈表的頭節點 headA 和 headB &#xff0c;請你找出并返回兩個單鏈表相交的起始節點。如果兩個鏈表沒有交點&#xff0c;返回 null 。 圖示兩個鏈表在節點 c1 開始相交&#xff1a; 代碼 …

可視化與動畫:構建沉浸式Vue應用的進階實踐

在現代Web應用中&#xff0c;高性能可視化和流暢動畫已成為提升用戶體驗的核心要素。本節將深入探索Vue生態中的可視化與動畫技術&#xff0c;分享專業級解決方案與最佳實踐。 一、 Canvas高性能渲染體系 01、Konva.js流程圖引擎深度優化 <template><div class"…

?模型驅動的DeepInsight Copilot在螞蟻的技術實踐

本文整理自潘蘭天&#xff08;螞蟻數據智能團隊數據分析平臺技術專家)在DA數智大會2025上海站的演講實錄。 本文圍繞AI技術在數據分析領域的應用及DeepInsight Copilot產品展開。DeepInsight是一款螞蟻長期深耕數據分析領域的BI產品&#xff0c;本文首先介紹了DeepInsight Copi…

Express教程【003】:Express獲取查詢參數

文章目錄 3、獲取URL中攜帶的查詢參數3.1 參數形式&#xff1a;查詢字符串3.2 參數形式&#xff1a;動態參數3.3 參數形式&#xff1a;Json數據 3、獲取URL中攜帶的查詢參數 3.1 參數形式&#xff1a;查詢字符串 1??通過req.query對象&#xff0c;可以訪問到客戶端通過查詢…

在CentOS7上使用tree查看目錄樹

文章目錄 1. 利用yum安裝tree2. 利用rpm安裝tree2.1 下載tree的rpm包2.2 上傳到云主機2.3 安裝tree軟件 3. 使用tree查看目錄樹4. 實戰小結 1. 利用yum安裝tree 執行命令&#xff1a;yum -y install tree CentOS7停止更新&#xff0c;即使更新鏡像源&#xff0c;也無法正常安裝…

大規模JSON反序列化性能優化實戰:Jackson vs FastJSON深度對比與定制化改造

背景&#xff1a;500KB JSON處理的性能挑戰 在當今互聯網復雜業務場景中&#xff0c;處理500KB以上的JSON數據已成為常態。 常規反序列化方案在CPU占用&#xff08;超30%&#xff09;和內存峰值&#xff08;超原始數據3-5倍&#xff09;方面表現堪憂。 本文通過Jackson與Fas…

華為交換機S12708常用命令

以下是華為S12708交換機&#xff08;高端園區/數據中心核心交換機&#xff09;的常用運維命令&#xff0c;涵蓋基礎配置、狀態查看、故障排查等場景&#xff1a; 一、基礎配置命令 1. 系統管理 system-view # 進入系統視圖 sysname S12708-Core # 設置設備名稱 clock timez…

通過海康螢石API控制家里相機的云臺及抓圖

通過海康螢石API控制家里相機的云臺及抓圖 一、背景二、環境準備2.1 注冊開發者賬號2.2 安裝依賴庫2.3 創建`.`env`文件三、代碼片段解釋3.1 加載并使用環境變量3.2 發送HTTP請求的封裝函數3.3 獲取AccessToken3.4 分頁查詢設備列表3.5 抓拍圖片3.6 開始云臺控制3.7 控制云臺并…

XCUITest 是什么

XCUITest&#xff08;全稱 Xcode UI Test&#xff09;是蘋果官方提供的 iOS/macOS UI 自動化測試框架&#xff0c;集成在 Xcode 開發工具中&#xff0c;專門用于測試 Swift/Objective-C 開發的應用程序。 1. XCUITest 的核心特點 ? 官方支持&#xff1a;蘋果原生框架&#xf…

mapbox高階,PMTiles介紹,MBTiles、PMTiles對比,加載PMTiles文件

????? 主頁: gis分享者 ????? 感謝各位大佬 點贊?? 收藏? 留言?? 加關注?! ????? 收錄于專欄:mapbox 從入門到精通 文章目錄 一、??前言1.1 ??mapboxgl.Map 地圖對象1.2 ??mapboxgl.Map style屬性1.3 ??Fill面圖層樣式1.4 ??PMTiles介紹1.5…

5.0以上版本antv/g6使用心得

1. 畫布只重新渲染數據 graph.render graph.drawgraph,fitview()graph.fitCenter()setData塞入新的數據 const updateGraph (data) > {if (!graph) {console.warn("Graph is not initialized");return;}graph.clear();graph.setData(data);graph.render(); };…

4.5V~100V, 3.8A 峰值電流限, 非同步, 降壓轉換器,LA1823完美替換MP9487方案

一&#xff1a;綜述 LA1823 是一款易用的非同步&#xff0c;降壓轉換器。 該模塊集成了 500mΩ 低導通阻抗的高側 MOSFET。LA1823 使用 COT 控制技術。此種控制方式有利于快速動態響應,同時簡化了反饋環路的設計。LA1823 可以提供最大 2A 的持續負載電流。LA1823有150kHz/240kH…

如何定位并優化慢 SQL?

如何定位并優化慢 SQL? 一、慢 SQL 的定義與影響 1.1 什么是慢 SQL? 慢 SQL是指執行時間超過預期閾值的SQL語句,通常由以下特征: 執行時間超過慢查詢閾值(如MySQL默認10秒)消耗大量CPU/IO資源導致連接堆積或系統負載升高關鍵結論:慢SQL是數據庫性能瓶頸的主要誘因,可…

提升WSL中Ubuntu編譯速度的完整指南

在 WSL&#xff08;Windows Subsystem for Linux&#xff09;中使用 make 編譯項目時&#xff0c;如果發現編譯速度非常慢&#xff0c;通常是由以下幾個原因導致的。以下是一些常見的排查和優化方法&#xff1a; &#x1f50d; 一、常見原因及解決方案 ? 1. 文件系統性能問題…

77. 組合【 力扣(LeetCode) 】

文章目錄 零、原題鏈接一、題目描述二、測試用例三、解題思路四、參考代碼 零、原題鏈接 77. 組合 一、題目描述 給定兩個整數 n 和 k&#xff0c;返回范圍 [1, n] 中所有可能的 k 個數的組合。 你可以按 任何順序 返回答案。 二、測試用例 示例 1&#xff1a; 輸入&…