출처 : https://twitter.com/tencentcloud

Tencent Global Digital Ecosystem Summit

IT업계에 종사하는 사람들에게 대표적인 IT컨퍼런스를 꼽으라 하면 AWS Summit이 빠지지 않을것 이다. 그만큼 규모도 가장 크고 많은 명사들이 진행하는 테크세션이 있기 때문일 것인데, Tencent Cloud에는 이런 행사가 없나 생각하고 있던 차에 Tencent Global Digital Ecosystem Summit 2023 이 개최된다는 소식을 들었고 감사하게도 참관할 수 있는 기회를 얻었다. 9월 7일,8일 양 일간 개최된 행사에 나는 둘째 날만 참석을 했고 이 글은 행사 참관 전 과정을 주관적으로 기록하였다.

행사명 : Tencent Global Digital Ecosystem Summit
개최일 : 2023/09/07 ~ 2023/09/08
개최장소 : 중국 심천 (Shenzhen World Exhibition & Convention Center)

 
 

행사장

 

 
행사 둘째 날, Summit이 열린 Shenzhen World의 모습. 가까이 찍어서 사진으로는 체감이 잘 안되는데 정말 넓다. 택시에
서 내려서 정말 한참을 걸어야했다.
 
 

 
 
 

행사장 내부는 1, 2층으로 구성되어 있고 작은 소회의실 마다 테크세션이 진행 중이었다.
 
 

 

 
 
 
 
 
 
 
 
 

테크세션

내가 참석한 둘째 날에는 28개의 세션이 열렸는데, Tencent에서 준비한 각종 기술세션 외에  Intel, NVIDIA 등 스폰서들의 프레젠테이션도 있었다.

이것 이외에 더 많은 세션이 있다.

 
 

이 중에서 내가 들은 세션은 자체 생성형AI 챗봇을 개발한 업체가 어떻게 Tencent Cloud의 상품을 통해 워크로드를 구축했는지 설명하는 세션과, Tencent Cloud와 중국 금융 서비스와의 성공적인 결합사례를 소개해주는 발표였다. 

 
 

발표는 중국어로 진행되었다. 어렸을 때 삼국지를 열심히 읽을 걸 그랬다.

 
 

세션마다 사람이 정말 많았다.

 
 
 
 
몇 개의 발표를 들으면서, Tencent Cloud가 중국에서 어떤 위치를 차지하고 있고 IT, 금융, 제조, 엔터테인먼트 등 다양한 산업 분야에 걸쳐 어떻게 활용될 수 있는지를 알게되었다. 또한 Tencent Cloud가 단순한 클라우드 서비스를 제공하는 역할을 넘어, 다양한 산업 분야에서 혁신을 주도하고 있는 글로벌 리더로서의 위치를 확고히 하고 있음을 느낄 수 있었다.
 
 
 

 
 
 
 
 
 
 
 
 
 
 

파트너 & 스폰서 부스체험

 
 
 

 세션을 듣고 아래층으로 내려가니 Tencent Cloud 파트너 사들의 부스가 꾸려져 있었다. 본 행사는 NVIDIA가 메인 스폰서로 참여했는데, 그래서 그런지 입구에 NVIDIA 부스가 눈에 먼저 띄었다. 사실 이런 부스에서 나눠주는 경품, 스티커, 브로슈어 등을 수집하고 다니는 것도 컨퍼런스의 묘미라.. 이때부터 물욕이 발동해서 이것저것 모으러 다닌 것 같다. 
 
 

 
 

엔비디아 부스에서는 NVIDIA의 Wechat official account를 팔로우한 뒤 몇 가지 개인정보를 입력하면 엔비디아 로고가 크게 박힌 에코백 같은 걸 나눠주는 행사를 했는데 내 개인정보보다 엔비디아 에코백이 더 가치 있는 것 같아서 망설임 없이 그들이 원하는 걸 주고 에코백을 받아왔다.

 
 
 
 
 

엔비디아 주가가 오름에 따라 점점 더 값어치가 있어지는 듯하다

 

 
 
 
 
 

 
 
서브스폰서로 참여한 인텔과 AMD의 부스. 아직 본격적으로 오픈을 안 해서 그런지 한산했다. 득템할 게 없어보여서 가볍게 지나쳤다.
 

물욕주머니를 얼굴에 한 가득 달고 다녀서 그런지 다들 나에게 눈길도 주지 않는 모습이다.

 
 
 
 
 
 
 
 
 
 

점심식사

누구보다 빨리 식당에 도착한 모습

 
 
AWS Summit에서도 사전등록하면 점심쿠폰을 줘서 도시락 같은 것을 먹었던 기억이 나는데 여기서도 점심식사를 제공해줬다. 본격적으로 행사부스를 돌아다니려면 체력이 필수이니 밥부터 먹었다.
 
 

이 날 첫 끼였다.

 
 
도시락을 받을 수 있었는데 메뉴도 고를 수 있고 맛있었다. 5분 만에 다 먹은 기억이 난다.
 
 
 
 
 
 
 
 

Tencent Cloud 홍보 부스

 
 
점심시간이 끝나고 다시 행사장으로 돌아왔다. 위의 사진 속 입구로 들어가면 Tencent Cloud의 상품팀에서 준비한 홍
보 부스 및 체험 섹션이 있었다. 
 
 

저 큰 차들을 어떻게 여기까지 들여놨을까

 

 
입구로 들어가니 제일 먼저 눈에 띈 자동차. 찾아보니 중국 전기차 브랜드 비야디의 하이엔드 라인이라고 하는데 Tencent 와 어떤 합작을 했나보다. 아마 차 안에 들어가는 소프트웨어 개발이나 탄소중립 같은 환경적 주제로 협력하지 않았나 싶다. (잘 모름) 
 
 

 
 
이 곳은 중국의 전자정부 서비스를 텐센트의 기술로 구현한 数字政务 서비스에 대한 안내를 해주는 부스였다. 우리나라의 정부24같은 솔루션이라고 이해했다.
 
 

 
 
옆에는 이렇게 빅데이터에 관한 코너도 있었고..
 

 
 
 

Tencent Cloud의 데이터베이스 상품에 대한 부스도 있었다. 텐센트클라우드의 완전관리형 데이터베이스에 대한 설명이 안내되어 있었고
 
 

 
 
이렇게 간단한 SQL문도 직접 작성해서 쿼리를 날려볼 수 있는 체험코너도 있었다.
 
 
 

????

 
 
 

그런데 이 부스 한 켠을 보면 저렇게 작고 귀여운 펭귄인형들이 밀봉(?) 되어있는걸 발견할 수 있다. 알고보니 스탬프 행사를 진행 중이었다. 
 
 
 
 

 
총 6개의 이벤트 부스가 있고 사진 속 이벤트 용지를 들고 방문하면 스탬프를 찍을 수 있는데 1, 4, 6번째 스탬프를 받을 때 펭귄인형을 하나씩 받을 수 있다. 다 모으면 특별상품을 주는 것 같았다.
 
 

 
 
 

다음 글에 계속 >>

 
 
 

 
 

 

 

Analysis

고객사는 글로벌 전자상거래 플랫폼으로 전 세계 고객들에게 상품을 판매하는 플랫폼을 운영하는 기업입니다. 내년을 목표로 새로운 지역에 서비스를 확장 오픈 하려는 계획을 가지고 있습니다. 타깃 지역에 대한 예상 고객 분석결과 클라우드 도입이 유리하다는 결론을 내린 상태입니다. 그러나 이미 IDC에 구축된 백엔드 시스템에 많은 도메인이 얽혀있어 복잡하고, 보안 문제가 존재하여 기존 IDC 리소스를 클라우드 VPC와 연결하는 아키텍처를 구축하길 원하는 상황입니다.

 

Architecture Blueprint

1) VPC 내에 3개의 가용 영역(AZ)을 설정하여, 각각에서 클래식한 N-tier 아키텍처를 구현합니다. 웹, 애플리케이션, 데이터베이스 레이어가 서브넷으로 구성되어 각각의 역할을 수행합니다. 정적 컨텐츠에 대한 전송은 EdgeOne을 통해 가속하여 전 세계 구매자에게 빠른 접근성을 제공합니다.

2) CLB는 각 레이어간 로드를 효율적으로 분산시키며, 추후 사업 규모 확대에 따라 탄력적인 리소스 관리를 위한 Auto-Scaling 도입을 고려할 수 있습니다.

3) 플랫폼의 빠른 구매 데이터 처리를 위해 Tencent DB for Redis를 인메모리 캐싱 데이터베이스로 선택합니다. 데이터베이스 레이어의 TencentDB for MySQL은 가용 영역별로 재해 복구 목적의 읽기 및 쓰기 복제본을 구성하여 고가용성을 확보합니다. 이는 구매자의 사용자 경험을 개선하고 데이터 처리 속도를 높이는 데 기여합니다.

4) COS를 통해 높은 I/O를 요구하는 데이터를 저장합니다. COS는 다양한 데이터 유형의 저장과 관리에 적합하며, 전자상거래 플랫폼의 이미지, 동영상, 사용자 데이터 등을 효율적으로 처리하는 스토리지 서비스입니다.

5) 고객사 플랫폼의 안정적인 운영과 데이터 동기화를 위해, IDC와 VPC 간에는 4개의 Direct Connect 연결과 2개의 액세스 포인트를 설계합니다. IDC1과 IDC2는 동일지역 IDC로, 단일 연결이 아닌 위와 같은 네트워크 연결방식을 통해 고가용성 보장합니다. 액세스 포인트의 DC연결은 각각 primary - secondary 구성으로 한쪽 연결에 문제가 발생하더라도 다른 연결을 통해 서비스의 연속성을 유지할 수 있습니다. 

6) 문제는 역시 비용입니다. 전용 회선을 이용하는 네트워킹 특성상 고가용성만을 고려한 설계 시 고객사가 비용 면에서 만족하지 못할 수도 있습니다. 이때는 1개의 액세스 포인트로 Primary-secondary 연결을 하거나 단일 연결을 하는 설계를 차선책으로 제안할 수 있습니다.

 

Overall

 

 고객사의 클라우드 아키텍처는 N-tier 아키텍처를 기반으로, 고가용성과 탄력성을 고려하여 설계되었습니다. IDC VPC 간의 Direct connect 연결은 서비스의 연속성을 보장하는 동시에 데이터 동기화의 안정성을 높입니다. 그러나 고가용성을 위한 네트워크 연결 방식은 비용적인 측면에서 고려가 필요하며, 비용 효율성을 고려한 설계 변경이 필요한 경우에 대비해 유연한 접근 방식을 제안할 있습니다. 경우에 따라 IDC- VPC 간 연결에 VPN을 도입하는 것도 생각해 볼 수 있겠습니다. 

 

Products we used

-Direct Connect : https://console.tencentcloud.com/dc

- CVM : https://console.tencentcloud.com/cvm

- EdgeOne : https://console.tencentcloud.com/teo

- CLB : https://console.tencentcloud.com/clb

- COS : https://console.tencentcloud.com/cos

- TencentDB for MySQL : https://console.tencentcloud.com/cdb

- TencentDB for Redis : https://console.tencentcloud.com/crs

 

 

 

이 글에서는 Tencent cloud의 VPC리소스가 외부 공용 인터넷에 접근하는 방식을
AWS의 internet gateway를 통한 방식과 비교하여 간단하게 설명한다.

 

 

 

 

AWS의 Internet gateway

 

 AWS의 퍼블릭 서브넷이 인터넷에 접속하려면 일반적으로 Internet gateway를 통해야한다. AWS의 공식문서 중 VPC 네트워킹에 관한 토폴로지를 보면 항상 대문처럼 생긴 Internet gateway를 확인할 수 있는데, VPC와 외부 인터넷을 연결시켜주는 통로 같은 느낌으로 꽤나 직관적인 느낌을 준다.

 

 애초에 AWS에서는 퍼블릭 서브넷과 프라이빗 서브넷의 구분을 해당 서브넷이 internet gateway와 직접적으로 연결되어 있는지 여부로 판단한다. 어떤 서브넷이 Internet gateway로 향하는 아웃바운드 트래픽 룰을 포함하고 있는 라우팅 테이블과 연결되어 있으면 그 서브넷을 퍼블릭 서브넷이라고 부르는 것이다.

 

 

서브넷을 생성할 때 부터 public, private 속성을 결정하고,

그에따라 동일VPC 로컬 영역을 제외한 모든 트래픽을 Internet gateway로 내보내는 기본 라우팅 테이블이 자동으로 바인딩 된다.

심지어 퍼블릭서브넷 내부의 인스턴스가 퍼블릭IP를 할당 받은 상태여도 연결된 라우팅 테이블에서 Internet gateway에 대한 룰이 없으면 직접적으로 퍼블릭 네트워크와의 연결이 되지 않는다.

 

In Tencent cloud

하지만 Tencent cloud에서는 다르다. 일단 internet gateway라는 요소 자체가 명시적으로 존재하지 않는다. 따라서 AWS처럼 라우팅테이블의 구성에 따라 public, private 서브넷을 구분하지 않는다. (Tencent cloud 공식문서 어디에도 public subnet과 private subnet이라는 용어가 존재하지 않는다.)


그렇다면 어떻게 외부 인터넷에 접속할까? 

그냥 public IP(혹은 EIP)를 할당하면 된다. Internet gateway가 없기 때문에 (Tencent cloud 공식 문서에 internet gateway라는 용어가 없을 뿐이지 public gateway 등의 단어로 외부 인터넷 연결을 간접적으로 표현하긴 한다.) 

 

별도로 라우팅 룰을 적지 않아도 public IP가 인스턴스에 연결되어있다는 것이 외부 인터넷 엑세스가 가능하다는 의미가 된다.

실제로 Tencent cloud 콘솔에서 라우팅 테이블을 생성할때 목적지 중에 인터넷게이트웨이가 없는 것을 확인할 수 있다.

기본 라우팅 테이블의 경우에도 VPC 내부에 대한 로컬 룰 밖에 없다. 이렇게 되어 있어도 public IP (혹은 EIP)가 인스턴스에 바인딩 되어있다면, Tencent cloud는 자체적으로 해당 인스턴스의 인터넷 연결을 가능하게 한다.  Microsoft Azure의 경우도 비슷하다. Azure도 명시적인 인터넷게이트웨이의 존재가 없고, 라우팅 룰로 public/private 서브넷을 구분하지 않는다.

 

Public subnet / Private subnet

 정리하면, Tencent cloud에서는 internet gateway가 따로 없고 public IP(혹은 EIP)를 VPC네트워크 환경의 인스턴스에 바인딩하면 라우팅 테이블에 별도의 라우팅 룰이 없어도 외부 퍼블릭 네트워크에 접속이 가능하다.

그렇다면 서브넷의 public/private 구분은 어떻게 해야할까?

 AWS에서는 이에 대한 명확한 기준이 있기 때문에, 어떤 서브넷 안에 private IP만을 가진 인스턴스가 몇 개가 존재하든 간에 서브넷에 연결된 라우팅테이블에 internet gateway에 대한 룰이 있다면 그 서브넷은 퍼블릭 서브넷이다.

 Tencent cloud에서는 애초에 둘을 구분짓지 않기도 하지만, 위에서 예를 든 서브넷은 그야말로 둘 중 어느 곳에도 속하지 않는 존재인 것이다. 그러나 일반적으로 외부와의 직접적인 연결이 차단되어있고, NAT gateway를 통한 제한적인 아웃바운드 접속이 가능하게 설계된 서브넷은 프라이빗 서브넷으로 칭하고, 그 외의 서브넷은 퍼블릭하다고 보는 것이 타당할 것이다.

 

마치며

 VPC 네트워킹에서 Internet gateway의 명시적인 존재는 네트워크 트래픽 플로우를 이해하는데 도움이 될 수 있다. 라우팅  테이블을 통한 public 트래픽의 경우도 그렇고 심지어 private subnet에서의 NAT 프로세스를 보면 실제적으로 private IP를 public IP로 변환하는 작업은 NAT gateway가 아닌 Internet gateway에서 일어난다. (AWS의 경우 이 점을 공인문서에서 설명하고 있다.) 

 

 Tencent Cloud는 이러한 AWS Internet gateway가 담당하는 역할을 외부로 드러내지 않고 있다. 따라서 VPC와 서브넷을 생성할때 public/private 속성을 선택하지 않아도 되고, Internet gateway를 포함한 라우팅 룰에 대해 설정할 필요가 없다. 완전히 클라우드를 처음 접하는 사용자들에겐 이 방식이 오히려 쉽게 느껴질 수 있다.

 

 실제로 Tencent Cloud 콘솔을 사용해보면 타 벤더사들에 갖추고 있는 기능들을 모두 가지고 있으면서도 한결 더 간결한 UI와 친절한 사용자경험을 제공하는 것을 체험할 수 있는데 사용자 입장에서는 위와 같은 VPC 네트워킹의 방법을 포함하여 여러 가지 CSP 콘솔 중 장점만을 모아서 최선의 콘솔을 구현하기 위해 계속해서 노력 중 이라는 느낌을 받게 한다. 

 

 

출처 : https://chat.openai.com

ChatGPT Chatbot

 Slack에 ChatGPT를 연동하여 간단한 챗봇을 구현하는 작업은 이미 너무 유명하여 구글링만 해봐도 수 십개의 관련 블로그글이 검색된다. 가장 기본적인 방식은 AWS Lambda를 활용한 구현인데, 이번에 우리는 람다대신 Tencent cloud SCF로 메신저에 ChatGPT 챗봇을 만들어보기로 한다.

 

JANDI

출처 : https://www.jandi.com/landing/kr

 

 이번에는 슬랙 대신 JANDI라는 메신저를 활용할 예정이다. 사내에서 사용하는 메신저를 겸한 협업툴인데

 

 메신저 내에서 이미 '잔디커넥트'라는 자체기능을 지원하고 있다. 기본적인 웹훅 기능뿐 아니라, 아틀라시안 툴이나 깃허브 등을 연동하여 커밋 변경사항이 생기면 메신저를 통해 알람을 받는 것이 가능하다. 슬랙의 경우 인터랙티브 응답 시, 슬랙서버로부터 요청을 받은 후 3초 안에 응답하지 않으면 타임아웃에러가 나도록 설정되어 있는데, 슬랙봇을 호출하고 chatGPT 질의를 거쳐 메시지를 다시 수신하는 과정은 당연히 3초를 초과하기 때문에 추가작업이 필요하다.

 

 따라서 기존 슬랙과 람다를 통한 챗봇구현 방식은 중간에 SQS 등의 큐 서비스를 배치하여 비동기적으로 3초 룰에 대처하도록 설계하곤 하는데 잔디는 그런 타임아웃 제한이 없기 때문에 잔디 사용 시 아키텍처가 좀 더 간단해진다는 장점이 있다.

 

 또한 잔디 공식 블로그에서는 업무 자동화 툴인 zapier와 ChatGPT를 연동하는 방법을 자세히 소개하고 있는데(https://blog.jandi.com/ko/2023/03/15/how-to-chatgpt-like-a-pro/) 이 글에서는 zapier대신 Tencent cloud SCF와Tencent cloud API Gateway를 사용하는 방법을 소개한다.

 

아키텍처

 

대략적인 아키텍처는 아래와 같다.

잔디에서 '/' 기호를 붙여 챗봇을 호출하고 질문을 던지는 이벤트를 발생시키면 잔디의 웹훅으로 Tencent cloud API Gateway를 호출하고 해당 API Gateway를 트리거로 하는 SCF 코드가 실행되면 (SCF에는 ChatGPT에 질문을 던지고 대답을 리턴하는 코드를 구현한다.)  SCF는 리턴 값(챗gpt의 응답)을 잔디 수신 웹훅 URL로 전달하면 채팅창에 응답이 뿌려지는 과정이다. 

 

JANDI 발신 Webhook 설정

 

 JANDI 메신저에서 잔디 커넥트 부분 설정을 클릭하면 Webhook 발신 / Webhook 수신 두 개의 메뉴가 있다. Webhook 발신을 클릭하면 간단한 파라미터를 입력할 수 있고 챗봇이 생성될 토픽방을 선택하면 시작 키워드를 입력할 수 있다. 여기서 입력한 키워드 앞에 '/'기호를 붙이면 챗봇이 호출되는 방식이다.

 

 일반적으로 /chatgpt라는 호출 키워드를 많이 사용하지만 사내 직원들의 손쉬운 사용을 위해 /말동무라는 한글 키워드로 설정하였다. 마지막에 URL을 입력하는 부분이 있는데 여기에 뒤에서 생성할 API Gateway의 엔드포인트를 입력하면 된다.

 

다음으로 Webhook 수신 메뉴를 클릭해 보면 Webhook URL이 자동생성되는데 이 URL을 복사해 둔다. 나중에 SCF 코드 내에서 사용하게 된다.

SCF 함수 생성

순서상으로는 API부터 만들고 SCF 코드를 작성해야 하지만 API 생성 시 SCF를 트리거로 하려면 사전에 SCF가 생성되어 있어야 하기 때문에 미리 기본 SCF를 생성하는 작업을 한다.

 

Tencent cloud Serverless Cloud Function 콘솔에서 Function Service 항목에서 Create를 클릭한다.

 

 

Create from scratch를 선택한 뒤 Function type : Event-triggered function으로 설정하고 나머지 항목은 적절히 잘 입력한다. 입력이 완료되고 Complete를 누르면 SCF 생성완료.


API Gateway

다음은 잔디의 Webhook을 호출받을 API를 만들 차례다. Tencent cloud API Gateway 콘솔에 접속해서

 

Service 항목을 클릭한 뒤 API Gateway를 생성한다.

 

 

생성한 API Gateway를 클릭하고 Related APIs 항목에서 Create를 눌러 API 생성 메뉴를 띄운다.

 

 

Frontend type은 HTTP&HTTPS , Request method는 POST로 설정한다. path는 API엔드포인트 도메인 뒤에 붙을 경로를 의미하는데 적당히 네이밍 하면 된다. 여기서는 간단하게 JANDI2로 설정하였다.

 

다음 단계에서 Backend type은 SCF로 선택한 뒤 생성한 SCF함수를 선택한다. 이때 Function type은 Event-triggered function으로 한다.

 

마지막 단계에서 리턴 타입을 JSON으로 하고 API 생성을 완료한다.

 

 생성완료된 API의 정보를 확인하면 public domian API 엔드포인트를 얻을 수 있다. API호출 URL은 public domain + Access path 가 된다. 이미 본인이 보유하고 있는 다른 도메인을 바인딩해서 사용해도 되지만 테스트 단계이므로 일단 제공된 URL을 그대로 사용하기로 한다. 이 URL을 아까 전 JANDI 발신 Webhook 설정에서 URL을 입력하는 부분에 입력하면 된다.

OpenAI API Key 발급

 

이제 SCF 코드를 작성하기 전에 chatGPT API를 사용하기 위한 API Key를 발급받아야 한다.
OpenAI API Key 발급 URL (https://platform.openai.com/api-keys)로 이동해서 Secret Key를 생성하면 된다.

 

SCF 코드 작성


SCF 코드는(Nodejs기준) 총 3 부분으로 구성된다. 잔디로부터 메시지를 수신하여 chatGPT서버로 보낼 엔드포인트와 응답 값을 되돌려줄 잔디 측 수신처의 메타데이터는 모두 해당 OpenAI, JANDI의 공식 문서를 참고하여 작성하였다.

const express = require('express');
const axios = require('axios');
const serverless = require('serverless-http');
const app = express();
app.use(express.json());



app.post('/JANDI2', async (req, res) => {
  try {
    const userMessage = req.body.text; 
    const openaiResponse = await axios.post(
      'https://api.openai.com/v1/chat/completions',
      {
        model: 'gpt-3.5-turbo',
        messages: messages,
      },
      {
        headers: {
          'Authorization': `Bearer <OpenAI에서 발급받은 키 입력>`,
        },
      }
    );

POST요청을 통해 전달받은 메시지를 API Key와 함께 ChatGPT에게 전달한다.

    const chatGptMessage = openaiResponse.data.choices[0].message.content;

ChatGPT의 응답을 받아서

    await axios.post('<JANDI Webhook 수신 URL 입력>', {
      body: chatGptMessage,
    }, {
      headers: { 'Accept': 'application/vnd.tosslab.jandi-v2+json', 'Content-Type': 'application/json' },
    });


  } catch (error) {
    console.error('Error:', error);
    res.status(500).send({ error: 'Internal Server Error' });
  }

});

module.exports.main_handler = serverless(app);

 

잔디 Webhook 수신 URL로 던진다. 이때 성공(200) 케이스의 메시지의 경우 send 하면 매 번 챗봇을 호출할 때마다 잔디 메시지 창에 그대로 노출되므로 제외한다.

 

결과물 (...🤔)

/말동무를 사내 채팅방에서 호출하여 질문을 던져 본다.

 

정상적으로 응답이 오가는 걸 확인할 수 있지만 만족스럽지 않다.

 

가만 살펴보면 바로 전에 나눈 대화의 내용도 기억하지 못하고 있다. 그도 그럴 것이 SCF에 작성한 코드를 보면 단일 대화 이벤트에 대한 처리 이외에 이전 대화 히스토리를 유지하고 있는 부분이 빠져있다. 따라서 유저가 챗봇에 질문을 던질 때마다, 메모리 영역에서 이 대화를 히스토리에 추가하고, 질문을 할 때 이 히스토리를 ChatGPT에 통째로 전달하고 ChatGPT의 응답도 히스토리에 추가하여 전달한다. 예를 들면 이런 식이다.

유저 : 내 이름은 철수야
챗봇 : 네 철수님.

 

기존에는 위의 대화가 끝나고 새로운 질문을 던지면 독립적인 새 질문으로 전달되었지만, 이제는 새 질문을 입력하면 아래의 히스토리가 chatgpt에게 전해진다.

유저 : 내 이름은 철수야
챗봇 : 네 철수님.
유저 : 내 이름이 뭐랬지?

 

이전 대화 내용까지 다음 대화내용으로 전달하여 대화의 맥락을 기억하도록 전체 코드를 개선한다.

const express = require('express');
const axios = require('axios');
const serverless = require('serverless-http');
const app = express();
app.use(express.json());

let conv = {}; //대화 히스토리 저장


app.post('/JANDI2', async (req, res) => {
  try {
    const userMessage = req.body.text; 
    const uniqueID = req.body.senderId; // 대화 히스토리 식별자

    // 대화 히스토리 리콜
    const messages = conv[uniqueID] || [];

    messages.push({ role: 'user', content: userMessage });

    const openaiResponse = await axios.post(
      'https://api.openai.com/v1/chat/completions',
      {
        model: 'gpt-3.5-turbo',
        messages: messages,
      },
      {
        headers: {
          'Authorization': `Bearer <OpenAI 키 입력>`,
        },
      }
    );

    const chatGptMessage = openaiResponse.data.choices[0].message.content;

    // 대화 이력 업데이트
    messages.push({ role: 'assistant', content: chatGptMessage });
    conv[uniqueID] = messages;


    await axios.post('<잔디 Webhook 수신 URL 입력>', {
      body: chatGptMessage,
    }, {
      headers: { 'Accept': 'application/vnd.tosslab.jandi-v2+json', 'Content-Type': 'application/json' },
    });


  } catch (error) {
    console.error('Error:', error);
    res.status(500).send({ error: 'Internal Server Error' });
  }

});

module.exports.main_handler = serverless(app);

 

개선된 말동무의 지능

다시 챗봇을 호출하여 말을 걸어보면

 

개선된 지능을 확인할 수 있다. 

 

마치며

 ChatGPT와 서버리스를(Tencent Cloud SCF) 활용한 기본적인 챗봇을 구현해 보았다. 기존에 람다를 사용하던 사용자들도 별도의 학습 없이 함수를 생성할 수 있도록 콘솔이 잘 구성되어 있다.

 현재 JANDI에서는 일반회원 권한으로는 해당 기능을 적용하더라도 특정 토픽방에서만 사용이 가능하다.  '나와의 대화' 같은 공간에서 사용하기 위해서는 기업형 구독과 관리자 권한이 필요하니 참고한다.

 



참고사항

정상적으로 구현을 하더라도 로그에 429 에러가 찍히면서 응답이 오지 않을 수 있다. 이럴 때는 OpenAI의 API 사용을 위한 크레딧이 충전되지 않아서 그런 경우이니 사이트에서 금액을 충전해야 한다. 

 

충전 후에는 충전 이전에 발급받았던 API Key는 유효하지 않으니 새로 Key를 발급받아서 SCF 함수에 적용시켜야 한다.

 

 

 

ENI

 ENI(Elastic Network Interface)는 VPC 환경에서 가상 네트워크의 역할을 하는 논리적 네트워크 구성 요소로 온프레미스  환경에서 사용되는 NIC(Network Interface Card)에 대응되는 개념이다. 이 글에서는 Tencent cloud VPC 콘솔을 통해 ENI에 대한 개념을 설명한다.

 

ENI와 서브넷의 관계

ENI을 생성하려면 먼저 서브넷이 있어야 한다. ENI는 서브넷에 속하는 요소이며  서브넷은 VPC생성을 전제로 하니 다음과 같은 포함관계를 가진다.

 

Tencent cloud 콘솔에서 ENI를 생성 시 먼저 VPC와 Subnet을 선택해야 하는 것을 알 수 있다.

CVM 인스턴스와 ENI

 위에서 ENI는 넓게 보면 VPC에 속하는 것으로 설명했다. 즉, Tencent cloud에서 어떤 리소스가 VPC네트워킹의 자격을 얻으려면 해당 자원이 ENI에 연결되어 있어야한다. 따라서 CVM 인스턴스를 생성할때 기본적으로 1개의 ENI가 자동으로 연결된다. 이를 Primary ENI라고 한다. CVM 생성 시 인스턴스에 붙어있는 기본 Primary ENI는 unbound할 수 없다. 

 

 그렇다고 1개의 인스턴스에 1개의 ENI만 연결될 수 있는 것은 아니다. 우리가 컴퓨터에 여러개의 랜카드를 꽂는 것 처럼 1개의 인스턴스에는 여러개의 ENI와 바인딩 될 수 있다. 최대 연결 가능한 ENI의 갯수는 CVM Configuration 마다 차이가 있다. (참고 : https://www.tencentcloud.com/document/product/576/18527?from_cn_redirect=1)

 반대로 1개의 ENI에 여러 개의 인스턴스를 바인딩 하는 것은 가능할까? 불가능하다. 

 

 1개의 ENI는 한 번에 1개의 인스턴스에만 바인딩 될 수 있다. 인스턴스를 우리가 타는 택시라고 가정하고 ENI를 승객에 비유해보면 이해가 쉽다. 1대의 택시에는 여러 명의 손님이 동시에 탈 수 있지만, 1명의 손님이 여러 대의 택시에 동시에 탈 수는 없다. (상반신은 이쪽 택시에, 하반신은 저쪽 택시에, 하지 않는 이상..)

 

Security group 과 ENI

VPC 환경의 인스턴스를 생성할때 자동으로 기본 Security group과 사설 IP가 할당되는 걸 알 수 있는데, 이들 또한 인스턴스에 할당된 ENI에 연결되는 요소들이다. 같은 의미로,  1개의 ENI는 반드시 1개의 Security group을 가진다는 걸 알 수 있다.

 

 그렇다면 1개의 ENI는 여러 개의 Security group과 동시에 연결될 수 있을까? 가능하다. 

 

 1개의 CVM 인스턴스가 여러 개의 보안그룹 룰의 통제를 받을 수 있는 것과 같다.

Tencent cloud 콘솔에서도 특정 ENI에 여러개의 Security group 연결이 가능한 것을 확인할 수 있다. 이로 인해 VPC 네트워킹에서 보안정책을 좀 더 유연하게 관리할 수 있다.

 

ENI의 독립성

이렇게 보면 ENI가 굉장히 의존적인 것 같지만 그렇지 않다. ENI는 어느 인스턴스와도 연결되지 않아도 된다. 생성 전제조건인 VPC와 서브넷만 지정해주면 ENI 구성의 필수요소들 (Security group, MAC address, private IP)을 지닌채로 독립적으로 존재할 수 있다. 인스턴스에 연결되지 않은 ENI는 그 자체로는 어떠한 의미도 가지지 않을 뿐이다.

 

 

IP Address 와 ENI

CVM 인스턴스를 생성하면 인스턴스에 할당된 ENI에 랜덤하게 private IP가 부여된다. 이것이 곧 인스턴스의 private IP라고 볼 수 있다. 개별 ENI가 보유할 수 있는 private IP의 갯수는 CVM configuration에 따라 최소 6개에서 최대 30개이다. (https://www.tencentcloud.com/document/product/576/18527?from_cn_redirect=1)

 

Tencent cloud 에서 ENI 정보를 보면 부여된 private IP들을 확인할 수 있다. primary ENI의 primary IP(private)는 ENI 생성 시 ENI가 속한 서브넷의 CIDR 블록 내의 IP 값에서 랜덤한 값으로 설정되고, Secondry IP는 auto-assign이 가능하다. 추가로 생성되는 ENI (Secondary ENI)는 primary IP부터 auto-assign이 가능하다.

 

참고 : primary ENI의 primary IP는 추후 수정이 가능하지만, Secondary ENI의 primary IP는 수정이 불가능하다.

 

 

추가 Private IP

Primary ENI 의 primary IP (private) 를 제외한 나머지 private IP의 경우 assign 후에 해당 OS의 네트워크 설정을 통해 IP를 직접 추가해줘야 한다.

 

 

Tencent cloud ENI 콘솔에서 ENI를 생성하여 CVM와 연결하고

 

 

새로운 private IP (192.168.3.7)을 ENI에 할당한 뒤 동일 VPC 환경 내에서 해당 IP로 접속을 시도하면 접속이 안된다.

 

현재 ENI에 새로운 private IP(192.168.3.7)가 configure이 되어 있지 않아서 그렇다.

ip addr add <추가할 private IP> dev eth0

//이때 private IP는 서브넷 마스크까지 모두 입력해야 한다.

새 private IP를 추가하면

 

Private IP가 configure 된 모습을 확인할 수 있다. 이제 접속을 다시 시도하면 정상적으로 접속이 될 것이다. 이번엔 새로 Secondary ENI를 추가하여 private IP를 설정해보자.

 

ENI를 생성한 뒤 인스턴스와 바인딩 한 뒤 서버에서 확인하면

 

새로 추가한 ENI가 인식되는 걸 볼 수 있다. (eth1)

 

같은방법으로 Secondary ENI의 primary IP (192.168.3.12) 를 추가하면 된다. (이때 다른 ENI에 할당을 해도 OS계층에서 네트워크 설정을 변경한 셈이기 때문에 통신에는 문제가 없지만 되도록 콘솔설정과 같은 ENI에 매핑하는 것이 좋다.)

 

 

마치며

ENI는 VPC 네트워킹의 핵심 요소이고 VPC 네트워크 환경을 제어하는 리소스 이지만 라이트한 클라우드 유저나 혹은 자주 클라우드를 사용하는 사람들도 ENI에 대해 간과하고 넘어가는 경우가 많다. 사실 ENI에 대한 깊은 이해 없이도 서브넷과 VPC에 대한 간단한 개념만 있다면 콘솔을 통해 클라우드 리소스를 생성하고 VPC 네트워크 환경을 구성하는데에 큰 무리가 없기 때문이다. 또한 ENI는 단독으로 비용이 부과되는 서비스도 아니니 더욱 그렇다. 그러나 ENI는 VPC 네트워킹에서 빼놓을 수 없는 요소이기에 ENI를 이해하면 VPC를 좀 더 폭 넓게 활용할 수 있을 것 이다.

 

 

 
 

 

 

CHAT?

CHAT은 소셜 커뮤니케이션, 고객 서비스 메시징, 챗봇, 온라인 학습, 라이브 스트리밍, 대화형 게임, 웹 3, 음성 및 화상 통화 앱 또는 웹사이트 구축을 위한 확장 가능하고 빠른 API, SDK 및 UIKit이다. (참고: https://www.tencentcloud.com/products/im)

 

 텐센트클라우드 공식 홈페이지에서 소개하고 있는 CHAT의 기능이다. 한 마디로 카카오톡,텔레그램 같은 메신저 앱이나 인스타그램이나 틱톡같은 라이브스트리밍 기능을 지원하는 앱을 손쉽게 개발할 수 있도록 API나 SDK를 제공해주는 서비스라고 보면된다.

 

Demo (Messenger)

 

 CHAT의 상세한 기능 및 시나리오, 실제 사용사례 등은 텐센트클라우드의 관련 상품링크에 한글로 자세히 설명 되어있으니 (글 마지막 참고자료 링크참조) 참고하면 된다.

 

 CHAT에서는 정식 서비스 사용 전에 미리 개발자들이 프로그램을 구현해 볼수 있도록 Web, iOS, android 환경에서 Demo를 제공하는데, 이번에는 이 Demo들을 체험해보기로 했다. 텐센트클라우드 공식 홈페이지와 깃허브를 참고하여 iOS 환경에서의 채팅SDK와 Web환경(React)에서의 Web Live 데모를 구현한다.

 

SDKAppID와 Secret Key 얻기

 

CHAT 콘솔에 접속해서 Application management , Create Application을 차례로 클릭하여 애플리케이션을 생성한 뒤 생성한 애플리케이션 이름을 클릭하면 위와 같은 Application Details 창이 뜨는데, 여기서 SDKAppID  Secret Key를 얻는다.

 

iOS Demo 설치

1) 깃허브 CHAT Demo 설치링크 (https://github.com/TencentCloud/TIMSDK)를 클론하여 내려받는다.

git clone https://github.com/TencentCloud/TIMSDK

 

2) 다음은 iOS/Demo/TUIKitDemo/Private 하위 경로에 위치한 GenerateTestUserSig.h 파일을 편집기로 실행하고 static const int public_SDKAPPID = 0; , static NSString * const public_SECRETKEY = @"";의 값을 각각 위에서 얻은SDKAppID Secret Key로 변경한다.

static const int public_SDKAPPID = <SDKAppID>;
static NSString * const public_SECRETKEY = @"<Secret Key>";

 

cocoaPods 패키지관리자 설치가 필요하다.

pod --version

 

버전 확인 후 설치가 되어있지 않다면 설치한다. macOS 기준으로 homebrew를 이용하였다. 

$ brew cleanup -d -v
$ brew install cocoapods
$ pod setup

 

3) iOS/Demo 경로에서

 

다음 스크립트로 설치를 진행한다.

pod install
// 설치에러가 뜬다면 
pod repo update //를 통해 코코아팟 최신 버전 정보를 업데이트 한다.

 

**그래도 설치가 안된다면 같은 경로에서 CocoaPods 의존성 관리 파일인 Podfile.lock를 찾아 삭제 한뒤 다시 시도한다.

 

4) 패키지 설치가 완료되면 TUIKitDemo.xcworkspace파일을 Xcode로 불러오면 데모가 실행된다.

 

채팅 기능

 

설치된 데모코드를 보면 정말 채팅 앱을 위한 모든 기능이 구현되어 있다. 

 

Xcode에서 시뮬레이터를 Run하면 Tencent CHAT아이콘을 확인할 수 있다.

 

직접 시뮬레이터로 데모를 실행한 모습.

 

굳이 코드를 수정하지 않고도 데모가 CHAT 콘솔과 연동이 되어있기 때문에 콘솔에서 채팅방 설정, 회원정보 설정 등을 업데이트하면 데모에 반영이 된다.

 

이제 웹 소켓에 대한 이해가 없어도 누구나 간단하게 채팅 앱을 구현할 수 있다.

 

Demo (Web Live)

Secret Key와 SDKAppID를 얻는 과정까지는 동일하고, 역시 공식 가이드에 따라 설치를 진행해보자.

 

1) 소스코드 다운로드

$ git clone https://github.com/TencentCloud/chat-uikit-react
$ cd chat-uikit-react
$ npm install && cd examples/sample-chat && npm install

 

2) 다운로드가 완료되면 chat-uikit-react/examples/sample-chat/src/debug 하위경로의 GenerateTestUserSig.js를 편집기로 열어서 SDKAppID 와 Secret Key를 입력해준다.

 

3) 웹서버 실행

 

웹 서버를 실행하고

$ cd examples/sample-chat
$ npm run start

 

접속하면(http://localhost:3000) 데모가 실행된다.

 

테스트 아이디를 검색창에 입력한 뒤

 

추가된 아이디를 클릭하면

 

 

웹 라이브 채팅 데모가 실행된다. 채팅에 필요한 모든 기능이 탑재되어 있다.

 

데모가 실행된 웹 서버를 외부에 올리면 URL을 통해 다른 사람과의 채팅 체험이 가능하다.

 

마치며

이번에 적용해본 데모이외에 Tencent Cloud CHAT은 라이브스트리밍, 음성 & 화상 통화 , 온라인 학습 등 다양한 기능을 제공하고 있고 모두 데모로 체험이 가능하니 활용해보는 것도 좋을 것 같다. 또한 관련 상품팀에서 SDK 적용 및 빌드과정에서 발생하는 이슈에 대비하여 텔레그램이나 왓츠앱 등의 메신저로 실시간 CS도 제공하고 있다.

 

Tencent cloud Auto Scaling

 

Auto Scaling은 클라우드 시스템 자원을 필요에 따라 자동으로 추가하고 제거하는 스케일링 시스템이다. 이 글에서는 간단한 실습을 통해 콘솔에서 Tencent cloud Auto Scaling을 체험하는 내용을 담았다.

 

트래픽을 먹고사는 복제토끼🐰

 

Scale-out의 결과를 시각적으로 구현하기로 한다. 우선 CVM 인스턴스 1대를 토끼 한 마리로 가정한다. Auto Scaling 설정을 완료하고, 인위적으로 서버에 트래픽을 날려 부하를 준 뒤 스케일링을 통해 인스턴스가 추가되면 추가된 인스턴스 수에 따라 클라이언트의 웹 페이지에 토끼가 한 마리씩 추가되는 로직이다. 매우 간단한 시각화를 통해 Tencent cloud의 CVM이나COS 같은 다른 서비스도 자연스럽게 체험할 수 있다.

 

토끼 복제 과정🐰

먼저 COS 버킷에 토끼 이미지를 저장하고 Tencent cloud CVM으로 간단한 웹서버를 띄운 뒤 해당서버를 기준으로 Auto Scaling 을 세팅하고, 서버에 Auto Scaling 인스턴스의 갯수에 따라 토끼이미지를 렌더링하는 웹페이지 코드를 구현한다.

최종적으로 서버 퍼포먼스 테스트 툴을 (이 글에서는 wrk 사용) 이용하여 인위적으로 서버에 부하를 주어 늘어난 인스턴스 수에 따라 토끼의 수가 증가하는지 확인한다.

 

COS Bucket에 토끼 이미지 저장하기🐰

COS Bucket에 인스턴스의 수를 나타낼 토끼 이미지를 업로드 한다. Tencent cloud 콘솔 , COS Browser , TCCLI등 방법을 이용한다. 이 글에서는 TCCLI 커맨드 명령어를 소개한다.

 

coscmd config -a <SecretID> -s <SecretKey> -b <버킷이름> -r <리전>
coscmd upload <로컬 파일 경로> <버킷 이름>

 

이렇게 해서 토끼에 대한 COS 버킷의 엔드포인트를 얻었으면 웹서버를 생성한다.

 

 

간단한 웹서버 구현하기 (CVM)

Tencent cloud의 가상머신 CVM을 이용하여 가벼운 스펙의 테스트용 서버를 생성한다. 이 글은 CentOS 7.9 를 기준으로 한다.

 

서버 생성이 완료되면 접속하여 기본적인 세팅을 시작한다. 

 

서버에 nodejs 기준으로 각종 패키지 및 express 모듈을 설치한다. 또한 오토스케일링을 통한 CVM 인스턴스 수의 정보를 실시간으로 알려줄 API 호출을 위해 Tencent API 의 APIExplorer (https://console.tencentcloud.com/api/explorer?Product=as&Version=2018-04-19&Action=DescribeAutoScalingGroups)를 참고하면 코드 예제를 얻을 수 있다. 코드 예시를 보면 tencentcloud-sdk-nodejs-intl-en 패키지의 설치가 필요함을 알 수 있다.

 

마지막으로 CVM의 Security group 설정에서 웹서버 포트로 지정할 port:3000에 대한 인바운드트래픽을 허용해주면 준비는 끝난다.

 

 

소스코드

여기까지의 웹 서버의 코드는 다음과 같다.

const express = require('express');
const tencentcloud = require("tencentcloud-sdk-nodejs-intl-en");

const AsClient = tencentcloud.as.v20180419.Client;
const models = tencentcloud.as.v20180419.Models;

const Credential = tencentcloud.common.Credential;
const ClientProfile = tencentcloud.common.ClientProfile;
const HttpProfile = tencentcloud.common.HttpProfile;

let cred = new Credential("IKIDAEA0mU6hEi3LXZRBpMnHhBTp4XXXXXXX", "c8hHuYBtjsgMAnR9xrjyAKc3dXXXXXX");
let httpProfile = new HttpProfile();
httpProfile.endpoint = "as.tencentcloudapi.com";

let clientProfile = new ClientProfile();
clientProfile.httpProfile = httpProfile;


let client = new AsClient(cred, "ap-seoul", clientProfile);

const app = express();
const port = 3000;  //사전에 CVM의 Security group 설정 확인

async function getInstanceCount() {
    return new Promise((resolve, reject) => {
        let req = new models.DescribeAutoScalingGroupsRequest();
        

        let params = {
            AutoScalingGroupIds: ["XXXXXXX"] //Auto Scaling 설정이 끝나면 Scaling group ID를 넣는다.
        };
        req.from_json_string(JSON.stringify(params));

        client.DescribeAutoScalingGroups(req, function(err, response) {
            if (err) {
                reject(err);
                return;
            }
            
            resolve(response.AutoScalingGroupSet[0].InstanceCount);
        });
    });
}

app.get('/', async (req, res) => {
    try {
        const instanceCount = await getInstanceCount();
        let rabbitsHtml = '';
        for (let i = 0; i < instanceCount; i++) {
            rabbitsHtml += '<img src="https://rabbit-1316520384.cos.ap-seoul.myqcloud.com/rabbit-1316520384" alt="Rabbit" width="300" height="300">';
        }  //COS 버킷의 이미지경로
        res.send(`<html><body>${rabbitsHtml}</body></html>`);
    } catch (error) {
        res.status(500).send(`Error : ${error}`);
    }
});

app.listen(port, () => {
  console.log(`Example app listening at http://localhost:${port}`);
});

 

웹 서버를 실행시키고

 

브라우저에 CVM의 public IP:3000 을 입력해보면

 

다소곳한 토끼 한 마리를 볼 수 있다. 해당 서버의 인스턴스 수가 1대라는 뜻이기도 하다.

 

Auto Scaling 설정

1) Launch Configuration

먼저 Tencent cloud 콘솔의 Auto Scaling 섹션에서 Launch Configuration을 설정한다. Scale-out시 추가 생성될 서버의 스펙을 정하는 단계이다. 테스트용이니 만만한 스펙으로 적당히 설정한다.

 

2) Security Group

Security group을 설정한다.

초기 capacity의 설정이 AWS Auto Scaling의 그것과 약간 다르다. desired capacity 대신 Initial capacity를 입력하는 것으로 되어있는데, 추후 스케일링 그룹 생성 후 옵션에서 desired capacity를 설정할 수 있다. 이 실습에서는 각각 1, 2, 10으로 설정하였다. 토끼의 과도한 번식 현장을 목격하고 싶지 않다면 적절하게 Max capacity를 설정한다. 또한 실전에서는 인스턴스가 분배될 VPC 영역 설정은 다중 서브넷을 이용한 구성을 추천하지만 생략한다.

 

3) Alarm policy 설정

 

이제 어떤 조건에서 Scale-out이 진행될건지를 정해야한다. CPU Utilization, Public bandwidth, Private bandwidth, TCP Connection 등의 지표로 판단기준을 정한다. 있고 정책은 판단기준이 어떤 방식으로 특정값에 도달하는지에 따라 capacity의 서버 대수 만큼 서버를 추가할 것인지를 정한다.

 

 

예를들어 위와 같은 조건이라면 CPU utilization  1분동안, 평균 70%이상 측정된 구간이 연속적으로 3번 감지되면, 서버 1대를 추가한다는 의미이다. (스케일링이 한 번 진행된 후 cooldown 시간 이내에는 다음 스케일링이 발생하지 않는다.) 이번에는 최대한 적은 수고로 순식간에 Scale-out 효과를 체험하기 위해 if값에 각각 public bandwidth , MAX 2Mbps , 1을 입력하였다.

        let params = {
            AutoScalingGroupIds: ["XXXXXXX"] //Auto Scaling group ID
        };
        req.from_json_string(JSON.stringify(params));

 

마지막으로 완성된 Scaling group에 서버 CVM 인스턴스를 추가하고 Scaling group ID를 웹서버 코드 해당 부분에 입력한다.

 

토끼 복제하기

이제 모든 준비가 끝났다. 인위적으로 웹 서버에 부하를 발생시켜서 Scale-out을 진행한다. 여기서는 wrk를 이용하여 간단하게 트래픽을 발생시킨다.

 

1분 후 토끼우리를 확인하면

 

👏👏👏👏 서버가 10대로 늘어난 것을 확인할 수 있다.

 

콘솔에서 토끼들의 건강상태도 아주 좋은 것을 확인할 수 있다. (Tencent cloud는 Auto Scaling Group에서 주기적으로 서버에 ping 명령을 날려 1분안에 응답이 리턴되지 않으면 scale-in 하는 헬스체크 방식을 사용한다.)

 

마치며

 이 글을 통해 실무적이고 정교한 설계는 아니지만 간단한 조작을 통해 클라우드의 유연한 특성을 가장 많이 가지고 있는 Auto Scaling을 Tencent cloud의 상품으로 구현해보는 방법을 소개하였다. 기존 AWS를 사용하던 유저들도 학습부담 없이 콘솔상에서 충분히 체험이 가능하다.

>> 이전글에 이어

CVM 세팅하기

 

이제 본격적으로 CVM을 세팅한다. 총 5대의 CVM을 프로비저닝 하면 되는데, Bastion host용으로 사용할 CVM은 Public subnet에 두고, 나머지 4대의 가상머신은 Web server와 WAS로 쓸 것이기 때문에 모두 private subnet에 배치한다. 세팅이 끝나면 위와 같은 상태가 되어야 한다.

 

 

테스트 목적이므로 적당한 스펙과 이미지를 선택하여 인스턴스를 생성한다. 이때 각각 인스턴스가 속한 서브넷이 설계한 아키텍처에 맞게 설정되어야 한다.

 

Nginx 설치 및 세팅

서로 다른 AZ의 private subnet에 위치한 인스턴스 2대에 웹서버를 설치한다. 여기서는 Nginx를 기준으로 한다.

콘솔을 통해 직접 로그인 하거나,

 

먼저 점프서버 역할을 하는 Public subnet에 위치한 인스턴스에 ssh 접속을 하고 여기서 다시 목적지로 ssh 접속한다.

sudo apt update
sudo apt install nginx

 

Nginx 설치가 끝나면, 추후 CLB를 연결하여 트래픽 분산을 할때 로드밸런싱이 제대로 되는지 눈으로 확인할 수 있게 몇 가지 설정을 한다. (어차피 CLB 설정 시 헬스체크가 가능하기 때문에 이 과정은 생략해도 무방하다.) 

 

CLB 설정 시 엔드포인트 하위 경로를 /test로 지정하기로 하고, Nginx 기본 설정 파일(default)에서 이에대한 응답헤더를 추가한다.

server {
    listen 80;
    server_name www.example.com;

    location /test {
        add_header X-Served-By web1;
    }
	// Seoul zone1 서버의 경우 web1, zone2의 경우 web2.
}

 

그 다음은 /var/www/html/ 경로에 test.html 파일을 추가한 뒤 아래코드를 입력한다.

<html>
<head><title>Test Page</title></head>
<body>
  <h1>This request is served by web1</h1>
</body>
</html>

 

WAS 설치 및 세팅

WAS1, WAS2에 각각 로그인 한 뒤 아래의 스크립트를 입력하여 OpenJDK와 Tomcat을 설치한다.

 

OpenJDK:

sudo apt update
sudo apt install default-jdk

Tomcat :

sudo useradd -m -U -d /opt/tomcat -s /bin/false tomcat
wget <tomcat 홈페이지에서 최신 다운로드 링크를 입력 .tar.gz>
sudo tar xzvf apache-tomcat-*tar.gz -C /opt/tomcat --strip-components=1
sudo chown -R tomcat: /opt/tomcat

Tomcat 실행 : 

sudo systemctl start tomcat
sudo systemctl enable tomcat

 

CLB 설정

총 2개의 CLB 설정이 필요하다. 외부 트래픽을 Web1, Web2에 분배해줄 로드밸랜서 (EX_CLB), Web1,2를 통과한 트래픽을 WAS1, WAS2에 분배해줄 로드밸런서 (IN_CLB). 두 가지는 각각 public network 와 private network에 위치한다. 이 글에서는 EX_CLB를 생성하는 방법을 소개한다.

 

콘솔의 Cloud Load Balancing 메뉴에서 CLB 인스턴스를 구매한다.

Basic information 에서 생성된 CLB 엔드포인트를 확인할 수 있으며 도메인으로도 커스텀이 가능하다.

 

구입 후 CLB콘솔에서 생성한 CLB의 이름을 클릭하여 Listener management 메뉴로 가면 리스너 생성이 가능하다.

다음은 포워딩 룰을 생성한다. Nginx 기본환경 설정 시 하위경로로 했던 /test를 URL에 입력하고 밸런싱 알고리즘은 WRB로 설정 한다.

화질이 좀 좋지 않다.

 

이제 브라우저에 VIP주소/test 로 요청을 날리고 새로고침을 계속 눌러보면 web1 과 web2로 균등하게 로드가 분산되는 것을 눈으로 확인할 수 있다. 같은 방법으로 private network에 IN_CLB를 구현하면 된다.

 

현재까지의 세팅은 이렇다.

 

TencentDB for MySQL 설정

 

TencentDB for MySQL 메뉴에서 MySQL instance를 생성한다.

 

 

Source AZ 는 Seoul Zone1 , Replica AZ는 Seoul Zone2 로 설정한다.

 

 

이제 bastion host에 접속해서 MySQL의 private IP로 접속을 해보면

 

잘 되는 것을 확인할 수 있다

 

완성.

 

Security Group

마지막으로 각각의 인스턴스가 연관된 리소스와의 인터랙션만 허용하도록 Security group을 설정한다. 이 작업은 인스턴스를 생성할때 마다 그때그때 적용해 주는 것이 좋다. 설정 포트는 구현한 아키텍처와 설치한 소프트웨어에 따라 다를 수 있다.

1) Bastion host : 일종의 프록시 서버 역할을 하므로 ssh 접속이 가능하도록 22번 포트를 개방한다. 아웃바운드 트래픽은 모두 허용한다.

2) EX_CLB : 웹 트래픽을 받기 위한 HTTP(80) 포트를 오픈한다. (CLB 설정에 따라 HTTPS(443)도 해당) 아웃바운드 트래픽의 경우 Web server 로만 향하도록 설정한다.

3) Web server : EX_CLB를 통과한 트래픽과 Bastion host의 ssh 접속만 인바운드 허용한다. 아웃바운드 트래픽은 IN_CLB를 향한 트래픽을 허용하고 필요에 따라 추가설정한다.

4) IN_CLB : Web server 를 통과한 트래픽을 받기위한 포트와 Bastion host의 ssh 접속을 허용한다. 아웃바운드 트래픽은 WAS를 향한 트래픽을 허용하고 필요에 따라 추가설정한다.

5) WAS & DB : 마찬가지로 tomcat의 8080 포트에 대해 인바운드 트래픽을 허용한다. MySQL역시 3306 포트에 대해 인바운드 트래픽을 허용한다. 아웃바운드 트래픽은 모두 허용하거나 필요에 따라 설정한다.

 

마치며

이제까지 Tencent cloud 환경에서 간단한 3-tier 아키텍처를 구현하는 내용을 대략적으로 소개했다. 보는 것 처럼 실제 콘솔에서 클릭 몇 번으로 쉽게 구현이 가능하다. 기존 타 클라우드 사용자들 역시 Tencent cloud 콘솔이나 Terraform등의 IaC 툴로 기존 클라우드 벤더의 상품에 대응하는 리소스들의 프로비저닝이 가능하니 한 번 체험 해보는 것도 좋을 것 같다.

 

 

 

Analysis


고객사는 요즘 젊은 세대들의 필수품인 사진 편집 및 필터기능을 제공하는 플랫폼을 운영하는 기업입니다. 기업은 애플리케이션 내에서 자체 개발 알고리즘을 기반으로 한 사진 분석 서비스를 제공하고 있습니다. 이번에 플랫폼의 대대적인 기술적 개편을 진행하는 과정에서 해당 도메인에 대한 설계를 서버리스 아키텍처로 구현하길 원합니다. 고객사와 기존 아키텍처를 함께 점검하고, 이 중 서버리스에 적합한 유저의 유형을 분리하여 Tencent cloud의 SCF(Serverless Cloud Function)을 활용한 로직을 새로 도입하기로 하였습니다.

 

Architecture Blueprint


1) 유저가 애플리케이션에 사진을 업로드 하면 사진 화질을 개선해주는 기능을 구현합니다. (유저1) COS에 업로드 된 원본사진은 
유저가 선택한 해상도에 따라 서로 다른 SCF함수를 호출합니다. SCF함수는 COS업로드 이벤트를 트리거로하여 작성된 알고리즘 코드를 실행합니다.


2) 화질 개선이 완료된 사진 파일 결과물은 COS에 업로드되고 후처리 로직을 담당하는 또 다른 SCF를 호출하여 유저에게 전달됩니다. 


3) Bucket 업로드 이벤트가 SCF를 호출할 때 , 원본 파일에 대한 업로드 트리거가 SCF를 무한루프에 빠지게 할 가능성이 있습니다. 따라서 이미지 파일에 대한 메타데이터를 적절하게 태깅하여 파일의 before - after를 구분하도록 설계해야 합니다. 


4) 애플리케이션 유저가 자신이 사는 위치를 기반으로 가까운 사용자와 질문 및 답변을 교환할 수 있는 커뮤니티 기능을 구현합니다. (유저2, 유저3) 유저의 질문은 API Gateway를 통해 SCF함수에 전달되고 작성된 위치기반 답변자 검색 알고리즘 코드를 싱행하여 결과 값을 TencentDB for MongoDB에 기록합니다. 


5) 현재 Tencent cloud에서 자체 NoSQL 데이터베이스의 Stream을 추적하여 SCF를 트리거하는 기능을 제공하지 않으므로, DB에 저장된 값은 고객사의 기존 웹 서버를 통해 렌더링 합니다.


6) 질문자 - 답변자 간 매칭에 대한 비동기 처리는 Tencent cloud의 큐잉 시스템을 이용하여 구현합니다. 관련 POST 요청은 API GatewaySCF를 거쳐 TDMQ for Ckafka 에 쌓이게 됩니다. SCFCkafka 기반 트리거 기능을 제공합니다. 대기열 값을 비동기적으로 매칭 알고리즘이 구현된 SCF를 통해 처리하고 결과 값을 NoSQL 데이터베이스에 저장합니다.


7) SCF 구성 시, 재시도 메커니즘을 적절히 설계하여 에러를 핸들링하고, 발생하는 모든 로그는 CLS로 전송합니다. 이 과정에는 모든 요청 및 응답으로 인해 생성되는 로그 데이터도 포함하도록 합니다. 타임아웃이 중요한 서버리스 아키텍처에서 효율적인 트러블슈팅이 가능하게 됩니다.

Overall


기업의 사례는 전통적인 서버리스 아키텍처를 충실히 따르며, 기존에 AWS Lambda를 사용하던 엔지니어라면 추가적인 학습 부담 없이 유사한 방식으로 워크로드를 구축할 수 있도록 설계되었습니다.

 

대규모 애플리케이션의 경우, 기업은 도메인 별로 다양한 클라우드 아키텍처를 채택합니다. 이때 메인 서비스가 아닌 부분이나 새롭게 출시하는 기능에 있어서는 비용 효율성과 확장성을 고려해 서버리스 아키텍처가 유리한 경우가 있습니다.

 

이는 실제 프로덕션 환경 뿐만 아니라 코드의 단위 테스트를 위한 설정에서도 적절한 선택이 될 수 있습니다. Tencent cloud SCF는 기업에게 추가적인 부담을 주지 않으면서도, 효율적으로 시스템을 운영할 수 있는 방안을 제공합니다.

 

Products we used


- SCF : https://console.tencentcloud.com/scf

- API gateway : https://console.tencentcloud.com/apigateway

- COS : https://console.tencentcloud.com/cos

- TDMQ for CKafka : https://console.tencentcloud.com/ckafka

- CLS : https://www.tencentcloud.com/products/cls

- TencentDB for MongoDB : https://www.tencentcloud.com/products/mongoDB

 

 

 

 

3-tier architecture

3-tier 아키텍쳐란 일반적으로 비즈니스 로직을 프레젠테이션 계층 , 애플리케이션 계층 , 데이터베이스 계층으로 물리적/논리적으로 분리하여 구현하는 설계를 뜻한다. 이러한 계층 구성을 통해 고가용성 보장과 유연한 서비스 설계가 가능하다. 보통 프론트엔드, 백엔드, 데이터베이스의 기본 구성으로 이해해도 좋다. 글에는 Tencent cloud 클라우드 상품들로 간단한 3-tier 아키텍쳐를 만들어보는 과정을 담았다.

 

아키텍처

 

일반적인 클라우드의 N-tier 아키텍처와 다르지 않다. 1개의 VPC 2개의 가용영역을 구성하여 각각 4개의 서브넷으로 분리하고 (Public subnet x 1 , Private subnet x 3) Private subnet Web server , WAS , DB 서버를 배치한다. DB TencentDB for MySQL 사용한다. public subnet 1대는 bastion host 역할을 한다.

 

트래픽 전달 과정

 

 인바운드 트래픽

  • 클라이언트의 요청 트래픽은 첫 번째 CLB로 전달되어 서로 다른 가용영역에 있는 웹 서버에 로드밸런싱 되고 동적 콘텐츠에 대한 요청은 다시 내부 CLB로 전달하여 WAS에서 나눠서 처리한다. DB는 TencentDB for MySQL의 멀티 AZ 구성을 이용하여 마스터 DB와 슬레이브 DB로 분리 설계한다.

아웃 바운드 트래픽

  • 내부 프라이빗 리소스가 외부로 트래픽을 전달하는 경우 NAT gateway를 통하여 공인 IP를 부여받아 외부와 통신한다.

Tencent cloud에서는 AWS와 달리 별도의 Internet gateway 설정 없이 EIP(혹은 Public IP) 만으로 외부 퍼블릭 서브넷 리소스의 외부 인터넷 연결이 가능하다. 프라이빗 서브넷의 경우 NAT Gateway를 통해야 하므로 (EIP가 할당된 CVM을 public gateway로 하여 외부 인터넷으로 라우팅 하는 방법도 있긴 하다. 이에 대한 내용은 이후에 다른 글에서 자세히 설명하기로 한다.) 퍼블릭 서브넷에 NAT Gateway를 두고 내부 프라이빗 서브넷의 외부 인터넷 트래픽 요청을 라우팅 한다.

 

해야 할 것들

다음과 같은 순서로 실습을 진행한다.

1) VPC & Subnet 설정
2) 라우팅 설정 (NAT & Security group & Routing table)
3) CVM 세팅 및 Web server , WAS 설치
4) CLB 설정
5) TencentDB for MysQL 설정

 

VPC & Subnet 설정

 

VPC

 

Tencent cloud console에서 Virtual Private Cloud 메뉴로 이동하여 ap-seoul 리전에 VPC를 생성한다.

이때 Tencent cloud에서 생성가능한 VPC IP의 범위는 아래와 같다. 

10.0.0.0 - 10.255.255.255 (/12 ~ /28)
172.16.0.0 - 172.31.255.255 (/12 ~ /28)
192.168.0.0 - 192.168.255.255 (/16 ~ /28)

 

모두 RFC1918에서 정의한 사설 IP 영역으로, 원하는 CIDR Block을 선택하여 VPC 생성을 완료한다.

 

 

Subnet

 

VPC콘솔 subnet 메뉴에서 방금 생성한 VPC 내부에 8개의 서브넷을 생성한다.

 

Seoul zone1, Seoul zone2 두 개의 가용영역에 4개의 서브넷을 배치한다.

완성~

 

 

 

서브넷 생성까지 무사히 마쳤다면 위와 같은 구조가 된다.

이제 퍼블릭 서브넷을 위한 NAT Gateway 생성과 라우팅 테이블 설정을 해보도록 하자.

 

 

NAT gateway

 

VPC콘솔 NAT gateway 메뉴에서 새로운 NAT gateway를 생성한다.

 

 

NAT라우팅을 통해 변환될 publicIP는 보유하고 있는 EIP에서 선택해도 되고, 새로 생성해도 된다.  bandwidth cap 제한의 경우 NAT gateway를 통해 나가는 트래픽의 대역폭의 최대 값을 제한하는 옵션인데,

 

NAT와 EIP의 bandwidth cap 중 낮은 값이 우선적용된다.  

(NAT gateway Outbound bandwidth cap이 20 Mbps , EIP bandwidth cap이 30 Mbps인 경우, 아웃바운드 트래픽의 최대 대역폭은 둘 중 낮은 값인 20 Mbps를 기준으로 제한을 받게 된다.)

 

 

Routing table 생성하기

 

두 개의 라우팅 테이블이 필요하다. 편의상 public routing table , private routing table 이라 하자.

public routing table에는 VPC로컬 트래픽에 대한 방향을 안내하는 룰만 설정한다.
(Tencent cloud의 경우 나머지 외부 인터넷으로 나가는 트래픽에 대해서는 별도의 라우팅 룰이 필요하지 않다.)

 

private routing table에는 목적지가 VPC 로컬 이외의 트래픽의 경우 NAT gateway로 보내는 룰을 추가한다.

 

 

NAT gateway에서 새로운 라우팅 룰이 적용된 것을 확인할 수 있다.

 

 

 

>> 다음글에 계속

 

+ Recent posts