4. # 수십만명이 동시에 접속하는 온라인 인터넷 방송 ‘America TV’ 의
채팅 기능을 구현한다고 생각하자.
# 채팅 서버만해도 수십대 또는 수백대가 필요할 것인데,
어떻게 부하 분산하고 무중단 확장할 수 있을까?
실제로 이런거 없음. 그냥 예를 들어..
5. # 네트워크 비용을 최소화 하고, 성능을 극대화 하기 위한 방법이 필요하다
# 로컬 통신을 극대화 하기 위한 분산 기법이 될 수 있겠다.
분산 서버 아키텍처 설계는 네트워크 비용이 커질 수 밖에 없지. 분산된 서버들간에 데이터 통신이나 데이터 공유가 필요하니까 말이다.
분산 서버 아키텍처 설계에서 최대한으로 서버간 데이터 전송을 하지 않도록 해야 한다. 물론 모든 경우에 적합하지는 않다.채팅 같은 경우가 적합하겠지 말이다.
비용이라고, 꼭 돈만이 아니다!
이런거 크게 신경 쓰기 싫다면, 역시 Round Robin 하면 된다.
7. # 분산된 채팅 서버를 할당해주는 Session 서버를 별도로 만들었다.
Session Server
-‐ 채팅방 별 Channel 서버 할당
(할당할 서버목록을 가지고 있어야 함)
-‐ Channel 서버 접속을 위한 인증
Channel Server
-‐ 실시간 메시지 송수신 처리 (채팅 서버)
-‐ 모든 Client 는 Channel 서버에 접속 유지
-‐ Client 수에 따라 유동적으로 Scale-‐out 필요
session 서버는 zookeeper 의 channel 서버 목록을 동기화 하고 있다.
channel 서버가 실행되면, zookeeper 에 znode를 생성
server / A^123.45.67.01:9001
B^123.45.67.01:9002
C^123.45.67.01:9001
D^123.45.67.01:9002
E^123.45.67.01:9001
F^123.45.67.01:9002
G^123.45.67.01:9001
H^123.45.67.01:9002
Session Server
Channel Server A
.
.
.
.
zookeeper
Channel Server B
Channel Server C Channel Server D
Channel Server E Channel Server F
Channel Server G Channel Server H
.
.
.
.
watching
create Node
123.45.67.01:9001 123.45.67.01:9002
123.45.67.02:9001 123.45.67.02:9002
123.45.67.03:9001 123.45.67.03:9002
123.45.67.04:9001 123.45.67.04:9002
8. # 가장 먼저, Session 서버는 접속할 Channel Server 정보를 알려 준다.
server / A^123.45.67.01:9001
B^123.45.67.01:9002
C^123.45.67.02:9001
D^123.45.67.02:9002
E^123.45.67.03:9001
F^123.45.67.03:9002
G^123.45.67.04:9001
H^123.45.67.04:9002
Session Server
Channel Server A
.
.
.
.
zookeeper
Channel Server B
Channel Server C Channel Server D
Channel Server E Channel Server F
Channel Server G Channel Server H
.
.
.
.
watching
create Node
123.45.67.01:9001 123.45.67.01:9002
123.45.67.02:9001 123.45.67.02:9002
123.45.67.03:9001 123.45.67.03:9002
123.45.67.04:9001 123.45.67.04:9002
hDps://session-‐server/node/americatv/kimeve
hDps://session-‐server/node/americatv/yumdaeng
채팅방 -‐ kimeve
채팅방 -‐ yumdaeng
server : C, url : 123.45.67.02:9001
server : F, url : 123.45.67.03:9002
-‐ 실제로, Session 서버는 client 의 접속 인증처리도 함께 해야 하기 때문에, 인증 Token 을 생성하여 Client 에 전달해야 할 것이다. (인증 토큰은 Client 가 Channel Server 에 접근할 때 함께 전달한다.)
9. # 그 다음, Client 는 할당받은 channel 서버에 접속해서 메시지를 송수신 한다.
server / A^123.45.67.01:9001
B^123.45.67.01:9002
C^123.45.67.02:9001
D^123.45.67.02:9002
E^123.45.67.03:9001
F^123.45.67.03:9002
G^123.45.67.04:9001
H^123.45.67.04:9002
Session Server
Channel Server A
.
.
.
.
zookeeper
Channel Server B
Channel Server C Channel Server D
Channel Server E Channel Server F
Channel Server G Channel Server H
.
.
.
.
watching
create Node
123.45.67.01:9001 123.45.67.01:9002
123.45.67.02:9001 123.45.67.02:9002
123.45.67.03:9001 123.45.67.03:9002
123.45.67.04:9001 123.45.67.04:9002
채팅방 -‐ kimeve
채팅방 -‐ yumdaeng
channel : kimeve
server : C
url : 123.45.67.02:9001
channel : yumdaeng
server : F
url : 123.45.67.03:9002
socket (TCP)
socket (TCP)
-‐ 실제로, Client 가 Channel Server 에 연결 요청할 때는, 인증 토큰을 함께 전달하고, Channel Server 는 인증 토큰이 유효한 값인지 확인하고 ConnecOon 을 맺어야 할 것이다.
같은 채팅방에 있는 Client 는 모두 같은 서버에 접속하게 해서, Local 통신하게 하자 !! ( 네트워크 비용이나, 성능 향상 )
10. # 그럼 이제 본론이다.
Session 서버는 어떻게 Channel 서버를 할당해야 할까?
11. # STEP 1. Consistent Hashing
server / A^123.45.67.01:9001
B^123.45.67.01:9002
C^123.45.67.01:9001
D^123.45.67.01:9002
E^123.45.67.01:9001
F^123.45.67.01:9002
G^123.45.67.01:9001
H^123.45.67.01:9002
Session Server
Channel Server A
.
.
.
.
zookeeper
Channel Server B
Channel Server C Channel Server D
Channel Server E Channel Server F
Channel Server G Channel Server H
.
.
.
.
watching
create Node
123.45.67.01:9001 123.45.67.01:9002
123.45.67.02:9001 123.45.67.02:9002
123.45.67.03:9001 123.45.67.03:9002
123.45.67.04:9001 123.45.67.04:9002
zookeeper 로 부터 동기화 되는 서버 목록 데이터를 기반으로
Session 서버에는 Consistent Hashing 함수 구현한다.
28. # 그런데,
Channel 서버가 추가되거나 삭제되면, Consistent Hashing 값이 달라진다.
kimeve 채팅방은 Channel Server C 를 할당했다. 신규 Channel Server 를 추가해서 Consistent Hashing 을 갱신했더니, 이제 Channel Server F 를 할당하더라.
29. # STEP 2. Using allocaRon data table
Session Server
Channel Server A
.
.
.
.
zookeeper
Channel Server B
Channel Server C Channel Server D
Channel Server E Channel Server F
Channel Server G Channel Server H
.
.
.
.
watching
create Node
123.45.67.01:9001 123.45.67.01:9002
123.45.67.02:9001 123.45.67.02:9002
123.45.67.03:9001 123.45.67.03:9002
123.45.67.04:9001 123.45.67.04:9002
REDIS
hDps://session-‐server/node/americatv/kimeve
Consistent Hashing 함수를 통해 ‘Channel Server C’ 를 할당한다.
HSET
socket (TCP)
kimeve : C : 1
접속한 정보는 실시간으로 REDIS 에서 관리한다.
KEY 서버이름
현재 접속자 수
(당연히, 처음 적속했다면 1 이다)
GET
In-‐Memory DB 에 현재 접속 정보를 관리하고, 서버 할당시 확인한다.
속도 때문에 redis 를 사용했지, 꼭 이것만 할 수 있는건 아니다.
REDIS 에 서버 접속 정보가 있는지 확인한다.
KEY값이 kimeve 인 데이터가 REDIS 에 있는지 확인한다.
1
2
3
30. Session Server
Channel Server A
.
.
.
.
zookeeper
Channel Server B
Channel Server C Channel Server D
Channel Server E Channel Server F
Channel Server G Channel Server H
.
.
.
.
watching
create Node
123.45.67.01:9001 123.45.67.01:9002
123.45.67.02:9001 123.45.67.02:9002
123.45.67.03:9001 123.45.67.03:9002
123.45.67.04:9001 123.45.67.04:9002
REDIS
hDps://session-‐server/node/americatv/kimeve
REDIS 에서 조회한 Channel Server C 정보를 반환한다.
HSET
socket (TCP)
kimeve : C : 2
접속한 정보는 실시간으로 REDIS 에서 관리한다.
KEY 서버이름
현재 접속자 수
현재 접속자 수는 Channel Server 에서 구해서
REDIS 의 값을 갱신한다.
(이제 2명이 되었다!)
GET
In-‐Memory DB 에 현재 접속 정보를 관리하고, 서버 할당시 확인한다.
이미 접속한 Client
REDIS 에 서버 접속 정보가 있는지 확인한다. 있다!!!
KEY값이 kimeve 인 데이터가 REDIS 에 있는지 확인한다.
1
2
3
새로 접속하는 2번째 client
# STEP 2. Using allocaRon data table
31. Session Server
Channel Server A
zookeeper
Channel Server B
Channel Server C Channel Server D
Channel Server E Channel Server F
Channel Server G Channel Server H
.
.
.
.
watching
create Node
123.45.67.01:9001 123.45.67.01:9002
123.45.67.02:9001 123.45.67.02:9002
123.45.67.03:9001 123.45.67.03:9002
123.45.67.04:9001 123.45.67.04:9002
REDIS
HSET
kimeve : C : 2
GET
Channel Server I
신규 추가된 Channel 서버
123.45.67.05:9001
server / A^123.45.67.01:9001
B^123.45.67.01:9002
C^123.45.67.02:9001
D^123.45.67.02:9002
E^123.45.67.03:9001
F^123.45.67.03:9002
G^123.45.67.04:9001
H^123.45.67.04:9002
I ^123.45.67.05:9002Zookeeper 에 Node 생성
Consistent Hashing 갱신 !!!
kimeve 채팅방은
Consistent Hashing 결과 값은 C 였지만,
Channel Server I 가 추가된 후
Consistent Hashing 결과 값이 H 가 되었다.
하지만,
REDIS 에는 C 이므로,
kimeve 채팅방에 C 를 할당할 수 있다.
만약, kimeve 채팅방이 다시 만들어 진다면,
그때는 H를 할당 한다.
# STEP 2. Using allocaRon data table
32. # Channel 서버의 접속량에 따라 가중치를 부여해보자.
Session 서버는, 더 많이 처리할 수 있는 스펙 좋은 Channel 서버나 접속량이 적어 놀고 있는 Channel 서버가 더 많이 할당 되도록 해야 할 것이다.
33. server / A^123.45.67.01:9001 (160)
B^123.45.67.01:9002 (160)
C^123.45.67.01:9001 (160)
D^123.45.67.01:9002 (160)
E^123.45.67.01:9001 (320)
F^123.45.67.01:9002 (320)
G^123.45.67.01:9001 (160)
H^123.45.67.01:9002 (160)
Session Server
Channel Server A
.
.
.
.
zookeeper
Channel Server B
Channel Server C Channel Server D
Channel Server E Channel Server F
Channel Server G Channel Server H
.
.
.
.
watching
123.45.67.01:9001 123.45.67.01:9002
123.45.67.02:9001 123.45.67.02:9002
123.45.67.03:9001 123.45.67.03:9002
123.45.67.04:9001 123.45.67.04:9002
# STEP 3. Weighted Consistent Hashing
Consistent Hashing Ring 에 replica 수가 가중치가 된다.
Default 는 160 개의 relica 가 생성되며,
스펙 좋은 서버는 relica 수를 더 많이 한다.
다른 서버에 비해 CPU 나 메모리 상황이 좋은 서버들 (E, F)
Create Node with Data
zookeeper node 생성시 replica 수를 함께 저장한다.
34. server / A^123.45.67.01:9001 (1)
B^123.45.67.01:9002 (1)
C^123.45.67.01:9001 (160)
D^123.45.67.01:9002 (1)
E^123.45.67.01:9001 (1)
F^123.45.67.01:9002 (320)
G^123.45.67.01:9001 (1)
H^123.45.67.01:9002 (160)
Session Server
Channel Server A
.
.
.
.
zookeeper
Channel Server B
Channel Server C Channel Server D
Channel Server E Channel Server F
Channel Server G Channel Server H
.
.
.
.
watching
Update Node Data
123.45.67.01:9001 123.45.67.01:9002
123.45.67.02:9001 123.45.67.02:9002
123.45.67.03:9001 123.45.67.03:9002
123.45.67.04:9001 123.45.67.04:9002
# STEP 3. Weighted Consistent Hashing
relica 수를 1로 설정하여 Consistent Hashing 을 다시 생성하면, 서버 할당 대상이 되기 희박하다.
(하지만, 같은 채팅방에 Client 접속이 늘어난다면, 계속 할당해주기는 할 것이다.)
Client 의 ConnecXon 이 적은 서버들 (C, F, H)
2500
15
2610
1890
3150
1979
24
32
Client 의 ConnecXon 이
많이 연결된 서버들 (A,B,D,E,G)
channel 서버의 현재 연결된 Client 수가 초기 설정한 임계치를 초과 하면,
zookeeper node 의 데이터(replica 수)를 1 로 수정한다.
현재 ConnecOon 수 (예)
35. # 만약 엄청 유명한 BJ 라면, 한대의 채팅 서버가 감당할 수 없다!
네트워크 비용을 최소화 하기 위해 같은 채팅방의 Client 가 하나의 Channel 서버와 연결한다는 것은..... 사실은 현실적이지 못했다.
‘마리텔’ 을 생각해보자. 박종원 쉐프 방송에 수천명이 접속해 대화 할 것이 아닌가? 이걸 단일 서버에서 처리한다는건 말도 안된다.
(솔직히... 수천명의 대화 내용을 읽는 것도 이해 할 수 없다.)
36. Session Server
Channel Server A
zookeeper
Channel Server B
Channel Server C Channel Server D
Channel Server E Channel Server F
Channel Server G Channel Server H
.
.
.
.
watching
create Node
123.45.67.01:9001 123.45.67.01:9002
123.45.67.02:9001 123.45.67.02:9002
123.45.67.03:9001 123.45.67.03:9002
123.45.67.04:9001 123.45.67.04:9002
REDISPUB
SUB ‘G’
123.45.67.05:9001
kimeve 채팅방 접속 Clients
PUB
SUB ‘C’
PUB
# STEP 4. Sharing messages between distributed servers
채팅방당 최대 연결 가능 수를 임계치로 설정하고, 초과 하면 다른 Channel 서버에 접속하도록 한다. 어쩔 수 없다 ㅠ,.ㅠ
Channel 서버간 통신은 Redis 의 Pub/Sub 을 사용한다.
채팅방 당 최대 400 까지
Channel 서버가 Startup 될 때 Redis 에 서버ID 를 키로하여
Subscribe 한다.
Channel 서버 C 는 총 ConnecOon 1,300 중
kimeve 채팅방이 ConnecOon 400 으로 임계치를 초과 했다!
그러므로, Session 서버는 다른 새로운 Channel 서버를 할당해 준다.
37. # 드디어, 정말 부하 분산이 잘될 것이다!
표준편차도 계산해본 Consistent Hashing 을 적용했을 뿐더러, 서버 부하 상황에 따라 가중치도 자동 조절 되도록 했다!
최대한 네트워크 비용을 줄였다! 같은 채팅방에 접속한 Client들은 모두 같은 서버에 접속하기 때문에, 하지만 Client 가 너무 많으면 어쩔 수 없이 나누긴 했지만 말이다.
38. # 그런데. 이상하다!
여전히 하나의 서버에 몰릴 때가 있다.
이정도라면, 할만큼 한거 아닌가? ㅠ ,. ㅠ
39. # STEP 5. Changing replica quanRty SOFTLY
Channel 서버는 ConnecOon 수에 따라 Session 서버가 분배를 유연하게 할 수 있도록 해야 한다.
그래서, Channel 서버는 ConnecOon 수에 따라 Replica 수를 결정하여 Consistent Hashing 을 상황에 따라 수시로 최적화 해야 한다.
server / A^123.45.67.01:9001 (1)
B^123.45.67.01:9002 (1)
C^123.45.67.01:9001 (160)
D^123.45.67.01:9002 (1)
E^123.45.67.01:9001 (1)
F^123.45.67.01:9002 (320)
G^123.45.67.01:9001 (1)
H^123.45.67.01:9002 (160)
Session Server
Channel Server A
.
.
.
.
zookeeper
Channel Server B
Channel Server C Channel Server D
Channel Server E Channel Server F
Channel Server G Channel Server H
.
.
.
.
watching
Update Node Data
123.45.67.01:9001 123.45.67.01:9002
123.45.67.02:9001 123.45.67.02:9002
123.45.67.03:9001 123.45.67.03:9002
123.45.67.04:9001 123.45.67.04:9002
Client 의 ConnecXon 이 적은 서버들 (C, F, H)
2500
15
2610
1890
3150
1979
24
32
Client 의 ConnecXon 이
많이 연결된 서버들 (A,B,D,E,G)
channel 서버의 현재 연결된 Client 수가 초기 설정한 임계치를 초과 하면,
zookeeper node 의 데이터(replica 수)를 1 로 수정한다.
# STEP 3. Weighted Consistent Hashing ? 이제는.. 160 에서 바로 1 로 줄어드는것이 문제다!
40. SCALE 60
BUFFER 10
MAX_LEVEL 4
REPLICA_BASE_NUM 4
Channel 서버의 ConnecOon 수에 따라 Replica 수를 결정하는 변수를 정하자!
ConnecOon 수 증가
SCALE : 60
600 120 180 240
Replica 수 변화의 단계
50 70 110 130 230 250170 190
BUFFER : 10
Replica 수를 결정하는 모수
Channel 서버의 ConnecOon 수 임계치 결정 모수
Channel 서버의 ConnecOon 수 임계치 변경 버퍼
ConnecOon 수 : 1 ~ 70
Replica 수 는 = REPLICA_BASE_NUM ^ LEVEL
Replica = 4^4 = 256
ConnecOon 수 : 70 ~ 130
Replica = 4^3 = 64
ConnecOon 수 : 130 ~ 190
Replica = 4^2 = 16
ConnecOon 수 : 190 ~ 250
Replica = 4^1 = 4
ConnecOon 수 : 250 ~
Replica = 4^0 = 1
ConnecOon 수 : 50 ~ 0
Replica = 4^4 = 256
ConnecOon 수 : 110 ~ 50
Replica = 4^3 = 64
ConnecOon 수 : 170 ~ 110
Replica = 4^2 = 16
ConnecOon 수 : 230 ~ 170
Replica = 4^1 = 4
ConnecOon 수 : ~ 230
Replica = 4^0 = 1
# STEP 5. Changing replica quanRty SOFTLY
예
시
41. SCALE 60
BUFFER 10
MAX_LEVEL 4
REPLICA_BASE_NUM 4
Channel 서버의 ConnecOon 수에 따라 Replica 수를 결정하는 변수를 정하자!
Replica 수 변화의 단계
Replica 수를 결정하는 모수
Channel 서버의 ConnecOon 수 임계치 결정 모수
Channel 서버의 ConnecOon 수 임계치 변경 버퍼
# STEP 5. Changing replica quanRty SOFTLY
server / A^123.45.67.01:9001 (4)
B^123.45.67.01:9002 (256)
C^123.45.67.01:9001 (64)
D^123.45.67.01:9002 (256)
E^123.45.67.01:9001 (64)
F^123.45.67.01:9002 (256)
G^123.45.67.01:9001 (256)
H^123.45.67.01:9002 (1)
config / SCALE (60)
BUFFER (10)
MAX_LEVEL (4)
REPLICA_BASE_NUM (4)
Session Server
Channel Server A
zookeeper
Channel Server B
Channel Server C Channel Server D
Channel Server E Channel Server F
Channel Server G Channel Server H
watching
watching
update Node Data
123.45.67.01:9001 123.45.67.01:9002
123.45.67.02:9001 123.45.67.02:9002
123.45.67.03:9001 123.45.67.03:9002
Channel 서버는 ConnecOon 수와 설정 변수를 바탕으로
replica 수를 변경하여 Zookeeper 데이터를 갱신한다.
그리고, replica 수가 변경되면
Session 서버가 Consistent Hashing 을 재구성 한다.
zookeeper 의 데이터를 수정하면,
모든 Channel 서버의 설정값이 모두 일괄 변경된다.
42. # 이상하게 복잡해 보이지만 . . .
그냥, Replica 수를 천천히 조절하며 Consistant Hashing 을 최적화 하는 거임.
43. # github.com/xpush/node-‐xpush 에서 구현하고 있는데...
정리가 다 되려면, 추석은 지나야 될 듯.
명절에는 고향에서 코딩이죠!!
xpush.io@gmail.com
2015.08
프로젝트 관련 문의는 yohany@gmail.com 로 주세요.