본문 바로가기
서버구축 (WEB,DB)

MySQL Innodb ZFS 베스트 프랙티스

by 날으는물고기 2010. 2. 4.

MySQL Innodb ZFS 베스트 프랙티스

NEELAKANTH NADGIR, 2009년 5월 26일  

ZFS 상에서 실행되는 MySQL 퍼포먼스를 얘기할 때 가장 멋진 것은 거의 튜닝할 부분이 없다는 것입니다. 보통 ZFS 를 튜닝 하는 것은 악으로 간주 됩니다. 그러나 종종 필요할 때도 있습니다. 이 글에서는 ZFS 에서 좀 더 좋은 퍼포먼스를 이끌어 낼수 있는 튜닝 포인트와 몇가지 퍼포먼스 버그들에 대해 지적할 것입니다. 이러한 버그들은 수정이 이루어 졌을때 제시해 드린 튜닝은 필요 없어질 것입니다.

참을성이 부족한 분들을 위해서 요약본을 먼저 제시해 드립니다. 이러한 권고사항과 관련된 이유들은 아래에서 확인하시기 바랍니다.

  1. ZFS recordsize 를 이노디비 페이지 사이즈와 일치 시킵니다 (이노디비 데이타파일들은 16KB, 로그파일들은 128KB)
  2. 만약 쓰기 작업이 많은 워크로드라면, Separated ZFS Intent Log 를 유지 합니다.
  3. 만약 데이타베이스 워킹 셋 사이즈가 메모리에 맞지 않는다면, SSD 를 L2ARC 로 사용함으로써 큰 이득을 얻으실 수 있습니다.
  4. 배터리에 의해 백업되는 캐시를 가진 스토리지 디바이스를 사용하거나 ZFS 를 다른 파일 시스템들과 비교할때 캐시 flush 를 끕니다.
  5. ZFS Adaptive replacement cache(ARC) 대신에 MySQL/이노디비 캐시를 사용합니다.
  6. ZFS prefetch 를 끕니다.
  7. 이노디비 double write buffer 를 끕니다.

각각의 항목을 자세히 살펴 봅시다.

What ZFS recordsize 를 이노디비 페이지 사이즈와 일치 시킵니다 (이노디비 데이타파일들은 16KB, 로그파일들은 128KB)
How zfs set recordsize=16k tank/db
Why

퍼포먼스의 가장 큰 이득은 ZFS 레코드 사이즈를 IO 의 사이즈와 일치 시킴으로써 얻을 수 있습니다. 이노디비 Page 는 16KB 이고 대부분의 읽기 IO 가 16KB 사이즈 (몇몇 합쳐질 수 있는 prefetch IO 를 제외한) 이기 때문입니다. ZFS 의 기본 레코드 사이즈는 128KB. 입니다. 읽기 사이즈와 ZFS 레코드 사이즈의 불일치는 심한 IO 를 유발할 수 있습니다. 만약 16KB 읽기 작업을 수행하고 해당 데이타가 ARC 에 아직 존재하지 않는다면 데이틀 얻기 위해서 128KB 를 읽어야 합니다. ZFS 는 작은 읽기 작업을 수행할 수 없습니다. 왜냐하면 체크섬이 전체 블럭에 의해서 계산되기 때문에 데이타의 무결성을 검증하기 위해서 모두 읽어 들여야 합니다. IO 사이즈와 ZFS 레코드 사이즈를 일치 시키는 또 다른 이유는 읽기-수정-쓰기 패널티 때문입니다. ZFS 레코드 사이즈가 128KB 이고 이노디비가 페이지를 수정할때, 만약 ZFS 레코드가 아직 메모리에 존재하지 않는다면 해당 데이타는 디스크로 부터 읽어져야 하고 디스크에 쓰기 전에 수정되어야 합니다. 이것은 IO 레이턴시를 크게 증가시킬 수 있습니다. ZFS 레코드 사이즈와 IO 사이즈를 일치 시킴으로써 이러한 문제를 없을 수 있습니다.

이노디비 로그 파일들은 쓰기 작업이 보통 순차적으로 이루어 지고 사이즈도 다양합니다. 기본적으로 ZFS 레코드 사이즈 128KB 를 사용함으로써 읽기-수정-쓰기 작업의 비용을 줄일 수 있습니다.

Note

데이타베이스 파일을 생성하기 전에 레코드 사이즈를 지정해 주어야 합니다. 만약 이미 파일들을 생성하였 다면 파일들이 새로운 레코드 사이즈를 얻을 수 있게 복사해 주어야 합니다. stat(2) 커맨드를 이용해서 레코드 사이즈를 조사해 보실 수 있습니다 (IO Block:)

What 만약 쓰기 작업이 많은 워크로드라면, Separate ZFS Intent Log 를 유지 합니다.
How zpool add log c4t0d0 c4t1d0
Why

쓰기 레이턴시가 다수의 MySQL 워크로드에서는 아주 중요합니다. 일반적으로 쿼리는 몇몇 데이타를 읽고 계산을 하고, 데이타를 업데이트를 한 다음에 트랜잭션을 커밋 합니다. 커밋을 위해서 이노디비 로그가 수정 됩니다. 많은 트랜잭션들이 동시에 커밋될 수 있습니다. 커밋에 대한 이러한 "대기" 시간이 짧은 것이 중요 합니다. ZFS 에서는 동기화 쓰기가 Separate Intent Log 를 사용함으로써 빨라질 수 있습니다. Sysbench 읽기-쓰기 로 테스트 한 결과 약 10-20% 정도의 속도 향상을 얻을 수 있었습니다.(slog)

Note
  • 만약 여러분의 쿼리 실행이 디스크에서의 물리적인 읽기가 수반된다면 쓰기 시간은 별로 중요하지 않을 수 있습니다. 이 제안을 반드시 여러분의 실제 워크로드에서 테스트해 보시기 바랍니다.
  • Bug 6574286 이 수정될때 까지 여러분은 slog 를 제거하실 수 없습니다.
  • 이노디비는 사실 여러가지 종류의 쓰기 작업을 수행 합니다 (로그 쓰기, 데이타스페이스 쓰기, 삽입 버퍼 쓰기) slog 기능은 풀 전체에서 사용가능하고 그러므로 몇몇 쓰기 (데이타스페이스 쓰기) 같이 slog 로 가지 않아야 할 것들도 가게 됩니다. 이것은 Bug 6832481 ZFS separate intent log bypass property 에 의해서 수정될 수 있습니다.
  • 또한 ZFS 트랜잭션 싱크 타임 동안에 ZFS IO 큐(35 deep) 또한 꽉 찰 수도 있습니다. 이것은 쓰기가 슬롯이 빌때 까지 기다려야 한 다는 뜻입니다. Bug 6471212: need reserved I/O scheduler slots to improve I/O latency of critical ops 가 예약된 슬롯을 사용하여 해결 합니다. Bug 6721168 slog latency impacted by I/O scheduler during spa_sync 또한 확인할 가치가 있습니다.
What L2ARC (혹은 Level 2 ARC)
How zpool add cache c4t0d0
Why

만약 여러분의 데이타베이스가 메모리에 잘 맞지 않는다면, 여러분이 데이타베이스 캐시를 미스할때 마다 디스크에서 블럭을 읽어와야 합니다. 이러한 비용은 일반적인 디스크에서 상당히 높습니다. 데이타베이스 캐시 미스 레이턴시는 한개 혹은 여러개의 SSD 를 레벨-2 캐시 혹은 L2ARC 로 사용함으로써 줄이실 수 있습니다. 여러분의 데이타베이스 워킹 셋 사이즈에 따라서 메모리와 L2ARC 사이즈는 성능에서 몇수십배의 차이를 보실 수 있습니다.

Note
What 안전한 경우에는 ZFS 캐시 flush 를 끕니다
How

ZFS Evil tuning guide 는 이 파라미터에 대한 더 자세한 정보를 제공합니다. 해당 문서를 참고하시기 바랍니다.

Why

ZFS 는 디스크 및 캐시와 함꼐 안정적으로 동작하도록 디자인 되었습니다. 데이타가 디스크에 저장이 필요할때 마다 ZFS 는 캐시 flush 커맨드를 디스크에 내립니다. 배터리에 의해 백업되는 캐시를 가진 디스크들은 어떠한 작업도 수행할 필요가 없습니다(참고로 캐시 flush 커맨드는 nop 입니다) 많은 스토리지 디바이스들이 이것을 올바르게 해석하고 올바르게 작업을 수행합니다. 그러나 몇몇 스토리지 시스템들은 여전히 캐시 flush 커맨드를 올바르게 해석하지 못합니다. 이러한 스토리지 시스템들에서 ZFS 가 캐시 flush 커맨드를 내리지 못하도록 막는 것은 IO 레이턴시를 크게 줄이는 효과를 얻을 수 있습니다. Sysbench 읽기-쓰기 테스트에서 약 30% 정도의 퍼포먼스 향상을 볼 수 있었습니다.

Note
  • 배터리로 백업되지 않는 캐시에서 이 튜닝값을 사용하는 것은 오류시에 일관성을 훼손시킬 수 있습니다.
  • ZFS 를 쓰기 캐시가 안보기에 활성화 되어 있는 파일 시스템들과 비교할때, 공정한 비교를 위해서 반드시 이 옵션을 사용하시기 바랍니다.
What ZFS Adaptive replacement cache(ARC) 대신에 MySQL/이노디비 캐시를 사용합니다.
How my.cnf 를 통한 설정 그리고 ARC 사이즈를 제한
Why

여러분이 MySQL/이노디비를 ZFS 와 사용할 때에는 복수의 캐싱레벨을 가지게 됩니다. 이노디비는 고유의 버퍼 풀을 가지고 있고 ZFS 는 ARC 를 가지고 있습니다. 두가지 모두 각각 어떤것을 캐시 하고 flush 할지 독립적으로 결정을 내리게 됩니다. 두개 모두 동일한 데이타를 캐시할 경우도 존재합니다. 이노디비 내부의 캐시를 통해서 여러분은 좀 더 짧은(그리고 빠른) 코드 경로로 데이타에 접근하실 수 있습니다. 또한 이노디비 버퍼 캐시가 꽉 찼을때, 이노디비 버퍼 캐시에 대한 미스는 ARC 에 데이타가 캐시되어 있더라도 더티 버퍼의 flush 를 유발합니다. 이것은 불필요한 쓰기 작업을 유발합니다.. 비록 ARC 가 메모리에 대한 압력에 따라서 동적으로 줄어들고 늘어나지만, 가장 효과적인 것은 단순히 그것을 제한 하는 것입니다. 저희는 보통 (7~200%) 정도 ZFS 보다 이노디비에 캐싱 하는 것이 빠르다는 것을 발견 하였습니다

Note

ARC 는 모든 데이타, 단순히 메타 데이타 혹은 파일시스템 기반에서 아무런 데이타도 캐싱하지 않도록 튜닝될 수 있습니다. 아래의 튜닝 조언을 참고하시기 바랍니다.

What ZFS prefetch 를 끕니다.
How /etc/system: set zfs:zfs_prefetch_disable = 1
Why

대부분의 파일시스템은 prefetch 같은 종류를 구현합니다. ZFS prefetch 는 선형적인 (증가 혹은 감소하는), 스트라이드, 멀티블럭 스트라이드 IO 스트림을 감지하고 퍼포먼스에 이득이 있다고 판단되면 prefetch IO 를 수행 합니다. 이러한 prefetch IO 는 일반적인 읽기 보다 낮은 우선순위를 가지고 있고 일반적으로 잇점이 있습니다. ZFS 는 또한 낮은 수준의 prefetch( 일반적으로 vdev prefetch 라고 불림) 기능을 통해서 데이타의 공간적인 지역성을 도와줄 수 있습니다.

이노디비에서 행들은 프라이머리 인덱스의 순서에 따라서 저장됩니다. 이노디비는 두 종류의 prefetch 요청을 수행합니다; 하나는 순차적인 페이지를 접근할때 발생되고 다른 하나는 익스텐트 안에서 랜덤액세스에 의해서 발생합니다. prefetch IO 명령을 내릴때 이노디비는 파일이 프라이머리 키 순서대로 배치되어 있다고 가정합니다. ZFS 에서는 그렇지 않습니다. 저희들은 여전히 이노디비 prefetch 에 대한 영향도를 조사하고 있습니다.

OLTP 워크로드에서 데이타를 랜덤한 순서대로 읽는 다는 것은 잘 알려진 사실입니다. 그래서 prefetch 로는 이득을 얻기 힘듭니다. 그러므로 저희들은 ZFS prefetch 를 끄기를 권고 합니다

Note
  • 만약 여러분이 프라이머리 캐시 전략을 단순 메타데이타 캐시로 변경하였다면 파일 레벨 prefetch 를 수행하지 않을 것입니다.
  • 만약 레코드 사이즈를 16K 로 설정했다면 하위 레벨 prefetch 를 수행하지 않을 것입니다.
What 이노디비 double write buffer 를 끕니다.
How skip-innodb_doublewrite in my.cnf
Why

이노디비는 테이블스페이스 내의 페이지들을 안전하게 업데이트 하기 위해서 double write buffer 를 사용 합니다. 이노디비는 먼저 변경사항을 이 버퍼에 쓰고 그 다음에 데이타 페이지에 씁니다. 이것은 부분적인 쓰기를 막기 위해서 입니다. ZFS 는 부분쓰기를 허용하지 않기 때문에 여러분은 안전하게 이 옵션을 끄실 수 있습니다. 저희들의 테스트에서 약 5% 정도의 성능 향상을 얻었습니다.

Note


[원문] MySQL Innodb ZFS Best Practices

출처 : http://blog.sdnkorea.com
728x90

댓글