1. 程式人生 > 其它 >numa節點_社群投稿 | NUMA架構與資料庫的一些思考

numa節點_社群投稿 | NUMA架構與資料庫的一些思考

技術標籤:numa節點

前言 在很久之前,筆者被約稿希望能夠分享一下關於 SequoiaDB 和作業系統 kernel 引數之間的關係,以及官網介紹的 Linux 優化引數的含義和對資料庫的作用。去年整理髮布過一篇實踐分享,詳見《常見問題引數調優實踐(一) 》,但是這個方面的內容一直由於別的事情,被耽誤了。近期筆者又被催稿了,所以這次會認真記錄一下自己的心得,希望能夠為廣大“色塊er”提供一些有益的幫助。 SequoiaDB 對 NUMA的建議 通常來說,我們在使用SequoiaDB時,關於 NUMA 架構的設定建議,是直接將 NUMA 特性關閉,以避免作業系統因為 NUMA 的特性而造成資料庫有較大的效能影響。 關閉 NUMA 特性的設定建議,很多初次接觸 SequoiaDB 的使用者都沒有注意到這個關鍵的設定。實際上 NUMA 對作業系統的影響是巨大的,今天就讓我們來好好針對 NUMA 相關內容進行介紹。 CPU 架構的故事

關於 CPU 的多核架構,常見的有三種主要的架構:SMP、MPP、NUMA,其設計的目的,都是為了能夠讓伺服器或者叢集擁有更好的處理效能。

1.SMP SMP(Symmetric multiprocessing),一般被翻譯為“對稱多處理”架構,有時候也會被稱為“均衡多處理”架構。在現代的伺服器中,擁有超過一個處理器,並且所有處理器通過一個系統匯流排連線資源,每個處理器對資源的使用許可權均等。 這種架構最大的優勢在於“均等”,在作業系統的支援下,無論程序是處於使用者空間,或是核心空間,都可以分配到任何一個處理器上執行。因此,程序可以在不同的處理器間移動,達到負載平衡,使系統的效率提升。 但是其缺點也非常明顯,就是由於多處理器都共同使用一個系統匯流排,而系統匯流排的頻寬是有限的,故伺服器的處理器數目受限,且效能受限。

2. MPP

MPP(Massively Parallel Processor),一般被稱為“大規模並行處理機”,也是大家日常所說的“平行計算技術”。它的表現形態就是通過多臺伺服器組成一個物理分佈邏輯統一的超強處理器,一個複雜計算被拆分成多個程序在多個伺服器上執行,每個程序均擁有獨立的資源,多個程序通過訊息傳遞的方式進行互相通訊。 MPP 這個名詞被 Hadoop 大資料技術所帶火,其實它的設計思路非常的樸素,就是因為SMP 架構下的伺服器無法整合更多的CPU 算力,所以人們就通過“堆”機器的形式,將叢集中總的 CPU 算力增加到一個單伺服器無法抗衡的規模,從而取得更加強大的計算能力。

3. NUMA

NUMA(Non-Uniform Memory Access)架構,中文翻譯為“非統一記憶體訪問架構”,是站在前人的肩膀上做出的優化設計。它融合了 SMP 和 MPP 架構的特點,能夠讓伺服器提供更加出色的 CPU 計算能力。

隨著摩爾定律的持續發揮作用,伺服器 CPU 主頻越來越高,並且開始往多核架構的方向狂奔。但是在 SMP 架構下,多處理器共用北橋來讀取記憶體的設計,已經成為限制多處理器效能的瓶頸。

天才的設計師們於是就想到:如果將記憶體訪問器也做拆分,問題不就迎刃而解嗎?每個處理器分配獨立的記憶體,就不會再有 SMP 架構下受北橋讀取記憶體的效能影響。

NUMA的影響與優化

1. NUMA 對系統的影響

在 NUMA 架構下,記憶體是直接 attach 到各個 CPU 上,CPU 訪問自身記憶體資源的效能是訪問別的 CPU 的記憶體資源的三倍。

b2544f34d6dd839b627c081536b3980d.png 在這種特性的表現下,作業系統肯定要出來搞事情。 例如在 Linux 作業系統下,如果系統識別到了 NUMA 架構,預設的記憶體分配方案就是:優先嚐試在請求執行緒當前所處的 CPU 的 Local 記憶體上分配空間。如果 Local 記憶體不足,優先淘汰 Local 記憶體中無用的 Page。 如果資料庫執行在 Linux 系統下,結合著 NUMA 的技術特性和 Linux 對記憶體的分配原則,會對資料庫的效能,甚至對作業系統的執行效率都會有直接的影響。在大多數的 Linux 系統版本中,預設設定下 NUMA 架構下對系統的影響
  • NUMA 特性被開啟,執行緒申請記憶體優先從本 CPU 中獲取記憶體資源;

  • 系統缺少記憶體動態分配策略,使得在某些 CPU 中出現記憶體傾斜;

  • 如果某個 CPU 中持續出現嚴重的記憶體資源緊張,則會觸發系統的 kswapd 服務開始做記憶體回收操作;

  • 如果記憶體資源小於最小的 kernel 中的 min_free_kbytes 設定,則還會觸發 Linux 系統的 OOM 機制,啟動程序 Killer 操作。

2. NUMA 對資料庫的影響

NUMA 架構,實際就是系統為了讓 CPU 能夠儘可能利用高效能的記憶體資源,而導致記憶體資源分配不均勻的問題。

NUMA 架構對於資料庫的影響,存在以下負面影響:

  • 某些 CPU 單元的記憶體資源緊張,或者持續觸發 kswapd 服務,影響效能;

  • 檔案系統快取不足,導致cache 資料被釋放,降低資料庫訪問時的記憶體命中率;

  • 整體系統剩餘大量的記憶體,但是資料庫卻遇到 OOM 錯誤,甚至被 Killer 強行退出服務的現象;

  • 作業系統出現記憶體不足問題,導致大量資料被暫時保存於Swap交換空間中,系統響應速度降低,甚至出現卡死現象;

3. NUMA 對記憶體分配的影響

以 LinuxCentos7.6 為例,如果伺服器的 CPU 存在 48 cores,總記憶體大小為256GB,如果一個 SequoiaDB的資料節點 PID=175039,在沒有對 NUMA 做任何的調整,通過社群中的Jeremy Cole(https://blog.jcole.us/)提供的 numa-maps-summary.pl 程式(http://jcole.us/blog/files/numa-maps-summary.pl)可以看到每個 CPU zone 對記憶體的分配極其不均衡。

$> numactl --hardwareavailable: 2 nodes (0-1)node 0 cpus: 0 2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32 34 36 38 40 42 44 46node 0 size: 130976 MBnode 0 free: 1415 MBnode 1 cpus: 1 3 5 7 9 11 13 15 17 19 21 23 25 27 29 31 33 35 37 39 41 43 45 47node 1 size: 131072 MBnode 1 free: 946 MBnode distances:node   0   1  0:  10  21  1:  21  10$> perl numa-maps-summary.pl < /proc/175039/numa_mapsN0        :      2118702 (  8.08 GB)N1        :      8729319 ( 33.30 GB)active    :      1327629 (  5.06 GB)anon      :       428874 (  1.64 GB)dirty     :       428875 (  1.64 GB)kernelpagesize_kB:         8232 (  0.03 GB)mapmax    :          906 (  0.00 GB)mapped    :     10419213 ( 39.75 GB)

4. NUMA架構下優化策略

資深的 DBA 們,或多或少對 NUMA 架構都有曾經被統治的恐懼,但如果明白了 NUMA 架構下的調優策略,其實可以避免很多不必要的煩惱。在關於 NUMA 和資料庫之間的愛恨情仇,網上廣泛流傳兩篇神作,就是Jeremy Cole發表的分析 NUMA 架構的作用和影響(https://blog.jcole.us/2010/09/28/mysql-swap-insanity-and-the-numa-architecture/),以及NUMA架構下對MySQL的調優方式(https://blog.jcole.us/2012/04/16/a-brief-update-on-numa-and-mysql/)。

針對 NUMA 架構的原理和其對 Linux 的影響,Jeremy Cole 建議:

1. 使用 numactl --interleave=all CMD 啟動資料庫服務,以實現資料庫程序無視 NUMA 關於 CPU 記憶體分配的策略,可以使得各個 CPU 區域的記憶體均勻分配;

2. 在啟動資料庫程序前,採用清空作業系統的環境方式,以釋放更多的記憶體資源;

在 SequoiaDB 資訊中心中,對 NUMA 架構的建議,更加簡單、直接,“關閉 NUMA 設定”。

以 Linux Centos 7.6環境為例,如果伺服器擁有 CPU 48 cores,總記憶體大小為256GB,並且關閉了 NUMA 設定,假設 SequoiaDB 的資料節點 PID=243123,通過檢查資料節點的記憶體分配,可以發現伺服器的記憶體資源以一個大記憶體池形式進行管理和分配。

$> numactl --hardwareavailable: 1 nodes (0)node 0 cpus: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47node 0 size: 262044 MBnode 0 free: 3094 MBnode distances:node   0  0:  10$> perl numa-maps-summary.pl < /proc/243123/numa_mapsN0        :     3238724 ( 12.35 GB)active    :      381544 (  1.46 GB)anon      :       89479 (  0.34 GB)dirty     :       89479 (  0.34 GB)kernelpagesize_kB:        1348 (  0.01 GB)mapmax    :        1056 (  0.00 GB)mapped    :     3149310 ( 12.01 GB)
所以讀者們可以看到,通過關閉 NUMA 設定的方式,就可以有效避免系統對記憶體資源分配不均勻的問題。 關閉 NUMA

1.檢查NUMA設定

由於 NUMA 的設定是關於多個 CPU 對多個記憶體區進行非均勻的記憶體分配,所以如果整個系統預設就只有一個記憶體區,則無需做調整了。 以 LinuxCentos7.6 系統為例,通過以下命令可以檢視 CPU 和記憶體的分配情況
$> numactl --hardwareavailable: 1 nodes (0)node 0 cpus: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47node 0 size: 262044 MBnode 0 free: 3094 MBnode distances:node   0  0:  10

如果 available = 1 nodes,則證明無需做其他 NUMA 的設定。

如果出現 available > 1 nodes,則證明存在多個記憶體區域,需要主動關閉 NUMA 設定。

$> numactl --hardwareavailable: 2 nodes (0-1)node 0 cpus: 0 2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32 34 36 38 40 42 44 46node 0 size: 130976 MBnode 0 free: 1415 MBnode 1 cpus: 1 3 5 7 9 11 13 15 17 19 21 23 25 27 29 31 33 35 37 39 41 43 45 47node 1 size: 131072 MBnode 1 free: 946 MBnode distances:node   0   1  0:  10  21  1:  21  10

2. 關閉NUMA

以 Linux Centos 7.6 系統為例,使用 root 使用者對 /etc/default/grub 檔案進行編輯,在 GRUB_CMDLINE_LINUX 引數的末尾增加 :numa=off,例如:

GRUB_CMDLINE_LINUX="crashkernel=auto rd.lvm.lv=vg_root/root rd.lvm.lv=vg_root/swap rhgb quiet numa=off"
  • 如果系統中存在/etc/grub2.cfg 檔案(MBR 分割槽表),則執行

grub2-mkconfig -o /etc/grub2.cfg
  • 如果系統中存在/etc/grub2-efi.cfg 檔案(EFI+ GPT分割槽表),則執行

grub2-mkconfig -o /etc/grub2-efi.cfg
  • 然後重啟伺服器,再檢查系統的啟動日誌,可以發現系統已經主動關閉了NUMA的設定。

$> grep -i numa /var/log/dmesg…[    0.000000] Command line: BOOT_IMAGE=/vmlinuz-3.10.0-693.21.1.el7.x86_64 root=/dev/mapper/vg_root-root ro crashkernel=auto rd.lvm.lv=vg_root/root rd.lvm.lv=vg_root/swap rhgb quiet numa=off[    0.000000] NUMA turned off[    0.000000] Kernel command line: BOOT_IMAGE=/vmlinuz-3.10.0-693.21.1.el7.x86_64 root=/dev/mapper/vg_root-root ro crashkernel=auto rd.lvm.lv=vg_root/root rd.lvm.lv=vg_root/swap rhgb quiet numa=off…
同理,通過 numactl -- hardware 命令檢查,同樣也會顯示 available = 1 nodes。 後記 本次就以 NUMA 架構進行了介紹,希望能夠讓大家瞭解關於它更多的知識。筆者也希望各位 DBA 在部署 SequoiaDB 時,千萬不要遺漏關閉 NUMA 的設定,否則在複雜的生產環境中,天知道什麼時候會遇到 NUMA 的大坑。

附錄

$ cat numa-maps-summary.pl#!/usr/bin/perl# Copyright (c) 2010, Jeremy Cole # This program is free software; you can redistribute it and/or modify it# under the terms of either: the GNU General Public License as published# by the Free Software Foundation; or the Artistic License.# # See http://dev.perl.org/licenses/ for more information.## This script expects a numa_maps file as input.  It is normally run in# the following way:##     # perl numa-maps-summary.pl < /proc/pid/numa_maps## Additionally, it can be used (of course) with saved numa_maps, and it# will also accept numa_maps output with ">" prefixes from an email quote.# It doesn't care what's in the output, it merely summarizes whatever it# finds.## The output should look something like the following:##     N0        :      7983584 ( 30.45 GB)#     N1        :      5440464 ( 20.75 GB)#     active    :     13406601 ( 51.14 GB)#     anon      :     13422697 ( 51.20 GB)#     dirty     :     13407242 ( 51.14 GB)#     mapmax    :          977 (  0.00 GB)#     mapped    :         1377 (  0.01 GB)#     swapcache :      3619780 ( 13.81 GB)#use Data::Dumper;sub parse_numa_maps_line($$){  my ($line, $map) = @_;  if($line =~ /^[> ]*([0-9a-fA-F]+) (\S+)(.*)/)  {    my ($address, $policy, $flags) = ($1, $2, $3);    $map->{$address}->{'policy'} = $policy;    $flags =~ s/^\s+//g;    $flags =~ s/\s+$//g;    foreach my $flag (split / /, $flags)    {      my ($key, $value) = split /=/, $flag;      $map->{$address}->{'flags'}->{$key} = $value;    }  }}sub parse_numa_maps(){  my ($fd) = @_;  my $map = {};  while(my $line = )  {    &parse_numa_maps_line($line, $map);  }  return $map;}my $map = &parse_numa_maps(\*STDIN);my $sums = {};foreach my $address (keys %{$map}){  if(exists($map->{$address}->{'flags'}))  {    my $flags = $map->{$address}->{'flags'};    foreach my $flag (keys %{$flags})    {      next if $flag eq 'file';      $sums->{$flag} += $flags->{$flag} if defined $flags->{$flag};    }  }}foreach my $key (sort keys %{$sums}){  printf "%-10s: %12i (%6.2f GB)\n", $key, $sums->{$key}, $sums->{$key}/262144;}
1ca76ee40a9095ee922df9de25bb305a.png 往期技術乾貨 社群投稿 | 巨杉資料庫對接數倉資料實踐與體驗 分散式資料庫的資料備份/恢復,這些你一定要了解

社群投稿 | SequoiaDB監控與開發實踐分享

巨杉Tech | 談談資料庫核心調優巨杉核心筆記|MVCC多版本控制原理巨杉核心筆記|分散式事務漫談巨杉核心筆記|會話(Session)

巨杉Tech|SequoiaDB高可用原理詳解

巨杉Tech|分散式資料庫負載管理WLM實踐

巨杉Tech|巨杉資料庫的HTAP場景實踐

巨杉Tech|SequoiaDBSQL例項高可用負載均衡實踐

巨杉Tech|併發性與鎖機制解析與實踐

巨杉Tech|幾分鐘實現巨杉資料庫容器化部署

巨杉Tech |“刪庫跑路”又出現,如何防範資料安全風險?

巨杉Tech|分散式資料庫千億級超大表優化實踐

社群分享|SequoiaDB+JanusGraph實踐

巨杉Tech|巨杉資料庫的併發malloc實現

03e30dbe20ee8b441d1e1627313f0801.png 1d2a2b64d2d7771510df1e0055113b02.png 4c2089c196a78497632f0634a0a2c270.png 點選 ,獲取更多精彩內容~