阿里云环境部署Hyperledger Fabric之SIGSEGV问题分析和解决经验分享

简介: 引言 最近收到Hyperledger社区的一些朋友反馈在阿里云环境上部署开源区块链项目Hyperledger Fabric的过程中遇到了和SIGSEV相关的fatal error,正好我此前也遇到并解决过类似的问题,因此这里分享一下当时问题的分析过程和解决的经验,希望能带来一点启发和帮助。

最近收到Hyperledger社区的一些朋友反馈在阿里云环境上部署开源区块链项目Hyperledger Fabric的过程中遇到了和SIGSEV相关的fatal error,正好笔者此前也遇到并解决过类似的问题,因此这里分享一下当时问题的分析过程和解决的经验,希望能为大家带来一点启发和帮助。


问题描述

在部署Hyperledger Fabric过程中,peer、orderer服务启动失败,同时cli容器上执行cli-test.sh测试时也报错。错误类型均是signal SIGSEGV: segmentation violation。错误日志示例如下:

2017-11-01 02:44:04.247 UTC [peer] updateTrustedRoots -> DEBU 2a0 Updating trusted root authorities for channel mychannel
fatal error: unexpected signal during runtime execution
[signal SIGSEGV: segmentation violation code=0x1 addr=0x63 pc=0x7f9d15ded259]
runtime stack:
runtime.throw(0xdc37a7, 0x2a)
        /opt/go/src/runtime/panic.go:566 +0x95
runtime.sigpanic()
        /opt/go/src/runtime/sigpanic_unix.go:12 +0x2cc
goroutine 64 [syscall, locked to thread]:
runtime.cgocall(0xb08d50, 0xc4203bcdf8, 0xc400000000)
        /opt/go/src/runtime/cgocall.go:131 +0x110 fp=0xc4203bcdb0 sp=0xc4203bcd70
net._C2func_getaddrinfo(0x7f9d000008c0, 0x0, 0xc420323110, 0xc4201a01e8, 0x0, 0x0, 0x0)

分析过程

我们进行了深入分析和试验,在Hyperledger Fabric这个bug https://jira.hyperledger.org/browse/FAB-5822的启发下,采用了如下workaround可以解决这个问题:

  • 在docker compose yaml里对peer、orderer、cli的环境变量加入GODEBUG=netdns=go

这个设置的作用是不采用cgo resolver (从错误日志里可看到是cgo resolver抛出的错误)而采用pure go resolver。

进一步分析golang在什么情况下会在cgo resolver和pure go resolver之间切换:

  • golang的官方文档说明:https://golang.org/pkg/net/

    Name Resolution
    The method for resolving domain names, whether indirectly with functions like Dial or directly with functions like LookupHost and LookupAddr, varies by operating system.
    On Unix systems, the resolver has two options for resolving names. It can use a pure Go resolver that sends DNS requests directly to the servers listed in /etc/resolv.conf, or it can use a cgo-based resolver that calls C library routines such as getaddrinfo and getnameinfo.
    By default the pure Go resolver is used, because a blocked DNS request consumes only a goroutine, while a blocked C call consumes an operating system thread. When cgo is available, the cgo-based resolver is used instead under a variety of conditions: on systems that do not let programs make direct DNS requests (OS X), when the LOCALDOMAIN environment variable is present (even if empty), when the RES_OPTIONS or HOSTALIASES environment variable is non-empty, when the ASR_CONFIG environment variable is non-empty (OpenBSD only), when /etc/resolv.conf or /etc/nsswitch.conf specify the use of features that the Go resolver does not implement, and when the name being looked up ends in .local or is an mDNS name.
    The resolver decision can be overridden by setting the netdns value of the GODEBUG environment variable (see package runtime) to go or cgo, as in:
    export GODEBUG=netdns=go # force pure Go resolver
    export GODEBUG=netdns=cgo # force cgo resolver*

根据这一线索,我们对比了此前部署成功环境和最近部署失败环境各自的底层配置文件,最终找到了不同之处:

  • 在老环境(区块链部署成功)上的容器里,查看

    # cat /etc/resolv.conf 
    nameserver 127.0.0.11
    options ndots:0
    
  • 在新环境(区块链部署失败)上的容器里,查看

    # cat /etc/resolv.conf 
    nameserver 127.0.0.11
    options timeout:2 attempts:3 rotate single-request-reopen ndots:0
    

这个差异导致了老的成功环境是采用pure Go resolver的,而在新的失败环境被切换到cgo resolver, 这是因为含有pure Go resolver不支持的options single-request-reopen。

注:Pure Go resolver目前仅支持ndots, timeout, attempts, rotate
https://github.com/golang/go/blob/964639cc338db650ccadeafb7424bc8ebb2c0f6c/src/net/dnsconfig_unix.go

       case "options": // magic options
            for _, s := range f[1:] {
                switch {
                case hasPrefix(s, "ndots:"):
                    n, _, _ := dtoi(s[6:])
                    if n < 0 {
                        n = 0
                    } else if n > 15 {
                        n = 15
                    }
                    conf.ndots = n
                case hasPrefix(s, "timeout:"):
                    n, _, _ := dtoi(s[8:])
                    if n < 1 {
                        n = 1
                    }
                    conf.timeout = time.Duration(n) * time.Second
                case hasPrefix(s, "attempts:"):
                    n, _, _ := dtoi(s[9:])
                    if n < 1 {
                        n = 1
                    }
                    conf.attempts = n
                case s == "rotate":
                    conf.rotate = true
                default:
                    conf.unknownOpt = true
                }
            }

进一步的,我们尝试分析是什么原因导致了新老容器内的resolv.conf的内容变化,发现了原来是最近宿主机ECS的配置文件发生了变化:

  • 失败的环境 - 新创建的ECS:

    # cat /etc/resolv.conf
    # Dynamic resolv.conf(5) file for glibc resolver(3) generated by resolvconf(8)
    #     DO NOT EDIT THIS FILE BY HAND -- YOUR CHANGES WILL BE OVERWRITTEN
    nameserver 100.100.2.138
    nameserver 100.100.2.136
    options timeout:2 attempts:3 rotate single-request-reopen
    
  • 成功的环境 - 原来的ECS:

    # cat /etc/resolv.conf
    # Dynamic resolv.conf(5) file for glibc resolver(3) generated by resolvconf(8)
    #     DO NOT EDIT THIS FILE BY HAND -- YOUR CHANGES WILL BE OVERWRITTEN
    nameserver 100.100.2.136
    nameserver 100.100.2.138
    

另一方面,我们也尝试分析为什么切换到cgo resolver之后会产生SIGSEGV的错误,以下这篇文章解释了static link cgo会导致SIGSEGV的错误:

而这个Hyperledger Fabric的bug则指出了Hyperledger Fabric的build(尤其是和getaddrinfo相关方法)正是static link的:
https://jira.hyperledger.org/browse/FAB-6403

至此,我们找到了问题的根源和复盘了整个问题发生的逻辑:

  • 近期新创建的ECS主机中的resolv.conf内容发生了变化 -> 导致Hyperledger Fabric的容器内域名解析从pure Go resolver切换至cgo resolver -> 触发了一个已知的由静态链接cgo导致的SIGSEGV错误 -> 导致Hyperledger Fabric部署失败。

解决方法建议

更新Hyperledger Fabric的docker compose yaml模板,为所有Hyperledger Fabric的节点(如orderer, peer, ca, cli等)添加环境变量GODEBUG=netdns=go以强制使用pure Go resolver。

相关实践学习
基于ECS搭建云上博客
本实验教您如何在ECS云服务器(Alibaba Cloud Linux 3)的环境下,通过部署LAMP环境并安装WordPress快速搭建个人博客。
7天玩转云服务器
云服务器ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,可降低 IT 成本,提升运维效率。本课程手把手带你了解ECS、掌握基本操作、动手实操快照管理、镜像管理等。了解产品详情:&nbsp;https://www.aliyun.com/product/ecs
目录
相关文章
|
设计模式 敏捷开发 JavaScript
开箱即用的中后台管理模版,建议收藏!
开箱即用的中后台管理模版,建议收藏!
1521 0
非华为笔记本安装华为电脑管家
非华为笔记本安装华为电脑管家
|
9月前
|
Kubernetes 容器 数据库
K8S 部署 阿里云 PolarDB-X 集群(企业版、标准版)minikube 教程
本文介绍在 Minikube Kubernetes 环境中部署 PolarDB-X 数据库的完整实践,涵盖环境准备、Operator 安装、企业版与标准版集群部署。通过 Helm 快速部署 Operator,并分别搭建分布式与三节点高可用架构,验证核心功能。虽 K8S 部署便捷,但生产环境建议谨慎使用,尤其对有状态数据库系统。附系列前8篇安装指南供参考。
3124 5
|
监控 安全 Java
Spring Cloud 微服务治理技术详解与实践指南
本文档全面介绍 Spring Cloud 微服务治理框架的核心组件、架构设计和实践应用。作为 Spring 生态系统中构建分布式系统的标准工具箱,Spring Cloud 提供了一套完整的微服务解决方案,涵盖服务发现、配置管理、负载均衡、熔断器等关键功能。本文将深入探讨其核心组件的工作原理、集成方式以及在实际项目中的最佳实践,帮助开发者构建高可用、可扩展的分布式系统。
740 1
|
9月前
|
Ubuntu Linux 数据库
Linux 环境 Docker 安装 Polardb-X 数据库 容器 教程
本文介绍如何通过 Docker 快速部署 Polardb-X 数据库容器,实现一键启动。涵盖镜像拉取、容器运行、登录验证等步骤,操作简便,适用于快速开发与测试环境。附往期7篇主流系统安装教程。
1823 5
|
存储 关系型数据库 分布式数据库
PolarDB开源数据库进阶课14 纯享单机版
PolarDB不仅支持基于“共享存储+多计算节点”的集群版,还提供类似开源PostgreSQL的单机版。单机版部署简单,适合大多数应用场景,并可直接使用PostgreSQL生态插件。通过Docker容器、Git克隆代码、编译软件等步骤,即可完成PolarDB单机版的安装与配置。具体操作包括启动容器、进入容器、克隆代码、编译软件、初始化实例、配置参数及启动数据库。此外,还有多个相关教程和视频链接供参考,帮助用户更好地理解和使用PolarDB单机版。
1368 1
|
PHP 计算机视觉
罗德里格斯公式推导,以及如何使用cv2.Rodrigues进行旋转矩阵和旋转向量之间的相互转化
罗德里格斯公式推导,以及如何使用cv2.Rodrigues进行旋转矩阵和旋转向量之间的相互转化
1348 0
|
JavaScript 测试技术 Go
Hyperledger fabric部署链码(一)打包链码
fabric部署chaincode-go(智能合约)系列之一
902 0
|
分布式计算 Hadoop Java
Hadoop集群搭建,基于3.3.4hadoop和centos8【图文教程-从零开始搭建Hadoop集群】,常见问题解决
本文是一份详细的Hadoop集群搭建指南,基于Hadoop 3.3.4版本和CentOS 8操作系统。文章内容包括虚拟机创建、网络配置、Java与Hadoop环境搭建、克隆虚拟机、SSH免密登录设置、格式化NameNode、启动Hadoop集群以及通过UI界面查看Hadoop运行状态。同时,还提供了常见问题的解决方案。
Hadoop集群搭建,基于3.3.4hadoop和centos8【图文教程-从零开始搭建Hadoop集群】,常见问题解决
|
安全 Linux PHP
深入理解Linux中的chmod命令
【8月更文挑战第20天】
963 1