블로그 이미지
OSSW(Open Source System SoftWare

calendar

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        

Notice

관계형 테이터베이스 테이블을 redis로 옮기기


1. redis 자료형

  • 문자열, String: 일반적인 key - value, hash로 보면 된다. range, between 이런 것 없다. 그냥 오직 그 key
  • 목록, List: 그냥 배열, push & pop 용, 순서가 색인, 중복된 value, 목록 이름이 key. 하나의 목록을 샤딩할 수는 없다.
  • 집합, Set:: 중복된 value를 가질 수 없는 집합 - RDB 인덱스의 value가 된다. insert = sadd, delete = srem , index key update = smove
  • 해시, hash: RDB의 테이블, key가 테이블이름, field가 Primary Key, value가 json 칼럼들값들, 하나의 해시는 샤딩할 수 없다.
  • 정렬된 집합, sorted set: btree 인덱스 구현용, 하나의 집합을 샤딩할 수 없다. 아래에서 설명
여기서 보듯이 scale out 관점에서 문자열 자료형(key-value)을 제외하고는 모두 scale out에 유연하지 않다. 즉, 문자열 자료형을 외 자료형을 사용한다면, 분산 처리는 응용프로그램에서 독자적으로 구현해야한다. 이 부분에 대해서는 좀 더 고민해 보고 다음 글에서 다루기로 하겠다.

2. RDB 테이블을 redis로.

위에서 살펴 보았듯이, 하나의 테이블은 하나의 해시로 만들면 된다.

문제는 하나의 해시는 redis 서버에서 안쓰면 버린다는 expire 설정을 하는 것도 비효율적이다. 버렸는데, 다시 필요하다면, RDB 에서 테이블 전체를 다시 가져와야하기 때문이다.
즉, 어느 테이블을 redis 서버로 가져올 것인가는 결국 그 redis 서버에서 사용할 수 있는 메모리 크기와 직접적으로 관련된다. swap 메모리를 사용해 가면서까지 굳이 RDB 테이블을 모두 redis로 가져오겠다는 생각은 안하는 것이 좋을 것이다. 

여기서는 커뮤니티 게시판을 서비스를 대상으로 rdb를 redis로 옮기는 것을 살펴보고자 한다.

기존 rdb의 erd는 다음과 같다.


2.1. 사용자들 테이블

사용자들 테이블은 그룹들 테이블과 M:M 관계이다. redis와 같은 key-value 형태의 데이터베이스에서는 이런 다대다 관계는 문자열 키로 값은 그냥 json array로 푸는 것이 제일 편하다.

SET 사용자들:1 '{"로그인ID": "gildong", "이름": "홍길동", "비밀번호": sha256(passwd), "이메일": "user@gmail.com", "사용여부": "Y", "groups"=[1,2,3]}'

그룹들 테이블은 단순하게,

SET 그룹들:1 관리자
SET 그룹들:2 일반사용자
SET 그룹들:3 공동저자
....
이런 형태로 문자열 키로 지정할 수도 있고,

HSET 그룹들 1 관리자
HSET 그룹들 2 일반사용자
....
이런 형태의 hash 테이블 형태로 구현할 수도 있다.

redis 서버의 key 관리 측면에서는 hash 테이블 형이 유용하겠지만, 훗날 분산환경을 위해서는 위의 문자열 키 형태가 더 유용하다.

한편, 관리 차원에서 전체 회원수를 알기 위해서,

SCAN 0 MATCH "사용자들:*" count 100000000000

이런 형태의 명령을 사용하는 것은 정말 위험한 짓이다. 이런 경우를 대비에서 "totalcount::사용자들" 같은 문자열 키를 하나 할당하고, 그 값으로 전체 사용자 수를 기록하고 있는 것이 바람직하다. 이 값은 회원 가입이 있을 때, INCR, 탈퇴할 때, DECR 명령을 이용해서 증,차감 하면 될 것이다.

2.1.1. 사용자들 테이블의 인덱스들

redis에서 그 키에 대한 값을 구할 때, '=' 연산만 가능하다.
즉 >, < , between 같은 연산이 필요하다면, 하나의 정렬된 집합 키(RDBMS의 인덱스가 된다)를 만들고, ZRANGE 명령을 이용해야 한다.

사용자들 테이블에는 총 3개의 인덱스가 정의되어있다.

하나는 기본키이며, 이 키를 사용해서는 오직
= 연산으로만 검색하겠다고 결정해서, 사용자들:1, 사용자들:2... 같은 문자열키를 사용했다.
즉,
SELECT * FROM 사용자들 WHERE 사용자번호 BETWEEN 100 AND 200
같은 쿼리를 사용하지 않겠다는 것이 전제 되어 있다.

두번째 인덱스는 로그인ID에 대한 유니크 인덱스이다.
로그인ID로 검색하는 것을 오직 = 연산만 허용하겠다면,
앞에서 언급한 HSET을 이용한 hash 테이블로도 충분하다.

HSET 사용자들_로그인ID_색인 a@emai.com 1

이 hash 테이블의 키는 email, 값은 사용자 번호가 될것이다.

즉,
SELECT * FROM 사용자들 WHERE 이메일 = 'a@email.com'
형태의 쿼리 작업을 redis로 푼다면,

다음 절차를 거친다.
  1. HGET 사용자들_로그인ID_색인 a@email.com
  2. GET 사용자들:1
한편,
SELECT * FROM 사용자들 WHERE 이메일 like 'a@email%'
형태의 쿼리를 인덱스를 사용해서 처리하고자 한다면,
상황은 좀더 복잡해진다.

이것을 구현하려면, redis 정렬된 집합을 사용해야한다.

ZADD 사용자들_이메일_색인 1 a@email.com
형태로 색인자료를 만드며, email 값 앞에 있는 1은 사용자번호다.

그리고, 이 색인의 범위검색을 하려면, '[', '(' 문자를 추가해서 범위 검색을 한다.
ZRANGEBYLEX 사용자들_이메일_색인 '[a@email' '(a@emaim'
형태로 사용한다.
SQL 구문으로 바꾸면,
WHERE 이메일 >= 'a@email' and 이메일 < 'a@emiam'
이 될것이다.
즉, 이메일 like 'a@email%' 는 위와 같이 변환해서 사용해야한다.

찾으려고 하는 값인 한글인 경우는 좀 더 복잡해진다.

where 이름 like '대한민%'
이라면, '[대한민' '(대한믽' 이 될것이다. 
마지막 한 글자의 unicode 다음 글자다. 어떻게 구하는지는 스스로 공부를.

이렇게 해서, 정렬된 집합을 이용한 색인 검색이라면, 다음 절차를 거친다.
  1. ZRANGE|ZRANGEBYSCORE|ZRANGEBYLEX 사용자들_이메일_색인 최소값 최대값
  2. 위명령 결과의 배열로 해서,
    for 값 in 값배열
        ZSCORE 사용자들_이메일_색인 값
    형태로 또 사용자 번호 배열을 만들고,
  3. for 사용자번호 in 사용자번호배열
       GET 사용자들:사용자들번호
형태의 복잡한 작업을 해야한다.
물론 2번 작업을 단순화 하기 위해서, 앞에서 이야기한 이메일 기준 hash 테이블도 만들고, 그것을 조회하는 것도 한 방법일 것이다.

세번째 인덱스인 로그인ID에 대한 유니크 인덱스다.
이 인덱스도 email 인덱스 처리방식과 똑같다.

2.2 게시판 테이블

게시판 테이블도 사용자 테이블과 크게 다르지 않기 때문에 설명은 생략하고,
여기서는 드디어 작성일시 기준 비유니크 인덱스를 구현해야 한다.
즉, 같은 작성일시에, 여러개의 게시물이 존재할 수 있음을 가정한 것이다.

(쓸데 없이 옆길로 샌 이야기: 단일 redis 서버를 사용하고, 위 모델링을 실재 구현한다면,
게시물의 작성일시는 절대로 같을 수 없다. 왜냐하면, redis 서버는 단일 프로세스 단일 쓰레드로 사용자 명령을 처리하기 때문에, 모든 명령이 직렬화 된다. 즉 같은 시간이 있을 수 없다. 하지만 사용자 편의를 위해 작성일시를 초단위까지만 사용하겠다면, 충분히 같은 작성일시에 여러개의 게시물이 있을 수 있다)

이렇게 비유니크 인덱스도 정렬된 집합을 사용해서 구현한다.

2.2.1. 게시물 작성일시 색인

redis에서는 시간자료형이 없다. 작성일시 값은 결국 문자나 숫자로 저장되어야한다.
2018-07-01 12:30:25 형태의 문자로 저장하든가, 이 시간의 unixtimestamp 값으로 저장한다.

문자로 저장한다면, ZRANGEBYLEX로 범위검색을 할것이고, 숫자로 저장한다면,
ZRANGEBYSCORE로 검색하면 된다.

작성일시를 문자열로 처리하는 경우
ZADD 게시판_작성일시_색인 1 '2018-07-01 12:30:25'
형태가 될것이고, 앞에서 다룬 것과 똑같이 1은 게시판 기본키인 게시물번호다.

작성일시를 숫자로 처리한다면,
ZADD 게시판_작성일시_색인 1530621697 1
형태가 될 것이고, 1530621697 숫자는 unixtimestamp 값이고, 뒤에 1은 게시물번호가 된다.

이 색인을 이용한 =, >, <, >=, <=, between 연산은 직접 구현해야한다.


2.3 태그 테이블

태그 테이블은 단순하게 생각하면, 집합을 사용하면 된다.

SADD 태그:서울 1
SADD 태그:서울 5
SADD 태그:서울 100
....
서울이라는 태그를 지정한 모든 게시물 번호를 찾으려면,
SMEMBERS 태그:서울
형태로 게시물 번호를 요소로 하는 배열을 만들고,
그 배열의 각 요소를 기본키로해서 게시판:게시물번호 문자열 키에 대한 값을 구하면 된다.

여기서 중요한 것은 SMEMBERS는 현재, limit offset count 기능이 아직까지는 구현되지 않았기에,
한 태그의 값인 게시물번호를 모두 찾아 응용프로그램에게 넘겨준다.
그렇기 때문에, 한 키에 대한 SMEMBERS의 결과값이 많으면 많을수록 이 명령의 성능이 더 떨어진다.

3. 마무리

INSERT INTO t VALUES (.....)
=> SET t:pk 'json'

SELECT * FROM t where pk_column = pk_value
=> GET t:pk_value

SELECT * FROM t WHERE int_column >= start_value and int_column <= end_value
=> ZRANGEBYSCORE t_int_column_index start_value end_value
     loop primary_keys
        GET t:pk_value

SELECT * FROM t WHERE text_column LIKE 'find_str%'
=> ZRANGEBYLEX t_text_column_index '[find_str' '(find_sts'
     loop primary_keys
       GET t:pk_value

SELECT t.* FROM t, tags WHERE t.pk = tags.pk_value AND tags.tag = 'tag_value'
=> SMEMBERS tags tag_value
     loop pk_values
       GET t:pk_value


- posted by 김상기

'1. 미들웨어이야기 > 06. redis' 카테고리의 다른 글

rdb 테이블을 redis로  (0) 2018.06.16
posted by 김상기 ioseph

1. PostgreSQL 논리적 디코딩 소개

http://postgresql.kr/docs/current/logicaldecoding.html


9.4 버전에서 새로 등장한 개념으로,

트랜잭션 로그를 출력 플러그인을 이용해서 사용자 정의 형태로 변환하는 기능을 말합니다.


기존 복제가 트랜잭션 처리에서 먼저 기록한(write-ahead) 내용을 다른 서버로 그대로 보내서 그것을 재실행하는 방식의 스트리밍 복제였다면, 논리적 디코딩을 이용하면 논리적 개념으로 데이터베이스 복제가 가능해 집니다.  이 말은 대상 데이터베이스가 똑 같은 OS에, 똑 같은 버전의 PostgreSQL 서버여야 할 필요가 없으며, 심지어 MySQL이나 기타 다른 데이터베이스, 더 나아가 굳이 데이터베이스가 아니어도 복제가 가능하다는 것을 의미합니다. 트랜잭션 로그를 분석해서 원하는 출력 양식으로 바꿀 수 있는 출력 플러그인만 있다면 말이지요.


2. 논리적 디코딩 출력 플러그인들

  • test_decoding
    배포판에 포함된 테스트 용도, SQL이나, pg_recvlogical 명령으로 확인 가능합니다.
  • decoder_raw
    https://github.com/michaelpq/pg_plugins/tree/master/decoder_raw
    트랜잭션 로그를 만들었던 DML로 출력
  • pglogical
    https://2ndquadrant.com/en/resources/pglogical/
    트리거 기반 테이블 단위 복제 솔루션인 slony를 대체할 테이블 단위 복제 솔루션, 멀티 마스터 기능은 아니고, 마스터에서 배포하고 슬레이브에서 구독하는 방식으로 단방향 복제 솔루션입니다.
  • decoding_json
    https://github.com/leptonix/decoding-json
    트랜잭션 로그를 분석해서 그 내용을 json 양식으로 만듭니다. 자료를 뽑을 때는 pg_recvlogical 명령을 사용해서 확인해 볼 수 있습니다.

 

3. 개념

논리적 디코딩 기능을 이용 하는 절차는 다음 순서로 진행합니다.

  1. 원본 서버의 환경 설정값을 확인합니다.
    replication 권한이 있는 사용자가 있어야 하고, (슈퍼유저와 분리하는 것이 안전합니다, - 대신에 아래 pglogical 용이라면, 이 사용자에게 pglogical 관련 객체들 사용할 수 있는 권한도 부여해야합니다. 테스트 용도로라면, 그냥 postgres 슈퍼 유저를 사용하세요)
    CREATE ROLE replicatest REPLICATION LOGIN;

    pg_hba.conf 파일에서 해당 사용자가 스트리밍 복제를 할 수 있도록 설정하고,
    host replication replicatest 192.168.0.10/32 trust

    postgresql.conf 파일에서 wal_level 값은 logical, max_replication_slots 값은 0 보다 크게, max_wal_senders 값도 0보다 크게 지정하고,

    필요하다면 변경한 설정값을 반영하기 위해서 서버 재실행합니다.

    (pglogical 기능 테스트라면 복제 내용을 재 실행할 대기서버 쪽에도, max_replaction_slots 값이 0 이상이어야 하더군요)

  2. 원본 서버 (배포 서버)에서 pg_create_logical_replication_slot() 함수를 이용해서 논리 복제 슬롯을 만듭니다.

    여기서 기억해야 할 것은 이 슬롯이 만들어지는 순간부터 트랜잭션 로그가 논리 복제 기능을 사용하는 응용프로그램(또는 다른 서버)에서 다 빼내가기 전까지 트랜잭션 로그를 지우지 않는다는 것입니다.
    사용하지 않는 복제 슬롯을 만들어두면, 결국 pg_xlog 쪽 WAL 파일 재활용을 하지 않게 되고, 결국 해당 디렉터리 가용 공간이 없어지게 되어 서비스 장애까지 이어질 수 있습니다. 주의해야 합니다.

    논리적 복제 슬롯을 만들 때, 매개변수로 출력 플러그인을 지정합니다.
    SELECT
    pg_create_logical_replication_slot('슬롯이름', '출력플러그인이름', '플러그인에서사용하는옵션이름', '옵션값')
    형태로 SQL 구문으로 지정할 수 있고,
    pg_recvlogical 명령같이 논리적 복제를 구현하는 응용프로그램측에서 스트리밍 복제 프로토콜을 이용 해당 슬롯을 만들 수도 있습니다.

  3. 논리 디코딩을 이용하는 응용프로그램(또는 서버)에서 원본 서버에서 발생한 DML에 대한 트랜잭션 로그를 사용합니다. 사용은 두 가지가 있는데, 하나는 그 로그를 꺼내오는 경우(get)고, 다른 하나는 그냥 두고 가져다 쓰는 경우(peek)입니다.

    응용프로그램이 트랜잭션 로그 디코딩을 요구하면, 출력 플러그인이 해당 복제 슬롯 정보를 확인하고, 해석해야할 트랜잭션 로그를 WAL 파일에서 찾아서 그것을 해당 플러그인 출력 양식에 맞춰 응용프로그램 쪽으로 보냅니다. 이때, get 방식으로 요청하면, 복제 슬롯 상태값에서 lsn(로그 시퀀스 번호)을 증가합니다.

  4. 원본 데이터베이스 서버가 기억하는 복제 슬롯 정보는 마지막 꺼내간 lsn 번호입니다. 즉, 그것을 사용하는 응용프로그램에서 그 자료가 제대로 쓰였는지는 전혀 모릅니다. 또한 이 상태는 checkpoint 작업으로 디스크에 영구 보관됩니다. checkpoint 전 서버 비정상 종료가 있었다면, 서버가 다시 시작되고, 다시 해당 슬롯을 사용하는 응용프로그램 트랜잭션 로그를 달라고 요청하면 이전에 이미 받았던 자료가 올 수도 있습니다.  즉 논리적 복제 슬롯을 이용하는 응용 프로그램이나, 서버는 반드시 이 부분의 중복 처리에 대한 정책을 세워야 합니다.

  5. 해당 복제 슬롯의 상황은 pg_replication_slots 뷰에서 이 슬롯을 스트리밍 리플리케이션 프로토콜로 사용한다면, pg_stat_replication 뷰에서 그 상황을 볼 수 있습니다.


4. pglogical

2ndQuadrant 사에서 만든 PostgreSQL 확장 모듈입니다.

이 글은 https://2ndquadrant.com/en/resources/pglogical/pglogical-installation-instructions/ 페이지 기준으로 몇가지 작업을 하면서 정리한 것입니다.


이 확장 모듈은 트리거 기반 복제 솔루션인 slony 의 대안으로 개발되었습니다.  왜냐하면, slony가 나온 뒤 PostgreSQL 서버는 background worker, logical decoding 등 많은 기능이 추가되어 이 기능들을 잘 쓰면 테이블 단위 복제가 가능할 것이다는 생각이 들었기 때문입니다.


기본 개념은 운영 서버에서 배포하고, 슬레이브 서버에서 구독하는 방식입니다. 이 배포와 구독은 pglogical 모듈을 설치하고, 재실행하면 생기는 background worker 프로세스가 관리하고, 내용 전달은 pglogical_output 이라는 모듈에서 제공하는 논리적 디코딩 출력 플러그인을 사용해서 스트리밍 복제 프로토콜을 이용합니다.


즉, 배포와 구독 서버간 스트리밍 복제가 가능하도록 설정이 먼저 되어 있어야 합니다. 물론 이전의 스트리밍 복제 대기 서버를 구축하는 것 처럼 pg_basebackup을 이용해서 운영서버 전체를 백업하고 재구축할 필요는 없습니다. 그저 깡통 데이터베이스에 필요한 테이블만 있으면 됩니다.


 

작업 방법은 다음과 같습니다.


  1. 제일 먼저 할 작업은 운영 서버는 배포 역할을 할 수 있도록, 대기 서버는 구독 역할을 할 수 있도록 스트리밍 복제 환경을 만들어야 합니다. 자세한 설명은 윗 페이지 참조

  2. pglogical 이라는 확장 모듈을 설치합니다.
    github (https://github.com/2ndQuadrant/pglogical) 에서 소스를 받아서 직접 컴파일을 하거나, 위 홈페이지에서 해당 패키지를 설치하거나, 자기 환경에 맞게 설치합니다.

  3. psql 창에서 CREATE EXTENSION pglogical; CREATE EXTESION pglogical_output; 두 모듈을 설치합니다.

  4. 각 서버(노드)는 pglogical 모듈을 이용해서 논리적 복제를 사용하겠다는 정보로, 제일 먼저 각 노드별 노드 등록을 합니다. pglogical.create_node() 함수 이용. 이 작업은 각각의 노드에서 해야 합니다. 즉, 접속 dsn 값은 자기 자신의 서버로 접속하는 정보를 입력합니다.

  5. 배포 서버 쪽에서는 배포할 세트를 만들고, 그 세트 안에 배포할 객체들을 등록합니다. 현재는 테이블과 시퀀스입니다. pglogical.create_replication_set(), pglogical.replication_set_add_sequence(), pglogical.replication_set_add_table() 함수를 이용합니다.  확장 모듈을 설치하면, 기본으로 사용할 수 있도록 default 라는 세트가 이미 등록되어 있기 때문에, 특별한 경우가 아니면, 그냥 default 세트에 원하는 객체들을 포함시기는 작업 (repliaction_set_add_*) 만 하면 됩니다.

  6. 구독 서버는 위에서 작업한 자신의 노드 등록과 함께, 구독 등록도 해야 합니다. pglogical.create_subscription() 함수 이용. 이 때 기억해야 할 것은 논리적 스트리밍 복제 슬롯이 만들어지는 시점 - 트랜잭션 로그를 보내는 시작 lsn 값이 지정되는 시점 - 은 구독 서버가 구독 작업을 시작하는 시점이라는 점입니다. 즉, 구독 이후부터 발생한 변경 사항이 구독 서버에 적용 될 것이라는 점입니다.
    (해당 테이블을 아에 그대로 복제하겠다면, pglogical.alter_subscription_resynchronize_table() 함수를 이용합니다.)

    또 하나 기억해야 할 것은 구독 시작 이후 그 구독 서버를 더 이상 사용하지 않아  서버가 중지된 상태여도, 명시적으로 구독 중지(pglogical.drop_subscription() 함수 이용) 처리를 하지 않았다면, 구독 신청으로 만들어진 논리적 복제 슬롯은 삭제 되지 않는다는 점입니다. 이 말은 해당 슬롯의 마지막 lsn 뒤 부터는 모든 트랜잭션 로그를 보관하겠다는 것을 의미합니다. 결국 pg_xlog 쪽 가용 공간이 점점 줄어 나중에는 서버 장애로까지 발전할 수도 있다는 것입니다.


4.1 pglogical 한계

논리적 복제를 이용하기 때문에, 논리적 복제 한계가 그대로 있습니다. 자세한 이야기는 이 글 맨 앞에 언급한 사용 설명서를 참조하세요.


CREATE EXTENSION 명령이 데이터베이스 단위로 이루워짐으로 결국 이 복제 작업도 데이터베이스 단위일 수 밖에 없으며, 여러 데이터베이스를 여러 객체를 복제하는 상황이라면, 그 만큼의 스트리밍 복제 환경이 구축되어야 합니다.


또한 복제 작업은 background worker 프로세스로 진행 됨으로 슈퍼 유저 권한으로 작업이 진행된다는 점입니다. 슈퍼 유저 권한을 부여하고 싶지 않다면, pglogical 스키마 안에 있는 모든 객체를 사용할 수 있는 권한을 스트리밍 복제 작업하는 계정에게 부여해야 합니다. 


그 외 여러 한계점들에 대해서는 2ndQuadrant 사 홈페이지를 참조하세요.


5. 마치며

이상으로 논리적 복제와 그것을 이용하는 pglogical 확장 모듈을 이용한 테이블 단위 복제에 대해서 살펴봤습니다.  실무 환경에서 이 복제 정책을 도입 할 때는 꽤 많은 다양한 예외 상황을 고려해야 합니다.  구독 서버에서 해당 자료가 변경 된 경우와, 그 테이블이 복잡한 관계성을 유지하고 있는 경우(트리거, 참조키, 상속)에서 자료 동기화 유연성을 어떻게 확보할지, 그리고, 구독 서버의 장애시 배포 서버의 트랜잭션 로그 관리 등 꼼꼼하게 여러
상황을 따져봐야 할 것입니다.


하지만, 좀 더 유연하게 생각하면, 파티션 테이블을 만들고, 하위 테이블 들에 대해서 서로 이 pglogical로 묶으면 부하 분산용 다중 마스터 환경도 구현 가능할 듯합니다. 참신한 아이디어만 있다면, 충분히 유용하게 사용될 수 있는 모듈임에는 분명한 듯합니다.


- posted by 김상기


posted by 김상기 ioseph

0. PostgreSQL 20주년

올해로 PostgreSQL이 세상에 나온 지 스물 돌이 되었습니다.

마이클 스턴브래커 어르신의 postgres 프로젝트까지 거슬러가면 이보다 훨씬 더 오래되었겠지만, PostgreSQL이라는 이름이 등장한 지는 올해로 20년이 되었네요.

이 기념으로 PostgreSQL 커뮤니티에서는 위와 같이 포스터도 만들면서 자축하고 있습니다. 또한 올 해로 열 번째 열린 PostgreSQL 개발자 사용자 회의가 캐나다 오타와에서 열렸고, 제가 다니고 있는 회사 지원으로 이번에 같이 일하고 있는 동료와 함께 저도 참석하게 되었습니다.

이 글은 올 해 열린 PGCon 행사 참관 후기입니다.


1. PGCon 소개

PGCon (http://pgcon.org) 행사는 PostgreSQL 개발자, 사용자가 일 년에 한 번 모이는 PostgreSQL 최대 행사입니다. 참석하는 사람들은 대부분 PostgreSQL 커뮤니티 메일링 리스트에서 꾸준히 활동하는 사람들로 매번 메일로만 의견을 주고 받던 사람들이 한 자리에 모여 여러 주제로 발표도 하고, 토의도 하고, 같이 술을 마시며 놀기도 하는 행사입니다.

주로 다루는 내용은 크게 세 부분으로 구분되는데,

하나는 PostgreSQL 차기 버전에 대한 토의 - 일반적인 새 기능 발표회 같은 분위기가 아니라 서로 의견을 주고 받으며 서로의 부족한 부분을 채워나가는 자리입니다. 여기서 발표되는 새 기능들은 대부분 차기 버전에 수용되기는 하지만 막상 구현된 모습은 이 발표 때의 모습과는 사뭇 다른 경우가 제법 있었습니다.

다른 하나는 각 기업들, 각 지역 커뮤니티들의 사례 발표들로 구성됩니다. 대부분의 발표는 PostgreSQL 엔진에 촛점이 맞춰져 글로벌 개발자 그룹도 자리를 함께 하면서 자신들이 만든 프로그램이 어떻게 쓰이고, 어떤 점이 미흡하고, 어떻게 개선해 나갈 것인가를 살펴봅니다.

또 다른 하나는 PostgreSQL을 사용하는데 필요한 부가 솔루션, PostgreSQL을 이용한 솔루션을 소개합니다. 그 또한 오픈 소스로 되어 있는 것이 대부분이고, 자기 회사의, 또는 자신들의 오픈 소스 프로젝트를 자랑하는 자리입니다.


2. 오타와 여행

우리나라에서 캐나다 오타와까지는 비행기로 한 번에 가는 교통편이 없어, 토론토를 거쳐 국내선으로 갈아타고 갔습니다. 인천에서 토론토까지 14시간, 국내선 갈아타는 시간 3시간, 토론토에서 오타와까지 1시간, 오토와 공항에서 숙소까지 1시간, 이동하는데만 거의 20시간이 걸렸습니다.

관광을 위해서는 박물관과 미술관 관람을 제외하면 하루면 충분히 다 둘러 볼 수 있는 자그마한 도시였습니다.

랜드마크인 캐나다 국회의사당과 그 옆에 흐르는 운하와 그 강변으로 있는 박물관과 미술관 그리고 앞에 있는 대성당, 그리고, 캠퍼스 담장이 없는 오토와 대학 - 첫날 회의 참석 등록을 하러 가는 길에 잠깐만 짬 내면 다 둘러 볼 수 있는, 한 국가의 수도라기 보다는 어느 한적한 마을을 들린 듯했습니다.

그리고 매일 식사를 책임졌던 바이워드 시장 - 재래시장이라고 소개는 하고 있으나, 식당과 상점들로 가득한 그냥 한 구역이였습니다.

다음은 행사장 건물 앞에서 찍은 사진입니다.



3. PGCon 2016 내용

http://pgcon.org/2016

총 5일에 걸친 긴 일정이었는데, 앞 이틀은 사용법 강좌를 다루고, 이틀은 각 주제들에 대한 발표와 질의응답 형태의 회의, 마지막 날은 사용자들이 모두 모여 그 자리에서 여러 주제들을 발의하고 토론하는 형태로 진행되었습니다.

참여자들 대부분이 글로벌 개발 그룹 구성원이거나, 각국 컨트리뷰터, PostgreSQL 전문 기술 지원 업체 엔지니어들이었기 때문에, 발표 중간 중간 질문과 답변이 오고 가고 자기 의견을 주장하기도 하고, 전세계 사람들이 모였으니, 의사소통이 안되는 부분은 그 자리에 참석한 다른 분이 대신 통역해 주기도 하는 참 역동적인 모임이었습니다.

참석한 발표들의 간단 요약


3.1. PostgreSQL 확장성 소개

http://www.pgcon.org/2016/schedule/attachments/424_PGCon-PostgreSQL-Extensibility.pdf

제가 생각해도 PostgreSQL 이야기의 키노트로 딱 맞는 주제였습니다.

PostgreSQL은 관계형 데이터베이스 관리 시스템이기도 하지만, 내가 꿈꾸는 어떤 데이터베이스를 만들고자 할 때 그 데이터베이스를 만들 수 있는 하나의 개발 도구로 사용할 수 있는 아주 훌륭한 도구임을 소개하고 있습니다.

그래프 데이터베이스를 PostgreSQL 기반으로 만들고 있는 국내 업체인 비트나인도 한 예가 될 것입니다.


3.2. 얀덱스 메일 전환 성공기

http://www.pgcon.org/2016/schedule/attachments/426_2016.05.19%20Yandex.Mail%20success%20story.pdf

러시아 포탈 업체의 메일 서비스 (https://mail.yandex.com/)를 오라클에서 PostgreSQL로 전환했던 엔지니어 삽질기를 소개했습니다. 중간 중간 실패한 이야기들과 지금의 모습으로 결정하고 사용자들이 전혀 눈치 못 채게 자료를 옮겨가는 전략 등, 다양한 마이그레이션 전략을 소개했습니다.

초당 25만 tps 성능을 유지하는 방법, 300TB의 거대 용량을 전환하는 전략 등 DB 입장에서도 놀랍지만, 전체 설계 입장에서도 살펴볼 것이 많은 발표였습니다. 

이 발표에서 가장 인상 깊었던, 누구나 공감할 수 밖에 없었던 순간


3.3. ERROR: snapshot too old

http://www.pgcon.org/2016/schedule/attachments/420_snapshot-too-old.odp

오라클에서 봤던 그 오류 메시지 도입에 대한 이야기였습니다.

이 오류가 필요했던 이유, 설정 방법, 대응 방법 등을 소개하고 있습니다.

기업 친화적인 Postgres Advanced Server를 판매하고 있는 EnterpriseDB사의 발표였습니다.

이번 발표 세션들 가운데, 성능 이슈 관련, 기업 운영 환경 입장에서의 개선 이슈들은 대부분 이 EnterpriseDB사가 맡았습니다. 하나의 실험 정신 투철한 데이터베이스가 기업에서 사용되고, 그 범위가 넓어지고, 이 회사의 매출이 증가하고 그것이 다시 오픈소스 발전에 기여할 수 있도록 하겠다는 흔히 말하는 오픈 소스 에코 시스템의 좋은 사례 같습니다.


3.4. B-Tree 이야기

http://www.pgcon.org/2016/schedule/attachments/423_Btree

러시아 대표 PostgreSQL 기술지원 업체인 Postgres Professional, https://postgrespro.ru/ 의 엔지니어가 설명한 PostgreSQL 색인 이야기입니다.

특별한 이야기는 없지만, PostgreSQL을 처음 접하는 이들에게는 딱 알맞는 내용으로 구성되어있습니다.

물론 국내 문서도 찾아보면 이 보다 더 자세히 소개한 문서들이 많지만, 잠깐 소개합니다.


3.5. 쿠바에서의 PostgreSQL

http://www.pgcon.org/2016/schedule/attachments/398_PgConf2016_Cuba.pdf

개인적으로는 가장 인상 깊었던 발표였습니다.

쿠바 PostgreSQL 사용자 그룹이 어떻게 만들어졌고, 어떤 활동을 해 왔고, 현재 이런 모습이다는 식을 낯선 스페인어 억양의 영어 발표여서, 읽을 수 있는 것은 윗 링크의 발표 화면들과 발표자의 표정과 몸짓 뿐.

가장 크게는 쿠바의 독특한 정치적 성향 때문이기도 하겠지만, 그 보다 산학 협력 환경, 커뮤니티를 유지하고, 자료를 발표하고, 그런 활동들로 기업 내에서도 저변 확대되어 가는 이야기를 들으면서 국내 PostgreSQL 활성화 방안에 대한 부분도 같이 고민해 볼 수 있었던 시간이었습니다.


3.6. 단순 쿼리의 속도 향상

http://www.pgcon.org/2016/schedule/attachments/400_RunSimpleQueryFaster.pdf

EDB사 엔지니어가 쿼리 실행기를 해킹해서 얻은 성능 향상에 대한 발표였습니다.

요지는 현 쿼리 실행기가 단순 쿼리에 대해서는 많이 느리니, 단순 쿼리로 판단되면, 실행기 내부 작업을 단순하게 처리하도록 작업 내역을 분기하자는 것입니다.

커뮤니티 메인 코드에 반영 될 가능성은 별로 없어 보였지만, 자신들의 해킹이 기업 환경에서는 이렇게 쓸모 있다는 식의 발표를 아주 정량적으로 자료를 수집하고, 논리적으로 기존 개발 그룹에 설득하는 작업이었습니다.

한편으로 보면, 오픈 소스 공동 개발에서 꼭 필요한 활동입니다.


3.7. 반짝 이야기들

열 명이 넘는 발표자들이 각 5분 정도 짧게 제 각각의 이야기를 발표하는 시간도 있었습니다.

pgAdmin4 열심히 만들고 있다. PGCon.Asia 를 싱가포르에서 진행되었다. TPC-H 벤치마킹의 필요성 방법, ....

이 중에 꽤 재미났던 발표는

http://www.pgcon.org/2016/schedule/attachments/408_LightningTalkSergeRielau.pdf

DB의 하드웨어 스펙은 어느 정도면 적당한가에 대한 한 사례 발표였습니다.


3.8. PostgreSQL 보다 빠르게

http://www.pgcon.org/2016/schedule/attachments/399_postgresql-96-scalability-perf-improvements.pdf

이 발표도 EDB 엔지니어가 했습니다.

이번에는 data page 크기에 대한 고려, 트랜잭션 로그 쓰기에서 잠금 문제 등 엔진 해킹을 통한 성능 개선 사례 발표였습니다.


3.9. Atomic 프로젝트 안에서의 PostgreSQL

컨테이너 자동화 프로젝트인 atomic 프로젝트 참여자가 atomic으로 PostgreSQL을 사용하면, 고가용성이 얼마나 손쉽고, 좋아지는가에 대한 소개였습니다.

http://jberkus.github.io/love_failover/

엉청나게 많은 오픈 소스 프로젝트를 소개했습니다.

여기서 배우는 것. 이젠 잘 만들어 쓰는 것보다 잘 가져다 쓸 놈이 어디 있고, 그 놈은 이런 장단점이 있어 이런 조합으로 구성하는 것이 제일 낫다는 것을 빨리 아는 것이 중요하다는 것.


3.10. PoWA

이번에는 프랑스 대표 PostgreSQL 기술지원 업체인 dalibo 의 자사 PostgreSQL 모니터링 도구인 PoWA 소개였습니다.

모니터링 도구가 필요하다면, 이것으로 구축해 보는 것도 좋을 것 같습니다. 이 도구의 특징은 실시간으로 해당 데이터베이스의 필요한 인덱스를 추천해 준다는 점입니다.


3.11. NTT 빌링 시스템 마이그레이션 이야기

http://www.pgcon.org/2016/schedule/attachments/422_A%20Challenge%20of%20Huge%20Billing%20System%20Migration_20160520.pdf

일본 통신사인 NTT의 빌링 시스템 차세대 전환 이야기인데, 놀라운 사실은 이런 통신 기업 기간계 시스템에서 조차 차근하게 준비해서 PostgreSQL로 운영하게 되었다는 점이었습니다. 이 안에는 당연히 pg_hint 같은 쿼리 실행 최적화기를 마음대로 건드리는 NTT 자체 기술력이 바탕이 되었기 때문이기도 합니다.

이 발표의 핵심도 PGCon 이라는 독특한 회의에 촛점을 맞춰, '왜 PostgreSQL 개발 그룹은 pg_hint 같이 쿼리 힌트를 거부하는가?' 라는 아주 저돌적인 질문이었습니다.  기업 환경에서는 쿼리 힌트 기능은 필요악이기 때문에, PostgreSQL에서도 당연히 쿼리 힌트가 지원되길 바란다는 내용이었습니다.


3.12. 데이터베이스 벤치마킹

http://www.pgcon.org/2016/schedule/attachments/413_Benchmarking%20Databases%202016.pdf

데이터베이스 벤치마킹의 작위성에 대한 이야기였습니다. IT 업계에 오래 있었던 분들은 대부분 납득 가는, 어떻게 수치가 임의적으로 해석되고, 그것이 어떻게 포장 되는가에 대한 엔지니어 입장에서의 발표였습니다. 그 어떤 벤치마크 수치도 객관적이다고 말하기는 힘들겠지만, 일단 벤치마킹을 하려는 이들이 갖춰야할 객관성을 살펴 볼 수 있습니다.


3.13. 사용자 언컨퍼런스

https://wiki.postgresql.org/wiki/Pgcon2016userunconference

PGCon 행사의 꽃인 토론 마당

늘 wiki 페이지로 올 해는 이런 이야기가 있었구나는 식의 글만 보다가 직접 참여하게 되었지만, 언어의 장벽을 넘기는 힘들었습니다. 일상 회화나 겨우 할 수 있는 상황에서 기술 이야기를 넘어 제반 토론에 참여하고 의견을 내고 할 형편이 못 되어 참 아쉬웠습니다. 역시나 이 부분은 윗 링크가 정리되는 대로 다시 한 번 읽어 보는 것으로 만족해야겠습니다.

이 토론 마당의 첫 주제는 PostgreSQL이 제 오랜 기간 동안 사용되었고, 이제 기업들도 그 개발에 참여하고, 사업가, 개발자, 사용자들간의 이해득실을 따지게 되고, 여러 사회적, 정치적, 도덕적 상황들이 초창기 그저 멋진 데이터베이스를 만들어 쓰겠다는 순수함(?)을 많이 훼손되고 있는 마당에 이제는 이런 문제를 어떻게 하면 민주적으로 풀어낼 것인가를 그네들끼리 열심히 토론하고 있었습니다.

그저 일반론적인 이야기로는 건전한 대안 있는 비판은 언제나 생기 넘치는 조직으로 유지하는데 꼭 필요하다는 것 정도. 그리고 다양성을 인정하고, 합의는 민주적이여야 한다는 교과서 이야기입니다.

이 사진은 언컨퍼런스 시작하면서 각 주제 선정 작업 결과였습니다.

한 사람씩 이야기를 나눴으면 좋겠다는 주제를 이야기하고 같이 참여하겠다는 사람들을 조사하고 그 자리에서 시간과 장소를 결정하는 형식이었습니다.


4. 마무리

오픈 소스 전체에서 PostgreSQL은 정말 작은 한 소프트웨어일 뿐인데, 이렇게 많은 이들이 한 자리에 모여 며칠씩 서로 이야기를 나누며 어떤 이는 자기 경험을 나누고, 어떤 이는 열심히 공부하고, 서로 토론하는 모습이 참 인상적이였습니다.

물론 기업의 매출 증대를 위해 이해 관계자들은 이번 자리에서도 아주 전략적으로 접근하기도 했겠지요. 하지만, 비영리 단체가 기업과의 묘한 관계 유지 하면서 매년 이렇게 행사를 계속 유지하고 있는 것이 놀랍기도 했습니다.

끝나는 시간 열린 경매 시간도 참 인상 깊었습니다. 비영리 단체의 자금 조달 방법.

한 편의 긴 '그들만의 리그'라는 다큐멘터리 영화를 본 듯합니다.


5. 보너스

오타와 운하에서 바라본 캐나타 문명 박물관과 가티노시 야경 - 이 사진 찍어 보여 달라는 팀원의 부탁에 자다가 찍으러 감.


Posted by 김상기


posted by 김상기 ioseph

1. pgcrypto 확장 모듈 설치

데이터베이스 관리자 권한으로 해당 데이터베이스에 접속해서,

CREATE EXTENSION pgcrypto

쿼리문을 실행


기본적으로 해당 확장 모듈에 포함된 함수들은 public 스키마에 만들어짐


2. 기본 사용법

postgres=# \dx+ pgcrypto "pgcrypto" 확장 기능 안에 포함된 객체들 객체 설명 ------------------------------------------------------- function armor(bytea) function armor(bytea,text[],text[]) function crypt(text,text) function dearmor(text) function decrypt(bytea,bytea,text) function decrypt_iv(bytea,bytea,bytea,text) function digest(bytea,text) function digest(text,text) function encrypt(bytea,bytea,text) function encrypt_iv(bytea,bytea,bytea,text) function gen_random_bytes(integer) function gen_random_uuid() function gen_salt(text) function gen_salt(text,integer) function hmac(bytea,bytea,text) function hmac(text,text,text) function pgp_armor_headers(text) ... (36개 행)

함수 설명

armor, dearmor, pgp_*() 함수는 openpgp 구현 관계 쪽으로 오라클 DBMS_CRYPTO 하고 상관 없음, 여기서는 설명 생략

crypt, digest, hmac : 사용자 비밀번호 문자열 뭉개는 함수 (역함수 없음)

encrypt, encrypt_iv, decrypt, decrypt_iv : 단일키 기반 자료 암호화, 복호화

gen_salt : 임의의 salt 만드는 함수

gen_random_* : 부가 함수.


pgp (개인 메시지(email) 서명 및 암복호화에 대한 한 방법) 기반 비대칭 암복화까지를 고려하지 않는다면, 

평문 뭉개는 기능(digest, hmac)과 단일키 기반 암복호화 크게 두가지로 나뉨


2.1 사용자 비밀번호 뭉개기

postgres=# select digest('mypass', 'sha256');
                               digest                               
--------------------------------------------------------------------
 \xea71c25a7a602246b4c39824b855678894a96f43bb9b71319c39700a1e045222
(1개 행)

기업마다 보안정책이 달라서 이 암호문 뭉개기 작업에 대한 정책에서 임의의 저장된 key가 있어야 하는 경우는 hmac() 함수를 사용함.

한편 뭉개진 문자열 안에 그 키(이때는 소금이라 함)를 포함시키는 전통적인 crypt() 함수는 gen_salt() 함수와 함께 사용함,

gen_salt() 에서 만드는 salt 형태에 따라 뭉개는 방식을 달리함

postgres=# select crypt('mypass',gen_salt('bf'));
                            crypt                             
--------------------------------------------------------------
 $2a$06$dRBVXc2WpqOZQZj4tmAZzur0tQ2owGnI74BKoaaNuu8uboNsaa6tW
(1개 행)


그럼 사용자가 입력한 비밀번호가 맞는지 확인하려면?

당연히 입력한 문자열을 똑같은 방식, 똑같은 키(소금)으로 뭉개서 그 뭉개진 결과가 같으면 같다라고 판단 함


팀: 즉, 그 누구도 DB에 저장된 자료를 복호화해서는 안되는 자료는 이 방식으로 뭉개야 함

비밀번호는 새로 발급 되어야 하지, 예전 비밀번호를 찾아주는 서비스를 제공하면 안됨


2.2 자료 암호화 복호화

postgres=# select encrypt('안녕하세요','내키', 'aes');
              encrypt               
------------------------------------
 \x7e1dba6095d28477fb6d30e45569f780
(1개 행)
postgres=# select decrypt(decode('7e1dba6095d28477fb6d30e45569f780','hex'), '내키', 'aes');
             decrypt              
----------------------------------
 \xec9588eb8595ed9598ec84b8ec9a94
(1개 행)
postgres=# select convert_from(decrypt(decode('7e1dba6095d28477fb6d30e45569f780','hex'), '내키', 'aes'), 'utf-8');
 convert_from 
--------------
 안녕하세요
(1개 행)

중요한 부분은 decrypt() 함수 반환자료형이 bytea 형이라는 점

그래서, 그 원본 값이 문자열이었다면, convert_from() 함수로 적당한 문자열 인코딩으로 변환해 주어야 함

encrypt_iv() 함수는 암호화 과정에서 사용할 초기화 문자열을 임의로 지정할 수 있도록 하는 것임


2.3 그 외

http://postgresql.kr/docs/current/pgcrypto.html (pgcrypto 모듈 한글 설명서)


3. 오라클 DBMS_CRYPTO 패키지를 이용한 함수 마이그레이션

3.1 비밀번호 뭉개기

Oracle: dbms_crypto.hash()

PostgreSQL: digest(), 알고리즘은 oracle에서 썼던 숫자값을 적당한 문자열로 바꿔줌 (des, md4, md5, sha1...)


3.2. 단순 암복호화

오라클 dbms_crypto.encrypt(), decrypt() 함수도 PostgreSQL의 bytea 형과 같은 raw 형을 입력 자료형으로 받기 때문에, cast() 함수를 이용해서 적당한 형 변환을 해 주어야 함

Oracle: utl_raw.cast_to_raw('01234567890123456789012345678901') 또는 UTL_I18N.STRING_TO_RAW() 형태의 raw 변환 함수는

PostgreSQL: cast('01234567890123456789012345678901' as bytea)

형태로 바꾸고,

Oracle: DBMS_CRYPTO.DES_CBC_PKCS5 형태로 오는 type 인자값

PostgreSQL: encrypt, decrypt 함수의 알고리즘 인자에 '알고리즘-모드/pad:패딩' 형태로 지정함, 윗 예제라면, 'des-cbc/pad:pkcs' 가 됨


3.3 키가 외부에 있어, utl_file 패키지를 사용한 경우

일반적으로 oracle에서는 utl_file 패키지를 이용해서 directory 객체를 만들고, 그 안에 있는 특정 파일을 읽을 수 있도록 제공하지만,

PostgreSQL에서는 $PGDATA 디렉토리 안에 있는 파일만 읽을 수 있음.

즉, 해당 키 파일은 $PGDATA 디렉토리 안으로 옮겨와야 함

파일 읽는 함수는

Oracle:

utl_file.fopen('directory', 'keyfile', 'rb');

utl_file.get_raw(fh, key_str, 32 );

utl_file.fclose();

PostgreSQL: pg_read_binary_file('keyfile',0,32); (한 줄!)


4. 기존 응용 프로그램 코드 변경을 최소화 하는 법

해당 함수의 입출력 자료형을 최대한 맞추며, (convert_from, encode, decode 함수를 이용)

oracle 패키지 형태로 만들었다면, PostgreSQL에서는 스키마를 만들고, 그 안에 함수로 등록하면,

응용 프로그램 코드 변경을 최소화 할 수 있음

(물론 프로시져로 만들어, exec, call 형태로 호출하는 경우라면, select 구문으로 부득이 변경해야겠지만)


5. 샘플 코드 전체

CREATE SCHEMA mycrypto;
CREATE OR REPLACE FUNCTION mycrypto.encrypt(p_plain character varying)
 RETURNS character varying
 LANGUAGE plpgsql
AS $function$
declare
vkey bytea;
begin
vkey := pg_read_binary_file('keyfile',0,16);
return upper(encode(encrypt_iv(cast(p_plain as bytea), vkey, cast('0123456789012345' as bytea),'aes'),'hex'));
end;
$function$;

CREATE OR REPLACE FUNCTION mycrypto.decrypt(p_encrypt character varying)
 RETURNS character varying
 LANGUAGE plpgsql
AS $function$
declare
vkey bytea;
begin
vkey := pg_read_binary_file('keyfile',0,16);
return convert_from(decrypt_iv(decode(p_encrypt , 'hex'), vkey, cast('0123456789012345' as bytea),'aes'),'utf-8');
end;
$function$;

사용예:

postgres=# select mycrypto.encrypt('무궁화꽃이피었습니다');
                             encrypt                              
------------------------------------------------------------------
 1D6337A6A1EF052D66AB80C04DBD402E5DC78E5F14FCECA963CACB9EE6A2CD5F
(1개 행)
postgres=# select mycrypto.decrypt('1D6337A6A1EF052D66AB80C04DBD402E5DC78E5F14FCECA963CACB9EE6A2CD5F');
       decrypt        
----------------------
 무궁화꽃이피었습니다
(1개 행)

Posted by 김상기



posted by 김상기 ioseph

ᇂ1. 데이터베이스 성능이란

일반적으로 tps 초당 트랜잭션 수로 이야기함

문제는 트랜잭션의 정의가 모호함


2. PostgreSQL & pgbench

pgbench 는 기본적으로 tpc-b type 트랜잭션을 제공함

tpc-b type은 클라이언트 - 서버 환경의 구시대 유물이 되었음


3. 아직도 pgbench 가 중요한 이유

그럼에도 불구하고, 데이터베이스 서버가 운영되고 있는 호스트의 하드웨어 사양과

postgresql.conf 설정을 최적의 상태로 만들어 갈 지표를 찾는데, 이주 편한 도구 임


4. 작업 방법

최대 288 클라이언트까지 테스트할 계획임으로

pgbench -i -s 500 으로  자료를 초기화함

pgbench -T 600 -c 클라이언트수 -j 쓰레드수

형태로 클라이언트수와 쓰레드수를 동일하게 해서

해당 호스트의 core 수의 배수로 600초 (5분) 동안 부하를 주고 그 결과를 수집함


for i in `seq 8 8 288`

do

pgbench -T 600 -c $i -j $i > $i.result

done

grep '.....' *.result


5. gnuplot으로 차트 만들기

set title 'pgbench -T 600'

set grid

set terminal png size 640, 480

set output 'pgbench.png'

set xlabel 'clients' x,y

set ylabel 'tps' x,y

plot 'pgbench.result' with lines title '9.5', 'pgbench.result' using 1:3 with lines title '9.4', 'pgbench.result' using 1:4 with lines title '9.5'



6. 차트 읽기

해당 검사에서 최대 성능을 냈던 구간은 모든 버전에서 56-72 구간임

즉, 8 core 환경에서 코어 당 8배 정도의 클라이언트를 수용할 때 최적의 성능을 냄을 알 수 있음(tpc-b 타입 트랜잭션인 경우)


7. 그 외 빠진 이야기

해당 작업은 반드시 OS 모니터링도 함께 진행되어야 함

CPU, 메모리, 디스크I/O, 네트워크 I/O도 함께 봐야 함


8. 마무리

전체적으로 PostgreSQL 버전별 tps 값은 9.5가 제일 낮았음.

병목 구간에서는 일정하게 각 버전별로 성능 차이가 있음

해당 차트로 짤 수 있는 전략

해당 DB 서버로는 최대 100 이하의 클라이언트가 동시에 사용할 수 있도록 하는 것이 최적임

(검사 장비의 하드웨어 사양은 8core, 16G Mem, 10G iscsi HDD)


posted by 김상기

posted by 김상기 ioseph
2015.01.20 21:50 2. DBMS이야기/03. MongoDB

MongoDB는?

MongoDB의 고성능(high performance), 고 가용성(High Availability) 및

자동 스케일링을 제공하는 오픈 소스 문서 데이터베이스입니다.


Document Database

MongoDB에있는 레코드는 필드(Field) 및 값(Value)의 쌍으로 이루어지는 데이터 구조 문서(Document)입니다.

MongoDB의 문서는 JSON 객체와 유사하며, 필드의 값은 다른 문서들, 배열(Array)들 및

문서들의 배열(Array)을 포함 할 수 있습니다.


문서(Document 방식)를 사용하는 장점은 :

- 문서(RDBMS의 Object)는 다수의 프로그래밍 언어로 기본 데이터 타입에 대응합니다.

- 문서와 배열은 복잡한 조인이 포함될 필요를 줄일 수 있습니다.

- 동적 스키마는 자연스러운 다형성을 지원합니다.

  (다형성 : 작성코드를 수정하지 않고 다양한 자료형의 객체를 처리하도록 하는 기법)


주요 특징

고성능

MongoDB의 고성능 데이터 지속성을 부분적으로 제공합니다.

- 임베디드 데이터 모델에 대해 지원하여, 데이터베이스 시스템에 I/O 작업을 줄일 수 있습니다.

- 인덱스는 빠른 쿼리를 지원하고 내장된 문서와 배열에서 키(Key)를 포함 할 수 있습니다.


고 가용성 

고 가용성을 제공하기 위해, MongoDB의 복제셋(Replica Sets)라는 복제 기능을 제공합니다.

- 자동 페일 오버. (Fail-Over)

- 데이터의 불필요한 중복 방지


복제셋(Replica Set)는 중복 방지를 제공하고 데이터 가용성을 증가시키며,

동일한 데이터 집합을 유지하는 MongoDB의 서버 그룹입니다.


자동 스케일링

MongoDB의는의 한 부분으로 수평 확장성을 제공하는 핵심 기능을 제공합니다.

- 자동 샤딩은 시스템의 클러스터 사이의 데이터를 배포합니다.

- 복제셋은 짧은 대기 시간과 높은 처리량 배포를 위해 최종 일관성(eventually-consistent) 읽기를 제공 할 수 있습니다.



출처 : mongo-db                                                                  (Post by 진준호. 2015.01.20)

'2. DBMS이야기 > 03. MongoDB' 카테고리의 다른 글

1. MongoDB 소개  (0) 2015.01.20
0. NoSQL 이란  (0) 2014.11.23
posted by DB,MW,OS OSSW(Open Source System SoftWare

Name-Based VirtualHosts and SSL

하나의 Apache 웹서버에 동일한 포트로 다양한 SSL을 사용하는 서비스를 하기 위해서는 다음과 같은 방법을 사용하면 됩니다.

1. 가상호스 사용
    - ServerName을 달리 설정한다. 
    - 각 가상호스트마다 SSL 인증서를 설정한다.

2. NameVirtualHost 지시어 사용

설정 예제 참고하십시오.
Listen 192.168.1.1:443

LoadModule ssl_module   modules/mod_ssl.so

SSLPassPhraseDialog     builtin
AcceptMutex             flock
SSLSessionCache         shmcb:/var/cache/httpd/mod_ssl/ssl_scache(512000)
SSLSessionCacheTimeout  300
SSLMutex                default
SSLRandomSeed           startup /dev/urandom  256
SSLRandomSeed           connect builtin

NameVirtualHost 192.168.1.1:443

<VirtualHost 192.168.1.1:443>
        SSLEngine on
        SSLCipherSuite ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP

        SSLCertificateFile      /etc/ssl/star.example.com.crt
        SSLCertificateKeyFile   /etc/ssl/star.example.com.key

        ServerName      "one.example.com"
        DocumentRoot    "/var/www/html/one"

        CustomLog       "/var/log/httpd/one-access.log" combined
        ErrorLog        "/var/log/httpd/one-error.log"

        <Directory /var/www/html>
                AllowOverride none

                Order Allow,Deny
                Allow from all
        </Directory>
</VirtualHost>

<VirtualHost 192.168.1.1:443>
        SSLEngine on
        SSLCipherSuite ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP

        SSLCertificateFile      /etc/ssl/star.example.com.crt
        SSLCertificateKeyFile   /etc/ssl/star.example.com.key

        ServerName      "two.example.com"
        DocumentRoot    "/var/www/html/two"

        CustomLog       "/var/log/httpd/two-access.log" combined
        ErrorLog        "/var/log/httpd/two-error.log"

        <Directory /var/www/html>
                AllowOverride none

                Order Allow,Deny
                Allow from all
        </Directory>
</VirtualHost>

by hyeons 1월

'1. 미들웨어이야기 > 02. Apache' 카테고리의 다른 글

Apache Name-Based VirtualHosts and SSL  (0) 2015.01.06
apache redirectmatch  (0) 2014.12.03
Apache 로그 파일 관리  (0) 2014.12.03
Apache 설치  (0) 2014.12.03
알아두면 유용한 apache httpd실행 옵션  (0) 2014.12.03
apache graceful restart  (0) 2014.12.03
posted by lovelywas
2014.12.28 22:36 2. DBMS이야기/04. CUBRID

안녕하세요~!

12월의 마지막 주말은 잘 보내셨나요~?


올해의 마지막 세션은 큐브리드 DB 체크에 대해 알아봐요~


1. DB 일관성 확인하기

cubrid checkdb 유틸리티를 사용하면 인덱스와 다른 데이터 구조를 확인하기 위해 데이터와 로그 볼륨의 내부적인 물리적 일치를 확인할 수 있어요. 만일 cubrid checkdb 유틸리티의 실행 결과가 불일치로 나온다면 --repair 옵션으로 자동 수정을 시도해봐야해요


cubrid checkdb [options] database_name [table_name1 table_name2 ...]

table_name1 table_name2 에는 일관성을 확인하거나 복구하려는 테이블 이름을 나열할 수 있어요

-S, --SA-mode

서버 프로세스를 구동하지 않고 데이터베이스에 접근하는 독립 모드(standalone)로 작업하기 위해 지정되며, 인수는 없다. -S 옵션을 지정하지 않으면, 시스템은 클라이언트/서버 모드로 인식한다.

cubrid checkdb -S demodb
-C, --CS-mode

서버 프로세스와 클라이언트 프로세스를 각각 구동하여 데이터베이스에 접근하는 클라이언트/서버 모드로 작업하기 위한 옵션이며, 인수는 없다. -C 옵션을 지정하지 않더라도 시스템은 기본적으로 클라이언트/서버 모드로 인식한다.

cubrid checkdb -C demodb
-r, --repair

데이터베이스의 일관성에 문제가 발견되었을 때 복구를 수행한다.

cubrid checkdb -r demodb

인덱스의 이전 링크(previous link)에 오류가 있는지를 검사한다.

$ cubrid checkdb --check-prev-link demodb

인덱스의 이전 링크(previous link)에 오류가 있으면 복구한다.

$ cubrid checkdb --repair-prev-link demodb
-i, --input-class-file=FILE

-i FILE 옵션을 지정하거나, 데이터베이스 이름 뒤에 테이블의 이름을 나열하여 일관성 확인 또는 복구 대상을 한정할 수 있다. 두 가지 방법을 같이 사용할 수도 있으며, 대상을 지정하지 않으면 전체 데이터베이스를 대상으로 일관성을 확인하거나 복구를 수행한다. 특정 대상이 지정되지 않으면 전체 데이터베이스가 일관성 확인 또는 복구의 대상이 된다.

cubrid checkdb demodb tbl1 tbl2
cubrid checkdb -r demodb tbl1 tbl2
cubrid checkdb -r -i table_list.txt demodb tbl1 tbl2

-i 옵션으로 지정하는 테이블 목록 파일은 공백, 탭, 줄바꿈, 쉼표로 테이블 이름을 구분한다. 다음은 테이블 목록 파일의 예로, t1부터 t10까지를 모두 일관성 확인 또는 복구를 위한 테이블로 인식한다.

t1 t2 t3,t4 t5
t6, t7 t8   t9

     t10


2. DB 내부 정보 확인하기


cubrid diagdb 유틸리티가 제공하는 정보들은 현재 데이터베이스의 상태를 진단하거나 문제를 파악할 수 있어요.

cubrid diagdb [option] database_name
-d, --dump-type=TYPE

데이터베이스의 전체 파일에 대한 기록 상태를 출력할 때 출력 범위를 지정한다. 생략하면 기본값인 -1이 지정된다.

cubrid diagdb -d 1 demodb

-d 옵션에 적용되는 타입은 모두 9가지로, 그 종류는 다음과 같다.

타입설명
-1전체 데이터베이스 정보를 출력한다.
1파일 테이블 정보를 출력한다.
2파일 용량 정보를 출력한다.
3힙 용량 정보를 출력한다.
4인덱스 용량 정보를 출력한다.
5클래스 이름 정보를 출력한다.
6디스크 비트맵 정보를 출력한다.
7카탈로그 정보를 출력한다.
8로그 정보를 출력한다.
9힙(heap) 정보를 출력한다.


3. 서버/클라이언트에서 사용하는 파라미터 출력하기

cubrid paramdump [options] database_name
-o, --output-file=FILE

데이터베이스의 서버/클라이언트 프로세스에서 사용하는 파라미터 정보를 지정된 파일에 저장하는 옵션이며, 파일은 현재 디렉터리에 생성된다. -o 옵션이 지정되지 않으면 메시지는 콘솔 화면에 출력한다.

cubrid paramdump -o db_output demodb
-b, --both

데이터베이스의 서버/클라이언트 프로세스에서 사용하는 파라미터 정보를 콘솔 화면에 출력하는 옵션이며, -b 옵션을 사용하지 않으면 서버 프로세스의 파라미터 정보만 출력한다.

cubrid paramdump -b demodb
-S, --SA-mode

독립 모드에서 서버 프로세스의 파라미터 정보를 출력한다.

cubrid paramdump -S demodb
-C, --CS-mode

클라이언트-서버 모드에서 서버 프로세스의 파라미터 정보를 출력한다.

cubrid paramdump -C demodb


2015년 청양의 해 새해 많이 받으세요~!


출처 : 큐브리드 메뉴얼                                                                    (By. 진준호 2014.12.28)


'2. DBMS이야기 > 04. CUBRID' 카테고리의 다른 글

08. CUBRID DB 체크하기  (0) 2014.12.28
07. CUBRID 복구하기  (0) 2014.12.10
06. CUBRID 사용자, Database 파일, 백업  (0) 2014.11.11
05. CUBRID 기동과 정지  (0) 2014.10.20
04. CUBRID 시스템 카탈로그 & SQL  (0) 2014.10.05
04. CUBRID의 카탈로그와 테이블  (0) 2014.09.26
posted by DB,MW,OS OSSW(Open Source System SoftWare
2014.12.10 23:17 2. DBMS이야기/04. CUBRID

안녕하세요~

벌써 2014년 마지막 달이네요, 추운 날씨에 감기 안 걸리셨죠?

이번 화에는 복구에 대해 알아보겠습니다


CUBRID 환경에서 수행된 백업 작업에 의해 생성된 백업 파일, 활성 로그 및 보관 로그를 이용하여 특정 시점의 데이터베이스로 복구하는 작업으로, 진행하려면 cubrid restoredb 유틸리티 또는 CUBRID 매니저를 사용합니다.


 cubrid  restoredb  [options]  database_name


어떠한 옵션도 지정되지 않은 경우 기본적으로 마지막 커밋 시점까지 데이터베이스가 복구됩니다.

만약, 마지막 커밋 시점까지 복구하기 위해 필요한 활성 로그/보관 로그 파일이 없다면 마지막 백업 시점까지만 부분 복구됩니다.


옵션

입력값

설명 

기본값 

 -l

복구레벨 

복구 레벨 지정 (0,1,2)

 -d

복구시점 

복구 시점 지정 형식) 일-월-년:시:분:초

예) 10-12-2014:17:00:00

또는 backuptime : 마지막 백업 시점

가장 최근 시점 

 -B

파일경로 

복구할 백업 볼륨이 존재하는 디렉토리나 장치명 지정 

초기 로그 볼륨 위치 

 -p

 

archive 로그가 없을 경우 무시하고 수행 

 

 -u

 

데이터베이스 위치 파일내에 지정된 경로로 데이터

베이스와 로그 볼륨을 복구 (dataase.txt) 

 

 -list

 

백업을 수행하지 않고 백업 볼륨 목록을 출력 

 


-p 옵션이 지정되지 않은 경우, 사용자에게 옵션을 선택하라는 요청 메시지는 다음과 같이 나옵니다.

***********************************************************
Log Archive /home/cubrid/test/log/demodb_lgar002
 is needed to continue normal execution.
   Type
   -  0 to quit.
   -  1 to continue without present archive. (Partial recovery)
   -  2 to continue after the archive is mounted/loaded.
   -  3 to continue after changing location/name of archive.
***********************************************************
  • 옵션 0: 복구 작업을 더 이상 진행하지 않을 경우, 0을 입력한다.
  • 옵션 1: 로그 파일 없이 부분 복구를 진행하려면, 1을 입력한다.
  • 옵션 2: 복구 작업을 진행하기 위해 관리자는 현재 장치에 보관 로그를 위치시킨 후 2를 입력한다.
  • 옵션 3: 복구 작업을 계속하기 위해 관리자는 로그 위치를 변경한 후 3을 입력한다.


다음은 -list 옵션을 이용해서 볼륨 목록을 출력했을 경우입니다.

*** BACKUP HEADER INFORMATION ***
Database Name: /local1/testing/demodb
 DB Creation Time: Mon Oct 1 17:27:40 2008
         Pagesize: 4096
Backup Level: 1 (INCREMENTAL LEVEL 1)
        Start_lsa: 513|3688
         Last_lsa: 513|3688
Backup Time: Mon Oct 1 17:32:50 2008
 Backup Unit Num: 0
Release: 8.1.0
     Disk Version: 8
Backup Pagesize: 4096
Zip Method: 0 (NONE)
        Zip Level: 0 (NONE)
Previous Backup level: 0 Time: Mon Oct 1 17:31:40 2008
(start_lsa was -1|-1)
Database Volume name: /local1/testing/demodb_vinf
     Volume Identifier: -5, Size: 308 bytes (1 pages)
Database Volume name: /local1/testing/demodb
     Volume Identifier: 0, Size: 2048000 bytes (500 pages)
Database Volume name: /local1/testing/demodb_lginf
     Volume Identifier: -4, Size: 165 bytes (1 pages)
Database Volume name: /local1/testing/demodb_bkvinf
     Volume Identifier: -3, Size: 132 bytes (1 pages)

-list 옵션을 이용하여 출력된 백업 정보를 확인하면, 백업 파일이 백업 수준 1로 생성되었고, 이전 백업 수준 0의 전체 백업이 수행된 시점을 확인할 수 있다. 따라서, 예시된 데이터베이스의 복구를 위해서는 백업 수준 0인 백업 파일과 백업 수준 1인 백업 파일이 준비되어야 합니다.



복구할 때에는 고려해야 할 사항들이 있습니다.

  • 백업 파일 준비
    • 백업 파일 및 로그 파일이 저장된 디렉터리를 확인해야 합니다.
    • 증분 백업으로 대상 데이터베이스가 백업된 경우, 각 백업 수준에 따른 백업 파일이 존재하는지를 확인합니다.
    • 백업이 수행된 CUBRID 데이터베이스의 버전과 복구가 이루어질 CUBRID 데이터베이스 버전이 동일한지를 확인한다.
  • 복구 방식 결정
    • 부분 복구할지, 전체 복구할지 결정합니다.
    • 증분 백업 파일을 이용한 복구인지를 확인합니다.
    • 사용 가능한 복구 도구 및 복구 장비를 준비합니다.
  • 복구 시점 판단
    • 데이터베이스 서버가 종료된 시점을 확인합니다.
    • 장애 발생 전에 이루어진 마지막 백업 시점을 확인합니다.
    • 장애 발생 전에 이루어진 마지막 커밋 시점을 확인합니다.

모두 준비되셨으면, 복구 시~작~!

따듯한 하루 되세요~^^


출처 : 큐브리드 메뉴얼                                              By. 진준호 (2014.12.10)

'2. DBMS이야기 > 04. CUBRID' 카테고리의 다른 글

08. CUBRID DB 체크하기  (0) 2014.12.28
07. CUBRID 복구하기  (0) 2014.12.10
06. CUBRID 사용자, Database 파일, 백업  (0) 2014.11.11
05. CUBRID 기동과 정지  (0) 2014.10.20
04. CUBRID 시스템 카탈로그 & SQL  (0) 2014.10.05
04. CUBRID의 카탈로그와 테이블  (0) 2014.09.26
posted by DB,MW,OS OSSW(Open Source System SoftWare

1. 에러 메시지:

kernel: NOHZ: local_softirq_pending 100

 

2. 원인:

- 시스템이 어떤 소프트웨어 interrupt 를 처리하는 대신 CPU sleep 상태로 만드는 것

- 메시지 마지막의 숫자는 hexadecimal 로 표현되며, ‘100’ HRTIMER_SOFTIRQ 를 의미

- HRTIMER_SOFTIRQ High Resolution Timer(HRT) 에 대한 소프트웨어 interrupt(HRT에 대한 상세정보는 아래 참조 URL 참고)

- 커널 버전 2.6.22 이후부터 add debug 메시지

 

3. 조치 방안:

- /etc/grub.conf 파일에 nohz=off 옵션을 설정하여 disable 가능(, 커널 버전 2.6.32-431.el6 보다 상위 버전에서만 가능)

- 단순 정보성 메시지이므로 조치 필요 없음

 

4. 참조 URL:

http://kb.sp.parallels.com/en/119599

https://access.redhat.com/solutions/62637

http://studyfoss.egloos.com/viewer/5268468

 

posted by 박현명

아파치에서 설정한 도메인으로 접속한 모든 사용자에 대해 

모두 특정 url로 보내고 싶을때(서비스 잠시 문닫아 서비스 안내공지 페이지로 보낸다던가...)

RedirectMatch 옵션을 사용할 수 있습니다.


RedirectMatch (.*) http://aaa.com/pp.html




이와는 약간 다르게...뒤에 주소를 그대로 가지고 가면서 도메인만 변경되는 경우

도메인이 변경되어 뒤에 주소는 동일하나 도메인만 변경된 주소로 변경하여 Redirect 시킬 경우


Redirect http://aaa.com


'1. 미들웨어이야기 > 02. Apache' 카테고리의 다른 글

Apache Name-Based VirtualHosts and SSL  (0) 2015.01.06
apache redirectmatch  (0) 2014.12.03
Apache 로그 파일 관리  (0) 2014.12.03
Apache 설치  (0) 2014.12.03
알아두면 유용한 apache httpd실행 옵션  (0) 2014.12.03
apache graceful restart  (0) 2014.12.03
posted by LE07

 

*  Apache 로그 파일 관리

 

1. 로그 rotation 적용

 - 설명 : 아파치 rotatelogs를 이용하여 일자별 로그 생성

 - 설정방법 :  CustomLog "/usr/sbin/rotatelogs logs/access_%Y%m%d.log 86400" common


2. 로그 포맷 변경

- 설명 : 아파치 로그 출력을 아래의 항목으로 변경

- 설정방법 : LogFormat "%h - %t \"%r\" %s>s %b" common

항목

설명 

%A (지역화된) 완전한 요일 이름
%a (지역화된) 3-문자 요일 이름
%B (지역화된) 완전한 달 이름
%b (지역화된) 3-문자 달 이름
%c (지역화된) 날짜와 시간
%d 2-자리 일
%H 2-자리 시간 (24 시간 시계)
%I 2-자리 시간 (12 시간 시계)
%j 3-자리 날짜수
%M 2-자리 분
%m 2-자리 달
%p (지역화된) 12 시간 시계의 am/pm
%S 2-자리 초
%U 2-자리 주일수 (주의 첫번재 날은 일요일)
%W 2-자리 주일수 (주의 첫번재 날은 월요일)
%w 1-자리 요일수 (주의 첫번째 날은 일요일)
%X (지역화된) 시간
%x (지역화된) 날짜
%Y 4-자리 연도
%y 2-자리 연도
%Z 시간대 이름
%% 문자그대로 `%'

 

 

by. 현주희 (11월)

 

'1. 미들웨어이야기 > 02. Apache' 카테고리의 다른 글

Apache Name-Based VirtualHosts and SSL  (0) 2015.01.06
apache redirectmatch  (0) 2014.12.03
Apache 로그 파일 관리  (0) 2014.12.03
Apache 설치  (0) 2014.12.03
알아두면 유용한 apache httpd실행 옵션  (0) 2014.12.03
apache graceful restart  (0) 2014.12.03
posted by DB,MW,OS OSSW(Open Source System SoftWare