Orchestrator Discover源码分析
在梳理HostnameResolveMethod和 MySQLHostnameResolveMethod 两个参数时我产生了一些迷惑. 所以深入看了下orchestrator源码, 再此记录下.
orchestrator-client
阅读orchestrator-client可以发现, 我们可以通过运行以下命令做”服务发现”
1 | orchestrator-client -c discover -i 172.16.120.10:3306 |
orchestrator-client是一个脚本, 用方便的命令行界面包装API调用.
它可以自动确定orchestrator
集群的leader, 并在这种情况下将所有请求转发给leader.
它非常接近于orchestrator
command line interface.
orchestrator-client -help 有bug, 已提交PR.
orchestrator-client help信息也没有介绍-i参数
查看orchestrator-client源码
1 | while getopts "c:i:d:s:a:D:U:o:r:u:R:t:l:H:P:q:b:e:n:S:h" OPTION |
可以看出-i
的值给了instance变量. 在main行数中会先处理instance
1 | function main { |
to_hostport是一个函数. 可以看出 -i
可接受hostname:port
/ ip:port
/ hostname
/ ip
1 | # to_hostport transforms: |
run_command会实际根据命令行传参, 调用对应的函数
1 | function run_command { |
discover函数
1 | function discover { |
这里api其实也是个函数, 就不展开看了. 其本质最终是执行curl命令
1 | curl ${curl_auth_params} -s "/api/discover/$instance_hostport" | jq '.' |
其实就是调用http接口
orchestrator discover接口
^99dde2
在 go/http/api.go 中定义了orchestrator提供的接口. 其中, 可以找到discover对应的路由信息
1 | this.registerAPIRequest(m, "discover/:host/:port", this.Discover) |
那接下来重点, 就是看Discover方法了
Discover
以下内中
↓↓↓
表示下钻进对应函数中
这里一点一点看
1 | // Discover issues a synchronous read on an instance |
看第7行
->getInstanceKey
1 | instanceKey, err := this.getInstanceKey(params["host"], params["port"]) |
getInstanceKeyInternal
1 | func (this *HttpAPI) getInstanceKeyInternal(host string, port string, resolve bool) (inst.InstanceKey, error) { |
->NewResolveInstanceKeyStrings
1 | // NewResolveInstanceKeyStrings creates and resolves a new instance key based on string params |
####### ResolveHostname
这个函数代码较多, 主要是这段
1 | resolvedHostname, err := resolveHostname(hostname) |
这里就是根据 HostnameResolveMethod参数进行解析了
- none, default: 什么也不处理, 直接原样返回
- cname: 取CNAME
- ip: 根据hostname取ip
getHostnameIP 实际会调用 net.LookupIP
LookupIP looks up host using the local resolver. It returns a slice of that host’s IPv4 and IPv6 addresses.
简单看一下net.LookupIP
1 | // /etc/host |
所以说, getHostnameIP, 你给他传ip, 返回的还是ip. 给他传主机名, 就要看你有没有配置解析了
<-NewResolveInstanceKeyStrings
所以NewResolveInstanceKeyStrings就是根据HostnameResolveMethod将传进来的host 解析了一下. 以HostnameResolveMethod默认值default为例, 就是原样返回. instanceKey.Hostname就是-i host:port
中的host. 这个host可以是ip也可以是主机名
1 | func (this *HttpAPI) getInstanceKeyInternal(host string, port string, resolve bool) (inst.InstanceKey, error) { |
<-getInstanceKey
继续往下读Discover
1 | // Discover issues a synchronous read on an instance |
->ReadTopologyInstance
这是重点, 开始”发现” 拓扑结构
1 | instance, err := inst.ReadTopologyInstance(&instanceKey) |
-> ReadTopologyInstanceBufferable
就是读拓扑节点, 读出这个节点的信息, 和他有哪些从库以及他的主库. 然后将一些信息写入backend db, 还会缓存一些信息到”buffer”, 下次读可以直接从”buffer”读
这个函数很长, 这里只摘部分代码
1 | // ReadTopologyInstanceBufferable connects to a topology MySQL instance |
<- ReadTopologyInstance
继续往下读Discover
1 | // Discover issues a synchronous read on an instance |
树藤摸瓜DiscoverInstance
从上面可以看到, 只发现了 172.16.120.10:3306 自身, 也发现了他的从库和主库, 但只是把他的从库ip,port存入了instance.Replicas, 主库存入了instance.MasterKey, 没有再进一步探测这些从库和主库.
其实继续的”发现”工作是在DiscoverInstance
中做的
1 | // DiscoverInstance will attempt to discover (poll) an instance (unless |
discoveryQueue
全局搜discoveryQueue, 肯定有人消费这个队列
果然搜到 instanceKey := discoveryQueue.Consume()
1 | // handleDiscoveryRequests iterates the discoveryQueue channel and calls upon |