暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

orchestrator的discover模块

原创 清酒和歌 2022-01-18
894

orchestrator的discover原理

当我们发出命令:

orchestrator-client -c discover -i hostname:port
复制

首先,orchestrator会发现给定的实例,即命令中的hostname:port这个实例,然后进而通过该实例来发现整个拓补结构。
具体如何进行发现?通过以下两步进行discover:
1、使用MySQLHostnameResolveMethod和HostnameResolveMethod两个参数来发现给定实例,即 -i hostname:port这个实例。
2、使用DiscoverByShowSlaveHosts来发现整个拓补结构。

MySQLHostnameResolveMethod和HostnameResolveMethod详解

一、HostnameResolveMethod

HostnameResolveMethod代码位于inst/resolve.go第106行:
这是一个解析hostname的函数。可以看到取值有四种:

none:直接return回传入的hostname
default:直接return回传入的hostname
cname:调用getcname函数,解析到cname,然后return
ip:getHostnameIP这个函数主要的动作是调用net.LookupIP(hostname)这个函数,拿到真实ip地址,然后返回之

func resolveHostname(hostname string) (string, error) { switch strings.ToLower(config.Config.HostnameResolveMethod) { case "none": return hostname, nil case "default": return hostname, nil case "cname": return GetCNAME(hostname) case "ip": return getHostnameIP(hostname) } return hostname, nil }
复制
二、MySQLHostnameResolveMethod

MySQLHostnameResolveMethod代码位于inst/instance_dao.go第421行:
可以看到取值有三种:

none:什么也不做
“default”, “hostname”, “@@hostname”:可以看到db.QueryRow中有个变量叫做mysqlHostname的,他是通过查询实例数据库,使用select @@global.hostname语句来查询到的值
“report_host”, “@@report_host”:这个也很好理解,是通过发出一个ifnull(@@global.report_host, ‘’)语句来实现的

... db.QueryRow("select @@global.hostname, ifnull(@@global.report_host, ''), @@global.server_id, @@global.version, @@global.version_comment, @@global.read_only, @@global.binlog_format, @@global.log_bin, @@global.log_slave_updates").Scan( &mysqlHostname, &mysqlReportHost, &instance.ServerID, &instance.Version, &instance.VersionComment, &instance.ReadOnly, &instance.Binlog_format, &instance.LogBinEnabled, &instance.LogReplicationUpdatesEnabled) ... switch strings.ToLower(config.Config.MySQLHostnameResolveMethod) { case "none": resolvedHostname = instance.Key.Hostname case "default", "hostname", "@@hostname": resolvedHostname = mysqlHostname case "report_host", "@@report_host": if mysqlReportHost == "" { err = fmt.Errorf("MySQLHostnameResolveMethod configured to use @@report_host but %+v has NULL/empty @@report_host", instanceKey) goto Cleanup } resolvedHostname = mysqlReportHost default: resolvedHostname = instance.Key.Hostname }
复制
DiscoverByShowSlaveHosts

那么在通过以上代码发现给定的实例后,现在就会通过DiscoverByShowSlaveHosts这个参数来完成整个拓补结构的发现。具体如何发现的,且看下文:

代码位于inst/instance_dao.go下。
该参数有truefalse两种选项。

我们来一段一段解读,首先解读的部分是使用show slave hosts语句来发现的部分,代码如下:

// 这里首先读取配置文件中的DiscoverByShowSlaveHosts配置,如果设置为True的话,进入下面的逻辑 if config.Config.DiscoverByShowSlaveHosts || isMaxScale { // 这里去给定实例上发出一条SQL:show slave hosts,下面的事情就很简单了,就是做一些解析hostname之类的工作了 err := sqlutils.QueryRowsMap(db, `show slave hosts`, func(m sqlutils.RowMap) error { // MaxScale 1.1 may trigger an error with this command, but // also we may see issues if anything on the MySQL server locks up. // Consequently it's important to validate the values received look // good prior to calling ResolveHostname() host := m.GetString("Host") port := m.GetIntD("Port", 0) // 这里判断show slave hosts结果,如果host结果为空,则直接会返回失败 if host == "" || port == 0 { if isMaxScale && host == "" && port == 0 { // MaxScale reports a bad response sometimes so ignore it. // - seen in 1.1.0 and 1.4.3.4 return nil } // otherwise report the error to the caller return fmt.Errorf("ReadTopologyInstance(%+v) 'show slave hosts' returned row with <host,port>: <%v,%v>", instanceKey, host, port) } // 接下来,如果host不为空,那么会调用NewResolveInstanceKey(),该函数又吊用了newInstanceKey()这个函数,newInstanceKey()主要作用就是解析hostname,生成一个叫InstanceKey的结构体,内容为:instanceKye = &InstanceKey{Hostname: hostname, Port: port},最后return instanceKye,也就是对应下面的replicaKey这个变量 replicaKey, err := NewResolveInstanceKey(host, port) if err == nil && replicaKey.IsValid() { // 这个如果replicaKey有效,那么会进行正则匹配,规则就是配置文件中DiscoveryIgnoreReplicaHostnameFilters的配置,如果匹配到了会返回一个true,然而这里是!RegexpMatchPatterns,所以就是说匹配不到的话,会调用instance.AddReplicaKey(replicaKey)这个函数 if !RegexpMatchPatterns(replicaKey.StringCode(), config.Config.DiscoveryIgnoreReplicaHostnameFilters) { instance.AddReplicaKey(replicaKey) } foundByShowSlaveHosts = true } return err }) logReadTopologyInstanceError(instanceKey, "show slave hosts", err) }
复制

接下来来解读一下DiscoverByShowSlaveHosts设置为False的部分,foundByShowSlaveHosts这个变量在开始的时候,默认值给设置成了false。所以就相当于DiscoverByShowSlaveHosts为false。

if !foundByShowSlaveHosts && !isMaxScale { // Either not configured to read SHOW SLAVE HOSTS or nothing was there. // Discover by information_schema.processlist // 这里使用了协程,所以使用了wg waitGroup.Add(1) go func() { defer waitGroup.Done() // 对实例发出一个语句,就是查询processlist表,条件就是command IN ('Binlog Dump', 'Binlog Dump GTID')。后面基本和上面一样,只不过这个逻辑是通过processlist来发现拓补实例的 err := sqlutils.QueryRowsMap(db, ` select substring_index(host, ':', 1) as slave_hostname from information_schema.processlist where command IN ('Binlog Dump', 'Binlog Dump GTID') `, func(m sqlutils.RowMap) error { cname, resolveErr := ResolveHostname(m.GetString("slave_hostname")) if resolveErr != nil { logReadTopologyInstanceError(instanceKey, "ResolveHostname: processlist", resolveErr) } replicaKey := InstanceKey{Hostname: cname, Port: instance.Key.Port} if !RegexpMatchPatterns(replicaKey.StringCode(), config.Config.DiscoveryIgnoreReplicaHostnameFilters) { instance.AddReplicaKey(&replicaKey) } return err }) logReadTopologyInstanceError(instanceKey, "processlist", err) }() }
复制

结论

当你在使用或配置Orchestrator时,要注意MySQLHostnameResolveMethod、HostnameResolveMethod、DiscoverByShowSlaveHosts这三个参数的配置:

1、DiscoverByShowSlaveHosts设置为True,并且你的主机的hostname在安装mysql之前配置过,并且可以ping通主机名,那么你只需要在mysql配置文件中配置report_host和report_port参数,MySQLHostnameResolveMethod、HostnameResolveMethod这俩个配置只需要使用默认配置即可,即@@hostname和default。 2、DiscoverByShowSlaveHosts设置为True,但是你的主机的hostname是local时,那么你需要配置你的mysql配置文件:添加report_host和report_port。并且MySQLHostnameResolveMethod、HostnameResolveMethod这俩个配置需要配置为:none和none(或者这里可以改成:ip) 3、DiscoverByShowSlaveHosts设置为False,并且你的主机的hostname在安装mysql之前配置过,并且可以ping通主机名,那么你什么也不需要改动,直接discover即可。 4、DiscoverByShowSlaveHosts设置为False,但是你的主机的hostname是local时,那么你需要配置MySQLHostnameResolveMethod、HostnameResolveMethod这俩个配置需要配置为:none和none(或者这里可以改成:ip),使用IP地址来发现。
复制

结语

Orchestrator的配置还是挺复杂的,经过以上解读,是不是清晰了一些呢。
关于hook或者其他生态工具,可以看我开源的二次开发的orchestrator地址: Orchestrator
原创文章,转载请注明哟

最后修改时间:2024-11-26 09:14:04
「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论