千家信息网

如何使用MySQL MHA源代码进行监控检查

发表于:2025-11-14 作者:千家信息网编辑
千家信息网最后更新 2025年11月14日,本篇文章给大家分享的是有关如何使用MySQL MHA源代码进行监控检查,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。一、前言在研究的同时
千家信息网最后更新 2025年11月14日如何使用MySQL MHA源代码进行监控检查


本篇文章给大家分享的是有关如何使用MySQL MHA源代码进行监控检查,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。

一、前言

在研究的同时,把MHA的源代码也翻阅了一遍,现在准备把MHA一些重要内容梳理一下,既然是高可用工具,那么健康检测是一个基础工作,只有正确检测了数据库的故障,才能进行数据库的切换;而MHA的布局亦如此:

二、MHA健康检查核心调用函数链

注意我这里的函数调用链的规则是文件名|方法名,方法名中的或者表示的是,通过读取配置文件,执行其中的一个函数

MasterMonitor.pm|MHA::MasterMonitor::main()

->MasterMonitor.pm|MHA::MasterMonitor::wait_until_master_is_dead()

->MasterMonitor.pm|MHA::MasterMonitor::wait_until_master_is_unreachable()

->HealthCheck.pm|MHA::HealthCheck::wait_until_unreachable()

->HealthCheck.pm|MHA::HealthCheck::ping_select(或者)

->HealthCheck.pm|MHA::HealthCheck::ping_insert(或者)

->HealthCheck.pm|MHA::HealthCheck::ping_connect(或者)

三、代码分析

我们主要看HealthCheck.pm|MHA::HealthCheck::wait_until_unreachable的实现

1) 该函数通过一个死循环,检测4次,每次sleep ping_interval秒(这个值在配置文件指定,参数是ping_interval),持续四次失败,就认为数据已经宕机

2)如果有二路检测脚本,需要二路检测脚本检测主库宕机,才是真正的宕机,否则只是推出死循环,结束检测,不切换

3)这里的GETLOCK(姑且说是分布式锁)就是用来保护数据库的访问,防止脚本多次启动的

4)该函数调用了三种经检测方法,如下:

PING_TYPE_CONNECT(ping_select),PING_TYPE_INSERT(ping_insert),PING_TYPE_SELECT(ping select),但是哪种最好呢,我建议是PING_TYPE_CONNECT,实际上PING_TYPE_CONNECT调用了ping_select的方法,比PING_TYPE_CONNECT更具有可靠性

# main function# 返回1,表示数据库有问题,但是不会切换;0表示数据库有问题,会切换(这里同时还会返回ssh连接状态,方便确认是网络问题,还是数据库问题)sub wait_until_unreachable($) {  my $self           = shift;  my $log            = $self->{logger};  my $ssh_reachable  = 2;  my $error_count    = 0;  my $master_is_down = 0;  eval {    while (1) {      $self->{_tstart} = [gettimeofday];      if ( $self->{_need_reconnect} ) {    #测试连接,连接正确返回0,否则返回1    ##这里有分布式GetLOCK,如果有别的会话,获取了分布式锁失败,也算连接不成功        my ( $rc, $mysql_err ) =          $self->connect( undef, undef, undef, undef, undef, $error_count );        if ($rc) {          #排除权限错误          if ($mysql_err) {            if (          #在这里并不是不能访问,可能只是权限错误              grep ( $_ == $mysql_err, @MHA::ManagerConst::ALIVE_ERROR_CODES )              > 0 )            {              $log->info("Got MySQL error $mysql_err, but this is not a MySQL crash. Continue health check.."              );          #sleep一段时间              $self->sleep_until();          #好吧,如果是权限错误的话,就一直在这里循环了,那么检测一致认为mysql正常,打印权限日志就行              next;            }          }          $error_count++;          $log->warning("Connection failed $error_count time(s)..");          #处理失败,更新status_file为20:PING_FAILING          $self->handle_failing();      #超过四次就跳出这个循环了          if ( $error_count >= 4 ) {        #返回1表示ssh可以可以到达,0表示ssh不能到达            $ssh_reachable = $self->is_ssh_reachable();        #返回为1表示数据库主库已经down,0则没有down            $master_is_down = 1 if ( $self->is_secondary_down() );        #退出循环,last            last if ($master_is_down);            $error_count = 0;          }          $self->sleep_until();          next;        }        # connection ok        $self->{_need_reconnect} = 0;        $log->info("Ping($self->{ping_type}) succeeded, waiting until MySQL doesn't respond.."        );      }      #释放连接,如果只是类型为PING_TYPE_CONNECT      $self->disconnect_if()        if ( $self->{ping_type} eq $MHA::ManagerConst::PING_TYPE_CONNECT );      # Parent process forks one child process. The child process queries      # from MySQL every  seconds. The child process may hang on      # executing queries.      # DBD::mysql 4.022 or earlier does not have an option to set      # read timeout, executing queries might take forever. To avoid this,      # the parent process kills the child process if it won't exit within      #  seconds.      my $child_exit_code;      eval {        if ( $self->{ping_type} eq $MHA::ManagerConst::PING_TYPE_CONNECT ) {          $child_exit_code = $self->fork_exec( sub { $self->ping_connect() },            "MySQL Ping($self->{ping_type})" );        }        elsif ( $self->{ping_type} eq $MHA::ManagerConst::PING_TYPE_SELECT ) {          $child_exit_code = $self->fork_exec( sub { $self->ping_select() },            "MySQL Ping($self->{ping_type})" );        }        elsif ( $self->{ping_type} eq $MHA::ManagerConst::PING_TYPE_INSERT ) {          $child_exit_code = $self->fork_exec( sub { $self->ping_insert() },            "MySQL Ping($self->{ping_type})" );        }        else {          die "Not supported ping_type!\n";        }      };      if ($@) {        my $msg = "Unexpected error heppened when pinging! $@";        $log->error($msg);        undef $@;        $child_exit_code = 1;      }      if ( $child_exit_code == 0 ) {        #ping ok        #ping是成功的话,则更新状态,然后将$error_count=0(持续累积4次,那就是连接有问题)        $self->update_status_ok();        if ( $error_count > 0 ) {          $error_count = 0;        }    #handle_failing启用了二路检测以及ssh_check这时候没结束需要kill掉        $self->kill_sec_check();        $self->kill_ssh_check();      }      #存在其他分布式监控      elsif ( $child_exit_code == 2 ) {        $self->{_already_monitored} = 1;        croak;      }      else {        # failed on fork_exec        $error_count++;        $self->{_need_reconnect} = 1;        $self->handle_failing();      }      $self->sleep_until();    }    $log->warning("Master is not reachable from health checker!");  };  if ($@) {    my $msg = "Got error when monitoring master: $@";    $log->warning($msg);    undef $@;    return 2 if ( $self->{_already_monitored} );    return 1;  }  #$master_is_down=0,返回1  return 1 unless ($master_is_down);   #0,$ssh_reachable返回1表示ssh可以可以到达,0表示ssh不能到达  return ( 0, $ssh_reachable );}1;三种检测机制函数#这个ping_connect正常返回0,错误返回1或者2,1是连接存在问题,2是获取锁失败#改函数调用了ping_selectsub ping_connect($) {  my $self = shift;  my $log  = $self->{logger};  my $dbh;  my $rc          = 1;  my $max_retries = 2;  eval {    my $ping_start = [gettimeofday];    #连接max_retries次,如果有错误,则退出    while ( !$self->{dbh} && $max_retries-- ) {      eval { $rc = $self->connect( 1, $self->{interval}, 0, 0, 1 ); };      if ( !$self->{dbh} && $@ ) {        die $@ if ( !$max_retries );      }    }    #ping_select()正常返回为0,错误返回为1    $rc = $self->ping_select();    # To hold advisory lock for some periods of time    #获取锁可能需要一定时间,所以在释放连接之前,需要等待一点时间    $self->sleep_until( $ping_start, $self->{interval} - 1.5 );    $self->disconnect_if();  };  if ($@) {    my $msg = "Got error on MySQL connect ping: $@";    undef $@;    $msg .= $DBI::err if ($DBI::err);    $msg .= " ($DBI::errstr)" if ($DBI::errstr);    $log->warning($msg) if ($log);    $rc = 1;  }  return 2 if ( $self->{_already_monitored} );  return $rc;}#语句SELECT 1 As Value,正常返回0,错误返回为1sub ping_select($) {  my $self = shift;  my $log  = $self->{logger};  my $dbh  = $self->{dbh};  my ( $query, $sth, $href );  eval {    $dbh->{RaiseError} = 1;    $sth = $dbh->prepare("SELECT 1 As Value");    $sth->execute();    $href = $sth->fetchrow_hashref;    if ( !defined($href)      || !defined( $href->{Value} )      || $href->{Value} != 1 )    {      die;    }  };  if ($@) {    my $msg = "Got error on MySQL select ping: ";    undef $@;    $msg .= $DBI::err if ($DBI::err);    $msg .= " ($DBI::errstr)" if ($DBI::errstr);    $log->warning($msg) if ($log);    return 1;  }  return 0;}#正常返回0,错误返回1,有个疑问,这里见得数据库表貌似没有清理吧sub ping_insert($) {  my $self = shift;  my $log  = $self->{logger};  my $dbh  = $self->{dbh};  my ( $query, $sth, $href );  eval {    $dbh->{RaiseError} = 1;    $dbh->do("CREATE DATABASE IF NOT EXISTS infra");    $dbh->do("CREATE TABLE IF NOT EXISTS infra.chk_masterha (`key` tinyint NOT NULL primary key,`val` int(10) unsigned NOT NULL DEFAULT '0') engine=MyISAM"    );    $dbh->do("INSERT INTO infra.chk_masterha values (1,unix_timestamp()) ON DUPLICATE KEY UPDATEval=unix_timestamp()"    );  };  if ($@) {    my $msg = "Got error on MySQL insert ping: ";    undef $@;    $msg .= $DBI::err if ($DBI::err);    $msg .= " ($DBI::errstr)" if ($DBI::errstr);    $log->warning($msg) if ($log);    return 1;  }  return 0;}

四、总结

1)数据库MHA的健康检查,最终调用的ping_select,ping_insert,ping_connect的一种,检测的时间由ping_interval控制,其中ping_connect调用了ping_select

2)MHA最好配置二路检测,否则只是MHA主节点从自身ssh去检测主库是否正常,在MHA管理节点与主库网络存在问题的时候,有可能会发生误切换

3)注意:这里只列出了核心函数,其实在程序启动的时候,还有一些启动情况检查,基本是主库是否可连接,配置是否正确,从库是否正常等等

以上就是如何使用MySQL MHA源代码进行监控检查,小编相信有部分知识点可能是我们日常工作会见到或用到的。希望你能通过这篇文章学到更多知识。更多详情敬请关注行业资讯频道。

检测 数据 数据库 函数 错误 问题 检查 切换 循环 分布式 只是 方法 时间 权限 二路 配置 源代码 监控 健康 就是 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 实况足球数据库2021手游 网美网络技术有限公司 网络安全相关的专业有哪些 华为云服务器安全组udp 周村化工软件开发定制 网络安全手抄报复杂版8k纸 数据库导入报错列表不匹配 数据库怎样修改基本表 丹东悠逸网络技术有限公司分公司 深圳软件开发难学吗 湖北工业软件开发机构 搭建与管理网络服务器总结 没有终端服务器授权 株洲网络安全工程师免费试学 定制化服务器价钱 一个小的服务器要多少钱 哈尔滨 软件开发 数据库2008的优点 中泰跨境电子商务数据库技术 算法在软件开发重要吗 全民反诈网络安全教育心得 数据库应用选修课 qq好友恢复一直显示服务器繁忙 misc数据库是什么意思 达内培训机构游戏软件开发 支付宝网络技术郭轶凡 校园和网络安全的手抄报 第一幼儿园网络安全宣传 软件开发工程师核心能力 初学生网络安全调查问卷
0