월: 2015 7월

MySQL 5.5.43 to 5.5.45

1. 보안
OpenSSL 보안 패치 (45)

2. 기능추가
서버 기동 시 최초 버전 명 에러로그에 표기 (43)

3. 버그픽스
GROUP_CONCAT() 결과를 정렬 시 서버 종료를 발생시키던 문제 수정 (43,44)
다른 문자셋 데이터를 <=> 로 row 비교시 서버 종료를 발생시키던 문제 수정 (43)
특정 InnoDB 에러 발생 시 함수와 트리거 동작이 무시되던 문제 수정 (43)
옵티마이저가 임시테이블의 잘못된 필드에 대해 assertion failure 발생시키던 문제 수정 (43)
옵티마이저가 아우터 참조를 할 때 메모리 할당에 실패하여 서버 종료를 발생시키던 문제 수정 (43)
파티셔닝 테이블에 대한 올바른 CREATE_TIME, UPDATE_TIME 정보를 기록하도록 수정 (44)
XA PREPARE 트랜잭션이 명시적락을 걸어 셧다운시 assertion failure 발생시키던 문제 수정 (44)
에러 핸들링 시 DD캐시에서 FK 오브젝트가 제거될 때 서버 종료를 발생시키던 문제 수정 (44)
카운트 오버플로우로 SHOW ENGINE INNODB STATUS 가 마이너스값이 찍히던 문제 수정 (44)
소팅 알고리즘 merge chunk 사이즈가 너무 낮게 인식되어 서버 종료를 발생시키던 문제 수정 (44)
SHOW VARIABLES 뮤텍스들이 두번 락되어 서버 종료를 발생시키던 문제 수정 (44)
빈 InnoDB 테이블이 많을 때 INFORMATION_SCHEMA의 TABLES 와 COLUMNS 테이블이 메모리 과다사용 수정 (44)
innodb_flush_method 가 O_DIRECT 로 설정되어있을 때 os_file_create_simple_no_error_handling_func(), os_file_create_func() 가 다른 모드에서 동작 수정 (45)
NULL FK 오브젝트를 역참조할 때 assertion failure 발생 수정 (45)
purge_node_t 구조 내의 비일관성으로 롤백 시 인덱스 레코드를 찾지 못하는 문제 수정 (45)
CHAR(0) NOT NULL 컬럼에 대한 GROUP/ORDER BY 시 서버 종료를 발생시키던 문제 수정 (45)

Advertisements

vm.swappiness=0 에서의 mysql oom

https://www.percona.com/blog/2014/04/28/oom-relation-vm-swappiness0-new-kernel/
3버전대 새 커널에서 vm.swappiness=0 일 때 *제로 스왑* (스왑이 전혀 발생하지 않은) 상태에서 MySQL 서버 oom 떨어진다고 함
“Swapping is only initiated when nr_free + nr_filebacked high watermark, and hence there was no swapping, yet kernel invoked OOM.”

swappiness=0 동작 swappiness=0 에서 swapping out 을 완전히 끄는 건 아니고 최대한 안하려고 함 swappiness=0 에서 swapping out 을 완전히 피함
발생하는 문제 oom 대신 swapping 발생 페이지 캐시에 충분한 페이지가 있음에도 oom 이 발생하여 mysql 프로세스가 죽음
영구등록: /etc/sysctl.conf 내 vm.swappiness = 1
임시변경: echo 1 > /proc/sys/vm/swappiness

NUMA, swap insanity, MySQL

1. NUMA
UMA: Symmetric Multi-Processing (SMP) 또는 Uniform Memory Architecture (UMA) 라고 불리는 균등 메모리 아키텍쳐
프로세서들이 시스템에 장착된 모든 메모리 뱅크에 동등하게 억세스,
대용량 메모리가 확보되나 같은 메모리 주소를 참조하는 경우 지연이 발생

NUMA: 멀티프로세서를 위한 현대적인 메모리 아키텍쳐로 Non-Uniform Memory Access (NUMA) 또는 Cache-Coherent NUMA (ccNUMA)
프로세서마다 로컬 메모리를 가지고 있으며 로컬에 더 빠르게 엑세스
전체 시스템은 여전히 하나의 유닛처럼 동작하며 기본적으로 모든 메모리에 어디에서든 엑세스 가능
하지만 다른 노드의 리모트 메모리에 엑세스시 잠재적으로 높은 레이턴시와 퍼포먼스에 영향
다른 프로세서의 간섭을 받지 않고 메모리를 사용하나 할당 메모리 이상의 용량 사용이 어려움
http://lwn.net/Articles/254445/

멀티프로세서에서는 NUMA를 일반적으로 씀

2. “swap insanity”
2010년경에 “swap insanity” 라는 이슈가 MySQL 에서 발생
http://blog.jcole.us/2010/09/28/mysql-swap-insanity-and-the-numa-architecture/
http://blog.jcole.us/2012/04/16/a-brief-update-on-numa-and-mysql/

MySQL 이나 오라클 등 일반적인 DB는 단일로 멀티스레드 프로세스로 동작하며 거의 모든 시스템 메모리 사용
문제는 HW 스펙이 높아지고 스케일이 커지면서 노드가 둘로 나뉠 때 버퍼풀을 할당하는 시나리오에서 발생
기본 NUMA 메모리 할당 방식인 “current” 방식에서 순차적으로 노드에 버퍼풀을 채우면서 불필요한 스왑 유발
“current” 방식은 대체로 한번 메모리가 노드에 할당되면 계속 그자리에 머뭄

전체적으로는 free 메모리(노드1 쪽에)가 많이 남지만 노드0 의 free 메모리가 완전히 소진되어,
노드0의 free 를 확보하기 위해 swap out이 지속적으로 발생하고 CPU 사용률이 매우 높아짐

이 문제해결을 위해 쉽고 간편하게 널리 적용된 솔루션은 서버데몬 기동시 버퍼풀 메모리 할당을 인터리빙 방식의 라운드로빈R/R 기법으로 전환하는 것
노드에 대해 메모리 할당을 균등하게 하면서 각각의 노드에 NUMA식으로 프리/캐시 메모리를 허용

2012년 트위터의 MySQL 운영 시스템에서 연구가 진행되었고, 최종적으로 해결책 제시
1. numactl –interleave=all: MySQL 버퍼풀 NUMA 메모리 할당을 인터리빙 R/R 방식으로 전환하는 바로 위의 이야기
2. sysctl -q -w vm.drop_cache=3: mysqld 데몬이 구동되기 전 리눅스 페이지캐시, inode 캐시, 디렉토리 엔트리캐시 를 모두 해제
3. 캐시가 클린되면 mmap 의 MAP_POPULATE 플래그를 사용해 mysqld 기동 시 버퍼풀 프레임을 메모리에 즉시 할당

트위터 MySQL 브랜치 패치
https://github.com/twitter/mysql/commit/19cf63c596c0146a72583998d138190cc285df5c
https://github.com/twitter/mysql/commit/76e70595e32dc30b1e8de7c3bf86e54cc9cea769

1번 대응으로, –numa-interleave 서버 커맨드라인 옵션 추가
2번 대응으로, 캐시 flush(sync 및 drop)을 위한 –flush-caches 서버 커맨드라인 옵션 추가
3번 대응으로, innodb_buffer_pool_populate 변수 옵션을 추가
이후에 다른 fork 인 Percona Server 5.5 에서도 위 패치들을 모두 자사의 제품에 모두 병합

여기에도 문제는 존재:
NUMA 노드에 버퍼풀을 알맞게 배분시킨다고 생각되어져 왔으나
사실 런타임에 커넥션들이 각각의 스레드로 동작하는 MySQL 에서 NUMA 노드에 걸쳐 인터리빙으로 하는 것은 이치에 맞지 않음
버퍼풀의 조각들이 노드상황에 따라 스왑으로 빠졌다가swap out, 복귀swap in 될 수 있으며,
swap out된 부분들이 랜덤 쿼리들에 의해 리모트 노드에서 필요하게 되면 많은 예기치 않은 상황이 발생할 수 있었음
헤비 쿼리나, 임시 테이블, 소트의 경우 노드에 걸쳐있는 인터리빙 방식 역시 잠재적인 성능 문제가 존재

2010년부터 버그리포트에 등재되었음에도 https://bugs.mysql.com/bug.php?id=57241 https://bugs.mysql.com/bug.php?id=72811
오라클은 5년 동안 “swap insanity” 문제에 대한 특별한 대응을 하지 않다가 이번달 7월 13일에
출시 예정 버전인 5.6.27, 5.7.9 에 대응 패치가 되는 것으로 결정
https://www.flamingspork.com/blog/

innodb_numa_interleave 변수가 추가되어 이 변수를 enable 하면 메모리 할당 정책을 서버 셋업시 버퍼풀을 올릴 때엔 인터리빙으로 세팅하고
서버가 기동이 완료되면 기본정책인 로컬노드 정책으로 돌아가게 끔 하는 것
잘 동작한다면 성능에 많은 도움이 될 수 있을 것으로 보임
런타임 메모리 처리를 노드별로 비로소 제대로 하는 것이기 때문

3. 티몬
NUMA 를 확인하거나 정책을 변경하려면 numactl 이라는 wrapper 을 사용
NUMA 정책은,
# numactl –show
policy : default
preferred node: current #시스템 NUMA 정책이 기본값인 “current”, 각 프로세서가 바인딩되는 자신의 로컬 메모리를 사용하는 것
physcpubind: 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 #물리메모리는 H/T 해서 32코어 (8코어짜리 프로세서 2개)
cpu bind 0 1
node bind 0 1
mem bind 0 1

노드 배분은,
# numactl –hardware
available: 2 nodes (0-1) #2개의 노드
node 0 cpus: 0 1 2 3 4 5 6 7 16 17 18 19 20 21 22 23  코어 16개 노드0 에 할당
node 0 size: 65510 MB #노드0 사이즈는 db1 물리메모리 128GB 의 50%인 64GB 정도
node 0 free: 330 MB #노드0 프리사이즈
node 1 cpus: 8 9 10 11 12 13 14 15 24 25 26 27 28 29 30 31  여기는 노드1
node 1 size: 65536 MB
node 1 free: 62 MB
node distances: #노드0 과 노드1 간 리모트접근에 대한 코스트
node 0 1
0: 10 11 #노드0은 로컬 코스트가 10, 노드1로 가는 리모트는 11
1: 11 10 #노드1역시 로컬 코스트가 10, 노드0로 가는 리모트는 11

/proc/(mysqld_safe 의 pid)/numa_maps 쪽을 보면, 버퍼풀을 확인 가능
(가장 페이지수가 많은 부분이 버퍼풀)

# cat /proc/(mysqld_safe 의 pid)/numa_maps
…(중략)…
f3772989000 interleave:0-1 anon=26829097 dirty=26825135 swapcache=3973 active=25701286 N0=13425687 N1=13403410
…(중략)…

anonymous, dirty, active 페이지가 젤 큰걸 보면 버퍼풀이 확실, 2개의 노드 N0, N1 이 각각 반으로 나누어져 있음
그런데 젤 처음 가상메모리로 보이는 주소 다음 interleave:0-1 으로 표기
NUMA 정책을 프로세스, 스레드가 상속받아 적용시킬 수 있는데 시스템은 NUMA 이나 아마도 인터리빙으로 적용된 것으로 보임

NUMA map 을 서머라이즈 해보면 좀 더 명확
https://github.com/jeremycole/blog-files/blob/master/numa-maps-summary.pl

# perl numa-maps-summary.pl < /proc/(mysqld_safe 의 pid)/numa_maps
N0 : 14285522 ( 54.49 GB) #노드0
N1 : 13705842 ( 52.28 GB) #노드1
active : 26773842 (102.13 GB)
anon : 27989878 (106.77 GB)
dirty : 27985559 (106.76 GB)
mapmax : 385 ( 0.00 GB)
mapped : 1545 ( 0.01 GB)
swapcache : 4330 ( 0.02 GB) #swap out 된 녀석들

임시 방편으로 스크립트 수정

1)
start() {
lockcheck=0
ret=1

sync >& /dev/null
sync >& /dev/null
/sbin/sysctl -w ‘vm.drop_caches=3’ >& /dev/null && \ #트위터 최종 해결책 2번
/sbin/sysctl -w ‘vm.drop_caches=0’ >& /dev/null

2)
cmd=”`mysqld_ld_preload_text`$NOHUP_NICENESS”
numacmd=”/usr/bin/numactl –interleave all” #트위터 최종 해결책 1번
/usr/bin/numactl –show >& /dev/null
[ $? -eq 0 ] && \
cmd=”`mysqld_ld_preload_text`$numacmd $NOHUP_NICENESS”