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

MYSQL 和 NUMA情爱

232

NUMA 问题曾经一直是困扰DBA的一个大问题,MySQL在x86系统下存在严重的 “swap insanity” 问题。在NUMA架构越来越普遍的今天,这个问题越来越严重。

就是当你把主机大部分内存分配给InnoDB时,你会发现明明操作系统还有很多内存,但是却有很多内存被交换到了SWAP分区。

有两个方式可以解决这个问题:

  1. 在Linux Kernel启动参数中加上numa=off(这样也会影响到其他进程使用NUMA);

  2. 在mysqld_safe脚本中加上“numactl –interleave all”来启动mysqld。

当然如果跑多实例,我也用过直接绑定mysqld进程到某个numa节点的方式,不过这要求每个实例分配的内存不超过每个NUMA节点管理的内存。


关于多实列

至于为何使用多实例,因为MySQL对于多处理机和大内存的利用效率不佳,采用多实例可以很大程度提高MySQL对资源的利用,详情可以看Percona的白皮书中对多实例的测试:Scaling MySQL With Virident Flash Drives and Multiple Instances of Percona Server .

numactl这个程序的用法可以参照man手册:http://linux.die.net/man/8/numactl

基本用法是“numactl  [option] 程序路径”,例如我希望用numactl启动mysqld则是numactl  [option] usr/local/mysql/bin/mysqld。曾经我误以为numactl是控制某一个程序名,汗……亲手做过才明白是程序路径。

我只介绍几个重要参数
–interleave=all 这是使用交叉分配模式启动一个程序,也就是说程序可以随意跨节点用其他节点的内存,传说中这是效率最高的关闭NUMA特性的方法,只是传说。
–cpunodebind=node 这是把程序绑定在指定的node节点上运行,即使另一个物理节点是idle的,也不会去使用。
–localalloc 严格控制只在节点内分配内存,禁止分配其他节点下的内存到当前节点运行的程序。

我们启动MySQL希望的参数是 numactl –cpunodebind=node –localalloc mysqld_path
为了运维方便,我不可能每次mysql启动都这么执行,我依然希望通过/etc/init.d/mysql和mysqld_multi来管理mysql启动和关闭,于是我采用自定义启动脚本的方式。

首先编写自定义启动脚本如下:

    #!/bin/sh


    # Program Path
    NUMACTL=`which numactl`
    MYSQLD=/usr/alibaba/mysql/libexec/mysqld
    PS=`which ps`
    GREP=`which grep`
    CUT=`which cut`
    WC=`which wc`
    EXPR=`which expr`


    # Variables
    CPU_BIND=(`$NUMACTL --show | $GREP nodebind | $CUT -d: -f2 `) # CPU bins list
    CPU_BIND_NUM=${#CPU_BIND[@]} # How many CPU binds
    MYSQLD_NUM=`$PS aux | $GREP mysqld | $GREP -v grep | $GREP '\' | $WC -l`
    MYSQLD_NUM=`$EXPR $MYSQLD_NUM + 1`
    BIND_NO=`$EXPR $MYSQLD_NUM % $CPU_BIND_NUM ` # Calc Which CPU to Bind


    # echo CMD
    echo "$NUMACTL --cpunodebind=$BIND_NO --localalloc $MYSQLD" > tmp/mysqld.$MYSQLD_NUM


    # use exec to avoid having an extra shell around.
    exec $NUMACTL --cpubind=$BIND_NO --localalloc $MYSQLD "$@"
    复制


    方法是查看当前有多少个mysqld进程已经存在,并且通过numactl –show判断有多少个物理节点,从而判断当前的进程应该分配给哪个节点,例如有2个物理节点,没有mysqld进程,则分配当前进程到0节点,再启动一个实例,当前已经有1个mysqld进程,则分配到1节点,再启动一个实例到0节点……依次循环。

    然后在my.cnf文件中配置使用我们自己的脚本启动:

    [mysqld_safe]......ledir=/usr/local/mysql/bin/# 放自定义脚本的目录mysqld=mysqld_using_numactl # 自定义脚本的名称
    复制

    然后再用/etc/init.d/mysql或mysqld_multi启动mysqld进程就可以实现绑定了。
    你可以先启动一个实例,然后在MySQL里做一些消耗CPU的操作,可以观察到只有一个物理节点上的core有活动,哪怕这个节点的core全是100%的利用率,另一个节点的core也全部都是闲的~



    代码层面解决NUMA问题

    如果在代码层面彻底解决NUMA问题,那么我们需要解决两个问题:

    1. 全局内存应该采用interleave的分配方式分散在不同的numa node上;

    2. 线程内存应该采用local的分配方式分配在线程运行的numa node上

      Linux 提供了 set_mempolicy() 函数可以用来设置进程的内存分配策略,其中默认的MPOL_DEFAULT策略就是在当前运行的节点上分配内存,而MPOL_INTERLEAVE策略则是跨所有节点来分配内存

             #include <numaif.h>


      long set_mempolicy(int mode, const unsigned long *nodemask,
      unsigned long maxnode);
      复制



      因此对于MySQL Server和InnoDB引擎都需要做修改:

      1. 在mysqld_main()入口设置 set_mempolicy(MPOL_INTERLEAVE, NULL, 0) 启用全局分配方式;

      2. 在MySQL启动完成之后设置set_mempolicy(MPOL_DEFAULT, NULL, 0) 启用本地分配方式;

      3. 在InnoDB入口时设置 set_mempolicy(MPOL_INTERLEAVE, NULL, 0) 启用全局分配方式;

      4. 在Buffer Pool分配完成时设置 set_mempolicy(MPOL_DEFAULT, NULL, 0) 启用本地分配方式。

      MySQL 5.6.27, 5.7.9 发布之后,将会增加一个 innodb_numa_interleave 参数来控制这个策略。innodb_numa_interleave 如果打开,那么将会按上面的策略来设置内存分配方式,如果关闭或者主机不支持NUMA,那么还是按原来的方式分配。






      安装

      MYSQL二进安装

      MYSQL8.0 二进制安装

      MYSQL8024二进制安装脚本

      Percona8.0 通用二进安装

      Percona 8低版号升级


      原理

      MySQL Truncate undo  表空间

      MYSQL两段提交BINGLOG REDOLOG关系

      MYSQL双写和块裂

      MySQL 可以添加多少 text字段?

      MYSQL 热数据备份--Warmup特性

      MySQL 线程池

      MySQL InnoDB 事务锁源码分析

      MYSQL SHUTDOWN 过程认识

      InnoDB buffer pool flush策略



      备份和恢复

      MYSQL备份

      MYSQL的恢复

      使用MYSQLBINLOG工具恢复数据GTID范围

      MYSQL 8 加密和流失备份

      MYSQL 增量恢复

      Mysql 物理备份Xtrabackup

      MYSQL xtrabackup 全量压缩备份

      MYSQL xtrabackup 增量备份

      MYSQL 8 物理全量恢复2


      主从复制

      重建MYSQL主从库

      MYSQL 最大可用模式

      MYSQL ACTIVE DG 配置

      MYSQL BINLOG 二进制日志

      mysql反向同步

      MYSQL从库的并发恢复

      MYSQL延迟并发复制

      MYSQL的只读GTID复制

      MYSQL从库应用缓慢

      Percona8.0 主从

      MYSQL主从重要参数原理

      MYSQL 主从复制数据不一致的风险



      运维优化

      理解MYSQL组提交和二阶段提交

      MySQL两地三中心方案初步设计

      MYSQL微服务架构

      MYSQL-PTONLINE 改分区表

      MYSQL经典PID问题



      SQL优化

      MYSQL5.7优化了WHERE条件前后顺序

      基于案例理解MySQL执行计划

      MYSQL 单表千万变慢

      MYSQL也有HINT

      500万的单表性能

      MYSQL排序ORDER BY

      mysql大量的waiting for table level lock怎么办

      MYSQL METALOCK

      MYSQL 死锁

      MySQL的性能相关的视图

      MYSQL SQL巡检脚本

      MYSQL MEMCACHE插件

      MYSQL优化思路

      MYSQL LEFT JOIN 优化

      MYSQL 加字段优化

      MYSQL 字符集优化

      MYSQL ID 的混乱星海

      using filesort VS using temporary

      MYSQL REDO   内参

      MYSQL UNDO内参

      MYSQL InnoDB 预读


      MYSQL开发

      MYSQL 常用函数

      MYSQL 批量生成触发器

      如何优雅更新MYSQL大表?


      MYSQL分区维护

      分区表

      Mysql5.7范围分区操作

      MYSQL普通表 在线 改成 分区表

      MYSQL为什么分区要加入主键和唯一索引?

      MYSQL在线分区之表锁


      MGR集群

      MYSQL MGR 集群

      MYSQL MGR 从入门到精通01

      MYSQL MGR 从入门到精通 02

      MYSQL MGR  从入门到精通03

      MGR重启

      dba+开源工具:MySQL 8.0 MGR高可用VIP切换脚本



      源码阅读

      MYSQL 源码DEBUG编译

      Mysql 2038 的BUG

      MYSQL DEBUG 版本的发布




      压测试工具

      SYSBENCH


      MYSQL 安全

      MYSQL-SSL配置



      文章转载自海鲨数据库架构师,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

      评论