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

【实战 ES】实战 Elasticsearch:快速上手与深度实践-2.3.1 避免频繁更新(Update by Query的代价)

👉 点击关注不迷路
👉 点击关注不迷路
👉 点击关注不迷路


文章大纲

  • Elasticsearch数据更新与删除深度解析:2.3.1 避免频繁更新(Update by Query的代价)
    • 案例背景
    • 1. `Update by Query`的内部机制解析
      • 1.1 文档更新底层实现原理
      • 1.2 更新操作资源消耗模型
    • 2. 频繁更新引发的性能问题
      • 2.1 分段(`Segment`)爆炸效应
      • 2.2 版本控制开销
      • 2.3 真实问题诊断数据
    • 3. 真实场景压力测试数据
      • 3.1 测试环境
      • 3.2 不同更新频率对比(更新频率与性能衰减关系)
      • 3.3 性能衰减曲线
    • 4. 优化方案与替代策略
      • 4.1 数据结构优化
      • 4.2 写入模式改造
      • 4.3 版本控制优化配置
    • 5. 生产环境故障恢复实践
      • 5.1 紧急止血方案
      • 5.2 长期治理措施
      • 5.3 效果验证
    • 关键结论与最佳实践
      • 避坑指南
      • 终极解决方案

Elasticsearch数据更新与删除深度解析:2.3.1 避免频繁更新(Update by Query的代价)

案例背景

某物流追踪平台在业务升级后出现集群性能断崖式下降

  • 数据规模:每日处理5亿条物流状态更新
  • 更新模式:使用_update_by_query实时修改运单状态
  • 问题表现
    • 写入吞吐量从12万ops/s暴跌至2.3万ops/s
    • 查询延迟P99从180ms上升到2100ms
    • 磁盘IOPS持续保持98%以上

1. Update by Query的内部机制解析

1.1 文档更新底层实现原理

Update请求
创建新文档
标记旧文档为删除
Refresh操作后可见
Segment Merge时物理删除
  • 关键特性对比(不同写操作资源消耗对比):
操作类型写入放大系数磁盘IO类型是否触发Merge
Index(新建)1x顺序写入低概率
Update(更新)3-5x随机读写混合必然触发
Delete(删除)2-3x随机读+顺序写中等概率

1.2 更新操作资源消耗模型

  • 单次更新成本公式:
总消耗 = 读操作(获取原文) + 写操作(新文档) + 删除标记 + 版本更新 2.5 × 文档大小 × 副本数
  • 典型资源消耗比例:
    • CPU消耗:比新建操作高40-60%
    • 磁盘IO:比新建操作高300-500%
    • 内存压力:需要维护版本映射表

2. 频繁更新引发的性能问题

2.1 分段(Segment)爆炸效应

  • 更新操作对Lucene段的影响:
# 查看分段状态
GET /_cat/segments?v# 问题集群输出示例:
index      shard prirep segment generation docs.count size.mb
logs-2023  0     p      _6               1500000    350
logs-2023  0     p      _7               800000     180  # 更新产生的分段
logs-2023  0     p      _8               750000     170
  • 分段异常特征:
    • 小分段(<100MB)数量超过50个
    • 单个分片分段总数超过100
    • 存在大量docs.deleted>30%的分段

2.2 版本控制开销

  • 版本号映射表内存消耗:
总内存消耗  文档数 × 16 bytes × 副本数
  • 对于1亿文档的索引:
16B × 100,000,000 × 2 = 3.2GB

2.3 真实问题诊断数据

// 节点性能分析
{// "io" 部分包含了与磁盘输入输出(I/O)操作相关的性能指标"io": {// "write_throughput" 表示磁盘的写入吞吐量,即单位时间内磁盘能够写入的数据量// 这里显示为 "450MB/s",但注释提示正常值应小于 200MB/s// 较高的写入吞吐量可能意味着系统正在进行大量的数据写入操作,可能会对磁盘性能造成较大压力"write_throughput": "450MB/s",  // 正常值<200MB/s// "iowait_percent" 表示 CPU 等待磁盘 I/O 操作完成的时间占比// 这里的值为 98.7,意味着 CPU 大部分时间都在等待磁盘 I/O 操作,磁盘 I/O 可能成为系统的性能瓶颈//  iowait 可能会导致系统响应变慢,影响应用程序的性能"iowait_percent": 98.7},// "jvm" 部分包含了与 Java 虚拟机(JVM)相关的性能指标"jvm": {// "old_gc_count" 表示老年代垃圾回收(Old GC)的次数// 注释提示正常情况下老年代垃圾回收次数应小于 5 /分钟// 这里显示为 35,说明老年代垃圾回收过于频繁// 频繁的老年代垃圾回收会导致系统停顿,影响应用程序的响应时间和吞吐量"old_gc_count": 35,            // 正常<5/分钟// "buffer_pools" 表示 JVM 中的缓冲区池信息"buffer_pools": {// "direct" 表示直接缓冲区池的使用情况// "4.2GB/5GB" 表示当前直接缓冲区池已使用 4.2GB 的内存,总容量为 5GB// 这反映了堆外内存的使用情况,较高的使用比例可能会导致堆外内存压力增大,甚至可能引发内存溢出错误"direct": "4.2GB/5GB"        // 堆外内存压力}}
}

3. 真实场景压力测试数据

3.1 测试环境

组件配置详情
ES集群3节点(16C64G NVMe SSD)
测试数据集1亿条物流数据(含15个字段)
测试模式持续30分钟混合负载(更新+查询)

3.2 不同更新频率对比(更新频率与性能衰减关系)

更新频率吞吐量(ops/s)磁盘IOPS段数量/分片GC停顿(s/min)
100次/秒82,00018,000120.8
500次/秒47,00053,000383.2
1000次/秒19,00089,000716.5
2000次/秒服务不可用100%120+Full GC卡死

3.3 性能衰减曲线

Throughput (k ops/s)
100 ┤■■■■■■■■■■■■■■■■■■■■80 ┤■■■■■■■■■■■□□□□□□□□60 ┤■■■■■■■□□□□□□□□□□□□40 ┤■■■□□□□□□□□□□□□□□□□20 ┤□□□□□□□□□□□□□□□□□□□└───────────────────原始负载  更新+10%  更新+30%  更新+50%
  • 吞吐量的单位是千操作每秒(k ops/s)
    • 原始负载:对应柱状图高度达到 100 k ops/s 的柱子。这表明在原始负载的情况下,系统的吞吐量能够达到 100 千操作每秒,此时系统处于一个相对稳定且高效的处理状态。
    • 更新 +10%:柱状图高度约为 80 k ops/s。当负载在原始基础上增加 10% 时,系统的吞吐量下降到了 80 千操作每秒。这可能是因为系统开始受到额外负载的影响,资源逐渐变得紧张,但仍能保持较高的处理能力。
    • 更新 +50%:柱状图高度约为 40 k ops/s。当负载增加到原始负载的 50% 时,系统的吞吐量大幅下降到 40 千操作每秒。这显示出系统在高负载下已经难以维持高效的处理能力,可能出现了性能瓶颈,如 CPU 使用率过高、内存不足、磁盘 I/O 瓶颈等问题。

4. 优化方案与替代策略

4.1 数据结构优化

  • 不可变数据模型设计
    • 在不可变数据模型里,一旦数据被写入 Elasticsearch,就不会再被修改。
    • 若要更新数据,不会直接在原数据上操作,而是创建一条新的数据记录来替换旧的,旧数据仍然保留在系统中。
// 原始结构(可修改)
{"order_no": "20230809123456","status": "shipped","update_time": "2023-08-09T12:00:00"
}// 优化结构(不可变)
{"order_no": "20230809123456","status_history": [{"status": "created","time": "2023-08-09T10:00:00"},{"status": "shipped","time": "2023-08-09T12:00:00" }]
}

4.2 写入模式改造

  • 事件溯源模式
    在这里插入图片描述在这里插入图片描述

4.3 版本控制优化配置

# 调整索引配置
# 此操作是对名为 "orders"  Elasticsearch 索引进行配置调整,目的是优化索引的性能和功能,以适应特定的业务需求。
# PUT 请求用于更新资源,这里是更新 "orders" 索引的设置。PUT /orders/_settings
{"index": {# "refresh_interval" 用于设置索引的刷新间隔。# 索引刷新操作会将内存中的数据刷新到磁盘上,使其可以被搜索到。# 这里将刷新间隔设置为 "30s",即每隔 30 秒进行一次刷新操作。# 降低刷新频率可以减少磁盘 I/O 操作,提高索引性能,但会增加数据的可见延迟,即新写入的数据可能需要更长时间才能被搜索到。"refresh_interval": "30s",     # 降低刷新频率# "number_of_replicas" 表示索引的副本数量。# 副本用于提高数据的可用性和可靠性,当主分片出现故障时,副本分片可以替代主分片继续提供服务。# 这里将副本数量设置为 0,意味着在写入数据时关闭副本。# 关闭副本可以减少写入时的同步开销,提高写入性能,但会降低数据的冗余性和可用性。在数据写入完成后,可以根据需要再将副本数量调整回来。"number_of_replicas": 0,       # 写入时关闭副本# "soft_deletes" 用于配置软删除功能。# 软删除是指在删除文档时,并不立即从磁盘上物理删除文档,而是标记为已删除,以便后续可以恢复。"soft_deletes": {# "enabled": true 表示启用软删除功能。# 此功能从 Elasticsearch 7.0 版本开始支持,启用后可以在删除文档时保留文档的元数据,方便进行数据恢复和审计。"enabled": true,             # 7.0+ 启用软删除# "retention_leases" 用于控制软删除文档的保留策略。"retention_leases": {# "enabled": true 表示启用保留租约控制。# 保留租约控制可以确保在指定的时间内,软删除的文档不会被物理删除,以便在需要时可以恢复这些文档。"enabled": true            # 保留租约控制}}}
}

5. 生产环境故障恢复实践

5.1 紧急止血方案

# 第一步:限制更新速率# 此步骤的目的是对整个 Elasticsearch 集群的索引存储更新速率进行限制,避免因过高的写入速率导致磁盘 I/O 压力过大,影响集群的稳定性和性能。# PUT 请求用于更新集群的设置,这里更新的是集群的持久化设置,持久化设置会在集群重启后依然生效。PUT _cluster/settings
{"persistent": {# "indices.store.throttle.max_bytes_per_sec" 是一个集群级别的设置参数,用于限制索引存储时每秒允许的最大字节数。# 这里将其设置为 "50mb",意味着集群中所有索引在存储数据时,每秒写入磁盘的数据量不能超过 50 兆字节。"indices.store.throttle.max_bytes_per_sec": "50mb" }
}# 第二步:关闭副本加快 merge# 此步骤是为了在进行某些操作(如强制合并分段)时,提高操作的速度。因为副本的存在会增加数据同步和处理的开销,关闭副本可以减少这些额外的操作。# PUT 请求用于更新索引的设置,这里使用 /_all 表示对集群中的所有索引进行设置更新。
PUT /_all/_settings
{# "index.number_of_replicas" 用于设置索引的副本数量。# 这里将其设置为 0,即关闭所有索引的副本。这样在后续的强制合并分段操作中,就不需要考虑副本数据的同步问题,从而加快合并的速度。# 但需要注意的是,关闭副本会降低数据的冗余性和可用性,在操作完成后,建议根据实际需求恢复副本数量。"index.number_of_replicas": 0
}# 第三步:强制合并分段# 此步骤的主要目的是对名为 "orders" 的索引进行分段合并操作,以减少索引中的分段数量,提高查询性能。#  Elasticsearch 中,数据是以分段(Segment)的形式存储的,随着数据的不断写入和删除,分段数量会逐渐增多,这会增加查询的开销。# 通过强制合并分段,可以将多个小分段合并成较少的大分段,从而提高查询效率。# POST 请求用于触发强制合并操作。# /orders/_forcemerge 表示对 "orders" 索引执行强制合并操作。#?max_num_segments=10 是一个查询参数,指定合并后索引中分段的最大数量为 10POST /orders/_forcemerge?max_num_segments=10

5.2 长期治理措施

  • 三级更新策略
更新类型频率要求实现方式目标延迟
实时型<1秒应用层直接更新500ms
准实时型1-5分钟Kafka+批量更新3分钟
延迟型>30分钟Logstash聚合更新1小时

5.3 效果验证

  • 优化前后核心指标对比:
指标优化前优化后改善幅度
写入吞吐量19,000/s68,000/s258%
段数量/分片71987%
磁盘IOPS89,00022,00075%
GC停顿时间6.5s/min1.2s/min81%

关键结论与最佳实践

避坑指南

      1. 更新频率红线:单个分片每秒更新不超过50次
      1. 版本数监控:定期检查_version字段的统计分布
      1. 分段健康度:控制每个分片分段数<50,单个分段>100MB
      1. 更新模式选择
      • 单字段更新 → 使用Painless脚本
      • 多字段更新 → 整文档替换
      • 状态变更 → 采用追加模式

终极解决方案

  • Lambda架构实现
    在这里插入图片描述在这里插入图片描述

相关文章:

【实战 ES】实战 Elasticsearch:快速上手与深度实践-2.3.1 避免频繁更新(Update by Query的代价)

&#x1f449; 点击关注不迷路 &#x1f449; 点击关注不迷路 &#x1f449; 点击关注不迷路 文章大纲 Elasticsearch数据更新与删除深度解析&#xff1a;2.3.1 避免频繁更新&#xff08;Update by Query的代价&#xff09;案例背景1. Update by Query的内部机制解析1.1 文档更…...

【Python项目】基于Python的书籍售卖系统

【Python项目】基于Python的书籍售卖系统 技术简介&#xff1a;采用Python技术、MYSQL数据库等实现。 系统简介&#xff1a;书籍售卖系统是一个基于B/S结构的在线图书销售平台&#xff0c;主要分为前台和后台两部分。前台系统功能模块分为&#xff08;1&#xff09;用户中心模…...

spring boot + vue 搭建环境

参考文档&#xff1a;https://blog.csdn.net/weixin_44215249/article/details/117376417?fromshareblogdetail&sharetypeblogdetail&sharerId117376417&sharereferPC&sharesourceqxpapt&sharefromfrom_link. spring boot vue 搭建环境 一、浏览器二、jd…...

Linux下的shell指令(一)

作业 1> 在终端提示输入一个成绩&#xff0c;通过shell判断该成绩的等级 [90,100] : A [80, 90) : B [70, 80) : C [60, 70) : D [0, 60) : 不及格 #!/bin/bash read -p "请输入学生成绩:" score if [ "$score" -ge 90 ] && [ "$scor…...

JS禁止web页面调试

前言 由于前端在页面渲染的过程中 会调用很多后端的接口&#xff0c;而有些接口是不希望别人看到的&#xff0c;所以前端调用后端接口的行为动作就需要做一个隐藏。 禁用右键菜单 document.oncontextmenu function() {console.log("禁用右键菜单");return false;…...

GIt分支合并

分支 1: C0 → C1 → C2 → C3&#xff08;最新&#xff09; 分支 2: C0 → C4 → C5 → C6&#xff08;最新&#xff09;1. 找到共同父节点 C0 Git 会先找出 branch1 和 branch2 的共同祖先节点 C0。这通常借助 git merge-base 命令达成&#xff0c;虽然在日常使用 git merge…...

Sqli-labs

1.搭建【前提是已经下载安装好phpstudy_pro】 1.1源码准备 1.1.1源码下载 这里从github下载 https://codeload.github.com/Audi-1/sqli-labs/zip/masterhttps://codeload.github.com/Audi-1/sqli-labs/zip/master 1.1.2下载的靶场源码放到WWW下 将刚才下载的压缩包解压到…...

unreal engine gameplay abiliity 获取ability的cooldown剩余时间

unreal engine gameplay abiliity 获取ability的cooldown 版本 5.4.4 参考 测试代码 if (HasAuthority() && AbilitySystemComponent){TArray<FGameplayAbilitySpecHandle> OutAbilityHandles;AbilitySystemComponent->GetAllAbilities(OutAbilityHandles…...

【GenBI优化】提升text2sql准确率:建议使用推理大模型,增加重试

引言 Text-to-SQL(文本转 SQL)是自然语言处理(NLP)领域的一项重要任务,旨在将自然语言问题自动转换为可在数据库上执行的 SQL 查询语句。这项技术在智能助手、数据分析工具、商业智能(BI)平台等领域具有广泛的应用前景,能够极大地降低数据查询和分析的门槛,让非技术用…...

【六祎 - Note】SQL备忘录;DDL,DML,DQL,DCL

SQL备忘录 from to : 点击访问源地址...

高频 SQL 50 题(基础版)_1341. 电影评分

高频 SQL 50 题&#xff08;基础版&#xff09;_1341. 电影评分 思路 思路 (select Users.name results from Users left join MovieRating on Users.user_id MovieRating.user_id group by(Users.name) order by count(MovieRating.movie_id) desc,Users.name asc limit 1) u…...

JavaScript 变量命名规范

在编写JavaScript代码时&#xff0c;选择合适的变量名对于代码的清晰度、可读性和可维护性至关重要。一个良好的变量命名规范不仅能帮助团队成员更好地理解代码意图&#xff0c;还能减少错误发生的可能性。本文将介绍一些广泛接受的JavaScript变量命名规则和最佳实践。 命名的…...

解决 uView-UI和uv-ui 中 u-tabs 组件在微信小程序中出现横向滚动条的问题

问题描述 在微信小程序中使用 uView-UI 的 u-tabs 组件时&#xff0c;用户可能会遇到横向滚动条的问题。这不仅影响了页面的美观&#xff0c;还可能导致用户误操作。 问题原因 该问题的根本原因是未在微信小程序环境下屏蔽滚动条。uView-UI 的 u-tabs 组件默认只在 H5 环境下…...

20250304解决在飞凌的OK3588-C的Linux R4下解决使用gstreamer保存的mp4打不开

sync poweroff rootok3588:/# sync rootok3588:/# sync rootok3588:/# cd 107 rootok3588:/107# ls -l total 0 rootok3588:/107# sync rootok3588:/107# poweroff 20250304解决在飞凌的OK3588-C的Linux R4下解决使用gstreamer保存的mp4打不开 2025/3/4 10:58 缘起&#xff1a…...

build gcc

1&#xff0c;下载源码 wget https://gcc.gnu.org/pub/gcc/infrastructure/mpfr-4.1.0.tar.bz2 wget https://gcc.gnu.org/pub/gcc/infrastructure/gmp-6.1.0.tar.bz2 wget https://gcc.gnu.org/pub/gcc/infrastructure/mpc-1.2.1.tar.gz git clone --mirror https://github…...

【每日论文】How far can we go with ImageNet for Text-to-Image generation?

下载PDF或查看论文&#xff0c;请点击&#xff1a;LlamaFactory - huggingface daily paper - 每日论文解读 | LlamaFactory | LlamaFactory 摘要 近年来&#xff0c;通过在大规模数据集上训练&#xff0c;文本到图像&#xff08;T2I&#xff09;生成模型已经取得了显著成果&a…...

STM32 两个单片机之间的通信

STM32 两个单片机之间的通信 原创 HS 平凡灵感码头 2025年03月04日 11:25 广东 以上我们就是有A B两个板子来进行通信&#xff0c;A板将接收按键的键值&#xff0c;然后发送给B板&#xff0c;B板接收键值&#xff0c;然后判断键值控制LED翻转&#xff0c;然后把键值按字符形式…...

Linux 下使用traceroute来进行网络诊断分析

简介 traceroute 命令是一种网络诊断工具&#xff0c;用于跟踪数据包从系统到目标服务器的路径。它有助于识别网络延迟和路由问题。 安装 Debian/Ubuntu sudo apt install traceroute -yRHEL/CentOS sudo yum install traceroute -yFedora sudo dnf install traceroute -…...

基于vue框架的游戏商城系统cq070(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。

系统程序文件列表 项目功能&#xff1a;用户,分类,商品信息,游戏高手,游戏代练 开题报告内容 基于Vue框架的游戏商城系统开题报告 一、研究背景与意义 随着互联网技术的飞速发展和游戏产业的蓬勃兴起&#xff0c;游戏商城作为游戏产业链中的重要一环&#xff0c;迎来了前所…...

SpringBoot接入DeepSeek(硅基流动版)+ 前端页面调试(WebSocket连接模式)

文章目录 前言正文一、项目环境二、项目代码2.1 pom.xml2.2 DeepSeekController.java2.3 启动类2.4 logback-spring.xml2.5 application.yaml2.6 WebsocketConfig.java2.7 AiChatWebSocketHandler.java2.8 SaveChatSessionParamRequest.java2.9 index.html 三、页面调试3.1 主页…...

1688商品列表API与其他数据源的对接思路

将1688商品列表API与其他数据源对接时&#xff0c;需结合业务场景设计数据流转链路&#xff0c;重点关注数据格式兼容性、接口调用频率控制及数据一致性维护。以下是具体对接思路及关键技术点&#xff1a; 一、核心对接场景与目标 商品数据同步 场景&#xff1a;将1688商品信息…...

蓝牙 BLE 扫描面试题大全(2):进阶面试题与实战演练

前文覆盖了 BLE 扫描的基础概念与经典问题蓝牙 BLE 扫描面试题大全(1)&#xff1a;从基础到实战的深度解析-CSDN博客&#xff0c;但实际面试中&#xff0c;企业更关注候选人对复杂场景的应对能力&#xff08;如多设备并发扫描、低功耗与高发现率的平衡&#xff09;和前沿技术的…...

基于数字孪生的水厂可视化平台建设:架构与实践

分享大纲&#xff1a; 1、数字孪生水厂可视化平台建设背景 2、数字孪生水厂可视化平台建设架构 3、数字孪生水厂可视化平台建设成效 近几年&#xff0c;数字孪生水厂的建设开展的如火如荼。作为提升水厂管理效率、优化资源的调度手段&#xff0c;基于数字孪生的水厂可视化平台的…...

UR 协作机器人「三剑客」:精密轻量担当(UR7e)、全能协作主力(UR12e)、重型任务专家(UR15)

UR协作机器人正以其卓越性能在现代制造业自动化中扮演重要角色。UR7e、UR12e和UR15通过创新技术和精准设计满足了不同行业的多样化需求。其中&#xff0c;UR15以其速度、精度及人工智能准备能力成为自动化领域的重要突破。UR7e和UR12e则在负载规格和市场定位上不断优化&#xf…...

GruntJS-前端自动化任务运行器从入门到实战

Grunt 完全指南&#xff1a;从入门到实战 一、Grunt 是什么&#xff1f; Grunt是一个基于 Node.js 的前端自动化任务运行器&#xff0c;主要用于自动化执行项目开发中重复性高的任务&#xff0c;例如文件压缩、代码编译、语法检查、单元测试、文件合并等。通过配置简洁的任务…...

AI+无人机如何守护濒危物种?YOLOv8实现95%精准识别

【导读】 野生动物监测在理解和保护生态系统中发挥着至关重要的作用。然而&#xff0c;传统的野生动物观察方法往往耗时耗力、成本高昂且范围有限。无人机的出现为野生动物监测提供了有前景的替代方案&#xff0c;能够实现大范围覆盖并远程采集数据。尽管具备这些优势&#xf…...

2025年渗透测试面试题总结-腾讯[实习]科恩实验室-安全工程师(题目+回答)

安全领域各种资源&#xff0c;学习文档&#xff0c;以及工具分享、前沿信息分享、POC、EXP分享。不定期分享各种好玩的项目及好用的工具&#xff0c;欢迎关注。 目录 腾讯[实习]科恩实验室-安全工程师 一、网络与协议 1. TCP三次握手 2. SYN扫描原理 3. HTTPS证书机制 二…...

Python网页自动化Selenium中文文档

1. 安装 1.1. 安装 Selenium Python bindings 提供了一个简单的API&#xff0c;让你使用Selenium WebDriver来编写功能/校验测试。 通过Selenium Python的API&#xff0c;你可以非常直观的使用Selenium WebDriver的所有功能。 Selenium Python bindings 使用非常简洁方便的A…...

【FTP】ftp文件传输会丢包吗?批量几百个文件传输,有一些文件没有传输完整,如何解决?

FTP&#xff08;File Transfer Protocol&#xff09;本身是一个基于 TCP 的协议&#xff0c;理论上不会丢包。但 FTP 文件传输过程中仍可能出现文件不完整、丢失或损坏的情况&#xff0c;主要原因包括&#xff1a; ✅ 一、FTP传输可能“丢包”或文件不完整的原因 原因描述网络…...

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

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