Category: Database

Database 글을 모아 놓은 카테고리

Better VACCUM FULL For PostgreSQL 9.0

원문:https://wiki.postgresql.org/wiki/What’s_new_in_PostgreSQL_9.0#Better_VACUUM_FULL

지금까지 VACUUM FULL 은 매우 느렸다. 이 구문(Statement)는 테이블로부터 빈공간을 확보하고 그것의 크기(Size)를 줄였지만 VACUUM 은 만족할만큼 빠르게 동작하지 않았다.

이것이 느린 이유는 동작 방법에 문제가 있었기 때문이다. 레코드를 그들의 소스블럭으로부터 테이블에 시작점에 가까운 블럭으로 하나하나씩 읽어서 옮겼었다. 그리고 테이블에 끝이 빈공간이면 그 부분을 지웠다.

전략적으로 이러한 방법은 매우 비효율적(Inefficient) 이다. 레코드를 하나하나씩 옮기는 것은 랜덤 I/O를 발생시킨다. 게다가, 인덱스(Index)를 재구성하는 동안에 그것을 유지하고, 더 많은 비용이 들어가는, 인덱스는 파편화된다. 이럴바에는 VACUUM FULL이 다 끝나고 나서 재인덱스(reindex)를 하는 것이 낫다.

Version 9.0 에서 VACUUM FULL은 테이블과 동일한 또 하나의 테이블을 만들고 거거에 모든 레코드를 순차적이게 복사한다. 모든 레코드가 복사되고 나면, 인덱스를 재생성하고 예전 테이블은 삭제되고 새로운 테이블로 대체된다.

이것은 VACUUM 을 보다 빠르게 한다. 하지만 VACUUM FULL은 동작하는 동안에 AccessExclusiveLock 을 필요로 한다. 이전 방법과 비교했을때 이 방법의 결점은 VACUUM FULL을 했을 경우 새로운 버전의 테이블을 만들기 위해서 디스크에 테이블 크기의 2배의 용량을 사용할 수 있다는 것이다.

이제, 두가지 방법에 대해서 실시간으로 비교를 해보자. 먼저 아래와 같은 방법으로 테스트 데이터를 준비 했다.

8.4 버전에서는.

다 합해 대충 9초 정도 걸렸다.

9.0 버전에서는.

아직 이것은 제품에서(아마 서비스중에라는 뜻인듯..) VACUUM FULL 이 좋은 아이디어라는 뜻은 아니다. 만약 이것이 필요하다면, 아마도 VACUUM 정책이 올바르지 않기 때문일 것이다. (응?)

명시적 락킹(Explicit Locking)

이 문서는 PostgreSQL 9.1.2 문서중에 13.3 챕터를 해석한 것입니다. 전문 번역가도 아니고 중학교 영어만으로 해석한 것이어서 의미전달이 제대로 되지 않을 수도 있음을 미리 밝힙니다.

원문: http://www.postgresql.org/docs/9.1/static/explicit-locking.html

13.3 명시적 락킹(Explicit Locking)

PostgreSQL 은 테이블의 데이터에 동시적 접근(concurrent access)을 제어하기 위해서 다양한 락 모드(Lock mode)를 제공합니다. 이러한 모드들은 MVCC(다중 버전닝 동시성 제어)가 바라던 해동을 제공해주지 않을때에 애플리케이션 제어 락킹을 하려고 할때에 사용되어질수 있습니다.  또 대부분의 PostgreSQL 명령어들(commands)은 명령어가 실행되는 동안에 비호환적인 방법으로 참조하는 테이블이 변경되거나 버려지진(Dropped)않도록 하기위해서 자동적으로  적절한 락을 획득합니다. (예를들어, TRUNCATE는  같은 테이블에서 다른 연산들을 가지고 안전하게 동시에 실행되어지지 않을 수 있습니다. 그래서 안전성을 획득하기 위해서 강정적으로 테이블에 배타적 락(Exclusive Lock)을 얻얼 수 있습니다.)

13.3.1 테이블 수준의 락들(Table-Level Locks)

아래의 리스트는 PostgreSQL에 의해서 자동적으로 사용되어지는 사용가능한 락 모드와 문맥(contexts)들을 보여줍니다. 당신은 LOCK 이라는 명령어를 통해서 명시적으로 이러한 락들을 획득할 수 있습니다. 한가지 주목할 것은, 비록 이름에 “row”라고 되어있어도 테이블 수준의 락들(Table-Level Locks)이라는 것입니다. 락 모드의 이름들은 역사적입니다.

몇몇 확장된(extent) 이름들은 각 락 모드마다 전통적인 사용법과 반대적입니다. 하지만 의미론적으로는 모두 같습니다. 하나의 락 모드와 다른 락과의 차이에 대한 한가지 사실은 각각 상충되는 락 모드가 설정된다는 것입니다. 두개의 트랜잭션(transaction)은 같은 시점에 같은 테이블에서 상충적인 락 모드(locks of conflicting, 서로 모순되는 락 모드) 를 가질 수 없습니다. (하지만, 하나의 트랙잭션은 그 자체적으로 출돌이 나지 않습니다. 예를 들면, 같은 테이블에서 ACCESS EXCLUSIVE LOCK을 획득하고 후에 ACCESS SHARE LOCK를 획득할 수 있습니다. ) 상충적이지 않은 락 모드는 많은 트랜잭션에 의해서 동시적으로 가질 수 있습니다. 주목할 것은 특정 상황에서 어떤 락 모드는 자체 상충적(self-conflicting)이 됩니다. (예를들어, ACCESS EXCLUSIVE LOCK는 같은 시점에서 하나의 트랜잭션보다 더 많이 가질 수 없습니다.)

Table-level Lock Modes

ACCESS SHARE

오직 ACCESS EXCLUSIVE 락 모드와 상충적입니다.

SELECT 명령어는 참조하는 테이블에 이 모드의 락을 획득합니다. 일반적으로, 테이블에서 수정은 하지 않고 오직 읽기만을 하는 모든 쿼리들은 이 락 모드를 획득합니다.

ROW SHARE

이것은 EXCLUSIVE 와 ACCESS EXCLUSIVE 락 모드와 상충됩니다.

SELECT FOR UPDATE 와 SELECT FOR SHARE 명령어들은 대상 테이블에서 이 모드의 락을 획득합니다. (추가적으로 ACCESS SHARE 는 selected FOR UPDATE/FOR SHARE 가 아닌 참조되어지는 다른 모든 테이블을 락 합니다.

ROW EXCLUSIVE

이것은 SHARE, SHARE ROW EXCLUSIVE, EXCLUSIVE 와 ACCESS EXCLUSIVE 락 모드와 상충됩니다.

UPDATE, DELETE, INSERT 명령어는 대상 테이블에서 이 락 모드를 획득합니다. (추가적으로 ACCESS SHARE 는 다른 참조되어지는 모든 테이블을 락 합니다. 일반적으로, 이 모드는 테이블에서 데이터를 수정하는 모든 명령어들에 의해서 이 모드는 획득되어 집니다.

SHARE UPDATE EXCLUSIVE

SHARE UPDATE EXCLUSIVE, SHARE, SHARE ROW EXCLUSIVE, EXCLUSIVE, ACCESS EXCLUSIVE 락 모드와 상충됩니다. 이 모드는 VACUUM 실행과 동시적 스키마 변화에 대해서 테이블을 보호합니다.

VACUUM( FULL 제외), ANALYZE, CREATE INDEX CONCURRENTLY, 그리고 특정한 ALTER TABLE 폼에 의해서 획득됩니다.

SHARE

ROW EXCLUSIVE, SHARE UPDATE EXCLUSIVE, SHARE ROW EXCLUSIVE, EXCLUSIVE 그리고 ACCESS EXCLUSIVE 락 모드와 상충됩니다. 이 모드는 동시적으로 데이터를 변경하는 것에 대해 테이블을 보호 합니다.

CREATE INDEX(CONCURRENTLY 제외) 에 의해서 획득되어 집니다.

SHARE ROW EXCLUSIVE

ROW EXCLUSIVE, SHARE UPDATE EXCLUSIVE, SHARE, SHARE ROW EXCLUSIVE, EXCLUSIVE, ACCESS EXCLUSIVE 락 모드와 상충 됩니다. 이 모드는 동시적 데이터 변경과 특정시점에서 한 세션이 그것을 가지고 있기위해서 자체 exclusive(self-exclusive) 한 것에 대해서 테이블을 보호 합니다.

이 락 모드는 PostgreSQL의 어떤 명령어로도 자동적으로 획득되어지지 않습니다.

EXCLUSIVE

ROW SHARE, ROW EXCLUSIVE, SHARE UPDATE EXCLUSIVE, SHARE, SHARE ROW EXCLUSIVE, EXCLUSIVE, ACCESS EXCLUSIVE 락 모드와 상충 됩니다. 이 모드는 오직 동시적 ACCESS SHARE 락만을 허용합니다. 예를들어, 테이블로부터 읽을때에 한 트랜잭션이 이 락 모드로 홀딩되면 다중으로 실행을 할수 있습니다.

이 락 모드는 PostgreSQL의 어떤 명령어로도 테이블에 자동적으로 획득되어지지 않습니다.

ACCESS EXCLUSIVE

모든 모드의 락과 상충됩니다. 이 모드는 어떤 방법으로든 트랜잭션이 테이블에 접근하는 것을 보장합니다.

ALTER TABLE, DROP TABLE, TRUNCATE, REINDEX, CLUSTER, 그리고 VACUUM FULL 명령어에 의해서 획득되어 집니다. 또, 이 모드는 LOCK TABLE 구문에 대한 기본적인 락 모드 입니다.

Tip: 오직 ACCESS EXCLUSIVE 는 SELECT 구문을 블럭하는 락입니다.

한번 획득되어진 락은 트랜잭션이 끝날때가지 들고 있습니다. 하지만 만약에 저장시점이 설립된 이후에 락이 획득되어진 것이라면, 저장시점이 롤백되는 즉시 해제 됩니다. This is consistent with the principle that ROLLBACK cancels all effects of the commands since the savepoint. The same holds for locks acquired within a PL/pgSQL exception block: an error escape from the block releases locks acquired within it.

외부에서 Postgresql 접속할 수 있도록 설정하기

Postgresql 설치를 하게되면 외부에서 접속을 기본적으로 할 수 없게 되어 있다. 호스트 기반 인증 파일인 pg_hba.conf 파일만 고친다고 되지 않는다. 외부에서 접속하는 서버의 IP를 192.168.0.18 이라고 가정한다.

pg_hba.conf 파일

Postgresql 은 Host Based Authorization 기반으로 외부 접속을 제어 한다. 이는 pg_hba.conf 파일을 다음과 같이 편집함으로써 가능하다.

위 설정은 모든 데이터베이스에 대해서 모든 사용자에 대해서 192.168.0.18 에서 접속을 허용한다는 내용이다.

postgresql.conf 파일

이 파일도 반드시 설정을 바꿔줘야 외부에서 접속을 할 수 있다. 바꿔야 할 설정은 다음과 같다.

이걸하지 않하면, 외부에서 접속을 할 수 없다. 그리고 이 설정은 반드시 서버를 재시작 해줘야 한다. 따라서 보통 Postgresql 을 설치를 하면 기본적으로 이 설정을 해주고, pg_hba.conf 파일에서 모두 외부접속을 제어한다.

iptables 설정

보통 많은 사람들이 iptables 를 내려놓고 서버를 운영하는데, 매우 위험한 짓이다. 이를 내려놓고 하는 이유는 귀찮기 때문이다. 뭔가를 하는데 자꾸 않되고 하다가 찾다보면 결국 iptables 때문인걸 알게 되면 매우 화가나고 다음부터 이를 피하기위해서 iptables 를 꺼놓는다. 바보같은 짓거리에 서버 관리자로서 자질도 의심되는 행동이다.

Postgresql 을 위한 iptables 설정은 다음과 같다. 참고로 배포판에 rpm 으로 설치된 iptables 를 이용하는 방법이다.

이렇게 한 후에 iptables 를 재시작 해주면 된다.

PostgreSQL 과 문자셋

PostgreSQL 도 문자셋에 관해서 많은 옵션들을 제공한다. 그런데, 대부분은 이에 대해서 잘 모르는 듯해서 여기서 정리해 본다.

PostgreSQL 에서 문자셋 지정을 처음 하는 부분은 바로 설치를 마친후에 initdb 명령어를 사용하면서 부터다 대충 다음과 같이 사용한다.

문제는 저러한 문제셋 설정이 과연 향후 PostgreSQL 을 사용하는데 있어 어떤 영향을 주는가 하는 것이다. 먼저 PostgreSQL 은 ISO C 와 POSIX 등의 언어표현에 관해 지원 한다.

Locale

보통 initdb –locale=ko_KR.UTF-8 로 사용되어지는 것으로 운영체제에 종속적이다. 운영체제에서 지원하는 locale 만 사용할 수 있는데, 리눅스의 경우에는 ‘locale -a’ 명령어로 확인 가능하다.

이는 운영체제의 사용자에게 보여주는 메시지 문자를 지정한다. 만일 영어로 운영체제를 사용하고 싶다면 바로 이 locale 를 변경하면 된다. 그런데, locale 의 설정은 ‘ko_KR.UTF-8’ 처럼 나오는데 이는 language_territory.codeset 형태이다.

language 는 인간의 사용하는 언어이고 territory 는 ‘한 국가가 다스리는 영토, 지역’을 뜻한다. 예를들어서 fr_CA 도 있는데 이는 캐나다에서 사용하는 프랑스어라는 뜻이 된다. codeset 은 이러한 언어를 컴퓨터 언어로 표현하는 문자 셋이다.

이러한 형태가 나온 이유는 한 국가(영토, 지역)에서 두가지 이상의 언어를 사용할 경우를 대비한 것으로 풀이된다.

LC_COLLATE

이는 매우 중요한 것으로 다음과 같은 것에 영향을 미친다.

  1. 대소문자를 구분하는 기능.
  2. 문자열 정렬
  3. ‘like’ 문에서 인덱스를 사용여부 결정

이는 데이터베이스를 생성할때에도 지정할 수가 있는데, 지정하는 방법은 locale 과 같이 language_territory.codeset 형식이지만 codeset 은 생략하는 경우가 있다. 다음과 같은 명령어로 확인 가능하다.

문제는 이 LC_COLLATE 는 initdb 시에 한번 결정이 되면 바꿀 수 없고 하지만, Template 을 1번이 아닌 0번으로 할 경우에는 가능하다. Template1 은 initdb 때 생성되는 일종의 Master  DB라 보면되고 모든 데이터베이스는 이 Template1 을 기반으로 생성되어진다.

LC_CTYPE

이는 문자의 범주를 정하는 것으로 각 언어마다 가지고 있는 고유한 특성을 타나내기도 한다. 예를들면 단어가 무엇인지, 대문자와 소문자,one byte 문자인지 multi byte 문자인지에 대한 정의등에 대한 것이다. 이는 initdb 실에 결정되면 바꿀 수 없다.

대부분 Locale 을 따라 지정하는게 낫다.

LC_MESSAGE  

이는 접속한 클라이언트에게 어떤 언어로 보여줄지를 결정한다.

LC_MONETARY 

이는 접속한 클라이언트에게 어떤 화폐단위로 보여줄 것인지를 결정한다.

LC_NUMERIC

이는 접속한 클라이언트에게 어떤 숫자단위로 보여줄 것인지를 결정한다.

LC_TIME

이는 접속한 클라이언트에게 날짜와 시간에 대한 포맷을 결정한다.

 

[번역] MySQL 5.7.6 릴리즈. 큰 변화에 준비하자.

이 글은 “MySQL 5.7.6 is out. Be prepared for big changes” 를 원작자의 허락을 받아 번역한 것입니다. 원본은 아래의 주소에 있습니다. 번역을 허락해준 Giuseppe Maxia 씨에게 감사 합니다.

오늘 오라클(Oracle)이 MySQL 5.7.6 마일스톤 16을 릴리즈(Release) 했다. 이것으로 MysQL 5.7 은 개발에 2년이 넘게 소요됐다. MySQL 5.6과 비교해 바뀐점은 아주 넓다. 주요한 팀(개발 팀)의 노력은 이전 릴리즈와 비교해 2배에서 3배의 성능 향상을 가지는 , MySQL 의 동작,스피드에 포커스를 맞춰왔다. 무엇이 새로운지에 대한 전체 리스트는 여기에 가지고 오기에는 너무나 많은 공간이 필요해, 나는 몇가지 키포인트들만 언급할 것이다.

  • 오라클은 MySQL 보안과 안전성 개선에 상당히 많은 에너지를 소비했다. 많은 새로운 기능을 볼수 있겠지만 아주 오래된 기능들은 deprecated 되었고 5.6에서 deprecated 된것들은 삭제되었다.
  • 설치과정은 MySQL 5.7 릴리즈되는 매 마일스톤마다 항상 좀 더 향상되는 것을 목표로 바뀌어왔다.하지만 이러한 노력은 이전버전과의 호환성을 깰 것이다.

이 기사에서는 나는 설치과정에서 크게 바뀐 부분을 언급할 것이다. MySQL 5.6 에서 mysql_install_db 는 데이터베이스 생성중에 랜덤 패스워드 생성기에 대한 옵션을 가지고 있다. 이 과정은 익숙하지 않지만 오랜시간동안 패스워드없이 root 사용자를 생성하도록 했던것을 직접적으로 끝장을 내는 행보였다. MySQL 5.7.4 에서, 그것은 좀더 바뀌어서, 랜덤 패스워드 생성기는 -skip-random-password 옵션으로 건너뛸 수 있지만 어쨌든 기본값이 됐다. MySQL 5.7.5 에서, 기본은 확정되었고 옵션은 -insecure 로 바뀌었다.

그리고 이제, MySQL 5.7.6 에서, 오래된 관행을 단속하고자: mysql_install_db 는 deprecated 됐고 mysqld -initalize 로 바뀌었다. (예전에 “mysqld -bootstrap” 으로 알려졌던 것은 현재 deprecated 됐다)

여기서 테스트 해보자:

이전 버전과 비교해, 가장 주목할 차이는 .mysql_secret 파일이 없다는 것이고 스크린에 임시 패스워드가 짧은 줄로 언급된다. 또, 한가지 더 중요한 행동상의 차이점으로 이 명령어는 오직 한번만 작동한다. 만약 데이터 디렉토리가 존재한다면, 그 스크립트는 데이터 생성 명령어들을 다시 적용할려고 할 것이다. mysqld -initialize 사용은 데이터 디렉토리가 존재하지 않을때에만 실행된다.

새롭게 생성된 데이터베이스 사용을 위해서는 이전과는 다른 꼼수가 있다.

우잉? 이게 뭘까? 이 명령어는 최근까지 잘 동작했다. 원인은 SET PASSWORD 문법이 변경되었는데 이제는 생자 텍스트를 인수로 받는다.

오래된 문법은 오직 deprecated 되었다는걸 뜻하지만 이것은 순간적으로 완벽하게 제거될 수 있다. 이것은 MySQL 5.7.7 에서 고쳐지길 희망한다. (뭔소리냐.. ㅡㅡ;;)

더 많은 변화는 GRANT, REVOKE, CREATE USER, 그리고 ALTER USER 사용에서 일어났는데 현재 좀 더 제한적이다. 만약 GRANT 명령어로 사용자들을 생성하려고 한다거나 승인권한을 인증옵션과 섞으려고할때에 경고 메시지를 받을 수 있다.

요컨대, 만약 MySQL을 설치하고 관리하는 자동화된 스크립트를 가지고 있다면, 당신은 waringins 을 활성화하고 테스트해야 한다, 오래된 관습을 가지는 호환성이 깨지는것에 대비해야 한다.

One such ‘old practice’ scripts that is broken by the new syntax changes is MySQL-Sandbox. I have just released an updated version (MySQL Sandbox 3.0.48) with a workaround for MySQL 5.7.6 changed SET PASSWORD syntax.

BTW, mysql.user 테이블에 password 필드가 삭제되었다고 말했나요? 이것은 많은 테스트를 멈추게하는 또 다른 놀라운 점이다.

 

[번역]레디스 슬레이브에서 “놓쳐버린” 키들.

이 문서는 다음의 글을 번역한 것입니다.

레디스 슬레이브에서 “놓쳐버린” 키들.

만약 당신이 레디스(Redis)에서 만료중인 키를(expiring key)(“임시적인 키”로 알려진) 사용하고 있다면, 당신은 레디스 마스터에서 새로운 슬레이브(Slave)를 붙였을때에 놀랄 수도 있습니다. 슬레이브에서 키 갯수(key count)가 마스터에서 키 갯수보다 약 25%정도 낮을 것입니다. 이것은 임시적인 키(volatile key)가 아주 많다면 특별하게도 정상적인 것입니다.

Redis Master-Slave

레디스 슬레이브가 키를 놓쳐버린 걸까? 단순하게 데이터를 잃어버린 걸까? 결론부터 말하자면 “아니오” 입니다. 그러나, 왜그런지 이해하길 희망하면서, 레디스 슬레이브가 어떠한 데이터도 잃어버리지도 않았는데도 더 적은 키 갯수를 보고합니다. 이것은 두가지 세세한 구현으로부터 발생됩니다: 어떻게 레디스는 키를 만료시키고 어떻게 레디스 마스터는 새로운 슬레이브에게 데이터셋(dataset)을 보내는지하는 것

어떻게 레디스는 임시적인 키들을 만료시킬까?

레디스는 임시적인 키들(volatile keys)을 만료로 지정한 순간에 메모리로부터 삭제를 하지 않습니다. 대신에, 그들은 두가지 방법중에 하나로 삭제를 합니다.

  1. 레디스 클라이언트가 키에 읽고 쓰기 연산을 수행할때에, 레디스 서버는 첫번재로 키가 존재하고 만료 시간을 가지고 있는지를 체크 합니다. 만약 키가 존재하고 만료시간이 지난 키라면 레디스는 즉시 명령어를 처리하기 전에 메모리로부터 키를 삭제합니다.
  2. 접근이 더 이상 없는 키의 경우 메모리에 임시적인 키가 영구적으로 남아있는 것을 방지하기 위해서 레디스는 만료 키를 위해서 단순한 패시브 알고리즘을 사용합니다: 매 10ms, 100개의 랜덤으로 임시적인 키들을 추출하고 즉각 만료가 지난 모든 키들을 삭제처리합니다. 만약 25% 혹은 그 이상의 키들이 삭제되었다면, 레디스는 즉각 다른 100개의 키를 추출하고 같은 일을 반복합니다.

위의 두번째 방법은 매우 중요한데, 키의 25% 이상이 이미 만료된 임시적인 키(메모리에서 아직 삭제가 되지 않은) 될 수 있다는 것을 의미한다. 레디스는 삭제되때까지 INFO 에 “keys”와 “expires”에 이러한 키들을 계속 포함시킬 것입니다.

어떻게 레디스는 새로운 슬레이브에 데이터셋을 보낼까?

레디스 슬레이브가 레디스 마스터에 붙었을때에, 마스터 서버는 그들의 데이터셋의 RDB 스냅샷을 생성하고 그것을 슬레이브로 보냅니다. 이때 레디스는 RDB 스냅샷을 생성할때에 아직 메모리에 남아있다 할지라도 이미 만료시간이 지난 키들은 포함하지 않습니다.

그래서, 왜 나의 슬레이브의 키 갯수는 마스터의 키 갯수보다 적을까?

슬레이브가 마스터 인스턴스에 붙으면, 슬레이브는 메모리에서 삭제되지는 않았지만 만료된 임시적인 키들을 포함하지 않은 데이터셋을 받습니다. 그리고 25% 이상의 키는 메모리에서 아직 삭제되지 않았지만 만료된 키일 수 있기 때문에 슬레이브는 마스터의 25% 이상 더 적은 키를 보여줄 것입니다. 덧붙여서, 이것은 모든 키가 없어져서 RDB 백업으로 레디스 서버를 복구할때에도 똑같은 일이 벌어집니다.

Redis 운영에 필요한 잡지식들.

Redis 는 In memory 기반으로 동작하기 때문에 메모리 관리가 매우 중요한데, 먼저 리눅스에 메모리 관리를 Redis 운영에 적합하도록 설정하는 것이 좋다.

먼저 Redis 는 Swap 을 사용하지 않고 물리 메모리 내에서만 운영하는 환경이다.

가상 메모리 overcommit 에 대해서 2 로 설정하는 것이 좋다. 2로 설정하게 되면 리눅스가 사용가능한 메모리는 다음과 같이 계산한다.

예를들어 32GB 물리 메모리를 가지고 있고 overcommit_ratio 가 50%라면  16GB 물리 메모리만 사용하게 된다. 그래서 overcommit_ratio 를 99% 로 설정을하면 모든 메모리를 사용하게 된다.

swappiness 는 0 ~ 100 사이에 값을 가진다. 0에 가까우면 메모리의 dirty page 가 있다고 하더라도 최대한 swap 을 하지 않지만 100에 가까우면 조금만 dirty page 가 있으면 swap 을 한다. Redis 를 물리 메모리만 사용하게끔 하고 싶다면 swappiness 를 0 으로 하는게 좋다.

Redis 의 save 옵션&&maxmemory-policy

Redis 는 메모리의 내용을 디스크로 보관하도록 하는 옵션이 여럿 있다. 그중에 save 옵션이 존재하는데, 다음과 같다.

위 두 조건중에 하나만 만족되도 Redis 는 메모리에 내용을 디스크에 쓰게된다. 만약, Redis 를 운영하는동안 위 조건을 하나도 만족하지 못한다면 디스크로 전혀 쓰는 행위가 발생하지 않게되고 maxmemory 에 닫게 되는 상황에서 maxmemory-policy 가 volatie-lru 로 되어 있다면 다음과 같은 상황에 직면하게 된다.

위 오류는 랜덤으로 key-value 를 생성해서 무한 set 을 돌린 결과 이다. maxmemory 는 512MB 였는데, expire 되는 key 가 하나도 없어 메모리는 항상 차게되어 있고 결국에는 더 이상 사용할 메모리가 없자 오류가 난 것이다.

이는 프로그램 운영 상으로도 매우 심각한 문제가 된다. Redis 는 ‘evicted_keys’ 가 존재하는데 보통은 메모리 부족현상으로 발생되는 거라고 생각한다. 그래서 메모리가 부족하면 evicted_key 만 나오고 프로그램은 예외가 발생하지 않을 거라고 생각한다.

evicted_keys 도 증가했지만 예외상황을 맞을수도 있다.

그렇다면 maxmemory-plicy 가 allkeys-lru 되어 있다면 어떻게 될까? 결론부터말하면 프로그램은 예외를 발생할 확률이 줄어든다. 예외를 발생시킬 수도 있지만 안될 확률이 높다. 프로그램은 잘동작하는 것처럼 보이지만 Redis 는 evicted 를 발생시키고 있다. 따라서 evicted_key 가 증가하는 현상이 보인다면 maxmemory 값을 늘려주는게 좋다.

bgsave 는 slave 와 접속을 차단한다. replication 은 SYNC 는 BGSAVE 를 발생시킨다.

먼저, 구분되어야 할게 있다. Master<->Slave 간의 replication 상태에서 데이터는 전송되지 않는다. 무슨 말이냐하면 Master 발생되는 명령어들을 그대로 Slave 에 던지는 방법이다. “set myhello ‘Hello'” 라는 명령어를 Master 에서 했다면 Slave 도 똑같은 명령어가 전달되지 데이터가 전달되지 않는다.

용어의 차이일 수 있는데, SYNC 시에는  slave 에게 데이터를 전송하기에 앞서 disk 에 rdb  파일을 생성한다. replication.c 에 다음과 같은 내용을 볼 수 있다.

rdb 파일은 백그라운드 프로세스를 생성시키고 rdb_filename 파일에 저장한다. 문제는 이러한 일이 벌어지는 동안에 접속은 차단된다.

closeListeningSockets 함수는 TCP/IP 접속 소켓을 닫게 된다.

결국 BGSAVE 가 발생하는동안 slave 접속은 차단된다. 그리고 다시 접속이 이루어지면 Full Sync 가 발생된다. 정리를하면 현재 Replication 이 된 상태라면 Sync 를 위해서 rdb  덤프는 발생되지 않는다. 하지만 새롭게 Replication 이 맺어지면 그때에는 Master 가 rdb 덤프를 하고 그리고 나서 데이터를 전송하게 된다. 실제로 새로운 Replication 이 맺어지면 파일 덤프가 다음과 같이 발생한다.

temp-5594.rdb 임시파일을 생성하고 나서 rdb_filename 으로 변경한다. Replication 상태에서 rdb 검프는 SYNC 에만 발생한다.

그런데, Redis 는 slave 가 잠시동안 접속이 차단될때에 Full Sync 가 발생하지 않도록 repl-backlog-size 에 복제를 위한 데이터를 저장해둔다. 주의해야할 것은 이 크기는 메모리 크기를 말하는 것으로 디스크에 데이터를 저장하지 않는다.

여기서 또 짚고 넘어가야할 것은 repl-backlog-size 가 작아서 runtime 으로 크기를 변경해주면 기존의 데이터는 다 지워지고 새로운 크기의 backlog 가 할당되는 방식을 취한다.

 

Redis 를 운영할때에 Master-Slave 로 운영한다면 모든 것을 메모리로만 운영할 수는 없다. Slave 로 Replication 을 할때마다 BGSAVE 가 발생하고 이는 일시적으로 Slave 와의 접속을 차단하기 때문이다. Slave 와의 접속이 차단된 후에 다시 연결이 되었을 경우에 Full Sync 가 발생할 수 있다.

diskless 를 통한 slave sync

이는 사실상 트릭같다. disk sync 은 Master 가 bgsave 로 메모리에 데이터를 점프한 후에 그것을 slave 로 전송하는 방법이다. bgsave 가 작동하게 되면 slave 와의 연결은 잠정적으로 끊어지게 된다.

하지만 disklee sync 는 bgsave 가 동작하지 않으며 Master 가 아닌 Slave 가 Master 로부터 메모리의 내용을 전송받아 덤프 파일을 생성한 후에 이것을 메모리에 올리는 방식이다. Master 로부터 Slave 가 데이터를 전송받을때, Master 는 “redis-rdb-to-slaves *:6379” 프로세스가 생성돼 전송을 담당한다. Slave 에서는 전송된 데이터를 파일로 저장하기위해서 별도의 프로세스는 작동하지 않는다.

Master의 메모리 내용을 Slave 가 덤프 받는 방식이 diskless sync 이며 수십기가의 메모리 내용을 전송해야하기 때문에 네트워크 상태가 좋아야 한다.

Python redis 테스트 스크립트.

랜덤으로 키를 생성해서 값을 넣도록 만든 Python redis 테스트 스크립트.

 

Redis 설치하기

redis

 

Redis 는 Key-Value 로 데이터를 저장하는 NoSQL 서버 입니다. In Memory 기반으로 동작하기 때문에 빠른 응답속도를 보입니다.

이 문서는 Redis 설치에 관한 문서 입니다.

다운로드

의존성 패키지 설치

CentOS 의 경우에는 다음과 같이 설치를 해줍니다.

Ubuntu 의 경우에는 다음과 같이 설치를 해줍니다.

컴파일

설치

설치는 PREFIX 를 인자로 줘서 설치 디렉토리 위치를 지정해줄 수 있습니다.

Redis 의 설치는 오로지 실행파일들만 복사해 줍니다.

설정

Redis 는 설치 후에 각종 설정을 할 수 있도록 스크립트를 지원 합니다. 이 스크립트를 사용하면 각종 설정파일들을 복사해 줍니다. 이 스크립트는 utils 디렉토리에 존재 합니다.

자세히 보면 initscript 까지 설정을 해주고 실행까지 해줍니다. 설정파일 하나하나 복사해줄 이유가 없습니다.