BaikalDB 架构演进实录:打造融合向量化与 MPP 的 HTAP 查询引擎

导读

BaikalDB作为服务百度商业产品的分布式存储系统,支撑了整个广告库海量物料的存储和OLTP事务处理。随着数据不断增长,离线计算时效性和资源需求压力突显,基于同一份数据进行OLAP处理也更为经济便捷,BaikalDB如何在OLTP系统内实现适合大数据分析场景的查询引擎以应对挑战?

01 BaikalDB应对OLAP场景的挑战

BaikalDB是面向百度商业产品系统的需求而设计的分布式存储系统,过去多年把商业内部几十套存储系统全部统一到BaikalDB,解决了异构存储带来的各种问题,支撑了整个广告库的海量物料存储和复杂的业务查询。BaikalDB核心特点包括:

  • 兼容mysql协议,支持分布式事务:基于Raft协议实现三副本强一致性,通过两阶段提交协议保障跨节点事务的原子性与持久性‌。

  • 丰富检索能力:不仅支持传统的结构化索引、全文索引等,为解决LLM应用的向量需求,BaikalDB通过内置向量索引方式实现向量数据的存储和检索,一套系统支持结构化检索、全文检索、向量检索等丰富的检索能力,综合满足LLM应用的各种记忆存储和检索需求。

  • 高可用,弹性扩展:支持自动扩缩容和数据均衡,支持自动故障恢复和迁移,无单点。当前管理数千业务表与数十万亿行数据,日均处理百亿级请求‌。

△BaikalDB架构

随着业务发展,离线分析难以满足诉求,实时多维分析需求对BaikalDB大数据处理能力的要求显著提高。BaikalDB的查询引擎主要面向OLTP(联机事务处理)场景设计的,以下双重关键瓶颈使其应对OLAP (联机分析处理)有很大的挑战:

  1. 计算性能瓶颈:传统火山模型使用行存结构破坏缓存局部性、逐行虚函数调用风暴频繁中断指令流水线、单调用链阻塞多核并行扩展等等弊端,导致大数据分析性能呈超线性劣化。

  2. 计算资源瓶颈:Baikaldb单节点计算资源有限,面对大规模数据计算,单节点CPU、内存使用容易超限。

BaikalDB从OLTP向HTAP(混合事务/分析处理)架构演进亟需解决当前OLTP查询架构在面向大规模数据的计算性能瓶颈、计算资源瓶颈,并通过如向量化查询引擎、MPP多机并行查询、列式存储等技术手段优化OLAP场景查询性能。

02 BaikalDB OLAP查询引擎的目标

2.1 向量化查询引擎:解决OLTP查询引擎性能瓶颈

2.1.1 火山模型性能瓶颈

设计之初,由于BaikalDB主要面向OLTP场景,故而BaikalDB查询引擎是基于传统的火山模型而实现。

如下图所示,在火山模型里,SQL的每个算子会抽象为一个Operator Node,整个SQL执行计划构建一个Operator Node树,执行方式就是从根节点到叶子节点自上而下不断递归调用next()函数获取一批数据进行计算处理。 由于火山模型简单易用,每个算子独立实现,不用关心其他算子逻辑等优点,使得火山模型非常适合OLTP场景。

△select id, name, age, (age - 30) * 50 as bonus from peope where age > 30 火山模型执行计划

但当火山模型处理大量数据时有着以下三大弊端,这些弊端是导致火山模型面对大数据量分析场景查询性能差的元凶。

  1. 行式存储引发的缓存失效问题‌

    1. 数据局部性缺失‌:行式存储(Row-based Storage)将整行数据连续存放,当查询仅需部分列时,系统被迫加载整行冗余数据,容易造成Cache Miss。

    2. 硬件资源浪费‌:现代CPU三级缓存容量有限,行存结构导致有效数据密度降低。

  2. 逐行处理机制的性能衰减

    1. ‌函数调用过载‌:火山模型要求每个算子逐行调用 next() 接口,处理百万级数据时产生百万次函数调用。

    2. ‌CPU流水线中断‌:频繁的上下文切换导致CPU分支预测失败率升高。

  3. 执行模型的多核适配缺陷

    1. 流水线阻塞‌:Pull-based模型依赖自顶向下的单调用链,无法并行执行相邻算子。

    2. ‌资源闲置浪费‌:现代服务器普遍具备64核以上计算能力,单调用链无法充分利用多核能力。

当查询模式从OLTP轻量操作转向OLAP海量扫描复杂计算时,上述三个弊端导致的查询性能衰减呈现级联放大效应。虽然能做一些如batch计算,算子内多线程计算等优化,但并不能解决根本问题,获得的收益也有限。BaikalDB寻求从根本上解决瓶颈的方法,探寻新架构方案以突破性能瓶颈!

2.1.2 向量化查询引擎

多核时代下的现代数据库执行引擎,发展出了向量化查询引擎,解决上述火山模型的种种弊端,以支持OLAP大数据量查询性能。与火山模型弊端一一对应,向量化执行引擎特点是如下:

  1. 列式存储与硬件加速协同优化

    1. 列存数据紧凑布局‌:采用列式存储结构(Colum-based Storage),将同类型数据连续存储于内存,有效提升CPU缓存行利用率,减少Memory Stall。

    2. ‌SIMD指令集加速‌:通过向量寄存器批量处理128/256/512位宽度的连续数据单元,允许CPU在单个指令周期内对多组数据进行相同的操作。

  2. 批量处理提升缓存亲和性

    1. ‌数据访问模式优化‌:算子/计算函数内部采用批量处理机制,每次处理一批连续数据块。这种连续内存访问模式提升了 CPU DCache 和ICache 的友好性,减少 Cache Miss。

    2. 流水线气泡消除‌:批处理大量减少上下文切换,降低CPU资源空闲周期占比,显著提升流水线吞吐量‌。

  3. 多核并行计算架构创新

    1. Morsel-Driven Parallelism范式‌:将Scan输入的数据划分为多个数据块(称为morsel),morsel作为计算调度的最小单位,能均匀分发给多个CPU core并行处理。

    2. Push-based流水线重构‌:颠覆传统Pull模型,通过工作线程主动推送数据块至下游算子(算子树中的父节点),消除线程间等待开销。数据驱动执行,将算子树切分成多个线性的Pipeline,多Pipeline之间能并行计算。

△向量化执行引擎pipeline并行计算

2.2 MPP多机并行计算的启发:进一步提升OLAP查询性能

向量化执行引擎在OLAP场景有大幅度的性能提升,却仍然无法解决单台计算节点的CPU和内存受限的问题,同时随着处理数据量增大,单节点执行时间呈指数级增长。

为了打破这一单点限制,进一步提升OLAP查询性能,MPP(Massively Parallel Processing)大规模并行计算应运而生,其核心特点有:

  1. ****分布式计算架构:****基于哈希、范围等策略将数据分布到不同计算节点,实现并行计算加速,能显著缩短SQL响应时间。

  2. ****线性扩展:****各计算节点采用无共享架构,通过高速网络实现跨节点数据交换,天然具备横向扩展能力,可通过增加节点线性提升整体吞吐量‌。

△MPP: 3台计算节点并行计算

03 BaikalDB HTAP查询架构落地

3.1 巧妙结合Arrow Acero实现向量化查询引擎

BaikalDB团队在向量化执行引擎设计过程中,秉持"避免重复造轮子"的技术理念,优先探索开源生态的优秀解决方案‌。基于BaikalDB已采用Apache Arrow列式存储格式实现全文索引的技术积淀‌,团队发现Arrow项目最新推出的Acero流式执行引擎子项目展现出三大核心功能:①支持Arrow列式存储格式向量化计算,支持SIMD加速;②Push-Based流式执行框架支持Pipeline并行计算,能充分利用多核能力;③执行框架可扩展——这些特性与BaikalDB对向量化执行引擎的需求高度契合‌。最终团队选择基于Arrow列存格式和Acero流式计算引擎实现BaikalDB向量化执行引擎,不仅大幅度缩短了研发周期,更充分发挥了开源技术生态的协同优势‌。

BaikalDB巧妙结合开源Apache Arrow列存格式和Arrow Acero向量化执行引擎,通过将火山模型计划翻译为Acero执行计划,全程使用Arrow列存格式,计算最终列存结果再列转行返回给用户,在BaikalDB内部实现了适合大量数据计算的向量化查询架构。

核心实现包括以下五点:

  1. 数据格式:将源头RocksDB扫描出来的行存数据直接转为Arrow列存格式,SQL计算全程使用Arrow列存,最终将列存格式的计算结果再转换成行存输出给用户。

  2. 计算函数:将所有BaikalDB计算函数翻译成Arrow Compute Expression,每个Arrow计算函数运行一次处理万行数据,同时能支持部分如AVX2、SSE42等SIMD指令集,支持SIMD加速。

  3. 执行计划:将每个SQL生成的BaikalDB原生执行计划,转换成一个Acero执行计划Exec Plan(包含所有BaikalDB算子翻译成的Acero ExecNode Declaration树),使用Acero向量化执行引擎替换火山模型执行。

  4. 调度器:将进行数据扫描SourceNode的IO Executor和计算的CPU Executor独立开。

    1. 每个Baikaldb和BaikalStore实例内置一个全局的Pthread CPU IO Executor池,支持计算阶段的Push-based Pipeline并行计算,同时支持算子内并行计算,如Agg并发聚合、Join并发Build/Probe等。

    2. 每个SourceNode都独自一个Bthread IO Executor,支持Hash Join或Union的各个子节点能并发查表。

  5. RPC接口:Baikaldb和BaikalStore之间RPC使用Arrow列存格式替换行存pb格式进行数据传输,大幅度降低传输数据大小,同时去掉了pb序列化和反序列化的开销,加速了数据传输效率。

△BaikalDB火山模型(左) BaikalDB向量化引擎(中:Index Lookup HashJoin,右:HashJoin)

3.2 拆解执行计划实现MPP多机并行查询引擎

BaikalDB实现了向量化执行引擎后,大部分OLAP请求性能得到大幅度提升,但很快就遇到了受限于单计算节点资源和性能的case。团队首先对业务场景进行了分析,发现资源/性能卡点主要在集中在最后单点Agg/Join的计算上。

为了破除这一单点限制,因Agg/Join都依赖内部HashTable进行计算,很容易想到按照HashKey将源数据hash shuffle到不同的计算节点进行并行计算来加速计算性能,平摊计算需要的内存和CPU资源,每个计算节点依然可以使用向量化执行引擎加速单机计算性能。如下图所示,这一方案需要解决的核心问题有以下两点:

  1. 实现Exchange算子对进行跨节点数据Shuffle。

  2. 在执行计划合适的地方的插入Exchange算子对拆分为多个并行子计划Fragment。

△BaikalDB Agg Mpp执行示例

△BaikalDB Hash Join Mpp执行示例

3.2.1  Exchange算子跨节点数据shuffle

Exchange算子包括ExchangeSenderNode/ExchangeReceiverNode算子对,必须成对出现,进行跨节点数据分发和接收。ExchangeReceiverNode核心功能主要是接收对应的下游Fragment所有ExchangeSenderNode发来的数据,需保证不重不丢,进行超时处理等。ExchangeSenderNode核心功能是进行数据分发,其分发模式主要有以下三种,以支持不同的场景需求。

  1. SinglePartition:一个或者多个ExchangeSenderNode将所有数据直接完整发送到单个上游Fragment ExchangeReciverNode实例,使用场景如Fragment 0单个计算节点收集最终结果输出给用户。

  2. HashPartition:ExchangeSenderNode将所有数据都先根据指定HashKey计算每一行hash值,根据hash值将每行数据re-partition到不同的发送队列里,最终发送到上游Fragment多个ExchangeReceiverNode,使用场景如Store Fragment将rocksdb扫描出来的数据shuffle到上游多个实例进行Agg/HashJoin计算。

  3. BroadcastPartition:ExchangeSenderNode将所有数据都直接完整发送到多个上游ExchangeReciverNode,使用场景如Join小表数据直接完整发送到上游多个实例进行BroadcastJoin。

△BaikalDB Exchange算子实现(HashPartition)

3.2.2  执行计划拆解多个并行子计划Fragment

在插入Exchange算子对之前,需要给物理执行计划里的每个算子明确其分区属性PartitionProperty,标志着该算子是否可以分发到多个计算节点进行并行加速。PartitionProperty主要有三种:

  1. AnyParitition:该节点没有任何要求,如FilterNode,可以根据相邻节点分区属性情况单节点或多节点执行。

  2. SinglePartition:该节点必须要在单个计算节点上执行,如用于将最终数据打包发送给用户的PacketNode。

  3. HashPartition:该节点可以按照指定key将数据分发到多个计算节点上并行执行,当前只有AggNode和JoinNode会产生HashPartition。

如下图所示,明确了每个算子的分区属性后,需要加入Exchange算子对的位置就很清晰明了了:分区属性有冲突的相邻算子之间。

在物理计划中插入了Exchange算子对后,在一对ExchangeSenderNode/ExchangeReceiverNode之间进行拆解,即可以将单个物理执行计划拆分为多个子执行计划Fragment。单机执行的Fragment在本机执行,多机执行的Fragment发送给多个同集群其他计算节点进行异步执行,store fragment根据表数据分布情况分发给BaikalStore存储集群并行执行。

在MPP物理计划制定过程中,为了减少数据shuffle的开销,尽可能减少SQL shuffle数据量,BaikalDB也实现了多种查询计划优化手段,如limit下推、hash partition fragment合并等等。

△MPP物理计划制定过程

3.3  自适应策略支持一套系统应对TP/AP请求

BaikalDB设计HTAP架构的核心目标是一套系统能同时兼容OLTP和OLAP请求,无需业务进行任何改造,这需要系统拥有极强的兼容性。

目前BaikalDB内部有三种执行方式:火山模型、单机向量化执行引擎、MPP多机执行引擎,不同的执行引擎适用不同数据量级的SQL。随着数据量大小从小到大,适合的计算引擎是火山模型执行 → 单机向量化执行 → MPP多机并行执行,原因有以下两点:

  1. 火山模型执行对比向量化执行更为轻量,导致在OLTP小请求(如SQL涉及数据行数<1024)方面,传统火山模型性能比单机向量化执行性能更好。

  2. MPP执行会带来额外的网络开销(数据shuffle)、CPU开销(hash计算和re-partition),导致Baikaldb处理数据量需要超过一定阈值时,Baikaldb多机并行执行才能cover额外的网络/CPU开销,SQL性能才能提升,否则单机向量化执行是性能最优。

BaikalDB实现了智能执行引擎决策系统,支持SQL自适应选择合适的执行引擎,支持一套集群能同时满足业务OLTP和OLAP场景需求。技术实现包含两大核心机制:

  1. 向量化引擎动态热切换:BaikalDB支持SQL在执行过程中,随着数据量增大,从火山模型动态切换到向量化执行引擎执行。

  2. 统计信息驱动MPP加速:BaikalDB支持根据过去执行统计信息决策是否走MPP加速执行,当SQL统计的99分位处理数据行数/大小超过指定的阈值,则SQL直接通过MPP多机并行执行。

04  总结

4.1 项目收益

BaikalDB通过架构创新打造了HTAP架构,期望一套系统支持线上OLTP/OLAP请求,其技术演进路径呈现『混合执行引擎架构自适应选择』的特征:SQL自适应选择火山模型、向量化执行引擎、MPP多机并行执行引擎。

目前BaikalDB HTAP架构已经应用到线上多个业务,大数据量查询取得大幅度的性能提升,同时Baikaldb单点内存使用峰值也得以大幅度下降:

  • 单机向量化执行相对于火山模型执行,大数据量查询请求耗时平均下降62%,最大能下降97%(如11s优化到300ms),内存使用峰值最大能降低56%(57G->25G)。

  • MPP在单机向量化执行基础上,大数据量查询耗时还能进一步优化,查询耗时平均下降54%,最大能下降71%(如42s优化到12s),内存使用峰值最大能降低80%(5 hash partition)。

4.2 未来展望

BaikalDB HTAP架构目前还在不断发展,包括性能优化、丰富支持算子和计算函数等等,未来还预期结合列式存储、CBO等技术进一步提升OLAP场景性能:

  • 结合列式存储提升数据扫描性能:目前BaikalDB向量化查询引擎和MPP查询引擎全程基于Arrow列存格式,但是底层数据存储仍然是行存,存在一次行转列的开销;并且OLAP场景,更适合使用列存格式作为底层数据存储格式。BaikalDB当前在发展列存引擎,未来单机向量化和MPP能直接基于底层列式存储,进一步提升OLAP场景查询性能。

  • 结合CBO(Cost-Based Optimization)优化自适应MPP选择策略:当前BaikalDB是基于过去的执行统计信息判断SQL是否适合走MPP,当SQL过去执行统计信息波动巨大时,自适应判断方法可能会失效,未来可能结合代价模型来进一步优化MPP选择策略。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.pswp.cn/pingmian/84294.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【抖音小程序】通用交易系统-下单问题整理

在通用交易系统中&#xff0c;支付流程如下 1、服务端-预下单&#xff1a;生成参数与签名信息&#xff08;此过程不需要与抖音平台对接&#xff09; 参考 生成下单参数与签名_抖音开放平台 2、小程序用户端&#xff1a;根据返回的参数与签名&#xff0c;拉起抖音支付&#x…

模型参数、模型存储精度、参数与显存

模型参数量衡量单位 M&#xff1a;百万&#xff08;Million&#xff09; B&#xff1a;十亿&#xff08;Billion&#xff09; 1 B 1000 M 1B 1000M 1B1000M 参数存储精度 模型参数是固定的&#xff0c;但是一个参数所表示多少字节不一定&#xff0c;需要看这个参数以什么…

EurekaServer 工作原理

一、核心工作流程 二、核心组件解析 1. 自动配置引擎 入口&#xff1a;EnableEurekaServer 引入 EurekaServerMarkerConfiguration&#xff0c;创建标记Bean Marker触发条件&#xff1a;EurekaServerAutoConfiguration 检测到 Marker 存在时激活关键Bean初始化&#xff1a; …

Playwright 与 Selenium:自动化测试的两大主流工具对比

《Playwright 与 Selenium&#xff1a;自动化测试的两大主流工具对比》 *Playwright 和 Selenium 是自动化测试领域的两大主流工具&#xff0c;二者在架构设计、功能特性和适用场景上存在显著差异&#xff0c;以下是核心对比&#xff1a; 一、架构与设计理念 维度Playwright…

网络编程(Modbus进阶)

思维导图 Modbus RTU&#xff08;先学一点理论&#xff09; 概念 Modbus RTU 是工业自动化领域 最广泛应用的串行通信协议&#xff0c;由 Modicon 公司&#xff08;现施耐德电气&#xff09;于 1979 年推出。它以 高效率、强健性、易实现的特点成为工业控制系统的通信标准。 包…

R语言速释制剂QBD解决方案之二

影响含量均一性的显著因子&#xff08;%RSD&#xff09; 数据分析表明含量均一性的弯曲性不显著。如半正态图&#xff08;图12&#xff09;所示&#xff0c;影响含量均一性的显著因子为A&#xff08;原料药粒径&#xff09;和C&#xff08;MCC/Lactose&#xff09;。 mod2 <…

大模型原理、架构与落地

近年来&#xff0c;大模型&#xff08;Large Language Models&#xff0c;LLMs&#xff09;在人工智能领域迅猛发展&#xff0c;从GPT-3到GPT-4、Claude、Gemini、文心一言、GLM等模型相继发布&#xff0c;大模型已逐渐走出实验室&#xff0c;迈向产业落地。本文将从技术原理、…

WWDC 2025 macOS 26有哪些更新点

在2025年6月10日凌晨结束的WWDC 2025发布会中&#xff0c;苹果正式发布了全新的macOS 26&#xff0c;并给其命名为Tahoe。 以下为macOS相关的主要内容&#xff1a; 命名方式改变 苹果正式将各大系统的版本号改为对应年份&#xff0c;让命名方式更直观好记&#xff0c;macOS 2…

AI+预测3D新模型百十个定位预测+胆码预测+去和尾2025年6月10日第104弹

从今天开始&#xff0c;咱们还是暂时基于旧的模型进行预测&#xff0c;好了&#xff0c;废话不多说&#xff0c;按照老办法&#xff0c;重点8-9码定位&#xff0c;配合三胆下1或下2&#xff0c;杀1-2个和尾&#xff0c;再杀4-5个和值&#xff0c;可以做到100-300注左右。 (1)定…

.NET 8集成阿里云短信服务完全指南【短信接口】

文章目录 前言一、准备工作1.1 阿里云账号准备1.2 .NET 8项目创建 二、集成阿里云短信SDK2.1 安装NuGet包2.2 配置阿里云短信参数2.3 创建配置类 三、实现短信发送服务3.1 创建短信服务接口3.2 实现短信服务3.3 注册服务 四、创建控制器五、测试与优化5.1 单元测试5.2 性能优化…

解决HuggingFace不能git clone的问题

今天在从HuggingFace上clone项目的时候&#xff0c;一直出现超时问题&#xff0c;查了很多资料没有解决&#xff0c;后来向mentor请教了一下&#xff0c;可以通过镜像的方法解决这个问题&#xff0c;所以把方法放上来&#xff0c;希望对大家有帮助。 HuggingFace的服务器在国外…

Zookeeper 集群部署与故障转移

Zookeeper 介绍 Zookeeper 是一个开源的分布式协调服务&#xff0c;由Apache基金会维护&#xff0c;专为分布式应用提供高可用、强一致性的核心基础能力。它通过简单的树形命名空间&#xff08;称为ZNode树&#xff09;存储数据节点&#xff08;ZNode&#xff09;&#xff0c;…

简单聊下阿里云DNS劫持事件

阿里云域名被DNS劫持事件 事件总结 根据ICANN规则&#xff0c;域名注册商&#xff08;Verisign&#xff09;认定aliyuncs.com域名下的部分网站被用于非法活动&#xff08;如传播恶意软件&#xff09;&#xff1b;顶级域名DNS服务器将aliyuncs.com域名的DNS记录统一解析到shado…

服务器出现故障怎么办?快速排查与解决方法

服务器故障的常见原因分析 硬件故障&#xff1a;内存、硬盘、网络设备故障。 软件故障&#xff1a;操作系统、应用程序、数据库异常。 网络攻击&#xff08;如DDoS攻击&#xff09;造成资源耗尽。 快速排查故障的步骤 检查监控系统报警日志。 查看系统资源使用情况&#x…

Claude vs ChatGPT vs Gemini:功能对比、使用体验、适合人群

随着AI应用全面进入生产力场景&#xff0c;市面上的主流AI对话工具也进入“三国杀”时代&#xff1a; Claude&#xff08;Anthropic&#xff09;&#xff1a;新锐崛起&#xff0c;语言逻辑惊艳&#xff0c;Opus 模型被称为 GPT-4 杀手ChatGPT&#xff08;OpenAI&#xff09;&a…

Git 使用大全:从入门到精通

Git 是目前最流行的分布式版本控制系统&#xff0c;被广泛应用于软件开发中。本文将全面介绍 Git 的各种功能和使用方法&#xff0c;包含大量代码示例和实践建议。 文章目录 Git 基础概念版本控制系统Git 的特点Git 的三个区域Git 文件状态 Git 安装与配置安装 GitLinuxmacOSWi…

SpringBoot 框架第 1 次接口调用慢

文章目录 背景分析思路 1:DeepSeek 分析思路 2:日志分析思路 3:Arthas 分析下载 Arthas启动 Arthastrace 调用耗时分析Controller 调用耗时Service 调用分析ServiceImpl 耗时分析IService 耗时分析BaseMapper 耗时分析debug 执行链路MyBatisMapperProxy 解读解决思路 1:预热…

数据分析Agent构建

数据分析agent构建 代码资料来源于 Streamline-Analyst&#xff0c;旨在通过该仓库上的代码了解如何使用大语言模型构建数据分析工具&#xff1b; 个人仓库&#xff1a;Data-Analysis-Agent-Tutorial 不同的在于 Data-Analysis-Agent-Tutorial 是在 Streamline-Analyst 基础…

Java后端检查空条件查询

通过抛出运行异常&#xff1a;throw new RuntimeException("请输入查询条件&#xff01;");BranchWarehouseServiceImpl.java // 查询试剂交易&#xff08;入库/出库&#xff09;记录Overridepublic List<BranchWarehouseTransactions> queryForReagent(Branch…

6️⃣Go 语言中的哈希、加密与序列化:通往区块链世界的钥匙

Go 语言中的哈希、加密与序列化:通往区块链世界的钥匙 一、前言:离区块链还有多远? 区块链听起来可能遥不可及,似乎是只有密码学专家和资深工程师才能涉足的领域。但事实上,构建一个区块链的核心并不复杂,尤其当你已经掌握了一门系统编程语言,比如 Go。 要真正理解区…