* Redis protocol 이란 Redis client 와 Redis server 간 통신을 할때 사용되는 protocol 이다.
줄여서 RESP (Redis Serialization Protocol) 라고 부른다.


* 위 프로토콜의 장점은 무엇일까?

  • 구현이 쉽다.
  • 파싱이 빠르다.
  • 인간이 읽기 쉽다.

위의 장점으로만 보면 엄청 좋아보인다. 그래서 얼마나 좋은지 직접 확인을 하였다.

일단 RESP 의 마지막은 \r\n (CRLF)  로 끝난다.


아래의 sample 을 확인 하겠다. 일단 string 로 변수 를 초기화 한다음. 변수에 값을 넣고 그 값을 file 로 write 한다. 이 부분에서 확인해야 하는부분은 바로 변수에 들어가는 값이다.

str_buf = str()
str_buf = '*3\r\n$3\r\nset\r\n$2\r\nab\r\n$2\r\n11\r\n'

with open('resp.fmt', 'w') as fp:
    fp.write(str_buf)

해당 값은 \r\n 으로 구분되며 각각의 설명은 아래와 같다.

*3 : 전체 명령 LINE 수 이다.

여기서는 set {command} / ab {key_name} / 11 {value} 의 개수가 3개 이므로 3 으로 표시

$3 : 다음 라인의 size 이다. set 이므로 숫자는 3 이다.

$2 : ab 이므로 2


위의 파일을 실행 후 생성된 resp.fmt 를 아래와 같이 실행 한다.

$ cat resp.fmt | redis-cli -h 127.0.0.1 --pipe

All data transferred. Waiting for the last reply...

Last reply received from server.

errors: 0, replies: 1


$ redis-cli get ab "11"

redis-cli --pipe 명령어를 사용하여 replies: 1 이 표시되면 정상적으로 들어간것이다.


* 어떻게 사용할수 있을까?

나의 사용경험은 이렇다. 빠른 속도로 data 를 처리해야하는 웹서버 에서 redis 에 data 를 load 후 사용한 경험이 있었다.

이때, 기존은 data 들이 json 으로 되어 있어 json parsing 후 일일이 data 를 insert 하였는데 data 를 json file 로 생성하지 않고 resp format 형식으로 생성 후 필요할때마다 load 하고, load 된 key 를 expire 를 넣어 key 를  persistent 하게 보관하지 않아 memory over 가 발생되지 않게 한다. 이런식으로 사용을 하니 json load 및 parsing resource 를 감소할수 있었으며 client 가 redis command 를 resp 로 변환하는 resource 또한 줄일수 있다.

'기술 > Redis' 카테고리의 다른 글

Redis master / slave 설정  (0) 2019.02.08
Redis master / slave  (0) 2019.01.31
Redis 는 무엇  (0) 2019.01.31

* ASGI (Asynchronous Server Gateway Interface)

그대로 읽으면 비동기 서버 게이트웨이 인터페이스 이다. 

자세한 의미는 여기 을 참조한다. 대강 보면 웹 서버, 프레임워크, 응용프로그램 들의 호환성 표준 이라 생각 하면 될듯하다.


아래에서는 Async web server ( uvicorn / starlette ) 을 구성하고 동작시키는 예제를 확인 할것이다. (on Docker)


* sample_code


# 환경

## Host (Docker build)

NAME="Ubuntu" VERSION="18.04.1 LTS (Bionic Beaver)"

Docker version 18.06.1-ce, build e68fc7a


## Container OS /home/anywon # cat /etc/os-release NAME="Alpine Linux" ID=alpine VERSION_ID=3.8.1

## Lan /home/anywon # python3.6 -V Python 3.6.6

## Pip lib

starlette==0.9.9 uvicorn==0.3.23


Python 에서 async function 는 아래와 같이 def 지시어 앞에 async 가 붙는다.

async def test(): return 0

* sample_code 를 clone 후 script dir 에 있는 build.web_server.sh 를 실행하면 자동으로 docker images 가 생성이 된다.
Container OS 는 alpine 이며, Python 과 uvicorn, starlette 를 설치하여 구동이 된다.


# docker images

REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
web_server          1.0                 82e813dc9a6d        4 days ago          233MB

Docker images build 가 끝이나면 docker images command 를 통하여 images 를 확인할 수 있다. 그뒤

run_web_server_container.sh 를 실행하면 자동으로 Container 가 구동 되게 된다.


# docker ps -a
CONTAINER ID        IMAGE                 COMMAND                  CREATED             STATUS                      PORTS                    NAMES
fb5e0d810f66        web_server:1.0        "/usr/bin/supervisord"   30 minutes ago      Up 30 minutes                                        web_server

# ps -aux | grep python

root     13497  0.0  0.1  94976 24104 pts/0    S    17:28   0:00 /usr/bin/python3.6 /usr/bin/uvicorn --fd 0 app_server:app --log-level=info --http=h11
root     13498  0.0  0.1  94976 24024 pts/0    S    17:28   0:00 /usr/bin/python3.6 /usr/bin/uvicorn --fd 0 app_server:app --log-level=info --http=h11
root     13499  0.0  0.1  94976 24148 pts/0    S    17:28   0:00 /usr/bin/python3.6 /usr/bin/uvicorn --fd 0 app_server:app --log-level=info --http=h11
root     13500  0.0  0.1  94976 23984 pts/0    S    17:28   0:00 /usr/bin/python3.6 /usr/bin/uvicorn --fd 0 app_server:app --log-level=info --http=h11


위와 같이 STATUS 가 Up 상태이면 정상적으로 서버가 구동중이다. 또는 ps -aux | grep python 을 사용하여 확인이 가능하다.


* worker count 를 증가 하고 싶으면 아래와 같이 변경을 하면 된다.

files/conf 의 supervisord.conf 을 열고

[fcgi-program:uvicorn]
directory=/home/anywon/web_server
socket=tcp://0.0.0.0:18080
command=/usr/bin/uvicorn --fd 0 app_server:app --log-level=info --http=h11
numprocs=4
process_name=web_server-%(process_num)d
stdout_logfile=/home/anywon/supervisor/web_server_stdout.log
stdout_logfile_maxbytes=50MB   ; max # logfile bytes b4 rotation (default 50MB)
stdout_logfile_backups=10     ; # of stdout logfile backups (default 10)
stderr_logfile=/home/anywon/supervisor/web_server_stderr.log
stderr_logfile_maxbytes=50MB   ; max # logfile bytes b4 rotation (default 50MB)
stderr_logfile_backups=10     ; # of stdout logfile backups (default 10)

fcgi-program:uvicorn sction 의 numprocs=4 값을 변경 한다. (기본값은 4로 설정)



* 실행 코드

# Ref (uvicorn)   : https://www.uvicorn.org/
# Ref (starlette) : https://www.starlette.io/

from starlette.routing      import Mount, Route, Router
from starlette.applications import Starlette
from starlette.responses    import Response, JSONResponse
from starlette.requests     import Request

async def ping(request):
    headers = {'Content-Type' : 'text/plain'}
    return  Response('OK', status_code = 200, headers = headers)


async def sample(request):

    # Get body
    body = await request.body()

    # Get uri_1
    uri_1 = request.path_params['uri_1']

    # Get uri_2
    uri_2 = request.path_params['uri_2']

    # Get full url with queryString
    full_url = request.url

    # Get request headers
    headers    = request.headers

    # Get QueryString : dict
    qp = request.query_params

    headers = {
        'Content-Type' : 'application/json',
        'keep-alive' : 'timeout=30, max=100',
        'connection' : 'Keep-Alive'
    }

    # Response 
    # return  Response(data, status_code = 200, headers = headers])

    # Response JSON
    return  JSONResponse(data_json, status_code = 200, headers = headers)


API_VERSION = 'v1'

app = Starlette()
app.add_route('/', ping, methods=["GET"])
app.add_route('/', ping, methods=["PUT"])
app.add_route('/api/test' + API_VERSION + '/{uri_1}/{uri_2}', sample, methods=["GET"])
app.add_route('/api/test' + API_VERSION + '/{upload_path:path}', sample, methods=["PUT"])


실행이 되면 위의 app_server.py code 가 실행이 되며, add_route 를 통하여 원하는 uri 를 생성 및 method 를 지정할수 있다.

해당 route 의 request 가 발생되어 처리할 function 을 상단에 지정할수 있으며, 기본적으로 async  def 로 시작하여 async code base 를 확인할수 있다.

기본적인 사용 방법은 위의 sample code 를 보면 확인이 가능하며, 추가적으로 궁금한 사항은 여기 에서 확인 가능 하다.




'기술 > Python' 카테고리의 다른 글

Asyncio + ZeroMQ 를 사용한 Producer & Consumer  (0) 2019.02.11

* Etcd 는 설치가 매우 간단하다. Etcd Github 에서 미리 빌드된 바이너리를 제공한다. ( 각 OS 별로)

https://github.com/etcd-io/etcd/releases


각각의 Option 의 설명은 Google 을 하면 나오기 때문에 생략하며, 어떻게 cluster 를 구성 및 검증을 하는지 중점으로 확인 하겠다.


# 환경
[root@localhost host_ver]# cat /etc/os-release 
NAME="CentOS Linux"
VERSION="7 (Core)"
# pre-built 된 etcd binaries 로 동작한다.
2월 12 00:48 etcd
2월 12 00:48 etcdctl
2월 12 00:54 run_etcd_1.sh
2월 12 00:55 run_etcd_2.sh
2월 12 00:55 run_etcd_3.sh
# run_etcd_1.sh

#!/bin/bash
cur_path=`pwd`
nohup $cur_path/etcd \
    --data-dir /etcd-data_1 \
    --listen-client-urls http://127.0.0.1:2379,http://0.0.0.0:4001 \
    --listen-peer-urls http://127.0.0.1:2380 \
    --initial-advertise-peer-urls http://127.0.0.1:2380 \
    --initial-cluster-token test-etcd \
    --initial-cluster-state new \
    --name test-etcd-1 \
    --advertise-client-urls http://127.0.0.1:2379 \
    --initial-cluster test-etcd-1=http://127.0.0.1:2380,test-etcd-2=http://127.0.0.1:2480,test-etcd-3=http://127.0.0.1:2580, \
    --auto-compaction-retention 1 1>/dev/null 2>&1 &
# run_etcd_2.sh

#!/bin/bash
cur_path=`pwd`
nohup $cur_path/etcd \
    --data-dir /etcd-data_2 \
    --listen-client-urls http://127.0.0.1:2479,http://0.0.0.0:4101 \
    --listen-peer-urls http://127.0.0.1:2480 \
    --initial-advertise-peer-urls http://127.0.0.1:2480 \
    --initial-cluster-token test-etcd \
    --initial-cluster-state new \
    --name test-etcd-2 \
    --advertise-client-urls http://127.0.0.1:2479 \
    --initial-cluster test-etcd-1=http://127.0.0.1:2380,test-etcd-2=http://127.0.0.1:2480,test-etcd-3=http://127.0.0.1:2580, \
    --auto-compaction-retention 1 1>/dev/null 2>&1 &
# run_etcd_3.sh

#!/bin/bash
cur_path=`pwd`
nohup $cur_path/etcd \
    --data-dir /etcd-data_3 \
    --listen-client-urls http://127.0.0.1:2579,http://0.0.0.0:4201 \
    --listen-peer-urls http://127.0.0.1:2580 \
    --initial-advertise-peer-urls http://127.0.0.1:2580 \
    --initial-cluster-token test-etcd \
    --initial-cluster-state new \
    --name test-etcd-3 \
    --advertise-client-urls http://127.0.0.1:2579 \
    --initial-cluster test-etcd-1=http://127.0.0.1:2380,test-etcd-2=http://127.0.0.1:2480,test-etcd-3=http://127.0.0.1:2580, \
    --auto-compaction-retention 1 1>/dev/null 2>&1 &
# 확인_1 : 프로세스 구동
[root@localhost host_ver]# ps -aux | grep etcd
root     12333  1.0  1.3 10533132 24884 pts/0  Sl   00:55   0:10 /home/inisoft/etcd/host_ver/etcd --data-dir /etcd-data_1 --listen-client-urls http://127.0.0.1:2379,http://0.0.0.0:4001 --listen-peer-urls http://127.0.0.1:2380 --initial-advertise-peer-urls http://127.0.0.1:2380 --initial-cluster-token test-etcd --initial-cluster-state new --name test-etcd-1 --advertise-client-urls http://127.0.0.1:2379 --initial-cluster test-etcd-1=http://127.0.0.1:2380,test-etcd-2=http://127.0.0.1:2480,test-etcd-3=http://127.0.0.1:2580, --auto-compaction-retention 1
root     12344  0.8  1.1 10531016 21768 pts/0  Sl   00:55   0:08 /home/inisoft/etcd/host_ver/etcd --data-dir /etcd-data_2 --listen-client-urls http://127.0.0.1:2479,http://0.0.0.0:4101 --listen-peer-urls http://127.0.0.1:2480 --initial-advertise-peer-urls http://127.0.0.1:2480 --initial-cluster-token test-etcd --initial-cluster-state new --name test-etcd-2 --advertise-client-urls http://127.0.0.1:2479 --initial-cluster test-etcd-1=http://127.0.0.1:2380,test-etcd-2=http://127.0.0.1:2480,test-etcd-3=http://127.0.0.1:2580, --auto-compaction-retention 1
root     12356  0.8  0.9 10531016 17288 pts/0  Sl   00:55   0:07 /home/inisoft/etcd/host_ver/etcd --data-dir /etcd-data_3 --listen-client-urls http://127.0.0.1:2579,http://0.0.0.0:4201 --listen-peer-urls http://127.0.0.1:2580 --initial-advertise-peer-urls http://127.0.0.1:2580 --initial-cluster-token test-etcd --initial-cluster-state new --name test-etcd-3 --advertise-client-urls http://127.0.0.1:2579 --initial-cluster test-etcd-1=http://127.0.0.1:2380,test-etcd-2=http://127.0.0.1:2480,test-etcd-3=http://127.0.0.1:2580, --auto-compaction-retention 1
root     12434  0.0  0.0 112708  1020 pts/0    R+   01:11   0:00 grep --color=auto etcd

# 확인_2 : etcdctl 사용
[root@localhost host_ver]# ./etcdctl member list
3e7bc8c98f934b14: name=test-etcd-2 peerURLs=http://127.0.0.1:2480 clientURLs=http://127.0.0.1:2479 isLeader=false
57a9bb6573588be4: name=test-etcd-3 peerURLs=http://127.0.0.1:2580 clientURLs=http://127.0.0.1:2579 isLeader=false
d9a525d9b95ba08b: name=test-etcd-1 peerURLs=http://127.0.0.1:2380 clientURLs=http://127.0.0.1:2379 isLeader=true

# 확인_3 : 기타 명령어 by curl
[root@localhost host_ver]# curl -L '127.0.0.1:4001/v2/keys'
{"action":"get","node":{"dir":true}}
[root@localhost host_ver]# curl -L '127.0.0.1:4001/version'
{"etcdserver":"3.3.12","etcdcluster":"3.3.0"}[root@localhost host_ver]

# 확인_4 : data insert & check
[root@localhost host_ver]#  curl -X PUT -d value="hello etcd" '127.0.0.1:4201/v2/keys/test'
{"action":"set","node":{"key":"/test","value":"hello etcd","modifiedIndex":9,"createdIndex":9}}
[root@localhost host_ver]# curl -L '127.0.0.1:4001/v2/keys/test'
{"action":"get","node":{"key":"/test","value":"hello etcd","modifiedIndex":9,"createdIndex":9}}

## 4201 Port 로 insert 요청 후 4001 로 data 확인힌다.
## 참고, 하위 key 가 존재하면 상위 key 를 제거할시 ?recursive=true 를 사용하여야 한다.

* 정리 설치 및 cluster 구성이 간단하였으며, 확인 또한 편리했다. 
조금 더 자세한 명령어를 원하면 https://coreos.com/etcd/docs/latest/v2/api.html 참고하면 될듯하다.



'기술 > Etcd' 카테고리의 다른 글

Etcd 란?  (0) 2019.02.12

* ETCD

Core OS 에서 개발한 신뢰할수 있는 분산 Key-Value Store 정도로 볼수 있다.

https://github.com/etcd-io/etcd : 공식 Github 주소이다.


해당 주소 접속시 아래와 같은 설명을 볼수 있다.


  • Simple: well-defined, user-facing API (gRPC)
  • Secure: automatic TLS with optional client cert authentication
  • Fast: benchmarked 10,000 writes/sec
  • Reliable: properly distributed using Raft
간편 / 보안성 / 빠르고 / 신뢰성 등의 장점이 있다고 한다.
나는 Docker overlay network 를 구성할때와 간단한 API 로 Data CRUD 로 사용한 경험이 있다.


Disk 에 실제 data 를 쓰기 때문에 read / write 가 빠른 SSD 의 위치에 사용하면 좋을 것 같다.

'기술 > Etcd' 카테고리의 다른 글

Etcd installration & cluster  (0) 2019.02.12

* Producer & Consumer ( 생산자 & 소비자) 에 문제를 Python3.6 으로 작성해 보았다.

Asyncio (비동기) 작성되었으며, Message queue 인 ZeroMQ 를 사용하여 Producer 이하 (p) 가 Consumer 이하 (c) 에게 원하는 Message (broadcasting) 를 전달 후 각 c 들이 data  를 가져와 처리하는 예제 code 이다.

# 실행 ( pub )

import asyncio import sys, signal import zmq import zmq.asyncio kill = False def bind_zmq(port): print('try bind localhost %d' % port) context = zmq.asyncio.Context() socket = context.socket(zmq.PUB) socket.bind("tcp://127.0.0.1:%s" % port) return socket async def pub_func(): socket = bind_zmq(10010) count = 1 await asyncio.sleep(1) while True: data = "'message %d'" % count print('send_msg %s' % data) await socket.send_string(data) count = count + 1 if kill: break await asyncio.sleep(0.1) socket.close() async def async_task(): fts = [asyncio.ensure_future(pub_func())] for f in asyncio.as_completed(fts): await f def signal_handler(signal, frame): print('signal num %d' % signal) global kill kill = True if __name__ == "__main__": signal.signal(signal.SIGINT, signal_handler) signal.signal(signal.SIGTERM, signal_handler) loop = asyncio.get_event_loop() loop.run_until_complete(async_task()) loop.close()

# 실행 ( sub )

import asyncio import sys, signal import zmq import zmq.asyncio import random def connect_zmq(port): context = zmq.asyncio.Context() socket = context.socket(zmq.SUB) socket.connect("tcp://127.0.0.1:%s" % port) socket.setsockopt_string(zmq.SUBSCRIBE, '') # socket.setsockopt(zmq.SUBSCRIBE, b'') return socket async def sub_func(que): print('call sub_func') socket = connect_zmq(10010) while True: sub_msg = await socket.recv_string() # print('sub_msg %s in sub_func' % sub_msg) qs = que.qsize() if qs >= 90: print('warning que size over 90') if qs >= 98: print('dont inque') continue que.put_nowait(sub_msg) socket.close() async def proc_func(wk_id, que): print('call wk_id %d proc_func' % wk_id) while True: que_data = await que.get() slp_tm = random.uniform(0.3, 1.0) print('wk_id %d, que_data %s, slp_tm %f in proc_func' % (wk_id, que_data, slp_tm)) await asyncio.sleep(slp_tm) async def async_tasks(): que = asyncio.Queue(maxsize = 100) # fts = [asyncio.ensure_future(sub_func(que)), fts = [asyncio.ensure_future(proc_func(wk_id, que)) for wk_id in range(1,4) ] fts.append(asyncio.ensure_future(sub_func(que))) for f in asyncio.as_completed(fts): await f await que.join() def signal_handler(signal, frame): print('signal num %d' % signal) sys.exit(1) if __name__ == "__main__": signal.signal(signal.SIGINT, signal_handler) signal.signal(signal.SIGTERM, signal_handler) loop = asyncio.get_event_loop() loop.run_until_complete(async_tasks()) loop.close()

code 는 위와 같다. local address 의 10010 port 를 사용하며 pub code 가 message 값을 1씩 증가시키면서 publish 를 하게 되면 sub code 는 n개의 ensure_future object 로 publish 된 data 를 subscribe 하여 data 를 처리하는 방식이다. n번째의 ensure_future 객체 는 random 값으로 asyncio.sleep 를 각기 다르게 주기 때문에 어떤 객체부터 끝나는지 알수 없게 된다.


아래는 코드의 결과 이다.

# Pub


send_msg 'message 87' send_msg 'message 88' send_msg 'message 89' send_msg 'message 90' send_msg 'message 91' send_msg 'message 92' send_msg 'message 93' send_msg 'message 94' send_msg 'message 95' send_msg 'message 96' send_msg 'message 97' send_msg 'message 98' send_msg 'message 99' send_msg 'message 100' send_msg 'message 101' send_msg 'message 102' send_msg 'message 103' send_msg 'message 104' send_msg 'message 105' send_msg 'message 106' send_msg 'message 107' send_msg 'message 108' send_msg 'message 109' send_msg 'message 110' send_msg 'message 111'


# Sub


call wk_id 1 proc_func call wk_id 2 proc_func call wk_id 3 proc_func call sub_func wk_id 1, que_data 'message 90', slp_tm 0.405087 in proc_func wk_id 2, que_data 'message 91', slp_tm 0.699106 in proc_func wk_id 3, que_data 'message 92', slp_tm 0.806175 in proc_func wk_id 1, que_data 'message 93', slp_tm 0.977847 in proc_func wk_id 2, que_data 'message 94', slp_tm 0.343587 in proc_func wk_id 3, que_data 'message 95', slp_tm 0.348311 in proc_func wk_id 2, que_data 'message 96', slp_tm 0.383186 in proc_func wk_id 3, que_data 'message 97', slp_tm 0.925658 in proc_func wk_id 1, que_data 'message 98', slp_tm 0.797679 in proc_func wk_id 2, que_data 'message 99', slp_tm 0.591475 in proc_func wk_id 2, que_data 'message 100', slp_tm 0.808996 in proc_func wk_id 1, que_data 'message 101', slp_tm 0.427783 in proc_func wk_id 3, que_data 'message 102', slp_tm 0.469321 in proc_func wk_id 1, que_data 'message 103', slp_tm 0.367678 in proc_func wk_id 3, que_data 'message 104', slp_tm 0.466130 in proc_func wk_id 2, que_data 'message 105', slp_tm 0.978609 in proc_func wk_id 1, que_data 'message 106', slp_tm 0.978941 in proc_func wk_id 3, que_data 'message 107', slp_tm 0.396088 in proc_func wk_id 3, que_data 'message 108', slp_tm 0.752204 in proc_func wk_id 2, que_data 'message 109', slp_tm 0.310375 in proc_func wk_id 1, que_data 'message 110', slp_tm 0.637855 in proc_func wk_id 2, que_data 'message 111', slp_tm 0.820937 in proc_func wk_id 3, que_data 'message 112', slp_tm 0.631646 in proc_func wk_id 1, que_data 'message 113', slp_tm 0.430918 in proc_func wk_id 3, que_data 'message 114', slp_tm 0.462042 in proc_func wk_id 1, que_data 'message 115', slp_tm 0.495235 in proc_func



* 정리

wk_id 가 순차적으로 표시되다가 어느순간 slp_tm 이 길어지는 wk_id 는 그만큼 다시 표시될때까지 좀더 걸리게 된다.

이로 유추할수 있는 것은 proc_func 에서 await 를 만나면 해당 코루틴은 잠시 중지하고 다른 코루틴에게 스케줄링을 양보하는것을 볼수 있다.

만약, 여기서 Asyncio.sleep() 이 아니라 time.sleep() sync 함수를 사용하게 되면 전체적인 런루프가 sync 로 묶기게 되어 async 의 효용가치가 없어진다. async 로 code 를 작성할때 실수 했던 부분이다.

'기술 > Python' 카테고리의 다른 글

python asgi server ( uvicorn / starlette )  (0) 2019.02.19

* redis master
redis conf 를 확인 한다.  redis_master_conf.rtf
#  붙은 것은 주석 이기 때문에 신경을 쓰지 않아도 된다. (제거 가능)
daemon 설정 / pid , log path 등등 설정이 있다.
redis-server binary 사용하여 해당 conf 지정 redis 실행한다.

# 실행
./redis-server redis1.conf 

# 확인 ps -ef | grep redis ./redis-server 0.0.0.0:6379

# 접속 redis-cli -h 127.0.0.1 -p 6379 127.0.0.1:6379> info Replication # Replication role:master connected_slaves:0 master_repl_offset:0 repl_backlog_active:0 repl_backlog_size:104857600 repl_backlog_first_byte_offset:0 repl_backlog_histlen:0

* 처음 실행시 role:master 를 확인 할수 있다.


* redis slave
master conf 에 slaveof option 만 추가로 설정 하면 된다.

# redis slave conf ..

# slaveof <masterip> <masterport>

slaveof 127.0.0.1 6379

..

# 실행
./redis-server redis2.conf

# 확인 ps -ef | grep redis ./redis-server 0.0.0.0:6379 ./redis-server 0.0.0.0:6380

# 접속
redis-cli -h 127.0.0.1 -p 6380
127.0.0.1:6380> info Replication
# Replication
role:slave
master_host:127.0.0.1
master_port:6379
master_link_status:up
master_last_io_seconds_ago:3
master_sync_in_progress:0
slave_repl_offset:729
slave_priority:300
slave_read_only:1
connected_slaves:0
master_repl_offset:0
repl_backlog_active:0
repl_backlog_size:104857600
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0


* master 에 접속 하여 slave 확인

# master 접속 redis-cli -h 127.0.0.1 -p 6379 127.0.0.1:6379> info Replication # Replication role:master connected_slaves:1 slave0:ip=127.0.0.1,port=6380,state=online,offset=1345,lag=1 master_repl_offset:1345 repl_backlog_active:1 repl_backlog_size:104857600 repl_backlog_first_byte_offset:2 repl_backlog_histlen:1344

# Data Replication 확인

# master redis 에 abc key name 으로 123 값을 저장함


redis-cli -h 127.0.0.1 -p 6379 set abc 123 OK

# redis slave 접속 후 data 확인


redis-cli -h 127.0.0.1 -p 6380 get abc "123"


* 정상적으로 master 에 입력한 data 를 slave 에서 확인이 가능 하다.
이러한 구성은 redis 의 traffic 을 분산 하는데 좋은 구성이 된다. 하지만 오직 master 만 write 를 할수 있기 때문에 redis master 가 down이 되면 master 를 못하는 문제점이 있다.
그래서 redis-sentinel 이라는 app 이 존재한다. redis-sentinel 은 redis master 를 감시하다가 master 가 down 이 되면 redis slave 를 master 로 승격하는 역활을 한다.

'기술 > Redis' 카테고리의 다른 글

Redis protocol file 생성 (python)  (0) 2019.02.28
Redis master / slave  (0) 2019.01.31
Redis 는 무엇  (0) 2019.01.31

* Redis master / slave 란 ?

  1. Redis Replication
    1. Redis Replication 은 master / slave 구조로 되어 있다.
    2. master 는 write / read 가 가능하며 slave 는 read 만 가능하다. ( slave 에서도 write 가 가능하지만 성능 저하가 발생하여 사용하지 않는다. )
    3. master 는 n 개의 slave 를 가질수 있다.
    4. Replication 은 non-blocking 으로 동작하기 때문에 master 의 operation 에는 영향이 적다
Redis 의 master / slave (sentinel) 기능을 잘 사용하면 High-availability service 구성을 만들수 있다. 이는 나중에 설명하도록 하겠다.


'기술 > Redis' 카테고리의 다른 글

Redis protocol file 생성 (python)  (0) 2019.02.28
Redis master / slave 설정  (0) 2019.02.08
Redis 는 무엇  (0) 2019.01.31

* Redis 란 무엇인가  ? 위키백과

  1. Remote Directory Server의 약자
  2. In-memory DB
  3. 키-값 구조
  4. 오픈소스
내 말로 풀면, 키-벨류 저장소이며 사용이 간편하고 In-memory 라서 속도가 무진장 빠르다.
Cache data or 유실되도 상관없는 data 에 사용하면 적합할듯 하다.




'기술 > Redis' 카테고리의 다른 글

Redis protocol file 생성 (python)  (0) 2019.02.28
Redis master / slave 설정  (0) 2019.02.08
Redis master / slave  (0) 2019.01.31

+ Recent posts