Docker 中的基本 Go RPC 因 SIGSEGV 而失败

Posted

技术标签:

【中文标题】Docker 中的基本 Go RPC 因 SIGSEGV 而失败【英文标题】:Basic Go RPC in Docker fails with SIGSEGV 【发布时间】:2020-05-30 16:08:24 【问题描述】:

我正在尝试使用 Golang 在两个 docker 容器之间运行一个简单的客户端/服务器 RPC 示例。

当我在本地机器上运行它们时,构建和运行都完美无缺。我知道将它们构建到 docker 容器中可能会出现一些我需要解决的通信错误,但我什至无法到达那个阶段,因为我在尝试运行我的客户端时遇到了分段错误。

当我运行主(服务器)容器时,它可以工作,没有问题。但是当我运行工人(客户端)时,我得到了这个:

panic: runtime error: invalid memory address or nil pointer `   `dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x10 
pc=0x72425d]

goroutine 1 [running]:
net/rpc.(*Client).send(0x0, 0xc0000d61e0)
        /usr/local/go/src/net/rpc/client.go:72 +0x3d
net/rpc.(*Client).Go(0x0, 0x7e062d, 0xa, 0x7887e0, 
0xc0000b04a8, 0x788860, 0xb0c440, 0xc0000aa300, 
0xc0000d6190)
        /usr/local/go/src/net/rpc/client.go:316 +0xcc
net/rpc.(*Client).Call(...)
        /usr/local/go/src/net/rpc/client.go:322
main.main()
        /app/worker.go:20 +0x11c
exit status 2

我的master.go:

package main

import (
    "fmt"
    "net"
    "net/http"
    "net/rpc"
)

type Args struct 
    Addthis int


type Reply struct 
    Ret int

type Api int

func (master *Api) Add(args Args, reply *Reply) error 
    out := args.Addthis + 10
    reply.Ret = out
    return nil


func main() 
    var master = new(Api)
    rpc.Register(master)
    rpc.HandleHTTP()
    listener, _ := net.Listen("tcp", ":4040")
    fmt.Printf("\nServing on %d\n", 4040)
    http.Serve(listener, nil)

我的主 Dockerfile:

FROM golang:latest

WORKDIR /app

COPY ./ /app

EXPOSE 4040

ENTRYPOINT go run master.go

我使用以下方式构建和运行 master:

docker build -t master
docker run --net=testnet --name=master master

这很好用。

我的工人.go

package main

import (
    "fmt"
    "net/rpc"
)

type Args struct 
    Addthis int


type Reply struct 
    Ret int


func main() 
    var reply Reply
    client, _ := rpc.DialHTTP("tcp", ":4040")
    num := Args215
    client.Call("master.Add", num, &reply)
    fmt.Println("Here")
    fmt.Printf("\nGot back: %d\n", reply.Ret) 

我的工人 Dockerfile:

FROM golang:latest

WORKDIR /app

COPY ./ /app

EXPOSE 4040

ENTRYPOINT go run worker.go

我构建并运行worker:

docker build -t worker .
docker run --net=testnet --name=worker worker

那是我收到上述错误的时候。

谷歌搜索了三个小时,似乎没有任何帮助。我想我不知道要使用什么搜索。

我知道这可能实际上不会按原样进行通信,但我想调试通信问题,而不是处理分段错误。代码是我的教授提供的,不是作为作业的一部分,而是因为我要求它。他声称这对他来说没有问题,并且对我的故障排除没有帮助(我认为他实际上没有尝试将它部署在容器中,但我不会打电话给他。他很“敏感”)。 “尝试堆栈交换!”真的。

【问题讨论】:

不要忽略rpc.DialHTTP返回的错误(或其他错误)。 有证据表明客户为空。 HTTP 拨号可能存在​​非空错误。 完全正确!我发现了错误,现在我得到“拨号 tcp:4040:连接:连接被拒绝”然后我得到了 seg 错误。我认为这与我实际上没有输入 ip 的事实有关? 这意味着在 localhost 端口:4040 上没有任何监听。如果您正在运行两个单独的容器,则需要设置适当的网络,它不会在 localhost 上。您还应该正确处理错误,而不仅仅是继续尝试使用客户端。 【参考方案1】:
client, _ := rpc.DialHTTP("tcp", ":4040")

这基本上意味着您正在尝试连接到同一容器上的端口 4040,但是,您的主服务器在不同的容器中运行。要连接到您的主容器,您需要连接到 ip that docker has assigned automatically:4040(用于测试)或 setup your docker network 以正确使用容器。

【讨论】:

以上是关于Docker 中的基本 Go RPC 因 SIGSEGV 而失败的主要内容,如果未能解决你的问题,请参考以下文章

go微服务RPC的原理与Go RPC

go微服务RPC的原理与Go RPC

Go 中的 RPC 有某种缓存?

微服务学习RPC原理与Go RPC

go rpc 源码分析

摸清 Go RPC 原理的第一步!