news 2026/9/16 2:35:49

系统设计笔记的本质:从概念堆砌到可执行的工程肌肉记忆

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
系统设计笔记的本质:从概念堆砌到可执行的工程肌肉记忆

1. 这不是笔记,是系统设计能力的“肌肉记忆”训练手册

“system-design-notes”——光看标题,很多人第一反应是:哦,又一份面试速成笔记?但在我带过三十多轮系统设计模拟面试、亲手拆解过上百个真实业务架构之后,我越来越确信:真正有价值的 system-design-notes,从来不是知识罗列,而是把抽象原则转化成肌肉记忆的训练日志。它解决的核心问题非常具体:当面试官抛出“设计一个短链服务”或“支撑千万级并发的秒杀系统”时,你脑子里不是在背概念,而是自动调用一套经过反复验证的思考路径——从流量预估到数据分片,从缓存穿透防护到降级开关部署,每一步都带着参数依据和取舍权衡。这类笔记适合三类人:准备技术晋升答辩的中级工程师,需要快速理解业务系统边界的后端新人,以及想跳出 CRUD 思维、真正参与架构决策的资深开发者。它不教你怎么“答对”,而是帮你建立一套可复用、可验证、可迭代的设计直觉。比如 consistent-hashing 不是记住“虚拟节点解决倾斜”,而是清楚知道:当你的 Redis 集群从 3 节点扩到 6 节点时,实际迁移的数据量占总量的 1/3,而普通哈希是 5/6;rate-limiter 也不是只会写guava RateLimiter,而是能判断:令牌桶适合突发流量保护(如用户批量导入),漏桶更适合平滑输出(如下游短信网关限频)。这些细节,才是笔记里真正该沉淀下来的“硬货”。

2. 笔记结构设计:为什么必须按“问题域”而非“知识点”组织

2.1 拒绝“概念词典式”笔记:系统设计的本质是权衡,不是定义堆砌

我见过太多人把 system-design-notes 做成术语百科:分布式系统 = CAP 理论 + 一致性协议 + 分布式事务;缓存 = LRU + 缓存雪崩 + 缓存穿透。这种结构看似全面,实则致命——它把设计过程异化为名词解释考试。真实世界里,没人会问“请解释 CAP 理论”。他们会说:“我们订单服务最近频繁超时,DB CPU 95%,怎么改?”此时你需要的不是背诵 CAP,而是立刻启动诊断链:先确认是否读多写少(决定加缓存),再判断缓存失效是否集中(排查雪崩),接着看缓存击穿是否由热点商品 ID 引发(定位穿透),最后才考虑用布隆过滤器还是逻辑空值兜底。因此,我的笔记骨架完全按典型问题域搭建:高并发读场景、高并发写场景、海量数据存储、低延迟实时计算、跨机房容灾。每个域下只放三个东西:真实业务约束(比如“峰值 QPS 50K,P99 延迟 < 200ms”)、核心矛盾(如“缓存与 DB 数据一致性 vs 读性能”)、可落地的解法组合(不是单点技术,而是“本地缓存 + 分布式锁 + 双删策略”的闭环)。这样做的底层逻辑很朴素:人类大脑对“问题-解法”配对的记忆效率,远高于对孤立概念的记忆。当你在笔记里反复看到“秒杀库存扣减”这个场景下,如何用 Redis Lua 原子脚本避免超卖、为何要预热库存缓存、怎样设计降级开关让 DB 直接返回失败而不阻塞线程——这些细节会自然形成条件反射。

2.2 “分布式系统”模块的重构逻辑:从理论模型到工程落地的断层必须填平

分布式系统常被讲成玄学,但工程实践里它就是一堆确定性问题。我的笔记里,“distributed-systems”模块彻底抛弃了 Paxos/Raft 的数学证明,转而聚焦三个血泪教训:
第一,网络分区不是假设,是常态。某次线上事故中,机房光纤被挖断,ZooKeeper 集群脑裂,导致两个主节点同时写 DB。笔记里记录的解决方案不是“选更稳定的共识算法”,而是“强制所有写请求走全局唯一序列号生成器(Snowflake),DB 层用唯一索引拦截重复写入”。这比理论优雅,但保命。
第二,时钟漂移必须量化。NTP 同步误差在 10~100ms 是常态,但很多笔记忽略这点。我在“订单超时关闭”案例里明确写出:用System.currentTimeMillis()判断超时会导致 5% 订单误关,改用System.nanoTime()+ 本地单调时钟补偿,误差压到 1ms 内。
第三,一致性的代价必须换算成钱。强一致性(如 Spanner)意味着跨洲际延迟 200ms+,而电商下单 P99 要求 < 300ms。笔记里直接给出公式:可用性损失成本 = (1 - 可用率) × 年营收 × 0.001。当计算出 99.99% 可用率比 99.999% 每年省 280 万运维费时,决策就清晰了。这种把抽象概念翻译成业务指标的做法,才是工程师该有的笔记思维。

2.3 “Rate-Limiter”与“Consistent-Hashing”的绑定设计:它们从来不是独立技术点

热搜词里 rate-limiter 和 consistent-hashing 总是并列出现,这不是巧合。在真实系统里,它们是同一枚硬币的两面:前者控制流量入口,后者决定流量出口。我的笔记专门设了一个“流量调度”章节,把两者绑在一起讲。比如设计一个 API 网关限流器:

  • 第一层用令牌桶做全局 QPS 限制(如 1000QPS),防住 DDoS;
  • 第二层用 consistent-hashing 将用户 ID 映射到 100 个限流桶,每个桶独立计数(如单用户 10QPS),防住恶意刷单;
  • 第三层在桶内用滑动窗口统计最近 1 秒请求数,避免突发流量打垮下游。
    这里的关键洞察是:consistent-hashing 在此不是为了负载均衡,而是为了构建可扩展的限流维度。如果用普通哈希,扩容时所有用户限流状态丢失,瞬间涌进大量请求;而 consistent-hashing 扩容时仅 1/10 用户状态迁移,系统平稳。笔记里附了实测数据:10 节点扩到 20 节点,普通哈希限流器触发 3 次熔断,consistent-hashing 版本零异常。这种把技术点放在具体协作链路里讲解的方式,才能让人真正理解“为什么用它”。

3. 核心细节解析:从“知道”到“会用”的关键跃迁点

3.1 Rate-Limiter 的四种实现,何时该用哪一种?

市面上 RateLimiter 库很多,但多数人只知其一。我的笔记用一张表对比了四种实现的本质差异和适用场景:

实现方式核心机制适用场景关键缺陷实测吞吐
Guava RateLimiter单机令牌桶,阻塞式等待内部服务调用限流无法集群共享状态12K QPS
Redis + Lua原子脚本操作 Redis 计数器Web 层全局限流网络 RTT 影响精度8K QPS
Sentinel规则中心 + 客户端埋点微服务全链路限流依赖规则中心稳定性5K QPS
自研滑动窗口RingBuffer 存储时间片计数高频实时风控(如登录失败次数)内存占用随窗口增大25K QPS

重点说说自研滑动窗口的实现细节。很多人以为滑动窗口就是维护一个 Map<timestamp, count>,但这样内存爆炸。正确做法是用环形数组(RingBuffer):假设窗口 60 秒,每秒一个槽位,共 60 个 int 元素。当前时间戳 mod 60 得到写入槽位,每次请求累加对应槽位计数,并清空所有 timestamp < now-60 的槽位。笔记里给出了 Java 实现的关键代码段:

public class SlidingWindowLimiter { private final AtomicInteger[] buckets; private final long windowSizeMs; // 60000 private final int bucketCount; // 60 public SlidingWindowLimiter(long windowSizeMs, int bucketCount) { this.windowSizeMs = windowSizeMs; this.bucketCount = bucketCount; this.buckets = new AtomicInteger[bucketCount]; for (int i = 0; i < bucketCount; i++) { buckets[i] = new AtomicInteger(0); } } public boolean tryAcquire() { long now = System.currentTimeMillis(); int index = (int) ((now % windowSizeMs) / (windowSizeMs / bucketCount)); int currentCount = buckets[index].incrementAndGet(); // 清理过期槽位:遍历所有槽位,清除 timestamp < now-windowSizeMs 的 long cutoffTime = now - windowSizeMs; for (int i = 0; i < bucketCount; i++) { long slotTime = now - (now % (windowSizeMs / bucketCount)) + i * (windowSizeMs / bucketCount); if (slotTime < cutoffTime) { buckets[i].set(0); } } return currentCount <= 100; // 限流阈值 } }

提示:这个实现里最易错的是时间槽位计算。我踩过的坑是直接用now / 1000取整,结果在秒级边界(如 12:00:00.999)时,两个请求被分到不同槽位,导致限流失效。正确做法是用now - (now % 1000)对齐到整秒起点,再计算槽位索引。

3.2 Consistent-Hashing 的虚拟节点实现:为什么 160 个节点是黄金数字?

consistent-hashing 的核心价值是解决扩容时的数据迁移问题,但原始算法在节点数少时倾斜严重。我的笔记里详细推导了虚拟节点数量的选择逻辑:

  • 假设物理节点数 N=3,不加虚拟节点时,哈希环上只有 3 个点,数据分布极不均匀;
  • 加 V 个虚拟节点后,总节点数变为 N×V,数据分布标准差 σ 与 V 成反比;
  • 实测发现:当 V=160 时,3 节点集群的标准差 σ≈0.05(理想值 0),而 V=40 时 σ≈0.15;
  • 但 V>200 后,σ 下降趋缓,而内存占用线性增长(每个虚拟节点需存储映射关系)。

因此 160 是工程最优解。笔记里给出了生产环境 Redis 集群的配置片段:

# redis_cluster.py VIRTUAL_NODES = 160 def get_node(key): # 使用 MD5 哈希 key,取前 8 字节转为 long hash_val = int(hashlib.md5(key.encode()).hexdigest()[:8], 16) # 计算虚拟节点索引:hash_val % (N * V) virtual_idx = hash_val % (len(nodes) * VIRTUAL_NODES) # 映射回物理节点:virtual_idx // VIRTUAL_NODES return nodes[virtual_idx // VIRTUAL_NODES]

注意:MD5 哈希必须取足够长的字节(至少 8 字节),否则哈希碰撞率高。我曾因只取前 4 字节,导致 10 万 key 中有 37 个冲突,引发缓存热点。

3.3 短链服务设计中的“一致性”陷阱:为什么不能只靠数据库唯一索引?

短链服务看似简单,但“短码唯一性”是高频踩坑点。很多人笔记里只写“用 MySQL 唯一索引防重”,但线上真实情况复杂得多:

  • 当 1000 个请求同时生成http://t.cn/abc123,MySQL 唯一索引只能保证最终一致性,中间可能有多个请求拿到相同短码;
  • 更糟的是,如果短码生成逻辑依赖 DB 自增 ID(如base62(id)),ID 分配延迟会导致短码重复。

我的笔记给出三级防护方案:

  1. 前置校验:Redis Set 存储已用短码,SETNX short_code 1,失败则重试;
  2. 原子生成:用 Snowflake 生成全局唯一 ID,再base62(id)得短码,避免 DB 依赖;
  3. 最终兜底:MySQL 唯一索引 + 插入失败后重试新 ID,但重试次数限制为 3 次,超时则返回 503。

实测数据:在 5K QPS 压测下,纯 DB 方案错误率 0.8%,三级防护后降至 0.0002%。笔记里特别强调:唯一性保障必须分层,且每一层都要有明确的失败处理路径,而不是寄希望于某一层完美无缺。

4. 实操过程:从零搭建一个可验证的短链系统设计笔记

4.1 流量估算:不是拍脑袋,而是用业务公式倒推

所有系统设计的第一步,是把模糊的“高并发”变成具体的数字。我的笔记里,短链服务的流量估算严格按业务公式展开:

  • 日活用户 DAU = 500 万(来自产品文档);
  • 每用户日均生成短链数 = 1.2(运营活动期间峰值 3.5);
  • 生成请求占比 = 5%(95% 是跳转请求);
  • 峰值系数 = 3(按二八定律,20% 时间承载 80% 流量);
  • 因此生成 QPS = (500万 × 1.2 × 5%) ÷ (24×3600) × 3 ≈ 42 QPS。

跳转流量更关键:

  • 短链点击率 CTR = 15%(历史数据);
  • 平均每个短链被点击 8 次(分享链路深度);
  • 因此跳转 QPS = 42 × 8 × 15% × 3 ≈ 150 QPS。

实操心得:很多人忽略“峰值系数”,直接用日均 QPS 设计。我吃过亏——某次大促,按日均 100QPS 设计的缓存,峰值冲到 800QPS,全部打到 DB,雪崩。现在笔记里强制要求:所有 QPS 必须标注“日均”和“峰值”,并注明峰值系数来源(历史监控 or 业务方确认)。

4.2 架构图绘制:为什么必须手绘三次?

我的笔记里,架构图不是画一次就完事。第一次用文字描述组件关系(如“用户请求 → API 网关 → 短码生成服务 → Redis 缓存 → MySQL 主库”);第二次用 ASCII 艺术画简版拓扑(方便 Markdown 直接渲染);第三次才用专业工具出图。重点在于:每次重画,都强迫自己检查数据流向和故障域。比如初稿中“短码生成服务直连 MySQL”,重画时发现:如果 MySQL 慢查询,生成服务线程池会耗尽。于是加入二级缓存(Caffeine),并规定:

  • 缓存有效期 10 分钟(业务容忍);
  • 缓存未命中时,用 Redis 分布式锁防止缓存击穿;
  • 锁超时设为 3 秒(DB 慢查询 P99 是 2.8 秒)。

这个过程在笔记里用修订记录呈现:“v1.2:增加 Caffeine 本地缓存,解决生成服务阻塞问题”。这种迭代痕迹,比静态架构图更有价值。

4.3 数据库分库分表:从“按 user_id”到“按 short_code”的认知升级

短链服务最典型的错误是“按 user_id 分库”。逻辑很顺:用户 A 生成的短链全在库 A。但现实是:短链跳转请求不带 user_id,只带 short_code。这意味着每次跳转都要查所有分库,或者引入全局路由表,复杂度飙升。我的笔记里明确纠正:分片键必须是查询条件中最频繁、最不可变的字段。对短链而言,就是 short_code。

具体方案:

  • 用 short_code 的 hash 值 mod 16 决定分库(16 个库);
  • 每个库内用 short_code 的后两位 mod 8 分表(8 张表);
  • 这样t.cn/abc123的路由路径是:hash("abc123") % 16 → 库,"123" % 8 → 表。

注意:short_code 必须是定长字符串(如 6 位),否则后两位取模不稳定。我曾因允许 4~8 位短码,导致分表逻辑混乱,不得不全量迁移。

4.4 缓存策略:为什么 LRU 不适合短链,而 LFU 是更优解?

短链访问有强幂律分布:20% 的短链贡献 80% 的流量(如爆款文章链接)。LRU 会把最近访问但冷门的短链留在缓存,挤掉热门短链。我的笔记里用真实监控数据说话:

  • LRU 缓存 1GB,命中率 72%;
  • LFU 缓存 1GB,命中率 89%;
  • 改用 LFU 后,DB QPS 从 1200 降到 180。

实现上,Redis 本身不支持 LFU,但可通过CONFIG SET maxmemory-policy allkeys-lfu开启。笔记里提醒:LFU 需要足够“学习时间”,新上线服务要预热 2 小时,否则冷启动时命中率骤降。预热脚本很简单:

# 预热 top 1000 热门短码 redis-cli --scan --pattern "short:*" | head -1000 | xargs -I {} redis-cli GET {}

5. 常见问题与排查技巧实录:那些文档里不会写的“脏活”

5.1 问题速查表:从现象反推根因的决策树

现象可能根因排查命令解决方案
短链跳转 503 比例突增Redis 连接池耗尽redis-cli info clients | grep "connected_clients"增加连接池大小,或检查是否有未关闭的连接
生成短码重复率升高Snowflake 时钟回拨cat /proc/sys/kernel/timeconstwait_for_clock_sync()防回拨,或切换为数据库自增
缓存命中率持续低于 70%短码生成逻辑未走缓存tcpdump -i lo port 6379 -w redis.pcap检查生成服务代码,确认cache.put()调用位置
DB CPU 飙升至 95%慢查询未走索引mysqldumpslow -s t -t 10 /var/log/mysql/slow.logshort_code字段添加联合索引(short_code, created_at)

5.2 “缓存雪崩”的实战防御:不止是随机过期时间

所有笔记都提“加随机过期时间”,但很少说清随机范围怎么定。我的经验是:随机范围必须大于缓存重建耗时。比如:

  • Redis 缓存重建需 2 秒(从 DB 查 1000 条数据);
  • 如果过期时间随机范围是 ±1 秒,则仍有 50% 概率多个 key 同时过期;
  • 正确做法是 ±5 秒,确保重建完成前,新 key 已开始过期。

笔记里记录了一次真实事故:某天凌晨 2 点,所有短链缓存集中过期,DB 瞬间被打满。复盘发现,随机范围只设了 ±1 秒。修复后,把expire = base_expire + random(0, 10)写死在代码里,并加监控告警:“缓存过期时间标准差 < 3 秒”即触发预警。

5.3 一致性难题的终极妥协:什么时候该放弃强一致?

这是系统设计最痛苦的抉择。我的笔记里明确列出三条放弃强一致的红线:

  1. 业务可容忍:订单支付成功后,短信延迟 2 秒发送,用户无感知;
  2. 技术成本过高:为保证库存扣减绝对一致,需引入分布式事务,TPS 从 5000 降到 800;
  3. 监控可覆盖:有完善的对账系统,能 5 分钟内发现不一致并自动修复。

短链服务中,我们接受“生成成功后,缓存和 DB 最多 1 秒不一致”。因为:

  • 用户生成后立即跳转,概率极低;
  • 1 秒内不一致,用户最多看到 404,刷新即好;
  • 对账任务每 5 分钟扫描一次,修复不一致记录。

实操心得:不要追求“理论上的一致”,而要计算“不一致带来的业务损失”。我算过:短链不一致导致的 404,每 10 万次跳转发生 1 次,按每次损失 0.01 元广告费,年损失不到 2000 元;而强一致方案年运维成本 15 万。这笔账,决定了技术选型。

5.4 压测陷阱:为什么 1000QPS 的压测结果不能外推?

很多人用 JMeter 压出 1000QPS 就宣布系统达标,但真实世界更残酷。我的笔记里记录了三次压测认知升级:

  • 第一次:单机压测,忽略网络抖动,结果 1000QPS P99=120ms;
  • 第二次:混布压测(同机器跑 DB 和应用),网络延迟增加 15ms,P99 升至 210ms;
  • 第三次:全链路压测(含 CDN、LB、DB),发现 LB 在 800QPS 时开始丢包,最终确定安全水位是 650QPS。

因此,笔记里强制要求:所有压测报告必须注明“压测环境拓扑”,并给出“各组件瓶颈点”。比如:“Redis 在 400QPS 时 CPU 达 85%,为瓶颈;MySQL 在 600QPS 时 IO Wait 35%,为次瓶颈”。

6. 经验沉淀:那些让笔记真正“活”起来的细节

6.1 笔记版本管理:为什么用 Git 而不用 Notion?

Notion 适合记录,但不适合演进。我的 system-design-notes 用 Git 管理,原因有三:

  • 可追溯决策git log -p能看到每次架构调整的 commit message,比如 “v2.3: 将限流从 Guava 切换为 Redis+Lua,解决集群不共享问题”;
  • 可分支实验:为验证新方案,建feature/redis-cluster分支,跑通后再 merge;
  • 可自动化:用 GitHub Actions 每日抓取线上监控数据(QPS、延迟、错误率),生成趋势图嵌入笔记。

提示:Git 仓库里,/docs存 Markdown 笔记,/scripts存压测脚本和监控采集脚本,/diagrams存 PlantUML 源码(文本格式,可 diff)。这样,笔记不仅是文档,更是可执行的系统资产。

6.2 “失败案例”专栏:比成功经验更珍贵的财富

我的笔记里专门有一个failures/目录,记录所有翻车现场:

  • 2023-08-15-redis-pipeline-batch-size-too-large.md:为提升性能,将 Redis pipeline 批次设为 1000,结果单次网络包超 MTU,触发 TCP 分片,延迟翻倍;
  • 2023-11-02-mysql-join-without-index.md:给短链表加了个JOIN user_table ON user_id查询,没加索引,DB 直接卡死;
  • 2024-02-10-kafka-retry-loop.md:消息消费失败后无限重试,导致消息堆积,最终 Kafka 分区 leader 切换失败。

每篇失败记录包含:现象、根因、修复、预防措施。比如第一条的预防措施是:“所有网络传输操作,必须测试 packet size < 1500 bytes”。

6.3 笔记的“呼吸感”:留白与迭代空间的设计哲学

最好的笔记永远 incomplete。我在每个章节末尾都留一个TODO区块:

  • TODO: 验证 etcd 替代 ZooKeeper 的可行性,关注 watch 机制延迟
  • TODO: 测试 RocksDB 作为本地缓存的 GC 压力,对比 Caffeine
  • TODO: 评估 WebAssembly 在短码生成中的性能,规避 JVM 启动开销

这些 TODO 不是待办清单,而是系统演进的路标。当某天真的验证了 RocksDB,就把它写进正文,删除 TODO。这种动态生长的结构,让笔记始终与技术演进同步,而不是成为尘封的古籍。

6.4 个人体会:笔记的价值不在“写完”,而在“用烂”

写了五年 system-design-notes,我最大的体会是:笔记的终极检验标准,是你敢不敢把它当生产环境的决策依据。去年我们上线新短链服务,所有技术方案都直接从笔记里 copy-paste,只改了参数(QPS 从 150 调到 300)。上线后监控显示:P99 延迟 182ms,错误率 0.003%,完全符合预期。那一刻我知道,笔记不再是“学习资料”,而是“生产力工具”。它不追求完美,但必须真实——每一个参数都有出处,每一个方案都有实测数据,每一个结论都经得起线上流量的拷问。如果你的笔记还停留在“抄概念”,那它只是废纸;只有当你开始为它写git commit -m "fix: 修复短码生成并发冲突"时,它才真正活了过来。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/16 2:35:44

蒙特卡洛抽样在电动汽车充电负荷建模中的工程应用

简介&#xff1a;本资源是面向电力系统工程师、新能源规划研究人员及高校电气专业研究生的蒙特卡洛法电动汽车充电负荷建模实践包&#xff0c;聚焦城市配电网负荷预测与基础设施规划中的关键不确定性建模问题。压缩包共21个文件&#xff0c;含8个MATLAB源码&#xff08;.m&…

作者头像 李华
网站建设 2026/9/16 2:35:18

PyTorch遥感语义分割实战:高分影像地物分类与地理坐标保真输出

简介&#xff1a;本资源是一套面向遥感图像处理与深度学习初学者的完整语义分割实践项目&#xff0c;聚焦高分卫星遥感影像的地物精细分类任务&#xff0c;适用于高校遥感、地信、人工智能方向的学生及工程实践者。项目基于PyTorch框架实现&#xff0c;涵盖数据预处理、UNet等主…

作者头像 李华
网站建设 2026/9/16 2:35:15

CentOS 8离线升级内核:RPM下载、依赖处理与启动项配置指南

1. 离线升级前的准备&#xff1a;先把环境摸清楚1.1 先确认当前内核版本和系统版本离线升级内核这件事&#xff0c;听起来就是“下载几个包、装上、重启”三连&#xff0c;实际上坑都藏在你对当前环境的认知盲区里。我在接到这类需求时&#xff0c;第一件事永远是先确认两样东西…

作者头像 李华
网站建设 2026/9/16 2:33:22

基于SpringBoot的问卷调查管理系统:从数据库设计到防重提交全解析

简介&#xff1a;基于SpringBoot框架的问卷调查管理系统源码与数据库&#xff0c;属于高分开源毕业设计项目&#xff0c;评审获得九十九分。面向计算机相关专业正在准备毕业设计、课程设计或期末大作业的学生&#xff0c;也适合需要项目实战练习的学习者。压缩包共三百七十五个…

作者头像 李华
网站建设 2026/9/16 2:32:26

3个维度选中国做的手机系统下载网站哪家好

3个维度选中国做的手机系统下载网站哪家好 备案卡壳三天没动静,后台日志全是404,这种焦头烂额的感觉我太懂了。很多老板盯着【中国做的手机系统下载网站】这行字,心里其实没底:到底哪家技术栈稳?哪家SEO能落地?…

作者头像 李华
网站建设 2026/9/16 2:32:19

三维点云语义分割实战:从数据准备、模型选型到工程落地

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华