2014년 6월 15일 일요일

Memcached 복제 (2)

Memcached(Cache-only 모드) 복제 아키텍쳐

1편에서 언급했던 것처럼, MySQL Memcached 플러그인이 Caching과 InnoDB-only 모드로 작동하는 경우에는 Memcached를 통한 변경 내용이 InnoDB 스토리지 엔진에 적용되기 때문에 바이너리 로그에도 그 변경 내용이 기록된다. 즉 Caching과 InnoDB-only 모드에서는 자동적으로 복제 기능이 적용되는 것이다.

하지만 이 프로젝트의 목적은 InnoDB를 완전히 사용하지 않고 MySQL 서버를 Memcached 전용 서버로 사용하는 것이기 때문에, Cache-only 모드만 고려 대상인 것이다. 그런데 1편에서도 언급했듯이, 문제는 Cache-only 모드에서는 Memcached의 변경 내용이 MySQL 서버의 바이너리 로그에 기록되지 않는다는 것이다.

Cache-only 모드에서 바이너리 로그를 작동하도록 하는 것이 이 프로젝트의 목표인데, 이를 위해서는 아래 그림과 같이 마스터 MySQL의 바이너리 로그 기록과 슬레이브 MySQL의 릴레이 로그 재생(Replay) 기능을 수정했다.
(그림에서 파란색 선은 원래 MySQL 5.6이 가지고 있던 데이터의 흐름이며, 갈색 두꺼운 선이 수정된 기능을 의미한다.)



위의 그림에서 파란색 점선 화살표는, 이해를 돕기 위해서 MySQL Memcached의 Caching과 InnoDB-only 모드 작동 방식을 표시해둔 것이다.

그림에 표시된 번호별로 조금 더 상세히 살펴보도록 하자.
  1. InnoDB API에서는 Memcached를 통해서 유입된 변경 내용을 정해진 규칙(innodb_api_bk_commit_interval, daemon_memcached_r_batch_size, daemon_memcached_w_batch_size 시스템 변수)에 따라서 InnoDB 스토리지 엔진으로 전달하고, 바이너리 로그에 기록하도록 구현되어 있었다. 하지만 이 로직은 Cache-only 모드에는 해당되지 않는데, 이를 Cache-only 모드에서도 작동하도록 수정했다. Original MySQL에서는 Cache-only 모드에서는 InnoDB 테이블이 필요치 않지만, 이 기능을 위해서 Caching이나 InnoDB-only 모드와 같이 Memcached 플러그인을 위한 설정 테이블(innodb_memcache DB)과 컨테이너 테이블이 필요하다. 물론 데이터가 저장되지는 않지만, 껍데기 구조가 필요한 것이다.
  2. 슬레이브에서는 IO Thread에 의해서 만들어진 Relay log를 가져와서 다시 Memcached에 적용(SET/ADD/DELETE)해야 한다. 하지만 Original MySQL 서버에서는 Replication SQL Thread가 Memcached를 통하지 않고 즉시 InnoDB Storage Engine으로 데이터를 반영해버린다. 그래서 Replication SQL Thread가 Memcached Plugin으로 접근할 수 있는 방법이 필요한데, 이를 위해서 MySQL 서버에 libmemcached.so를 같이 빌드해서 Replication SQL Thread가 Memcached client로 작동할 수 있도록 했다.
  3. Memcached Client로 작동하는 Replication SQL Thread에서는 최대한 빠르게 Relay 로그의 내용을 Replay해야 하므로, TCP Socket 포트(11211)보다는 Unix socket을 사용하도록 했으며, Async 모드로 Memcached Plugin에 변경 내용을 적용하도록 수정했다.


그 이외의 개선 사항


  • MySQL Memcached Plugin이 TCP socket과 Unix domain socket을 동시에 지원하도록 개선
  • Memcached Plugin의 상태를 MySQL 서버의 상태 값(Global status variables)으로 모니터링할 수 있도록, 매 초단위로 Memcached의 상태 값을 MySQL 서버 상태 값으로 복사
    mysql> show global status like '%kmc%';
    +----------------------------------+--------------+
    | Variable_name                    | Value        |
    +----------------------------------+--------------+
    | Innodb_kmc_connection_structures | 2004         |
    | Innodb_kmc_curr_connections      | 2002         |
    | Innodb_kmc_curr_items            | 70638969     |
    | Innodb_kmc_pointer_size          | 64           |
    | Innodb_kmc_threads               | 8            |
    | Innodb_kmc_total_connections     | 5090         |
    | Innodb_kmc_total_items           | 778120599    |
    | Innodb_kmc_bytes                 | 18648687816  |
    | Innodb_kmc_bytes_read            | 460650586044 |
    | Innodb_kmc_bytes_written         | 497924594841 |
    | Innodb_kmc_cmd_get               | 7781206118   |
    | Innodb_kmc_cmd_set               | 778120599    |
    | Innodb_kmc_evictions             | 498675673    |
    | Innodb_kmc_get_hits              | 1043938514   |
    | Innodb_kmc_get_misses            | 6737267604   |
    | Innodb_kmc_limit_maxbytes        | 21474836480  |
    +----------------------------------+--------------+
  • Caching이나 Cache-only 모드와는 달리 InnoDB 잠금과 무관하게 작동함
    (하지만 여전히 InnoDB의 트랜잭션이나 일부 자원은 할당해서 사용함 --> 개선 예정)
  • MySQL 5.6.14의 메모리 릭과 Memcached plugin의 expiration time 설정 버그 보완
  • MySQL 서버의 각종 Disk sync 로직을 Async로 전환
  • expire_max_log_files 시스템 변수 추가
    바이너리 로그 파일의 개수를 이용한 자동 삭제 기능
  • 바이너리 로그 자동 삭제 기능의 이상 현상 모니터링용 상태 변수 Binlog_purge_failed 추가
    • 0 : 정상
    • 1 : ACTIVE 상태의 바이너리 로그를 삭제하려고 시도한 경우 설정
    • 2 : USE 상태의 바이너리 로그를 삭제하려고 시도한 경우 설정
  • kmc_connect_string 시스템 변수 추가
    Replication SQL Thread가 릴레이 로그 Replay시 접속할 Memcached 접속 정보 설정


사용 가능한 Memcached Operation

안타깝게도 KMC(Kakao Mem Cached, 복제 가능한 Memcached 서버)의 특성이나 구현 제약으로 인해서, 현재 버전에서는 일부 Memcached operation을 지원하지 않는다.

사용 가능
  • GET
  • SET
  • ADD
  • DELETE
  • REPLACE
사용 불가능
  • INCREMENT
  • DECREMENT
  • CAS

성능 고려 사항

일반적인 Original Memcached와 비교해서 GET 성능은 차이가 없다. 하지만 SET이나 ADD 그리고 DELETE와 같은 Operation은 Original Memcached와는 달리 KMC는 Memcached의 캐시에 기록후 바이너리 로그에 기록해야 한다. 물론 바이너리 로그 기록은 Sync mode로 작동하는 것은 아니지만 여전히 Original Memcached에 비해서 상당히 많은 자원을 사용하게 된다. 그래서 SET/ADD/DELETE Operation의 성능은 Original Memcached에 비해서 상당히 낮은 결과를 보일 것이다.

하지만, 일반적으로 Memcached의 특성상 SET/ADD/DELETE Operation의 수치는 그렇게 높지 않은 것이 일반적이다. 한번이라도 SET되면 그 이후부터는 SET operation이 줄어들고 GET operation이 늘어나기 때문이다. 만약 SET/ADD가  초당 10K 이상씩 실행되는 Memcached가 있다면, 이는 캐시 효율이 상당히 낮은 Memcached라고 볼 수 있다. 또한 이런 Memcached는 오히려 서비스의 처리 성능에 오버헤드만 유발하고 있다고 볼 수도 있다.

일반적인 Intel x86 장비에서 대략 초당 10K 정도 SET/ADD/DELETE operation을 한계로 고려하고 있는데, 이는 단일 서버의 한계가 아니라 복제 지연으로 인한 한계이다.

KMC 기타 제약 사항

  • Memcached 컨테이너 테이블의 이름은 "kmc_" 키워드로 시작해야 한다.
  • CAS와 INCR 그리고 DECR 명령 사용 불가
  • KMC 내부적으로 Memcached 프로토콜에서 flags 필드의 상위 2바이트를 사용함
    • Memcached의 flags중에서 하위 2바이트만 사용한다면 문제 없음

KMC 다운로드




** 마지막 편에서는 MySQL Memcached를 설치하고, 사용하는 방법 그리고 추천하는 설정에 대해서 간단히 소개하도록 하겠다.

댓글 없음:

댓글 쓰기