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

深入剖析HBase架构

一、 HBase请求全流程分析

HBase 从客户端发起请求到返回结果的过程,涉及多个核心组件的协作,包括客户端库、ZooKeeper、HBase Master、RegionServer、WAL、MemStore、HFile 等。下面我们以一次完整的读请求与一次写请求为例,深度剖析整个系统的组件交互流程及底层实现。


🔁 1. 全景架构概览

                  ┌───────────────┐│     Client     │└──────┬────────┘│┌──────────────▼──────────────┐│         ZooKeeper            │└──────────────┬──────────────┘│┌────────────▼─────────────┐│        HBase Master       │└────────────┬─────────────┘│┌─────────────────▼──────────────────┐│          RegionServer 集群         │└────┬────────┬────────┬─────────────┘│        │        │┌──▼──┐  ┌──▼──┐  ┌──▼──┐│RS-1 │  │RS-2 │  │RS-n │└──┬──┘  └──┬──┘  └──┬──┘│        │        │┌────▼──┐ ┌────▼──┐ ┌───▼────┐│Region1│ │Region2│ │RegionX │└──┬────┘ └──┬────┘ └───┬────┘▼         ▼         ▼[ MemStore | WAL | HFile | Bloom | BlockCache ]

🧪 2. 一次 读请求流程:Client 查询某个 RowKey

假设查询语句为:

Get get = new Get(Bytes.toBytes("user_123"));
Result r = table.get(get);

📌 步骤详解:

✅ Step 1:Client 初始化连接(首次请求)
  • Client 通过配置的 ZooKeeper 地址连接到 ZooKeeper。

  • 获取:

    • ROOT 表位置信息(.META 表)

    • .META 表中保存所有表的 Region → RegionServer 映射。

✅ Step 2:定位目标 Region
  • Client 从 .META 表中查出:

    • "user_123" 属于哪个 Region?

    • 该 Region 当前由哪个 RegionServer 管理?

:Client 具有缓存,后续访问不会再查询 ZooKeeper 或 META 表,提升性能。

✅ Step 3:向对应 RegionServer 发起 Get 请求
  • 请求被路由到目标 RegionServer。

  • RegionServer 按如下顺序查找数据:

1. MemStore(内存最新数据)
2. BlockCache(热点数据缓存)
3. HFile(持久化文件)+ BloomFilter + BlockIndex 精确定位
✅ Step 4:构造返回结果
  • RegionServer 返回 Result 给客户端,包含多版本、列族、具体字段等。


✏️ 3. 一次 写请求流程:Client 写入某条数据

Put put = new Put(Bytes.toBytes("user_123"));
put.addColumn("info", "name", Bytes.toBytes("Alice"));
table.put(put);

📌 步骤详解:

✅ Step 1:Client 查找目标 Region
  • 同样从 ZooKeeper → .META 查找 RowKey 所属 Region。

✅ Step 2:向对应 RegionServer 发送 Put
  • 客户端将数据打包后发送到目标 RegionServer。

✅ Step 3:RegionServer 写入数据(以下操作是原子性的)
  1. 写 WAL(Write-Ahead Log)

    • 写入磁盘日志文件,确保数据可恢复。

    • 顺序写,性能高。

  2. 写 MemStore

    • 将数据写入内存中的跳表结构(SkipList)。

    • 是一个写后读先缓存,数据按 RowKey 排序。

  3. 返回客户端 OK

    • 一旦 WAL 和 MemStore 写入完成,立即返回成功。

✅ Step 4:Flush 到磁盘(后台异步触发)
  • 当 MemStore 达到阈值(如 128MB),会被刷写到 HFile。

  • 刷盘操作:

    • MemStore → SSTable-like HFile(顺序写磁盘)

    • 同时清除 WAL 中对应的日志片段

✅ Step 5:HFile 后续 Compaction(合并)
  • Minor Compaction:多个小 HFile 合并为中等文件

  • Major Compaction:全量合并,清理无效版本、TTL 过期数据


🔁 4. 关键组件之间的交互示意(读写全流程)

Client│├──> ZooKeeper:获取 .META 表位置├──> .META RegionServer:查找目标 Region 位置信息│├──> 目标 RegionServer:│     ├── 读请求:│     │    ├── MemStore → BlockCache → HFile + Bloom│     │    └── 返回结果│     └── 写请求:│          ├── 写 WAL(顺序写磁盘)│          ├── 写 MemStore(内存结构)│          └── 返回成功│└── 后台:├── Flush → HFile├── Compaction(压缩合并)└── Region Split(切分,写多后自动触发)

🔍 5. 重要机制深入分析

机制描述
WAL顺序写磁盘,记录所有写入,宕机恢复依赖它
MemStore内存写缓存,按行键排序,写入后先读此处
BlockCache热数据缓存,命中则无需读磁盘
BloomFilter判断某行是否在该 HFile 中,减少磁盘读取
HFile类似 SSTable 的列存文件,按列族分布存储
Compaction合并 HFile,提高查询效率,清除旧版本
Region SplitRegion 写入过大自动拆分,提高并发能力

📈 6. 性能优化与负载均衡如何参与

场景机制
查询热点BlockCache + BloomFilter 加速
写入压力大Region 自动 Split,数据打散 RowKey
RegionServer 不均衡HMaster 定期触发 Region Balancer
查询慢预热缓存 / 使用 Secondary Index
写放大控制 Compaction 频率,避免过度合并

🧠 7. 总结

阶段组件功能
客户端HBase Client发起请求、ZooKeeper 寻址、缓存 Region 映射
服务发现ZooKeeper提供 .META/ROOT 定位、Master 选举
控制层HBase MasterRegionServer 管理、分裂、负载均衡
数据服务RegionServer执行读写请求、缓存、刷盘、压缩
数据层WAL、MemStore、HFile提供写入保障与高效查询能力

二、剖析WAL(Write-Ahead Log)写入机制和HFile 结构

我们现在深入剖析 HBase 的两个核心组件:

  • WAL(Write-Ahead Log)写入机制:确保数据写入的持久性和可靠性;

  • HFile 结构:是 HBase 持久化存储的核心格式,支持高效查询和压缩。


📝 1. WAL(Write-Ahead Log)机制

🔧 1. 作用

WAL 是 HBase 中写入操作的日志文件,所有写入操作必须先写 WAL,再写 MemStore,确保:

  • RegionServer 崩溃后能恢复数据;

  • 写入顺序一致性;

  • 提供持久性(P of CAP)。


📋 2. 写入流程详解

假设客户端执行如下操作:

put.addColumn("info", "age", 18);
table.put(put);
WAL 写入流程如下:
Client↓
RegionServer↓
1️⃣ 构造 WALEdit:- 包含:rowkey、columnFamily、qualifier、timestamp、value
2️⃣ 写入 WAL(sync/flush)- 顺序写入 HDFS 上的日志文件(hdfs://hbase/WALs/...)- 使用 FSDataOutputStream.sync() 保证持久化
3️⃣ 写入 MemStore
4️⃣ 返回客户端 OK

🧱 3. WAL 文件结构(HLog)

每个 WAL 文件由多个 WALEdit 构成,格式如下:

[HLogFile]├── [Header]├── [WALEdit 1]├── [WALEdit 2]├── ...└── [Trailer]
每个 WALEdit 包含:
  • RowKey(行键)

  • Column Family + Qualifier(列族+字段)

  • Timestamp

  • Value

  • SequenceId(全局递增 ID)

  • TxnId(用于 MVCC 多版本)


🛠 4. WAL 实现特性

特性描述
顺序写适合 SSD/HDD,性能稳定
回放机制崩溃时使用 WAL 进行 MemStore 恢复
Split多个 Region 共用一个 WAL,但在 split 后 WAL 文件会按 Region 切割
Rolling超过一定大小自动滚动新文件
多 WAL允许配置多个 WAL writer 提高并发写入(AsyncFSWAL)

🧊 2. HFile 存储结构

📦 1. HFile 是什么?

  • HBase 的底层文件格式;

  • 类似于 SSTable(Sorted String Table);

  • 所有 flush 后的数据最终都会落入 HFile。


🧱 2. HFile 结构图

[HFile]
├── Header
├── Data Blocks (K/V 列表)
│    ├── RowKey1 → 列族/字段 → Value
│    ├── RowKey2 → ...
│    └── ...
├── Bloom Filter
├── Meta Block (索引/统计)
├── Block Index (索引所有 Block)
└── Trailer (指向各部分的偏移地址)

🔍 3. HFile Block 结构(压缩 + 顺序)

HFile 中的数据按照 “Block” 存储,每个 Block 默认大小为 64KB,可配置。

每个 Block 结构如下:

[DataBlock]
├── Block Header
├── RowKey + CF + Qualifier + Value
├── 压缩块(Snappy/LZO/none)
└── 校验码(checksum)

🧮 4. HFile 支持的索引与优化

组件作用
BlockIndexRowKey → Block 的二级索引,用于定位具体 Block
BloomFilter判断 RowKey 是否存在某个 Block(减少磁盘访问)
TimeRange支持按时间过滤版本
Column Family 索引支持按 CF 查询优化
块缓存(BlockCache)热数据常驻内存,减少 IO 访问

💾 5. HFile 是如何被写入的?

当 MemStore 达到阈值时,触发 flush 操作:

MemStore(内存) ↓
HFile.Writer(构造器)↓
数据按 RowKey 排序、按列族写入↓
写入 Block → 压缩 → 累积索引↓
输出最终 HFile 文件 → HDFS

🔁 6. HFile 访问流程(查询时)

当查询一个 RowKey 时:

1. 查找 BlockIndex → 得到目标 Block 偏移量
2. 判断 BloomFilter:该行是否可能存在?
3. 定位 Block → 反序列化 + 解压缩
4. 查询对应字段,返回数据

🧠 3. WAL + HFile 协同机制

阶段作用组件
写请求WAL 写入保障事务性、持久性WAL
写入内存MemStore 提供写后读MemStore
刷盘将 MemStore 写入磁盘HFile
崩溃恢复读取 WAL 重建 MemStoreWAL
查询BlockIndex + Bloom + BlockCacheHFile

✅ 4. 小结

组件关键作用优势局限
WAL写前日志,宕机恢复保障顺序写,稳定可靠宕机后恢复有延迟
HFile高效读文件,列存结构支持压缩、索引、Bloom写放大(Flush+Compaction)
MemStore写入缓存,顺序排序快速写入、读命中内存受限,需及时 flush

三、详细分析HBase是如何做到海量数据秒级查询

HBase 是一个基于 Hadoop HDFS 构建的高性能、分布式、面向列的 NoSQL 数据库,专门为支持大规模数据存储与高效读写设计。它借鉴了 Google Bigtable 的设计思想,具有良好的可扩展性与高吞吐特性,特别适合实时读写和大数据分析。


🧱 1. HBase 整体架构图

                    ┌──────────────────────┐│     客户端 (Client)   │└────┬─────────┬───────┘│         │┌────────▼──┐   ┌──▼────────┐│ HBaseMaster│   │ Zookeeper │└────┬──────┘   └────┬───────┘│               │┌────────▼────────────────▼────────┐│      RegionServer 集群            │└────────┬────────┬────────┬────────┘│        │        │┌────▼──┐ ┌────▼──┐ ┌───▼────┐│Region1│ │Region2│ │RegionN │└────┬──┘ └────┬──┘ └───┬────┘▼        ▼        ▼┌──────┐ ┌──────┐ ┌────────┐│ HFile│ │ MemStore│ │WAL文件│└──────┘ └──────┘ └────────┘

🔍 2. 核心组件剖析

1. HMaster(主控节点)

  • 负责管理 RegionServer(RS),如负载均衡、Region 分裂与迁移。

  • 不参与读写数据,故单点故障不会影响服务可用性

  • 实际高可用通过 ZooKeeper 协调多 HMaster 实现。


2. RegionServer(数据处理节点)

每个 RS 管理多个 Region(逻辑分片),一个 Region 包含:

  • MemStore:内存中缓存写入数据。

  • HFile:最终落盘文件(以列族为单位组织)。

  • WAL(Write-Ahead Log):预写日志,防止宕机数据丢失。


3. Region(水平切分)

  • 每张表按 RowKey 范围划分为多个 Region。

  • 每个 Region 存储某一 RowKey 范围内的所有数据。

  • Region 是 HBase 的分区最小单位,可动态分裂。


4. ZooKeeper(协调组件)

  • 管理 RegionServer 的注册与发现。

  • 帮助 Client 获取表的元数据及 Region 位置信息。

  • 保障 Master 的选举与集群元数据一致性。


🧬 3. 数据存储结构

数据模型(面向列的稀疏表)

RowKey         ColumnFamily:Qualifier    Timestamp         Value
"user001"      info:name                 1680000000000     "Alice"
"user001"      info:email                1680000000001     "alice@example.com"
"user001"      login:ip                  1680000000002     "192.168.1.2"
  • 行键(RowKey):主键,按字典序排序,是读取性能的关键。

  • 列族(ColumnFamily):数据物理存储单位,存储在不同 HFile 中。

  • 列限定符(Qualifier):用户定义的具体列。

  • 版本(Timestamp):HBase 原生支持多版本。


⚡ 4. HBase 快速读写的关键机制

✏️ 1. 写入流程(高吞吐 + 容错)

Client → RegionServer →1. 写 WAL(顺序写磁盘)→2. 写 MemStore(内存结构)→3. 返回 Client 成功
  • 数据写入非常快(只需内存 + 顺序写日志)

  • WAL 保证数据可靠,宕机后可通过 WAL 恢复数据

  • 当 MemStore 达阈值时刷盘为 HFile(不可变)


🔎 2. 查询流程(高效率 + 列存结构)

Client → 查找目标 RowKey →1. 从 MemStore 查(最新数据)→2. 从 BlockCache 查(缓存 HFile)→3. 查 HFile → BloomFilter & BlockIndex → 精确定位
查询优化关键技术:
技术描述
Bloom Filter判断某 Key 是否存在于 HFile,避免无效 IO
BlockCache热点数据缓存到内存,极大加快读性能
RowKey 排序有序存储 + 范围扫描极快
列簇分离查询按需读取列簇,避免读无用数据

🧠 5. HBase 是如何支撑海量数据 + 快速查询的?

关键机制说明
水平扩展的 RegionServer 架构数据自动划分为多个 Region,Region 可自动迁移和负载均衡
基于 RowKey 有序存储可实现 O(log n) 范围扫描,支持前缀、范围查询等
列族 + 列限定符组织仅查询需要列,降低 IO 负载
Block Index + Bloom Filter + 缓存机制快速定位数据 block,跳过无关文件块
写入 WAL + MemStore,延迟刷盘提升写性能,避免频繁磁盘 IO
压缩 + 编码(LZO/Snappy + Prefix Encoding)提高磁盘利用率 + 提升扫描性能

🛠 6. HBase 的实际吞吐表现

指标表现(典型)
单节点写入5~10 万条/s(仅写 WAL + MemStore)
多 RegionServer横向扩展支持千万级 TPS
查询延迟毫秒~数十毫秒(RowKey 精确查找)
范围扫描高速(需合理 RowKey 设计 + filter)

🎯 7. 总结

✅ HBase 适用于:

  • 海量数据存储(PB 级别)

  • 高并发写入(实时入库)

  • 快速的单行/批量查询

  • 高可扩展性 + 高容错

❌ 不适用于:

  • 复杂多表 join、事务型场景

  • 非主键列模糊查询(需要额外索引服务如 Phoenix/ES)

四、热点rowkey 设计优化与负载均衡方案

热点 RowKey 问题是 HBase 中最常见、最容易导致性能瓶颈的场景之一。由于 HBase 是按照 RowKey 的字典序进行存储和查找,如果大量数据集中写入某一类 RowKey(如递增 ID、时间戳),就会导致:

  • 写入集中在少数几个 RegionServer 上,引发写热点;

  • MemStore 和 WAL 压力不均衡,造成 RegionServer 崩溃;

  • 负载不均衡,影响整体系统吞吐;

  • 查询热点也可能导致 RS 负载飙升。


🔥 1. 什么是热点 RowKey?

指大量写操作或读操作集中落到少数几个 RowKey 或同一个 Region 范围内的 RowKey。

典型例子:

RowKey = 用户ID + 时间戳
RowKey = 订单号(自增ID)
RowKey = 202505280101 // 固定时间前缀

结果:高并发场景下,全都写入同一个 Region,无法充分利用 HBase 的分布式架构。


🧪 2. 热点 rowkey 问题的表现

表现影响
RegionServer 瞬间 CPU 飙高写入压力集中
MemStore flush 频繁GC 压力大
Query QPS 上不去因为全靠一个 RS 抗压
Region 分裂过慢写入集中,其他 Region 空闲
客户端 timeout、WAL 写入延迟单点压力过大

🎯 3. 热点 RowKey 的优化策略

✅ 1. RowKey 前缀哈希/前缀打散(推荐)

将 RowKey 打散,前缀加随机前缀或 hash 前缀,打散写入热点。

原始 RowKey:    user_10001
打散后 RowKey:  03_user_10001  // 03 为前缀哈希(user_id.hash % N)

优点

  • 写入分散到多个 Region

  • 不影响精确查找(可通过二级索引或反向前缀组装)

缺点

  • 范围扫描复杂:需扫描多个打散前缀


✅ 2. 时间戳反转 + 前缀扰动

如果是时间排序的数据,可以将时间戳反转 + 打散前缀,避免新数据集中写入末尾 Region。

原始时间戳:202505280101 → 反转后 RowKey:798494719898
加扰动前缀:R03_798494719898

✅ 3. Salt 前缀 + 多 Region 预分区(PreSplit)

结合前缀 + Region 预分区,使得不同 salt 对应不同 Region。

RowKey: salt + "_" + 原始Key
如: 00_userA, 01_userB, ... 99_userZ建表时:
create 'user_table', 'info', SPLITS => ['00', '01', ..., '99']

通常建议 Salt 值为 10~100,根据实际 QPS 调整。


✅ 4. 基于业务字段构造高分散度 RowKey

构造 RowKey 时综合考虑业务高基数字段,例如:

RowKey = hash(用户ID) + 商品ID + 反转时间戳

要求满足:

  • 唯一性

  • 分散性(高基数字段在前)

  • 可按需组装业务字段


✅ 5. 热点数据异构缓存(如:ES / Redis)

  • 对热点行或聚合统计信息,使用 Redis/ES 缓存

  • HBase 仅做底层存储,缓存层做热点抗压


⚙️ 4. 负载均衡调优策略(Region 层面)

🔄 1. Region 自动 Split(分裂)

  • 每个 Region 写入超过 hbase.region.max.filesize(默认 10GB)时自动分裂

  • 配合预分区可以避免写入集中到一个大 Region

🤖 2. Region Rebalancer(自动负载均衡)

  • HMaster 会定期检查各 RegionServer 的 Region 数

  • 对过载节点自动迁移部分 Region 到空闲 RS

调优参数:

hbase.balancer.period = 300000   # 默认 5 分钟触发负载均衡
hbase.regionserver.handler.count = 30
hbase.master.loadbalance.bytable = true  # 分表均衡

🧠 5. 热点查询优化方案

✅ 1. BlockCache 提升热点数据命中率

  • 配置合理的 BlockCache 大小(hfile.block.cache.size

  • 热数据常驻内存,避免频繁读磁盘

✅ 2. 使用 Secondary Index 系统(如 Phoenix)

  • Phoenix 支持二级索引 + SQL 查询接口

  • 可加速非 RowKey 条件的查询(但写入时成本增加)

✅ 3. 查询打散(client 侧发起并行请求)

  • 对多个前缀扫描打散 RowKey 时,Client 并发发起多个 scan,聚合结果

  • 适合 Salt 分区 + 多线程扫描


✅ 6. 小结:热点 rowkey 优化建议清单

场景优化建议
写入过热RowKey 加前缀打散 / salt / 反转时间戳
查询过热BlockCache + 热点缓存层(Redis)
大表初始化创建时预 split,设置合理的 region 边界
范围查询较多结构中后部保留顺序字段,组合设计
负载不均衡启用 balancer,定期检查 Region 数量

五、如何解决Hbase 数据倾斜的问题

HBase 数据倾斜(Data Skew)是指数据在 Region(分区)之间分布不均,导致某些 RegionServer 承载大量请求(热点),而其他空闲,从而严重影响读写性能和系统的可扩展性。


📌 1. HBase 数据倾斜的常见表现

类型描述
写倾斜多个客户端写入集中在某些 RowKey,导致单 Region 压力巨大
读倾斜查询请求集中访问某些热点数据行或列族
Region 热点某 Region 因数据分布不均被频繁访问,RegionServer CPU 飙升

🧠 2. 数据倾斜的根本原因

  1. RowKey 设计不合理

    • 顺序 RowKey(如时间戳、递增 ID)导致所有写入集中于最后一个 Region。

  2. 预分区没做好

    • 没有预先创建好 Region 導致所有写入集中于一个 Region,未触发 split。

  3. 热点查询/更新集中访问某些行或列

    • 某些 RowKey(如某个用户ID)读写频率极高。


✅ 3. 解决 HBase 数据倾斜的实战方案

方案 1️⃣:RowKey 盐值打散(Salting)

  • 将 RowKey 前加 hash 前缀或固定范围前缀,使其打散到多个 Region。

✅ 示例:
原始 RowKey:    20250528_user123
加盐后 RowKey:  03_20250528_user123
  • “03” 是通过 hash(user123) % 10 计算出的前缀,共有 10 个前缀,对应 10 个 Region。

🧠 查询时需全表扫描所有前缀,可用 Union Scan / RowPrefixFilter 解决。


方案 2️⃣:预分区(Pre-Split Regions)

在建表时通过指定 SPLITS 参数,手动指定 RowKey 范围拆分 Region,避免所有数据集中写入默认 Region。

✅ 示例:
create 'user_log', 'info', SPLITS => ['10', '20', '30', '40', '50']

适合有明显 RowKey 范围规律的数据,如用户ID、时间戳等。


方案 3️⃣:RowKey 倒排设计(Reversed RowKey)

将 RowKey 中高频变动字段放前面,低变动放后面,或做倒排,使写入分布更均匀。

示例:
原始:   20250528_user123
倒排:   user123_20250528

方案 4️⃣:利用 Phoenix 自动盐值

如果使用 Phoenix(HBase 的 SQL 层),建表时可加 SALT_BUCKETS 自动打散 rowkey。

✅ 示例:
CREATE TABLE user_activity (user_id VARCHAR PRIMARY KEY,activity_time TIMESTAMP
) SALT_BUCKETS = 8;

方案 5️⃣:HFile Compaction 优化

  • 定期设置 Major Compaction,让 HFile 合并,避免小文件过多;

  • 使用 TTL / Delete 清理旧数据减少存储压力。


方案 6️⃣:冷热数据分离 / HBase 归档策略

  • 将冷热数据拆分成不同表或不同列族;

  • 热数据部署在 SSD + 高性能节点,冷数据可用 HDFS 归档或备份。


🚥 4. 读倾斜优化

技术描述
BlockCache热点 Block 预加载进内存,减少磁盘 IO
BloomFilter提高数据 Block 命中率,减少误读
RowFilter/PrefixFilter精确过滤,减少全表扫描
定期分析热点访问模式做缓存下沉(如 Redis 缓存热点行)

📈 5. 监控与调优

使用以下工具观察热点行为:

  • HBase UI(/master-status)

  • RegionServer JVM 指标(如 GC、MemStore 使用率)

  • JMX、Prometheus + Grafana 监控 Region 访问模式

  • HDFS Block 分布与 IO 压力分析


🎯 6. 总结

方法适用场景优点缺点
RowKey 盐值高并发写入简单直接查询需打散
预分区结构化 RowKey写入均衡分区需预估
RowKey 倒排时间序列数据分布均匀查询需额外处理
Phoenix 盐桶SQL 场景无侵入打散查询有影响
BloomFilter + BlockCache热点读优化快速命中内存占用大
冷热分层大数据归档降低热点压力实施复杂

相关文章:

  • 若依项目AI 助手代码解析
  • ImBatch 7.6.3 中文版 - 高效图片批量处理工具
  • [Javascript进阶]JSON.stringify与JSON.parse详解
  • 超级对话3:大跨界且大综合的学问融智学应用场景述评(不同第三方的回应)之三
  • 酒店管理系统设计与实现
  • 数据交易场景的数据质量评估
  • muduo库的初步认识和基本使用,创建一个简单查询单词服务系统
  • 【C++】STL详解(四)---Stack和Queue
  • ansible自动化playbook简单实践
  • MSTNet:用于糖尿病视网膜病变分类的多尺度空间感知 Transformer 与多实例学习方法|文献速递-深度学习医疗AI最新文献
  • C++高级编程深度指南:内存管理、安全函数、递归、错误处理、命令行参数解析、可变参数应用与未定义行为规避
  • 面试题 08.08. 有重复字符串的排列组合【 力扣(LeetCode) 】
  • 低功耗架构突破:STM32H750 与 SD NAND (存储芯片)如何延长手环续航至 14 天
  • OCC笔记:BRepMesh_IncrementalMesh的使用
  • 用Git管理你的服务器配置文件与自动化脚本:版本控制、变更追溯、团队协作与安全回滚的运维之道
  • day 26 函数专题
  • 尚硅谷redis7 90-92 redis集群分片之集群扩容
  • day41 python图像识别任务
  • Unity 中实现首尾无限循环的 ListView
  • 机房网络设备操作安全管理制度
  • 扬州市邗江区建设局网站/推广网络广告
  • 无锡网站建设优化/信息流广告投放平台
  • 网站备案需要拍照/百度关键词排名qq
  • 广告网站建设流程/国内最新新闻
  • 青岛网站建设邓巴迪/百度推广怎么注册账号
  • 做面点的网站/推广计划方案模板