Discord
Your Place to Talk and Hang Out
Categories ite
Discord Developer Portal
| General Information | 당신의 창조물을 뭐라고 불러야 할까요? 그것은 어떤 놀라운 일을 합니까? Discord에서 어떤 아이콘을 나타내야 하나요? 여기에 알려주세요! |
Installation | 사용자가 앱을 설치하는 방법을 선택하세요. 설치 링크를 생성하고, 지원할 인증 방법을 선택하고, 요청하려는 범위와 권한을 정의하세요. | |
OAuth2 | Discord를 인증 시스템으로 사용하거나 사용자를 대신하여 API를 사용하세요. 리디렉션 URI를 추가하고, 범위를 선택하고, 행운을 빌어 D20을 굴린 다음 시작하세요! | |
Bot | 봇 사용자와 함께 Discord에서 앱에 생기를 불어넣으세요. 사용자 서버에서 채팅에 참여하고 직접 상호작용하세요. | |
Rich Presence Art Assets | Discord와 게임을 긴밀하게 통합하고 플레이어가 클라이언트에 직접 접속하여 게임을 공유할 수 있도록 하세요. | |
Application Testers | 애플리케이션을 테스트하기 위해 최대 50명의 Discord 사용자를 초대할 수 있습니다. 이메일을 등록하고 긍정적인 태도를 갖고 있어야 합니다. ^) | |
Monetization | - | |
Activities | - |
Installation
- Authorization Methods
- 앱이 지원하는 인증 방법을 선택하세요. 앱은 사용자와 길드 모두에게 설치될 수 있습니다.
- "사용자 설치(User Install)" 또는 "길드 설치(Guild Install)" 방법 중 선택할 수 있다.
- Install Link
- 제공된 설치 링크를 사용하거나 사용자 정의 링크를 등록하세요. 사용자 정의 링크를 선택하면 앱을 추가하는 사용자는 Discord의 앱 추가 흐름 대신 귀하의 URL로 리디렉션됩니다.
- "None", "Discord Provided Link", "Custom URL" 중 하나를 선택 가능
- 기본 설치 설정
- 앱에서 요청할 기본 범위 및 권한 집합을 선택하세요.
Bot
- Build-A-Bot
- 봇 사용자를 추가하여 앱에 생기를 불어넣으세요. 이 작업은 되돌릴 수 없습니다(로봇은 파괴하기에는 너무 멋지기 때문입니다).
- Token
- 보안상의 이유로 토큰은 생성 시 한 번만 볼 수 있습니다. 토큰에 대한 액세스를 잊었거나 분실한 경우 새 토큰을 다시 생성하세요.
- 개발에 필요한 Access Token 은 여기에서 생성할 수 있다.
- 승인 흐름 (Authorization Flow)
- 이러한 설정은 봇에 대해 OAuth2 승인이 제한되는 방식(봇을 추가할 수 있는 사람 및 추가 방법)을 제어합니다.
- 공개 봇 (Public Bot)
- 공개 봇은 누구나 추가할 수 있습니다. 선택 취소하면 귀하만 이 봇을 서버에 가입시킬 수 있습니다. -> No/Yes
- OAuth2 코드 부여 필요 (Requires OAuth2 Code Grant)
- 애플리케이션에 여러 범위가 필요한 경우 애플리케이션에 토큰이 부여되기 전에 봇이 조인하지 않도록 전체 OAuth2 흐름이 필요할 수 있습니다. -> No/Yes
- 권한 있는 게이트웨이 인텐트 (Privileged Gateway Intents)
- 일부 #Gateway Intents는 봇이 확인된 경우 승인이 필요합니다. 봇이 확인되지 않은 경우 아래에서 해당 인텐트를 전환하여 액세스할 수 있습니다.
- 존재 의도 (Presence Intent)
- 봇이 현재 상태 업데이트 이벤트를 수신하는 데 필요합니다. -> No/Yes
- 서버 구성원 의도 (Server Members Intent)
- 봇이 GUILD_MEMBERS 아래에 나열된 이벤트를 수신하는 데 필요합니다. -> No/Yes
- 메시지 내용 의도 (Message Content Intent)
- 봇이 대부분의 메시지에서 메시지 콘텐츠를 수신하는 데 필요합니다. -> No/Yes
INFORMATION |
봇이 100개 이상의 서버에 도달하면 확인 및 승인이 필요합니다. 여기서 더 읽어보세요 |
- Bot Permissions
- 비트 수학에 도움이 필요하신가요? 아래 도구를 사용하여 필요한 기능을 기반으로 봇에 대한 권한 정수를 계산하세요.
- 필요한 권한을 목록에서 선택하면 해당 Permission 에 대한 Integer 를 Bitwise 계산하여 알려줌.
Gateway Intent
특히 규모에 따라 게이트웨이 연결을 통해 앱이 처리할 것으로 예상되는 데이터의 양과 관련하여 상태 저장 애플리케이션을 유지하는 것은 어려울 수 있습니다. 게이트웨이 의도 (Gateway intents) 는 계산 부담을 줄이는 데 도움이 되는 시스템입니다.
Performance Optimization
Discord가 Go에서 Rust로 전환하는 이유
가장 기본적인 최적화 만으로 Rust버전이 하이퍼 핸드튜닝된 Go버전보다 성능이 우월했음
- 디스코드는 "Read States" 서비스 : 어떤 채널과 메시지를 읽었는지 계속 추적.
- 하지만 Go의 메모리 모델과 GC는 레이턴시 스파이크를 만듬
Discord가 네트웍 디스크의 지연시간을 최소화한 방법
- Discord가 네트웍 디스크의 지연시간을 최소화한 방법 | GeekNews (Google Cloud Platform, Persistent Disk 레이턴시, etc ...)
- 쿼리량이 낮은 수준에서는 상관없지만, 특정 시점을 초과하면 1~2ms가 걸리는 읽기 시간 만으로도 디스크에서 읽는 대기열이 발생하며 쿼리 자체에 대해 시간 초과가 발생
- NVMe 기반의 로컬 SSD를 지원하지만 자체적으로 테스트해보니 안정성 문제가 있어서 중요한 데이터 저장소로 사용하기엔 맘이 편하지 않았음
- Persistent Disk는 서버에 실시간으로 연결/분리 가능하며, 다운타임 없이 리사이즈 가능, 언제나 스냅샷 생성가능하고, 기본으로 복제되게 설계됨
- 문제는 서버에 직접 붙어있지 않고 네트웍으로 연결 된다는 것
- 네트워크는 1~2ms, 직접연결된 디스크는 0.5ms
- 그래서 디스코드는 Local SSD 를 이용하지 않고, Persistent Disk 를 사용
문제 분석
- 로컬 SSD와 Persistent Disk 의 장점만 모은 저장 장치가 있다면 최고겠지만 그런 것은 없음. 장점중 일부만 가져온다면?
- 디스코드는 쓰기 지연시간은 문제가 아님. 성능에 영향을 미치는 것은 "읽기 지연시간"
- "다운타임 없는 디스크 리사이징"은 필수 기능은 아님. 사이즈는 미리 예측 가능
- 최종 요구 사항은
- GCP 에 그대로 있으면서
- 데이터 백업을 위해서 Point-in-Time 스냅샷 사용
- 읽기 지연시간 최소화를 최우선 순위로
- 기존 데이터베이스 업타임 보장을 희생하지 않을 것
- 소프트웨어 수준에서 이런 Super-disk를 만들 수 있을까?
Super-Disk 만들기
- 요구사항은 기본적으로 Write-Through 캐쉬였음. GCP의 로컬 SSD를 캐쉬로 사용하고, PD를 저장 레이어로 사용
- DB서버로 Ubunut를 사용하고 있어서, 리눅스 커널단에서 디스크 레벨의 캐쉬 적용 가능(dm-cache, lvm-cache, bcache 같은 모듈)
- 하지만, 실험해보니 캐쉬디스크에 배드섹터 발생시 전체 읽기 작업이 실패함
- 배드섹터가 발생하면 스토리지 레이어에서 읽어다 엎어써야 하는데, 평가한 디스크 캐슁 솔루션들은 이런 기능이 없었음
- 배드섹터 발생시 데이터베이스가 데이터 안정성 문제로 셧다운 되어버림
- md는 소프트웨어 RAID를 생성할수 있도록 지원
- SSD와 PD를 미러링 하는 것으로는 문제가 해결 되지 않음. 절반이상의 읽기는 PD에서 될 것이기 때문에
- md에는 전통적인 RAID에는 없는 "write-mostly" 가 있음
- 특정 디스크를 write-mostly로 지정하면 일반 읽기에서는 제외되며, 다른 옵션이 없을 때만 읽기가 실행됨. "느리게 연결된 기기에 유용"
- 즉, SSD와 PD를 RAID1으로 묶고, PD를 write-mostly로 세팅하면 요구사항을 맞출 수 있음
- RAID0 로 묶인 로컬 SSD 4개를 md0
- md0 와 Persistent Disk를 RAID1으로 묶은 md1 을 구성
DB 성능
- 딱 예상한 결과가 나왔음
- 피크시에도 디스크 오퍼레이션들이 큐에 쌓이지 않으며, 쿼리 레이턴시가 변하지 않음
- 성능 향상이 일어나서 각 서버당 처리 쿼리량이 더 늘어남
- RAID 사용해본 사람들은 이게 "그냥 동작할까?" 라는 의구심이 들겠지만, 실제로는 다양한 일이 있었고, 나머지는 따로 상세히 소개할 예정
Discord가 Cassandra에서 ScyllaDB + Rust로 전환한 이유
그러나 사용자 기반이 확장됨에 따라 Discord는 수조 개의 메시지를 효율적으로 처리해야 하는 어려운 과제에 직면했습니다. 기존 데이터베이스 시스템인 Cassandra는 핫 파티션으로 인해 속도 저하 및 성능 저하 문제가 발생했습니다.
- Discord는 성장하면서 메시징 저장소 DB를 계속 교체하였음
- 초기에는 단일 MongoDB. 2015년 11월에 메시지 수가 1억개로 늘어나면서 MongoDB 한계가 드러남
- 2017년에 12노드 클러스터 Cassandra로 전환하여 수십억개의 메시지를 저장
- 2022년에는 메시지가 수조개로 급증하면서 인프라가 177개 노드로 엄청 늘어났고, 대기시간 예측이 불가능하고 유지보수 비용이 엄청 비싸짐
- 카산드라 에서 디스코드의 문제는 Hot Partition이었음. DB의 특정 부분이 과부하 되어 전체 어플리케이션의 성능이 저하
- 카산드라 내부 데이터 구조가 LSM트리를 활용하므로 쓰기보다 읽기 비용이 더 많이 들고, 단일 서버에서 여러 사용자의 동시 읽기는 핫스팟을 만들고 성능 저하로 이어짐
- SSTable 압축과 같은 유지 관리 작업이 전체 성능에 영향을 미쳐서 문제를 가중 시킴
- 모놀리식 API, Rust로 구현된 데이터 서비스, ScyllaDB에 기반한 스토리지 시스템(C++로 개발된 Cassandra 호환 DB)등을 활용
- p99 read latency 는 카산드라의 40~125ms 에 비해 15ms로 감소
- p99 write latency 는 카산드라의 5~70ms 에 비해 5ms로 감소
- Rust의 Feareless Concurrency 기능을 이용하여 핫 파티션에 대한 동시 트래픽을 제어
- Rust의 라이브러리와 동시성 기능은 Discord 의 요구사항에 매우 적합했음
- 데이터 서비스는 API 모노리스와 데이터베이스 클러스터사이의 중개 서비스 역할을 수행
Discord가 웹소켓 트래픽을 40% 감소시킨 방법
- 클라이언트가 Discord에 연결하면 "게이트웨이"라고 하는 서비스를 통해 무슨 일이 일어나고 있는지에 대한 실시간 업데이트를 받음
- 2017년 말부터 클라이언트의 게이트웨이 연결은 zlib를 사용하여 압축되어 메시지의 크기가 2배에서 10배까지 작아졌음
- Zstandard(zstd)는 zlib보다 압축률이 높고 압축 시간이 짧으며, 사전 기능을 지원해 대역폭을 추가로 줄일 수 있음
- 2019년 zstd 테스트 결과는 그다지 긍정적이지 않았으나, 다시 시도해볼 가치가 있다고 판단함
Zstd 스트리밍
- Zlib은 스트리밍 압축을 사용한 반면, zstd는 그렇지 않았음
- 작은 페이로드에서 zstd가 zlib보다 성능이 떨어졌음
- Elixir용 zstd 바인딩인 ezstd를 포크하여 스트리밍을 추가함
- Zstd 스트리밍으로 전환한 결과 zlib 스트리밍보다 압축률과 속도 면에서 크게 개선됨
- 최적화 튜닝 - Chainlog, hashlog, windowlog 등 zstd 압축 매개변수를 조정하여 메모리 사용량과 압축 시간의 균형을 맞춤
See also
- Wildbeast - 다목적 Discord bot 프레임워크
- Overpass - 셀프호스트 스트리밍 플랫폼
- Revolt - 오픈소스 디스코드 대체제
- Slack
- Devzat - 개발자들을 위한 SSH 채팅 서버