1. 상황

Ubuntu 인스턴스에 CentOS 도커 컨테이너를 띄우고, 그 안에 PostgreSQL를 설치한 상태

 

그림으로 나타내보자면 아래와 같다.

 

내가 하고 싶은 것은

우분투에서 "CentOS에 설치된 PostgreSQL"에 접속해서 데이터를 추출해 MySQL(개발 DB)로 보내는 것!

 

그냥 접속하려고 했더니 계속 connection 에러가 나서 찾아보니..

이런 경우는 PostgreSQL에서 외부 접속을 허용해주어야 하고,

그러려면 바꿔야 할 설정과 설치해야 할 패키지들이 있어서 과정을 정리해보고자 한다 :)

 

 

2. 과정

 

0. 필요 패키지 설치

# Ubuntu에
sudo apt-get install -y postgresql-client
sudo apt-get install -y postgresql-client-common

# CentOS에
yum install -y firewalld net-tools

 

 

1. PostgreSQL이 CentOS 컨테이너의 네트워크 인터페이스에서 수신 대기 중인지 확인 - CentOS 컨테이너에서 실행

netstat -nlt | grep 5432

PostgreSQL이 0.0.0.0:5432에서 수신 대기 중이면 모든 IP 주소에서 연결을 수락할 준비가 되었음을 의미한다.

127.0.0.1:5432에서 수신하는 경우 외부 연결을 허용하도록 PostgreSQL 구성 파일을 수정해야 한다.

 

 

2. CentOS 컨테이너의 방화벽에서 PostgreSQL 포트(5432) 열기 - CentOS 컨테이너에서 실행

firewall-cmd --zone=public --add-port=5432/tcp --permanent
firewall-cmd --reload

 

3. /var/lib/pgsql/{version}/data/pg_hba.conf 수정 - CentOS 컨테이너에서 실행

host    all             all             {인스턴스 퍼블릭 IP}/22     md5

 

우분투에서 CentOS에 있는 PostgreSQL로 접속하려는 것이기 때문에 우분투 IP를 허용해주어야 한다.

pg_hba.conf 가장 하단에 있는 허용 목록에 우분투 IP를 host로 추가해준다.

 

4. /var/lib/pgsql/{version}/data/postgresql.conf 수정 - CentOS 컨테이너에서 실행

#listen_addresses = 'localhost' 를 아래로 변경
listen_addresses = '*'

 

5. PostgreSQL 재시작 - CentOS 컨테이너에서 실행

sudo systemctl restart postgresql-{version}

 

6. 접속 - Ubuntu 인스턴스에서 실행

psql -h {인스턴스 퍼블릭 IP} -U postgres

접속에 성공한 것을 확인할 수 있다~!!

클러스터 테이블 vs 논클러스터 테이블 비교

클러스터란?

  • 디스크로부터 데이터를 읽어오는 시간을 줄이기 위해서 자주 사용되는 테이블의 데이터를 디스크의 같은 위치에 저장하는 방법
  • 비슷한 레코드들을 동시에 조회하는 경우가 많아 효율적으로 조회하는 방법으로 고안됨
  • PK가 비슷한 레코드끼리 묶어서 저장하는 것 (MySQL)

 

클러스터 테이블(인덱스)

  • 테이블당 1개씩만 허용됨
  • PK 생성 시 그 컬럼은 자동으로 클러스터 인덱스가 생성됨
    * 일반 인덱스와의 차이
    • 클러스터링 되어 있다는 요소가 추가됨
    • 옵티마이저에서 일반 인덱스보다 높은 랭킹
  • PK를 설정하지 않은 경우는? InnoDB가 다음의 우선순위대로 대체 컬럼을 선택
    • UNIQUE NOT NULL 중 첫번째 인덱스를 클러스터 키로 선택
    • 자동으로 유니크한 값을 가지도록 AUTO_INCREMENT 컬럼을 내부적으로 추가해 클러스터 키로 선택
      * 하지만, 자동으로 추가되는 컬럼은 사용자에게 보이지 않아서 SQL에서 사용할 수가 없음
  • PK에 의해 레코드 저장 위치가 결정됨
    • PK값이 변경되면 -> 레코드의 물리적으로 행을 재배열함 -> 랜덤 액세스가 많이 발생해서 I/O 증가
    • PK를 신중히 결정해야 함
  • 인덱스 페이지의 리프 페이지가 곧 데이터. 즉, 테이블 자체가 인덱스
  • InnoDB 스토리지 엔진에서만 지원함
  • 장점
    • 그룹된 컬럼 데이터 행들이 같은 데이터 블록에 저장되기 때문에 디스크 I/O가 줄어 SELECT 시 처리 성능이 매우 빠름
    • 클러스터된 테이블 사이에 조인이 발생하면 처리 시간이 단축됨
    • INSERT, UPDATE, DELETE 시 항상 정렬 상태를 유지함
    • 이미 정렬된 상태로 저장되기 때문에 인덱스 테이블이 필요하지 않아 논클러스터보다 DB 용량을 덜 차지함
    • 테이블의 모든 보조 인덱스가 PK를 가지고 있기 때문에 인덱스만으로 처리될 수 있는 경우가 많음(커버링 인덱스)
  • 단점
    • 논클러스터보다 검색 속도는 더 빠르지만 INSERT, UPDATE, DELETE는 느림

 

논클러스터 테이블(인덱스)

  • 테이블당 249개 허용됨
  • 레코드의 원본은 정렬되지 않고, 인덱스 테이블만 정렬됨
    • 인덱스 페이지는 로그파일에 저장됨
  • 인덱스 자체의 리프 페이지는 데이터가 아니라 데이터가 위치하는 포인터(RID)이기 때문에 클러스터보다 검색 속도는 느리지만 INSERT, UPDATE, DELETE는 더 빠름

 

비교

  • 쉽게 책에 비유하자면 클러스터 테이블은 페이지를 알기 때문에 바로 그 페이지를 펴는 것(바로 접근)이고, 논클러스터 테이블은 목차에서 찾고자 하는 내용의 페이지를 찾고 그 페이지로 이동하는 것(한번 거쳐서 접근)과 같음

 

참고링크

본질 식별자 vs 인조 식별자 비교

본질 식별자

  • 업무에 의해 만들어진 식별자
  • 장점
    • PK 인덱스 활용 가능

 

인조 식별자

  • 업무적으로 만들어지지는 않지만 본질 식별자가 복잡한 구성을 갖고 있어 인위적으로 만든 식별자
  • 후보 식별자 중 PK로 선정할만 한 것이 없을 때 사용
  • 장점
    • 모델이나 SQL이 간단해짐
  • 단점
    • 인스턴스 생성 기준을 인조 식별자만으로 판단하기 어려움
    • 모델만 보고 업무를 이해하기 어려움, 특히 행위 엔터티에서 가독성이 저하됨
    • 유니크 인덱스를 추가로 사용하여 추가적으로 키를 관리해야 함
    • 중복 데이터로 인한 품질 문제
      PK를 인조 식별자로 구성한 경우, PK 제약은 인조식별ID에 대해 적용되어 있기 때문에 중복 데이터가 발생하더라도 DBMS에서는 막을 수 없기 때문에 애플리케이션 단에서 처리해야 하는 문제 발생
  • 아래와 같은 경우, 인조 식별자를 사용하는 것이 나을 수 있음
    • 복합키의 변경이 빈번할 경우
    • 복합키가 4개 이상일 경우
  • AUTO-INCREMENT 컬럼을 인조 식별자로 사용할 경우
    • 보조 인덱스도 필요하고, PK의 크기도 같을 때

 

결론

  • PK는 가능하다면 AUTO-INCREMENT 컬럼(인조 식별자)보다는 업무적인 컬럼(본질 식별자)으로 생성할 것
    • InnoDB의 PK는 클러스터 키로 사용되며, 이 값에 의해 레코드의 위치가 결정됨
    • 즉, PK로 검색하는 경우 논클러스터 테이블에 비해 매우 빠른 처리가 가능하여 InnoDB에서는 성능에 큰 차이가 발생함
    • 그러므로 컬럼의 크기가 크더라도 업무적으로 해당 레코드를 대표할 수 있다면 그 컬럼을 PK로 설정하는 것이 좋음
  • 인조 식별자의 남용을 피하고 꼭 필요한 경우에만 사용하는 것을 권장함
    • 인조 식별자는 불필요한 인덱스를 추가 생성해야 하고, 추가로 생성한 인덱스는 용량과 DML 성능에 영향을 줄 수 있음

 

참고링크

ACL

Access Control List의 줄임말로 redis 6부터 도입된 기능입니다.

 

다른 RDBMS(MySQL, Oracle 등)에는 유저별로 접근 가능한 범위를 정할 수 있지만

redis에는 유저라는 개념이 없었습니다.

 

ACL은 유저를 설정하고 실행 가능한 커맨드와 접근할 수 있는 키 측면에서 특정 연결을 가능하게 해줍니다.

 

# 1
ACL SETUSER alice on >p1pp0 ~cached:* +get

# 2
AUTH alice p1pp0
  • #1 : alice 라는 user를 생성한다.
    • 이름 
    • 패스워드 : p1pp0
    • 접근 가능한 키 패턴 : cached 로 시작하는 key들에 접근할 수 있다. (allkeys : 모든 키에 접근 가능)
    • 실행 가능한 커맨드 : 접근할 때는 get 만 사용할 수 있다. (allcommands : 모든 명령어 사용 가능)
  • #2 : alice 계정으로 redis를 사용하도록 한다.

비밀번호만 설정한다는 것은 "default" user를 사용한다는 의미입니다.

ACL feature를 사용하여 user를 생성하고, user가 접근할 수 있는 key와 command를 지정해놓는다면, redis를 조금 더 안전하게 사용할 수 있을 것입니다.

 

사용자 등록

> ACL SETUSER user on/off >password keys commands
  • user: user-id를 설정한다.
  • on/off: 사용 여부를 정한다. on이면 사용 가능하고, off이면 사용할 수 없다.
    • Off는 사용자는 등록하지만 일단 사용하지 못하게 할 경우 또는 기존 사용자를 사용하지 못하게 할 경우 사용한다.
    • 이 경우 새로 로그인(auth)은 할 수 없지만, 이미 로그인한 사용자의 사용을 막지는 못한다.
  • >password: '>' 구분자 다음에 지정한다. 자유롭게 지정할 수 있다.
    • 패스워드 없이 사용하려면 nopass를 지정한다. 로그인 시 어떤 문자열이든 입력해도 된다.
    • 패스워드를 지정했을 경우: auth user password 로 로그인
  • keys:
    • 모든 키 : allkeys 또는 ~*
    • 특정 패턴 : 예) ~user*, ~key* 이렇게 지정하면 user 또는 key로 시작하는 키에 대해서만 사용할 수 있다.
    • 키 X : Resetkeys
    • 키 패턴을 지정하면 매 명령마다 비교하므로 성능이 떨어질 수 있다. 성능이 우선일 경우 사용에 주의
  • commands:
    • 모든 명령 : allcommands 또는 +@all
    • 명령 X : Nocommands 또는 -@all
    • 명령은 그룹 또는 명령으로 추가 또는 뺄 수 있다.
      • 명령 그룹 : +@group/-@group, 명령 : +command/-command

 

사용자 조회

ACL GETUSER user

 

사용자 삭제

ACL DELUSER user

 

본인 확인

ACL WHOAMI

 

사용자 리스트 조회

ACL USERS

 

사용자 정보 리스트 조회

ACL LIST

 

사용자 정보 저장

ACL SAVE

 

사용자 정보 로드

ACL LOAD

 

명령 그룹 조회

127.0.0.1:6379> ACL CAT
1) "keyspace"
2) "read"
3) "write"
4) "set"
5) "sortedset"
6) "list"
7) "hash"
8) "string"
9) "bitmap"
10) "hyperloglog"
11) "geo"
12) "stream"
13) "pubsub"
14) "admin"
15) "fast"
16) "slow"
17) "blocking"
18) "dangerous"
19) "connection"
20) "transaction"
21) "scripting"
  • keyspace: del, expire, flushdb, keys, ttl, scan 등
  • read: get, lrange, smembers, zrange, hget, xrange 등
  • write: set, lpush, sadd, zadd, hset, xadd 등
  • set: sadd, scard, srem, spop 등
  • sortedset: zadd, zcard, srem, zpopmin 등
  • list: lpush, llen, lrem, lpop 등
  • hash: hset, hlen, ldel, hget 등
  • string: set, get, incr 등
  • bitmap: setbit, bitop, getbit 등
  • hyperloglog: pfadd, pfmerge, pfcount, pfselftest
  • geo: geoadd, geodist, georadius 등
  • stream: xadd, xlen, xrange, xdel 등
  • pubsub: publish, subscribe, pubsub 등
  • admin: bgsave, config, debug, shutdown 등
    Admin 명령은 dangerous 그룹에 포함된다.
  • fast: get, lpush, hget 등
  • slow: lrem, mset, save 등
  • blocking: blpop, brpop, brpoplpush, bzpopmin, bzpopmax, xread, xreadgroup
  • dangerous: flushdb, keys, shutdown, info, client 등
  • connection: hello, client, auth, echo, ping, command
  • transaction: watch, multi, unwatch, discard, exec
  • scripting: evalsha, eval, script

각 명령이 어느 그룹에 속하는지는 "command info 명령"을 사용해서 확인할 수 있다.

예를 들면, SET 명령은 write, string, slow이고, GET 명령은 read, string, fast이다.

 

패스워드 생성

ACL GENPASS [<bits>]
  • 디폴트로 64바이트 문자열로 패스워드를 생성한다.
  • 암호화 알고리즘으로 SHA-256을 사용한다.

 

ACL(Auth) 로그

ACL LOG [<count> | RESET]

✅ 공식문서

https://redis.io/topics/acl

 

목차

 

 

 

 

 

 

참고

http://redisgate.kr/redis/server/acl.php

https://sungbin.dev/post/Redis%20%ED%95%B4%ED%82%B9%EB%8B%B9%ED%95%9C%20%EC%9D%B4%EC%95%BC%EA%B8%B0

Pub/Sub - 메시지 브로커

Pub/Sub은 Publish/Subscribe의 줄임말입니다.

 

단어 자체에 구독/게시라는 뜻이 있듯이 Redis에서 Pub/Sub 기능을 사용하면

클라이언트가 채널을 통해 메시지를 주고받음으로써 서로 통신할 수 있습니다.

 

구조

클라이언트는 하나의 Topic을 "Sub"하고,

해당 토픽을 "Sub"한 다른 모든 클라이언트는 해당 Topic에서 "Pub"되는 메시지를 수신합니다.

 

MSDN blog

Topic이라는 매개체를 통해서 메시지를 전달하므로

수신자와 발신자가 서로를 알지 못하더라도 메시지를 송수신할 수 있습니다.

 

특징

메시지는 Redis에 저장되지 않고 채널을 구독하는 클라이언트에 실시간으로 전송된다는 점에 유의해야 합니다.

클라이언트에게 전달되면 이를 바로 삭제합니다.

 

예시

이를 통해 Redis 지원 애플리케이션에서 실시간 메시징 및 알림을 구현할 수 있습니다.

예를 들어 채팅 애플리케이션은 pub/sub를 사용하여 한 사용자에서 다른 사용자에게 실시간으로 메시지를 보낼 수 있습니다.

  1. 애플리케이션에는 각 대화에 대한 채널이 있고
  2. 대화에 참여하는 클라이언트는 해당 채널을 구독합니다.
  3. 사용자가 메시지를 보내면 애플리케이션은 해당 채널에 메시지를 게시하고
  4. 해당 채널을 구독하는 다른 모든 클라이언트는 실시간으로 메시지를 수신합니다.

 

👎 따라서 메시지를 저장하여 관리해야 되는 경우, Redis의 Pub/Sub은 적합하지 않을 수 있습니다.

👍 예를 들어 PUSH 메시지처럼 실시간으로 로그인된 사용자에게 메시지를 전달하는 기능을 구현할 경우, 유용하게 사용될 것입니다.

 

명령어

Commands Syntax Description
subscribe channel [channel...] 채널을 구독하여, 메시지를 수신받음 (동시에 여러개 구독 가능)
publish channel message 메시지 지정한 채널로 송신
pubsub subcommand [argument [argument ...]] 서버에 등록된 채널이나 패턴을 조회
psubscribe pattern [pattern ...] 채널 이름을 패턴으로 등록
unsubscribe [channel [channel ...]] subscribe로 등록한 채널 구독 해제
punsubscribe [pattern [pattern ..]] psubscribe로 등록한 패턴 채널 구독 해제

 

subscribe 명령어

파라미터로 명시한 채널을 구독합니다. 여러 개의 채널을 동시에 구독할 수 있습니다.

결과값 : 구독한 채널명, integer값 반환

> subscribe <채널명>

> subscribe <채널명1> <채널명2> ... # 여러 개의 채널을 등록하면, 각각의 채널로 메시지가 발행되면 모두 수신한다.

✔️ redis에서 channel을 생성하는 명령어는 없고, subscribe로 채널을 생성하고 구독하는 것으로 보면 됩니다.

 

publish 명령어

이제 ch1을 구독하는 subscriber가 생겼으므로,

publisher client에서 publish 명령어를 사용해 메시지를 발행하면

subscriber client에서 해당 메시지를 전달받게 됩니다.

> publish <채널> <내용>
(integer) 2 # 채널에 메시지를 발행했고, 2개의 클라이언트에게 전달되었음

publisher
subscriber

 

pubsub 명령어

administrator가 효율적으로 subscriber를 관리할 수 있도록 하는 명령어입니다.

  • channels : 활성화 된 채널
  • numsub : 특정 채널을 구독하고 있는 subscriber의 개수 확인
    • pattern subscription으로 구독하고 있는 subscriber는 count에 포함되지 않음
  • numpat : pattern subscription의 subscriber 개수 확인
    • 특정 채널의 subscriber가 아닌, 전체 subscriber 개수 return
# 활성화된 채널이 없을 때
> pubsub channels
(empty array)

# 아래의 SUBSCRIBE 명령어로 채널을 한 개 활성화 시켰을 때
> pubsub channels
1) "c1"

# 채널을 구독중인 클라이언트 수 확인
> pubsub numsub ch1
1) "ch1"
2) (integer) 1

# 패턴형으로 등록된 클라이언트 수 확인
> pubsub numpat
(integer) 0

 

psubscribe 명령어

수신할 채널 이름의 패턴을 등록하는 명령어입니다.

 

패턴은 아래와 같은 glob-style을 지원합니다.

  • '?' : 한 글자 대치
  • '*' : 공백이나 여러 글자 대치
# 패턴을 등록하여 수신시작
> psubscribe c*
Reading messages... (press Ctrl-C to quit)
1) "psubscribe"
2) "c*"
3) (integer) 1

# 패턴 채널을 등록된 채널에는 포함되지 않음
127.0.0.1:6379> pubsub channels
1) "c1"

# 패턴 조회 : 1개 확인
127.0.0.1:6379> pubsub numpat
(integer) 1

# 등록하지 않았던 채널 ch2로 메시지 보냄
> publish ch2 "test 2"
(integer) 1

# 패턴으로 구독 신청한 채널에 메시지가 추가됨
> psubscribe c*
Reading messages... (press Ctrl-C to quit)
1) "psubscribe"
2) "c*"
3) (integer) 1
1) "pmessage"
2) "c*"
3) "c2"
4) "test 2"

 

unsubscribe / punsubscribe 명령어

  • 기본 : redis-cli에서 ctrl+c로 구독 종료
  • 별도 클라이언트 : unsubscribe 명령어로 수신 중단
  • 패턴 채널 : punsubscribe 명령어로 수신 중단
  • 채널명 입력하지 않으면 : 해당 클라이언트에 등록된 모든 채널 삭제
> unsubscribe ch1*
1) "unsubscribe"
2) "ch*"
3) (integer) 1

> punsubscribe ch1*
1) "punsubscribe"
2) "ch*"
3) (integer) 1

 

 

 

 

참고

https://inpa.tistory.com/entry/REDIS-%F0%9F%93%9A-PUBSUB-%EA%B8%B0%EB%8A%A5-%EC%86%8C%EA%B0%9C-%EC%B1%84%ED%8C%85-%EA%B5%AC%EB%8F%85-%EC%95%8C%EB%A6%BC

https://velog.io/@tilsong/Redis%EC%9D%98-%EC%A3%BC%EC%9A%94-%EA%B8%B0%EB%8A%A5-2-PubSub

+ Recent posts