@RolandoMySQLDBA已经正确回答了这个问题……但他还指出,他的解决方案“很脏”。
这是一个非常真实的声明。:)
这里与我有关的不是该答案,而是原始问题似乎做出了错误的假设:
我可以查询两台服务器并询问哪一台是主服务器,然后对那台服务器执行所有查询。
问题在于,在MySQL复制中,主服务器永远不会真正意识到它是主服务器。
在MySQL异步复制中,“提升为主控”的概念并不是真正的概念。将MySQL服务器“提升”为主角色是在MySQL服务器“外部”发生的事情,而不是在MySQL服务器“内部”发生的事情。
不能通过任何类型的服务器配置来实现“升级为主服务器”,因为从技术上来讲,每个启用了二进制日志记录的MySQL服务器都是主服务器,即使它从来没有从服务器。 SHOW MASTER STATUS
无论从机与否,其工作方式完全相同,并返回完全相同的结果,并且具有2个从机的主机比具有1个从机或0个从机的主机或多或少是一个主机。同样,从属服务器都脱机的主服务器仍然与主服务器一样,因为当从属服务器重新联机时,他们将从上次中断的地方进行复制。
从某种意义上说,任一服务器的唯一“意识”不是它是否是主服务器,而是它是否是从服务器(或“不是”)。
这就是Rolando的解决方案所要问的:“您是奴隶吗?” 如果答案是否定的,那么假设是,这必须是主......他还指出,作为一个有缺陷的假设,如果STOP SLAVE;
发出。但是停止的奴隶仍然是奴隶,因此“(不是奴隶)”(在任何时候)并不等同于“成为主人”。
可以对假定的主服务器执行类似的测试:
SELECT COUNT(1) FROM information_schema.processlist
WHERE user = 'the_username_used_by_the_slave';
要么
SELECT COUNT(1) FROM information_schema.processlist
WHERE command = 'binlog dump';
如果该值为零,则说明未连接从站的IO线程。此测试有一个类似的缺陷,即如果从属服务器通过管理方式断开连接,处于隔离状态或发生故障,则它将无法连接。因此,这也无法解决任何问题。
更糟糕的是(对于这两种情况中的任何一种情况)information_schema.processlist“表”都是一个虚拟表,每次从中选择该表时都会具体化,这会花费时间并浪费资源。您的服务器越忙,它的成本就越高,因为每个线程的活动都必须被对等。
一个更轻量级的解决方案是:
SELECT @@global.read_only;
在从属服务器上,您可以/应该设置全局变量,read_only
以使没有SUPER
特权的用户无法无意间写入该变量(您的应用程序不应具有SUPER
)。如果手动将从属角色“提升”为主角色,则可以SET GLOBAL read_only = OFF
启用写操作。(无论如何设置,复制始终可以写入从属服务器)。
但是,我认为,这仍然遗漏了一个重要点:
我建议应用程序不应在主/从设置中试探性地做出此决定,并且当然不能基于逐个连接。 应用程序应使用硬配置选项,或者应用程序应保持警惕,并通过其他方式处理数据库连接目标。
或者,至少在主服务器出现故障之前,应用程序绝不应该切换,然后再也不要自己切换回去。
这就是为什么我说:一旦做出“决定”(由任何人或其他人决定)以使另一台服务器成为主服务器,则无论出于何种原因,即使应用程序重新联机,该应用程序也不允许出于任何原因而切换回原始主服务器。 ,无需干预。
假设您遇到了一个错误,并且发生了软件强制崩溃;mysqld_safe
忠实地重启mysqld
,InnoDB崩溃恢复可以完美地执行。但这需要几分钟。
同时,主机已关闭,因此您的应用程序已切换到从机。无论您的系统做什么,都已创建交易,下订单,转移资金,发布评论,编辑博客。
现在,原始母版重新联机。
如果您的应用程序切换回原始主服务器,您将遭受绝对的痛苦,因为接下来可能发生的事情是复制由于不一致而停止,因为您的应用程序同时更改了从属服务器上的数据时间。现在,您有两个数据库服务器,它们的数据不一致,您将必须手动对其进行协调。如果涉及美元,积分或贷项,则您的余额现在不匹配。
因此,至关重要的是,在没有您干预的情况下,不允许应用程序切换回原始主服务器。
等一下,您刚刚按照我的描述找到了这种情况的问题吗? 主服务器发生故障,但是您的应用程序将不使用从服务器,因为它认为从服务器仍然是从服务器,而不是information_schema.processlist
主服务器。即使主服务器关闭,从服务器上的查询仍将返回非零值。
因此,应用程序发现任何东西都没有多大意义,因为您必须手动STOP SLAVE
使该测试有用。
如果希望应用程序能够切换,更好的方法可能是使用循环复制配置服务器。
循环复制有其自身固有的问题,但是,只要您的应用程序始终始终一次只写入一台服务器,大多数这些问题就不会出现。换句话说,从复制的意义上讲,两台计算机始终同时是主服务器和从服务器,但是通过某种机制,您的应用程序始终一次仅指向一台计算机,作为它可以并且应该写入的“主机” 。
由于它们的分离,您无法在MySQL服务器上部署HA工具,但是可以使用在应用程序服务器上运行的HAProxy来实现它。该应用程序连接到本地主机上的“ MySQL”,这根本不是MySQL,但实际上是HAProxy ...,它将TCP连接转发到适当的MySQL机器。
HAProxy可以测试与MySQL服务器的连接,并且仅向接受连接并允许身份验证的MySQL计算机提供流量。
运行在应用程序服务器上的HAProxy的组合(与应用程序服务器必须做的其他一切相比,其对资源的需求不会很大-它几乎只是将套接字捆绑在一起,而忽略了它们的有效负载)...和MySQL循环复制根据问题的已知信息,我可能将采用这种方法。
或者,对于严格的手动设置,可以使用比“发现”简单得多的东西,例如应用程序服务器/etc/hosts
文件中带有主机名的条目,该主机名是应用程序用来连接到MySQL的,您可以手动更新-假设将slave升级为master是一个手动过程。
或者,使用Percona XtraDB Cluster进行更复杂的处理。但是,为此,您想要添加第三台服务器,因为在PXC中有3个节点,如果2台服务器可以互相看到但与1台服务器隔离(如果所有3台仍在运行),则2台服务器将保持运行,但是1个服务器s缩成一个小球,拒绝执行任何操作,因为它意识到这一定是奇怪的。之所以可行,是因为2意识到它们仍然构成了网络分裂之前在线的大多数节点,而1意识到并非如此。使用PXC,您的应用程序连接到哪个服务器并不重要。
我说的所有这些都是说“不要让应用程序轮询服务器以查看哪个是主服务器”,因为它迟早会咬住您,直到您咬住那一天之前,它都会蚕食您的性能。