自我表扬:《Dubbo 实现原理与源码解析 —— 精品合集》
表扬自己:《D数据库实体设计合集》

摘要: 原创出处 http://www.iocoder.cn/SOFA-Mosn/build-debugging-environment/ 「芋道源码」欢迎转载,保留摘要,谢谢!


🙂🙂🙂关注微信公众号:【芋道源码】有福利:

  1. RocketMQ / MyCAT / Sharding-JDBC 所有源码分析文章列表
  2. RocketMQ / MyCAT / Sharding-JDBC 中文注释源码 GitHub 地址
  3. 您对于源码的疑问每条留言将得到认真回复。甚至不知道如何读源码也可以请教噢
  4. 新的源码解析文章实时收到通知。每周更新一篇左右
  5. 认真的源码交流微信群。

1. 概述

本文,我们将基于 SOFA-Mosn 提供的 sofarpc-sample 示例,搭建一个能够断点调试的环境。

sofarpc-sample 示例的简介如下:

FROM 《配置 SOFARPC 协议 SOFAMesh》

  • 该样例工程演示了如何配置使得 SOFAMesh 作为 SofaRpc 代理。
  • SOFAMesh 之间的协议是 HTTP2 。
  • 为了演示方便,SOFAMesh 监听两个端口,一个转发 Client 的请求,一个收到请求以后转发给 Server 。

可能这样子胖友有点懵逼,下面我们来看一张图:

我是图

😈 可能有胖友又懵逼了,不是 Service Mesh 需要 Istio 么?在本文的搭建的示例里,Istio 并非必须。

2. 依赖工具

  • Go :1.9.2+

    笔者是 Mac 环境,使用 brew install go 安装的 Go 。

  • GoLand

    艿艿的惊叹:GoLand 竟然可以直接调试 Go 代码,完全不用配置环境,好棒!!!此处是不是应该让 GoLand 打一笔广告费到我账头上。

3. 获取代码

# 进入 GOPATH 下的 src 目录
cd $GOPATH/src
# 创建 github.com/alipay 目录
mkdir -p github.com/alipay
cd github.com/alipay

# clone mosn 代码
git clone git@github.com:alipay/sofa-mosn.git
cd sofa-mosn

最终 Mosn 的源代码代码路径为 $GOPATH/src/github.com/alipay/sofa-mosn

4. 导入IDE

使用萌萌的 GoLand 导入 $GOPATH/src/github.com/alipay/sofa-mosn 项目。

5. 启动 Mosn

① 右键 cmd/mosn/main 目录,Debug 运行,如下图所示:

右键 Debug 运行

② 毫无意外,我们发现并未 Debug 成功运行,日志如下:

API server listening at: 127.0.0.1:50592
NAME:
mosn - MOSN is modular observable smart netstub.

USAGE:
___go_build_github_com_alipay_sofa_mosn_cmd_mosn_main [global options] command [command options] [arguments...]

VERSION:
0.0.1

COMMANDS:
start start mosn proxy
stop stop mosn proxy
reload reconfiguration
help, h Shows a list of commands or help for one command

GLOBAL OPTIONS:
--help, -h show help
--version, -v print the version

COPYRIGHT:
(c) 2018 Ant Financial

为什么呢?因为我们没有配置 Mosn 需要的配置文件。修改 go build github.com/alipay/sofa-mosn/cmd/mosn/mainRun/Debug Configurations ,如下图所示:Run/Debug Configurations

  • 红框 Program arguments 填入 start -c /Users/yunai/Go/src/github.com/alipay/sofa-mosn/examples/sofarpc-sample/config.json 。其中,/Users/yunai/Go/src/github.com/alipay/sofa-mosn/examples/sofarpc-sample/config.json 修改成自己的 /Users/yunai/Go 修改成自己的 $GOPATH

然后,重新点击小虫虫,进入调试模式。输入如下日志:

API server listening at: 127.0.0.1:50637
2018/09/06 22:52:05 load config from : /Users/yunai/Go/src/github.com/alipay/sofa-mosn/examples/sofarpc-sample/config.json
2018/09/06 22:52:05 [INFO]start by config : &{Servers:[{ServerName: DefaultLogPath:stdout DefaultLogLevel: UseNetpollMode:false GracefulTimeout:0s Processor:0 Listeners:[{Name:serverListener Address:127.0.0.1:2046 BindToPort:true Inspector:false FilterChains:[{FilterChainMatch: TLS:{Status:false Type: ServerName: CACert: CertChain: PrivateKey: VerifyClient:false InsecureSkip:false CipherSuites: EcdhCurves: MinVersion: MaxVersion: ALPN: Ticket: ExtendVerify:map[]} Filters:[{Type:proxy Config:map[downstream_protocol:Http2 upstream_protocol:SofaRpc virtual_hosts:[map[name:serverHost domains:[*] routers:[map[match:map[headers:[map[name:service value:.*]]] route:map[cluster_name:serverCluster]]]]]]}]}] StreamFilters:[] LogPath:stdout LogLevel: HandOffRestoredDestinationConnections:false AccessLogs:[]} {Name:clientListener Address:127.0.0.1:2045 BindToPort:true Inspector:false FilterChains:[{FilterChainMatch: TLS:{Status:false Type: ServerName: CACert: CertChain: PrivateKey: VerifyClient:false InsecureSkip:false CipherSuites: EcdhCurves: MinVersion: MaxVersion: ALPN: Ticket: ExtendVerify:map[]} Filters:[{Type:proxy Config:map[downstream_protocol:SofaRpc upstream_protocol:Http2 virtual_hosts:[map[name:clientHost domains:[*] routers:[map[match:map[headers:[map[name:service value:.*]]] route:map[cluster_name:clientCluster]]]]]]}]}] StreamFilters:[] LogPath:stdout LogLevel: HandOffRestoredDestinationConnections:false AccessLogs:[]}]}] ClusterManager:{AutoDiscovery:false RegistryUseHealthCheck:false Clusters:[{Name:serverCluster Type:SIMPLE SubType: LbType:LB_RANDOM MaxRequestPerConn:1024 ConnBufferLimitBytes:32768 CircuitBreakers:[] HealthCheck:{Protocol: Timeout:0s Interval:0s IntervalJitter:0s HealthyThreshold:0 UnhealthyThreshold:0 CheckPath: ServiceName:} ClusterSpecConfig:{Subscribes:[]} Hosts:[{Address:127.0.0.1:8080 Hostname: Weight:0 MetaData:map[] TLSDisable:false}] LBSubsetConfig:{FallBackPolicy:0 DefaultSubset:map[] SubsetSelectors:[]} TLS:{Status:false Type: ServerName: CACert: CertChain: PrivateKey: VerifyClient:false InsecureSkip:false CipherSuites: EcdhCurves: MinVersion: MaxVersion: ALPN: Ticket: ExtendVerify:map[]}} {Name:clientCluster Type:SIMPLE SubType: LbType:LB_RANDOM MaxRequestPerConn:1024 ConnBufferLimitBytes:32768 CircuitBreakers:[] HealthCheck:{Protocol: Timeout:0s Interval:0s IntervalJitter:0s HealthyThreshold:0 UnhealthyThreshold:0 CheckPath: ServiceName:} ClusterSpecConfig:{Subscribes:[]} Hosts:[{Address:127.0.0.1:2046 Hostname: Weight:0 MetaData:map[] TLSDisable:false}] LBSubsetConfig:{FallBackPolicy:0 DefaultSubset:map[] SubsetSelectors:[]} TLS:{Status:false Type: ServerName: CACert: CertChain: PrivateKey: VerifyClient:false InsecureSkip:false CipherSuites: EcdhCurves: MinVersion: MaxVersion: ALPN: Ticket: ExtendVerify:map[]}}]} ServiceRegistry:{ServiceAppInfo:{AntShareCloud:false DataCenter: AppName:} ServicePubInfo:[]} RawDynamicResources:[] RawStaticResources:[]}
2018/09/06 22:52:05 [WARN]healthcheck for cluster is disabled
2018/09/06 22:52:05 [WARN]healthcheck for cluster is disabled
2018/09/06 22:52:05 [WARN]Mesh Doesn't Support Dynamic Router
2018/09/06 22:52:05 [WARN]Mesh Doesn't Support Dynamic Router
2018/09/06 22:52:05 [INFO]xds client start
2018/09/06 22:52:05 [ERROR]StaticResources is null
2018/09/06 22:52:05 [WARN]fail to init xds config, skip xds: null point exception

③ 验证 Mosn 启动成功

使用 telnet 连接 2045 端口。如下是艿艿的示例:

Yunai-Macbook:sofa-mosn yunai$ telnet 127.0.0.1 2045
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.

连接成功,表示 Mosn 启动成功。

6. 启动 SOFA-Server

① 启动

打开新的终端,输入命令。

# 跳到实例目录
cd $GOPATH/src/github.com/alipay/sofa-mosn/examples/sofarpc-sample
# 启动 SOFA-Server
go run server.go

② 验证

使用 telnet 连接 8080 端口。如下是艿艿的示例:

Yunai-Macbook:sofa-mosn yunai$ telnet 127.0.0.1 8080
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.

7. 启动 SOFA-Client

① 启动

打开新的终端,输入命令。

# 跳到实例目录
cd $GOPATH/src/github.com/alipay/sofa-mosn/examples/sofarpc-sample
# 启动 SOFA-Client
go run client.go

② 日志

Client 的日志如下:

2018/09/06 23:02:08 [DEBUG]connect raw tcp, remote address = 127.0.0.1:2045 ,event = ConnectedFlag, error = <nil>
2018/09/06 23:02:08 [DEBUG]AddConnectionEventListener Success, cb = &{context:0xc000175020 Protocol:SofaRpc Connection:0xc00017e380 Host:<nil> Codec:0xc000316000 ActiveRequests:0xc000174ff0 AcrMux:{w:{state:0 sema:0} writerSem:0 readerSem:0 readerCount:0 readerWait:0} CodecCallbacks:<nil> CodecClientCallbacks:<nil> StreamConnectionCallbacks:<nil> ConnectedFlag:false RemoteCloseFlag:false}
2018/09/06 23:02:08 [INFO]AppendHeaders,request id = 1, direction = 0
2018/09/06 23:02:08 [DEBUG]Decoderprotocol code = 1, maybeProtocolVersion = 0
2018/09/06 23:02:08 [DEBUG]deserialize header map: map[querystring: service:testSofa accept-encoding:gzip host:127.0.0.1:2046 date:Thu, 06 Sep 2018 15:02:08 GMT path:/ user-agent:Go-http-client/2.0 content-length:0]
2018/09/06 23:02:08 [DEBUG]Response ClassName is:
2018/09/06 23:02:08 [INFO]streamID=1,protocol=bolt
[RPC Client] Receive Data:1
Response Headers are: map[path:/ protocol:1 cmdtype:0 version:1 respstatus:0 classname: service:testSofa requestid:1 content-length:0 date:Thu, 06 Sep 2018 15:02:08 GMT resptimemills:1536246128878 x-mosn-endstream:yes x-mosn-streamid:1 accept-encoding:gzip host:127.0.0.1:2046 user-agent:Go-http-client/2.0 cmdcode:2 codec:1 classlen:0 headerlen:208 contentlen:0 querystring:]

Server 的日志如下:

[RPC Server] get connection : 127.0.0.1:50802
[RPC Server] reponse connection: 127.0.0.1:50802, requestId: 1

Mosn 的日志如下:

2018/09/06 23:04:47 [INFO]accept connection from:127.0.0.1:2045
2018/09/06 23:04:47 [INFO]OnReceiveHeaders, New stream detected, Request id = 1, StreamID = 3
2018/09/06 23:04:47 [INFO]AppendHeaders,request id = 3, direction = 0
2018/09/06 23:04:47 [INFO]AppendData,request id = 3, direction = 0
2018/09/06 23:04:47 [INFO]streamID=3,protocol=bolt
2018/09/06 23:04:47 [INFO]AppendHeaders,request id = 3, direction = 1
2018/09/06 23:04:47 [INFO]AppendData,request id = 3, direction = 1
2018/09/06 23:04:50 [ERROR]Error on read. Connection = 7, Remote Address = 127.0.0.1:50801, err = EOF
2018/09/06 23:05:51 [INFO]accept connection from:127.0.0.1:2045
2018/09/06 23:05:51 [INFO]OnReceiveHeaders, New stream detected, Request id = 1, StreamID = 5
2018/09/06 23:05:51 [INFO]AppendHeaders,request id = 5, direction = 0
2018/09/06 23:05:51 [INFO]AppendData,request id = 5, direction = 0
2018/09/06 23:05:51 [INFO]streamID=5,protocol=bolt
2018/09/06 23:05:51 [INFO]AppendHeaders,request id = 5, direction = 1
2018/09/06 23:05:51 [INFO]AppendData,request id = 5, direction = 1

如果胖友希望 SOFA-Client 持续启动,可以使用 go run client.go -t ,它将像激光枪一样,每 3 秒发射一次请求。biubiubiu~

8. 瞅一瞅 config.json

因为笔者也是刚刚才看了 Istio ,所以对 config.json 不是很理解。瞎比比解释下,直接来看配置文件:

{
"servers": [ // <1>
{
"default_log_path": "stdout",
"listeners": [
{
"name": "serverListener",
"address": "127.0.0.1:2046",
"bind_port": true,
"log_path": "stdout",
"filter_chains": [
{
"tls_context": { },
"filters": [
{
"type": "proxy",
"config": {
"downstream_protocol": "Http2",
"upstream_protocol": "SofaRpc",
"virtual_hosts": [
{
"name": "serverHost",
"domains": [
"*"
],
"routers": [
{
"match": {
"headers": [
{
"name": "service",
"value": ".*"
}
]
},
"route": {
"cluster_name": "serverCluster"
}
}
]
}
]
}
}
]
}
]
},
{
"name": "clientListener",
"address": "127.0.0.1:2045",
"bind_port": true,
"log_path": "stdout",
"filter_chains": [
{
"tls_context": { },
"filters": [
{
"type": "proxy",
"config": {
"downstream_protocol": "SofaRpc",
"upstream_protocol": "Http2",
"virtual_hosts": [
{
"name": "clientHost",
"domains": [
"*"
],
"routers": [
{
"match": {
"headers": [
{
"name": "service",
"value": ".*"
}
]
},
"route": {
"cluster_name": "clientCluster" // <2>
}
}
]
}
]
}
}
]
}
]
}
]
}
],
"cluster_manager": {
"clusters": [ // <3>
{
"Name": "serverCluster",
"type": "SIMPLE",
"lb_type": "LB_RANDOM",
"max_request_per_conn": 1024,
"conn_buffer_limit_bytes": 32768,
"hosts": [
{
"address": "127.0.0.1:8080"
}
]
},
{
"Name": "clientCluster",
"type": "SIMPLE",
"lb_type": "LB_RANDOM",
"max_request_per_conn": 1024,
"conn_buffer_limit_bytes": 32768,
"hosts": [
{
"address": "127.0.0.1:2046"
}
]
}
]
}
}
  • <1> 处的 servers 中,配置了两个 listeners ,分别是:

    • clientListener :监听 2045 端口。

      • 这也就为什么在 「5. 启动 Mosn」 中,我们可以使用 telnet 连接 2045 的原因。
      • 另外,在 examples/sofarpc-sample/client.go 中,看到 SOFA-Client 请求的也是 Mosn 2045 端口。代码如下:

        func main() {
        log.InitDefaultLogger("", log.DEBUG)
        t := flag.Bool("t", false, "-t")
        flag.Parse()
        if client := NewClient("127.0.0.1:2045"); client != nil {
        for {
        client.Request()
        time.Sleep(200 * time.Millisecond)
        if !*t {
        time.Sleep(3 * time.Second)
        return
        }
        }
        }
        }
        • "127.0.0.1:2045" 处。
      • <2> 处,配置路由转发给 "clientCluster" 集群。
    • serverListener :监听 2046 端口。😈 这里先跳过,继续往下看。

  • <3> 处的 cluster_manager 中,配置了两个 clusters ,分别是:

    • clientClusterhosts 地址只有一个是 "127.0.0.1:2046" 。即,请求会转发到 serverListener 上,因为它监听了 2046 端口。
    • clustershosts 地址只有一个是 "127.0.0.1:8080" ,即对应的 SOFA-Server 的地址。为什么是 SOFA-Server 的地址呢?答案在 examples/sofarpc-sample/server.go ,代码如下:

      func main() {
      ln, err := net.Listen("tcp", "127.0.0.1:8080")
      if err != nil {
      fmt.Println(err)
      return
      }
      server := &SofaRPCServer{ln}
      server.Run()
      }
      • "127.0.0.1:8080" 处。

OK ,我们回过头来看看 serverListener 。虽然在 sofarpc-sample 示例中,我们只启动了 Mosn 一个进程,但是通过配置两个 listeners 来模拟两个 Mosn 进程:

  • clientListener 提供给 SOFA-Client 请求。
  • serverListener 转发请求给 SOFA-Server 处理。

clientListenerserverListener 之间,通过 HTTP2 协议,clientListener 将请求转发到监听 2046 端口上的 serverListener

总结来说:

SOFA-Client => [2045] clientListener => serverCluster(serverListener) => serverCluster(SOFA-Server)

666. 彩蛋

作为还没入门 Istio 和 Go 语言的小菜鸡,灰常紧张的写完了这篇文章。如果有不正确的地方,烦请大佬深刻教育,小艿艿低头学习。


知识星球

文章目录
  1. 1. 1. 概述
  2. 2. 2. 依赖工具
  3. 3. 3. 获取代码
  4. 4. 4. 导入IDE
  5. 5. 5. 启动 Mosn
  6. 6. 6. 启动 SOFA-Server
  7. 7. 7. 启动 SOFA-Client
  8. 8. 8. 瞅一瞅 config.json
  9. 9. 666. 彩蛋