AWS RDS MySQL 主从同步延迟总结

最近居然被 MySQL 主从同步的问题坑了, 简直丢尽了老司机的脸, 总结一下.

问题很简单, 一个业务由于 MySQL 主从同步延迟导致读取的数据有问题. 问题解决了, 但如何在 AWS RDS 中获取 MySQL 的延迟信息呢? 非 AWS RDS 的传统 MySQL 中, 可以直接连到 server 通过 SHOW SLAVE STATUS 获取延迟信息.

RDS 呢?

0x00 无处不在的 Cloudwatch

AWS 中大多数(我也不确定是不是所有服务)都接入了 Cloudwatch. Cloudwatch 的好处就是可以作为一个中间层抽象, 将不同系统的数据抽象成一个模型, 统一通过 Cloudwatch API 访问. 就拿主从延迟来说, MySQL/MariaDB 和 PostgeSQL 的计算方法显然是不一样的:

  • MySQL/MariaDB: the Seconds_Behind_Master field of theSHOW SLAVE STATUS command
  • PostgreSQL: SELECT extract(epoch from now() - pg_last_xact_replay_timestamp()) AS slave_lag
  • 官方文档参见 Working with PostgreSQL, MySQL, and MariaDB Read Replicas

因此, 只要通过 Cloudwatch API 获取 ReplicaLag 这个 metric 的值就可以判断主从同步延迟, 不管是哪种 DB

def get_cloudwatch_replica_lag(rds_id, start_time, end_time)
    local_timezone = pytz.timezone('Asia/Shanghai')
    cloudwatch = boto3.client('cloudwatch')
    start_time_with_tz = local_timezone.localize(start_time)
    end_time_with_tz = local_timezone.localize(end_time)
    values = cloudwatch.get_metric_statistics(Namespace='AWS/RDS',
                                              MetricName='ReplicaLag',
                                              Dimensions=[dict(Name='DBInstanceIdentifier', Value=rds_id)],
                                              StartTime=start_time_with_tz,
                                              EndTime=end_time_with_tz,
                                              Period=60,
                                              Statistics=['Maximum'],
                                              Unit='Seconds').get('Datapoints')
    return values

0x01 Cloudwatch API "进城手册"

看上去挺简单的 API, 还是需要"进城手册", 避免挠头:

  1. Cloudwatch API 中的传入的时间必须携带时区, 默认是 UTC, 当然, 如果你厂高瞻远瞩的都按照 UTC 来使用时间了就不用操这个心了
  2. DBInstanceIdentifier 必须存在才会有数据, 若传入一个错误的 DBInstanceIdentifier 返回结果是空, 不要以为是没有 lag, 因此建议在 Cloudwatch API 前面加一个 RDS 的 DescribeInstance 调用, 确定 DBInstanceIdentifier 的值是正确的
  3. 返回结果的 datetime 也是 UTC
  4. Cloudwatch 虽然是监控数据, 但也是需要 IAM 权限的, 需要加上 IAM 中加上 cloudwatch:GetMetricStatistics 权限
  5. Period=60 代表获取1分钟粒度的数据, 这是 Cloudwatch 支持的最细颗粒度的数据
    {
      "Effect": "Allow",
      "Action": [
        "cloudwatch:GetMetricStatistics"
      ],
      "Resource": [
        "*"
      ]
    }

0x02 检查 ReplicaLag 的时间间隔

由于 Cloudwatch 支持的最细颗粒度的 metric 是1分钟, 因此仅仅获取前一分钟的数据可能会有 Cloudwatch 数据还未抓取到的问题.
建议是获取前一段时间(比如10分钟)的数据, 确保前10分钟的 ReplicaLag 都为0(或者小于一个可以接受的值), 则认为现在的状态是满足数据需求的.

总结

MySQL 主从同步从入行就知道是需要重点关注的, 结果还是忽略了一下就掉坑里了. AWS Cloudwatch 也支持根据 ReplicaLag 的值直接告警的, 建议一定要设置一个.

你可能感兴趣的:(AWS RDS MySQL 主从同步延迟总结)