Không phải cứ "hàng khủng" là tốt (tt)

Nhắc lại phần đầu, máy chủ Oracle của một khách hàng mặc dù có đến 32G RAM và 16CPU nhưng vẫn thường xuyên bị treo vì quá tải. Tôi được giao nhiệm vụ tìm hiểu nguyên nhân và nhờ sự hỗ trợ của Oracle Metalink, tạm thời tôi đã tìm ra đầu mối liên quan đến Hugepages.

HugePages là một tính năng được giới thiệu từ phiên bản Linux kernel 2.6. Linux sử dụng page như là đơn vị cơ bản của bộ nhớ - bộ nhớ vật lý được phân chia và truy cập theo từng page. Kích thước mặc định của một page trong kiến trúc x86 là 4KB, trong ia64 là 16KB, nghĩa là nếu tôi có 32G RAM, Linux sẽ tự động chia lượng RAM này thành 2^21 page, một con số khổng lồ.

Hugepages, như tên gọi của nó, giúp Linux tăng kích thước mỗi page lên, nhằm mục đích giảm số lượng page. Với kiến trúc x64, khi sử dụng Hugepages, mỗi page sẽ có kích thước lên đến 256MB, nghĩa là nếu tôi có 32RAM, Linux chỉ cần chia ra 128 hugepage là đủ.

Trước khi đi vào chi tiết những lợi ích của Hugepage, ta hãy cùng điểm qua hai thành phần rất quan trọng trong cách Linux quản lý bộ nhớ:

  • Page Table: Một page table là một cấu trúc dữ liệu ánh xạ giữa địa chỉ bộ nhớ ảo (virtual memory address) và địa chỉ bộ nhớ vật lý (physical memory address). Chúng ta đều biết, mỗi process trong Linux đều được kernel cấp cho một không gian bộ nhớ ảo tách biệt lẫn nhau. Các bộ nhớ ảo này sẽ được ánh xạ qua bộ nhớ vật lý thông qua các page table. Khi lượng RAM tăng quá lớn, sử dụng page với kích thước mặc định sẽ làm cho page table trở nên cực lớn. Khi đó kernel sẽ mất nhiều thời gian để dò tìm ánh xạ giữa địa chỉ bộ nhớ ảo và bộ nhớ vật lý.
  • TLB: TLB là một bộ nhớ đệm (còn gọi là buffer hay cache) nằm trong CPU; TLB chứa một phần của page table. TLB có kích thước cố định, được tạo ra nhằm mục đích tăng tốc việc chuyển đổi từ địa chỉ bộ nhớ ảo sang bộ nhớ vật lý (tốc độ truy xuất TLB cao hơn tốc độ truy xuất RAM nhiều lần). TLB là một tài nguyên có hạn, và đương nhiên nó cũng bị ảnh hưởng tương tự như page table nếu lượng RAM quá lớn.
Rõ ràng, việc sử dụng Hugepages sẽ đem lại nhiều lợi ích đáng kể trong trường hợp bạn có quá nhiều RAM, mà thiết thực nhất là:
  • Giảm thời gian truy xuất page table: Do số lượng page giảm xuống, kích thước của page table cũng giảm theo, do đó thời gian để kernel tìm kiếm trong page table sẽ giảm xuống đáng kể. Ngoài ra việc tận dụng TLB cũng sẽ trở nên hiệu quả hơn
  • Kernel không bao giờ swap out Hugepages: những vùng bộ nhớ đã được đánh dấu là hugepages sẽ nằm vĩnh viễn trong RAM (cho đến khi reboot hoặc sysadmin muốn thay đổi), kernel không bao giờ swap đám hugepage này ra ngoài ổ cứng. Đây chính là điểm hay nhất của Hugepages, nó giúp chúng ta có thể dedicate một vùng bộ nhớ dành riêng cho một dịch vụ quan trong nào đó trên hệ thống. Trong case này, tôi dùng cho SGA của Oracle.
Sau khi tìm hiểu kỹ về Hugepages, tôi quyết định trao đổi với các anh chị bên DBA cũng như phía lãnh đạo của khách hàng. Họ tỏ ra khá nghi ngờ, bởi lẽ cũng như tôi, họ nghĩ chỉ có thể áp dụng Hugepages được cho x86 mà thôi. Dẫu vậy, họ không còn cách nào khác cả, tôi lúc đó là niềm hi vọng duy nhất của họ, nên họ cũng quyết định cho phép tôi thực hiện.

Việc đầu tiên cần phải làm là tính số lượng Hugepages cần phải có để chứa đủ SGA hiện tại của thằng Oracle. Oracle có cung cấp sẵn một script để làm chuyện đó:
#!/bin/bash
#
# hugepages_settings.sh
#
# Linux bash script to compute values for the
# recommended HugePages/HugeTLB configuration
#
# Note: This script does calculation for all shared memory
# segments available when the script is run, no matter it
# is an Oracle RDBMS shared memory segment or not.

# Check for the kernel version
KERN=`uname -r | awk -F. '{ printf("%d.%d\n",$1,$2); }'`

# Find out the HugePage size
HPG_SZ=`grep Hugepagesize /proc/meminfo | awk {'print $2'}`

# Start from 1 pages to be on the safe side and guarantee 1 free HugePage
NUM_PG=1

# Cumulative number of pages required to handle the running shared memory segments
for SEG_BYTES in `ipcs -m | awk {'print $5'} | grep "[0-9][0-9]*"`
do
MIN_PG=`echo "$SEG_BYTES/($HPG_SZ*1024)" | bc -q`
if [ $MIN_PG -gt 0 ]; then
NUM_PG=`echo "$NUM_PG+$MIN_PG+1" | bc -q`
fi
done

# Finish with results
case $KERN in
'2.4') HUGETLB_POOL=`echo "$NUM_PG*$HPG_SZ/1024" | bc -q`;
echo "Recommended setting: vm.hugetlb_pool = $HUGETLB_POOL" ;;
'2.6') echo "Recommended setting: vm.nr_hugepages = $NUM_PG" ;;
*) echo "Unrecognized kernel version $KERN. Exiting." ;;
esac

# End
Như comment ở phần đầu cho thấy, script này tính tổng số lượng shared memory mà hệ thống đang có tại thời điểm chạy script. Tôi chạy script này ngay lúc thằng Oracle đang giãy chết, và kết quả là: Recommended setting: vm.nr_hugepages = 82.

Như vậy, tổng cộng lượng RAM mà tôi phải dành riêng cho thằng Hugepages là 82 x 256M = 20,5G. Do Oracle sẽ sử dụng đám hugepage này như là shared memory, vì thế, tôi phải điều chỉnh cấu hình Linux để nâng tổng dung lượng shared memory lên 25G, trong đó kích thước lớn nhất của một segment là 21G.

Tôi thêm ba dòng như sau vào /etc/sysctl.conf:
# single segment = 21G, Oracle SGA = 20G
kernel.shmmax = 22548578304
# total shared memory 25G
kernel.shmall = 1638400
# total hugepages = 20,5G
vm.nr_hugepages= 82
Nếu bạn không hiểu các dòng trên, hãy thử tự tìm trên Google tài liệu về kernel.shmmax và kernel.shmall để xem các thông số này nghĩa là gì. Do số lượng non-swappable RAM mà Oracle chiếm dụng là rất lớn, nên tôi phải thêm hai dòng sau đây vào /etc/security/limit.conf:

oracle soft memlock 22020096
oracle hard memlock 22020096

Hai dòng này cho phép user oracle được phép chiếm dụng tối đa 21G RAM. Nhắc lại, nếu bạn không hiểu những thông số này, thử tìm trên Google xem sao.

Chuẩn bị xong xuôi. Tôi yêu cầu được phép khởi động lại máy chủ. Lý do phải khởi động là sau một thời gian chạy, RAM đã bị phân chia thành nhiều mảnh nhỏ, cách duy nhất để gom RAM lại là khởi động lại máy chủ, rồi mới có thể chia RAM thành hugepage và gán 20G hugepage cho Oracle. Oracle rất thông minh, khi nó thấy có hugepage, nó sẽ tự động sử dụng hugepage, mà không cần phải cấu hình gì thêm.

Sau 20' chờ cho thằng Oracle nó dừng và đóng database lại, khách hàng cho phép tôi khởi động lại máy chủ. Máy chủ này nó khởi động cũng tương đối nhanh, chỉ mất chưa đầy 10' là đã xong rồi.

Việc đầu tiên phải làm là kiểm tra xem Linux đã chia RAM thành Hugepages chưa:
# cat /proc/meminfo | grep Huge
HugePages_Total: 82
HugePages_Free: 82
Hugepagesize: 262144 kB
Rồi đã có 82 hugepage đang nằm chờ thằng Oracle "sực". Tôi khởi động Oracle, và kiểm tra lại số lượng hugepage:
# cat /proc/meminfo | grep Huge
HugePages_Total: 82
HugePages_Free: 2
Hugepagesize: 262144 kB
Yahoooo! Oracle đã "ăn" mất 80 miếng hugepage x 256M = 20G, vừa bằng với cấu hình SGA của nó. Tôi báo cho khách hàng biết, kêu nhân viên của họ làm việc lại và tôi bắt đầu theo dõi xem hệ thống vận hành thế nào.


Thật là hồi hộp, không biết những điều chỉnh của tôi có hiệu quả hay không nữa. 10', 20', 30', 1 tiếng trôi qua, vmstat không thấy swap nữa rồi, top cũng không thấy kswapd nữa, toàn là Oracle, CPU idle 50%-60%, mọi thứ êm ru đến tận hôm nay!


Tôi đã từng làm rất nhiều case về performance tuning trên Linux nhưng chưa có lần nào thành công mỹ mãn như lần này, khi mà chỉ với vài dòng cấu hình đã đưa một máy chủ từ chỗ sống dở chết dở thành chạy trơn tru đến tận bây giờ, sau hơn 2 tháng mà vẫn chưa gặp sự cố nào khác. Tôi còn vui sướng hơn cả khách hàng của mình bởi lẽ nó giúp tôi lấy lại niềm tin sau nhiều lần làm performance tuning mà không thu được gì đáng kể.

Bài học rút ra từ case này: phải hiểu tận tường những công cụ mà bạn sử dụng nếu không có ngày nó sẽ gây hại khôn lường!

Comments

VnSpl0it said…
Hi mrro,

Hiện các server linux của mình chạy Centos 5 & Ubuntu Server (Feisty), mình thử "cat /proc/meminfo | grep Huge" thì ko thấy. Vậy là sao nhỉ ? Làm sao để triển khai HugePages trên 2 distro này ?

Mong bác cho mình 1 số llời khuyên
Thanx
Thai Duong said…
Hi vietwow,

Bồ xem thêm ở http://kbase.redhat.com/faq/FAQ_80_10166.shtm để biết cách enable Hugepages trên server.
VnSpl0it said…
Rất cám ơn bác mrro đã trả lời, nếu bác ko ngại thì cho mình hỏi thêm 1 câu luôn, là nếu mình muốn tìm hiểu về các cơ chế sử dụng hoạt động của physical memory, virtual memory cũng như cơ chế mapping giữa chúng trong OS Linux thì mình nên đọc tài liệu nào là tốt nhất ?

Thanx again
Thân
Thai Duong said…
vietwow: tôi có nói trong bài viết này rồi đó, bồ nên tìm cuốn understanding the linux kernel. Chú ý tìm đúng edition cho kernel mà bồ muốn tìm hiểu.
VnSpl0it said…
This comment has been removed by the author.
VnSpl0it said…
Ok, cám ơn bác nhiều, mình sẽ tìm đọc, mà dạo này công nhận bác viết nhiều bài hay ghê, đợt trước thì biến đâu mất tăm 1 thời gian dài, mình luôn là crazy fan của blog bác ^__^
Anonymous said…
Một case rất hay để học hỏi. Chúc mừng Thái, giờ mới thấy môn Hệ điều hành cần thiết ghê hen :).
conmale said…
Hì hì, optimization is an ART :)
VnSpl0it said…
Mong sắp tới bác mrro sẽ tiếp tục có những case study hoặc bài viết về Linux Memory nữa. Vì mình đang nghiên cứu về lĩnh vực này nên rất cần ^_^

Thân
VnSpl0it said…
À, bác mrro cho em hỏi thêm cái

21GB mà bác điều chỉnh ở trên là lượng RAM mà oracle được cấp phát từ 32 GB RAM của server & chỉ có lượng RAM (21 GB) này là sẽ được áp dụng Hugepage đúng ko bác ?

Còn 2 khái niệm :

+ kích thước lớn nhất của một segment là 21G

+ total shared memory 25G

Là sao nhỉ ? bác có thể giải thích rõ thêm ko ?

Thanx
Đỗ Văn Vinh said…
Bài này hay quá, pác cho em xin nhe!