I will share the initial reasons for introducing Golang and the architecture choices we made based on the scale of the chat service we developed over 4 years. Additionally, I will share the lessons learned from the problems we encountered while operating the service and how we resolved them.
1. 2023.08.05 | Go 도입 후, 4년 간 기록 | Gophercon Korea 2023 | 변규현
Go 도입 후, 4년 간의 기록
Engineering Lead of Chatting, Karrot
변규현
1
2. 2023.08.05 | Go 도입 후, 4년 간 기록 | Gophercon Korea 2023 | 변규현
소개
• Engineering Lead of Chatting,
Karrot
• AWS Serverless Hero
2
3. 2023.08.05 | Go 도입 후, 4년 간 기록 | Gophercon Korea 2023 | 변규현
목차
• Go 사용 현황
• Go를 시작한 계기
• Go의 좋은 점과 아쉬운 점
• 직접 겪은 메모리릭 & 성능 이슈
• Starvation mode of mutex
• CPU Throttling Optimization
• 메모리 최적화하기
• GC 튜닝하기
• 업무 생산성을 향상하는 케이스 공유
3
4. 2023.08.05 | Go 도입 후, 4년 간 기록 | Gophercon Korea 2023 | 변규현
가볍게 Golang을 사용하는
프로젝트들의 현황을 보여드릴게요.
4
5. 2023.08.05 | Go 도입 후, 4년 간 기록 | Gophercon Korea 2023 | 변규현
Golang을 사용하는 Repository 수
: 200+ 개
Golang을 사용하는 사람 수
: 50+ 명
5
6. 2023.08.05 | Go 도입 후, 4년 간 기록 | Gophercon Korea 2023 | 변규현
운영하는 서비스에서 얼마나 많은 요청을
처리하고 있을까요?
6
7. 2023.08.05 | Go 도입 후, 4년 간 기록 | Gophercon Korea 2023 | 변규현
한 서비스의 Req/sec
7
8. 2023.08.05 | Go 도입 후, 4년 간 기록 | Gophercon Korea 2023 | 변규현
또 다른 서비스의 Req/sec
8
9. 2023.08.05 | Go 도입 후, 4년 간 기록 | Gophercon Korea 2023 | 변규현
오늘은 이런 요청을 문제없이 처리하고 여러
서비스를 개발하면서 겪었던 내용에 대해서 공유할
예정이에요.
다양한 문제들에 대해서 여러 팀들이 여태까지
해결한 것들에 대해서 정리해보았어요.
9
10. 2023.08.05 | Go 도입 후, 4년 간 기록 | Gophercon Korea 2023 | 변규현
개인적으로 Go를 시작한 계기
1. 고언어가 있는지 한 번 알게 되는 상황이 벌어짐
2. 고언어로 무엇을 만들었는지 한 번 찾아봄
3. 고언어에 대해서 관심이 가서 장단점을 찾아봄
4. 가볍게 두어 개 로직을 작성해 봄
5. 실제 업무에 도입할지 고민하면서 어느 회사가 쓰는지 한 번 찾아봄
6. 여러 사람들이 작성한 글들을 보면서 상상함
7. 그리고 공부를 제대로 시작함
10
11. 2023.08.05 | Go 도입 후, 4년 간 기록 | Gophercon Korea 2023 | 변규현
회사에서 Go를 시작한 계기
1. 현재 기술로는 해결하기 어려운 상황이 발견됨
• Rails 서버로 감당하기 트래픽이 발생하고 있음.
• 이때 RDB의 60% 가까이 부하가 채팅트래픽이었음.
2. 무엇으로 이 문제를 해결할 수 있는지 찾아봄.
• 이때의 선택지는 Java+Spring, Typescript+NestJS, Golang
3. 장기적으로, 그리고 현재 리소스로 가장 괜찮은 것은 무엇일지 고민함
• Golang으로 해봅시다!
자세한 건 “당근마켓 개발팀 Go언어를 도입하다”(https://youtu.be/mLIthm96u2Q)
영상을 참고해주세요 😁
11
12. 2023.08.05 | Go 도입 후, 4년 간 기록 | Gophercon Korea 2023 | 변규현
Go의 좋은 점과 아쉬운 점은 무엇일까요?
간단하게 짚어보고 넘어가죠
12
13. 2023.08.05 | Go 도입 후, 4년 간 기록 | Gophercon Korea 2023 | 변규현
Go의 좋은 점
• 컴파일 속도가 빠르고 효율적임(초단위로 이뤄지는 컴파일 속도)
• 빠른 애플리케이션 시작 시간. 재시작이 필요한 경우에 빠르게 복구 가능
• GC(Garbage Collection)가 있어서 높은 성능을 유지하면서도 코드 관리가 용이함
• 멀티코어 CPU를 잘 활용할 수 있음. Goroutine과 Channel을 사용하여, 병렬작업을 쉽게 처리할 수 있음.
• 언어 표현이 단순하고, 개발 생산성이 뛰어남.
• 애플리케이션 프로파일링, 메트릭 수집 등 표준라이브러리에 포함되어 있어서 서비스 운영에 필요한 세부 모니터링과 성능 튜닝에
용이함.(pprof)
• 표준 라이브러리가 풍부함(텍스트, 암호화, 네트워크 등)
• 크로스 플랫폼에서 동작하는 앱을 쉽게 개발할 수 있음.
• 정적 타입 언어이므로 컴파일 타임에 대부분의 오류를 잡을 수 있음.
13
14. 2023.08.05 | Go 도입 후, 4년 간 기록 | Gophercon Korea 2023 | 변규현
Go의 아쉬운 점
• 라이브러리 생태계가 상대적으로 작음. 특히 데이터 분석과 같은 특정 도메인들은 아직 사용하는데 불편함이 있음
• 에러처리가 번거로움. 각 함수를 정의할 때 에러를 반환하도록 설계하기 대문에, 이를 체크하고 처리해야함. 코드 복잡도가
높아질 수도 있음.
• GC는 대규모 힙을 가진 시스템에서 성능 저하를 일으킬 수 있음
• 인터페이스를 적극 활용하면, 런타임 에러에 대해서 디버깅하는데 어려움이 있음. 동적으로 할당되기 때문에 컴파일
타임에 모든 문제를 발견하기 어려움.
• 다른 언어 대비 Generic 사용이 제한적임.
• Spring과 같이 표준화된 개발 방법론이 서비스 개발에 강제되지 않음. 사람에 따라 코드 작성 방식이 다를 수 있음.
14
15. 2023.08.05 | Go 도입 후, 4년 간 기록 | Gophercon Korea 2023 | 변규현
Go가 성능이 좋다고 알려져있죠.
그런데 성능 이슈가 있다면 무엇으로 인해 겪게
될까요?
15
16. 2023.08.05 | Go 도입 후, 4년 간 기록 | Gophercon Korea 2023 | 변규현
직접 겪은 메모리릭 & 성능 이슈
1. Starvation mode of Mutex
2. CPU Throttling Optimization
3. 메모리 최적화하기
4. GC 튜닝하기
16
17. 2023.08.05 | Go 도입 후, 4년 간 기록 | Gophercon Korea 2023 | 변규현
Mutex가 동작하는 모드가 상황에 따라 다르다는 걸
아시나요?
17
18. 2023.08.05 | Go 도입 후, 4년 간 기록 | Gophercon Korea 2023 | 변규현
Starvation mode of Mutex
18
19. 2023.08.05 | Go 도입 후, 4년 간 기록 | Gophercon Korea 2023 | 변규현
Starvation mode of Mutex
19
20. 2023.08.05 | Go 도입 후, 4년 간 기록 | Gophercon Korea 2023 | 변규현
Mutex mode
20
21. 2023.08.05 | Go 도입 후, 4년 간 기록 | Gophercon Korea 2023 | 변규현
Mutex mode
• Mutex는 Normal과 Starvation 중에서 하나의 mode로 있음
• Normal mode는 FIFO 순서대로 대기열에 들어감
• 만약 어떤 Goroutine이 1ms 이상 Mutex를 획득하지 못하면 starvation mode로 전환됨
• Starvation mode에선 mutex의 소유권이 대기열의 맨 앞에 있는 Goroutine에게 넘어감
• 새로운 Goroutine은 mutex를 획득하지 않음. 대기열 끝에 자신을 추가함.
• 만약 어떤 Goroutine이 뮤텍스의 소유권을 획득하고 대기열의 마지막이거나, 1ms이하로 대기했다면
mutex는 다시 normal mode로 전환됨
• starvation mode는 tail latency의 문제점을 예방하기 위해 중요한 선택임
21
22. 2023.08.05 | Go 도입 후, 4년 간 기록 | Gophercon Korea 2023 | 변규현
Solution of mutex starvation mode
• Starvation mode에 진입하여 Normal mode로 전환되지 않고
Queue에 쌓이기만 하는 상황이었음
• 기존 로직에서 Mutex를 여러개 사용할 수 있도록 개선함
• Mutex를 사용하는 그룹을 지정하고, 2000개의 Mutex로 로직을 수행
• MapReduce의 개념을 활용하였음
• 이때 Benchmark로 100/1000/2000/10000등 다양한 케이스에 대해서
돌려봤고, 매직넘버로 2000을 선택함
22
23. 2023.08.05 | Go 도입 후, 4년 간 기록 | Gophercon Korea 2023 | 변규현
Container 환경에서
원치 않는 CPU Throttling을 겪어본 적이 있나요?
23
24. 2023.08.05 | Go 도입 후, 4년 간 기록 | Gophercon Korea 2023 | 변규현
CPU Throttling Optimization
24
25. 2023.08.05 | Go 도입 후, 4년 간 기록 | Gophercon Korea 2023 | 변규현
CPU Throttling Optimization
25
26. 2023.08.05 | Go 도입 후, 4년 간 기록 | Gophercon Korea 2023 | 변규현
CPU Throttling Optimization
• https://github.com/golang/go/issues/33803
26
27. 2023.08.05 | Go 도입 후, 4년 간 기록 | Gophercon Korea 2023 | 변규현
NumCPU가 cgroup에 할당된 것보다
크게 잡히면 어떤 현상이 나타날까요?
27
28. 2023.08.05 | Go 도입 후, 4년 간 기록 | Gophercon Korea 2023 | 변규현
Go runtime scheduler 구조
• G - Goroutine.
• M - Worker thread, or Machine.
• P - Processor. Go code를 실행하기 위한 자원. M은 Go 코드를 실행하려면 관련 P가
필요함. 하지만 블록되거나 시스템 호출 중에는 P가 없을 수 있음
P와 M은 1대1 대응이 되어야함.
만약 cgroup에 할당된 CPU보다 P가 많게 된다면?
-> 할당되지 않은 P에서 처리하는 Goroutine이 스케쥴링 단에서 블로킹됨
28
29. 2023.08.05 | Go 도입 후, 4년 간 기록 | Gophercon Korea 2023 | 변규현
CPU Throttling Optimization
• https://github.com/uber-go/automaxprocs
29
30. 2023.08.05 | Go 도입 후, 4년 간 기록 | Gophercon Korea 2023 | 변규현
CPU Throttling Optimization
• https://github.com/uber-go/automaxprocs
30
31. 2023.08.05 | Go 도입 후, 4년 간 기록 | Gophercon Korea 2023 | 변규현
메모리 최적화 및 GC Tuning 경험이 있으신가요?
가장 높은 트래픽을 받는 서버 이야기에요.
31
32. 2023.08.05 | Go 도입 후, 4년 간 기록 | Gophercon Korea 2023 | 변규현
메모리 사용 개선하기
• 코드개선
• 불필요한 메모리 할당을 최소화
• 메모리 할당을 피할 수 없다면, 할당된 메모리를 재사용
• Runtime 개선
• GC 튜닝
32
33. 2023.08.05 | Go 도입 후, 4년 간 기록 | Gophercon Korea 2023 | 변규현
메모리 사용 개선하기
> 불필요한 메모리 할당을 최소화
• slice & map
• initialization 시에 필요한 만큼만 할당하여 런타임중에 불필요한 malloc 호출 및
mem copy를 줄임
• doubling을 피해 필요한만큼만 메모리 사용
33
34. 2023.08.05 | Go 도입 후, 4년 간 기록 | Gophercon Korea 2023 | 변규현
메모리 사용 개선하기
> 불필요한 메모리 할당을 최소화
• Cap을 미리 알 수 있는 경우, cap을 주어서 초기화
34
35. 2023.08.05 | Go 도입 후, 4년 간 기록 | Gophercon Korea 2023 | 변규현
메모리 사용 개선하기
> 할당된 메모리를 재사용
• 자주 사용되는 객체
• 생성 비용이 비싼 객체
• etc…
이러한 특성들을 가진 객체들에 대한 resource pool을 만듦
35
36. 2023.08.05 | Go 도입 후, 4년 간 기록 | Gophercon Korea 2023 | 변규현
메모리 사용 개선하기
> GC 튜닝하기
• GC Frequency가 높음. 400 gccycle/minute
36
37. 2023.08.05 | Go 도입 후, 4년 간 기록 | Gophercon Korea 2023 | 변규현
메모리 사용 개선하기
> GC 튜닝하기
• GC 작업이 CPU time의 30%를 소모
37
38. 2023.08.05 | Go 도입 후, 4년 간 기록 | Gophercon Korea 2023 | 변규현
메모리 사용 개선하기
> GC 튜닝하기
GC cycle의 횟수를 줄이면 나아질까?
• GC의 Cycle로 인한 Latency 영향도 최소화
• 인프라 비용 절감
38
39. 2023.08.05 | Go 도입 후, 4년 간 기록 | Gophercon Korea 2023 | 변규현
메모리 사용 개선하기
> GC 튜닝하기
• Go의 runtime은 GC와 관련된 많은 튜닝 옵션을 주지 않음.(JVM에 비하면…)
• 튜닝할 수 있는 파라미터가 2개 (1.20버전 기준)
• GOGC
• MemoryLimit
GC에 대한 설명은 go guide(https://tip.golang.org/doc/gc-guide) 참고
39
40. 2023.08.05 | Go 도입 후, 4년 간 기록 | Gophercon Korea 2023 | 변규현
메모리 사용 개선하기
> GC 튜닝하기
• Go runtime의 GC 알고리즘은 CMS
• CMS를 튜닝하는 방법들이 몇 가지 있는데, 저희가 선택한 방법은 soft limit을
기준으로만 GC를 수행함
• gc percent를 기준으로는 GC를 수행하지 않음
• latency가 중요한 서비스이다보니 GC가 Latency에 주는 영향을
최소화하고 싶었음
• GC cycle 횟수 감소를 목표로 설정함
40
41. 2023.08.05 | Go 도입 후, 4년 간 기록 | Gophercon Korea 2023 | 변규현
메모리 사용 개선하기
> GC 튜닝을 위해 고민한 점
• GC가 수행되기전에 순간적으로 메모리를 많이 사용하는 상황이 발생할 경우
OOM으로 어플리케이션이 비정상 종료될 수 있음
• 현재 운영중인 어플리케이션의 메모리 사용 패턴상 순간적으로 메모리를 많이
쓰는 케이스가 생기지 않음
• OOM의 위험이 없다보니 해당 패턴을 사용하기로 결정
• Soft limit을 너무 타이트하게 가져가지 않도록 어느정도 여유를 두고 적용함
41
42. 2023.08.05 | Go 도입 후, 4년 간 기록 | Gophercon Korea 2023 | 변규현
메모리 사용 개선하기
> GC 튜닝하기
• As was
• Default 값
• GOGC=100
• MemoryLimit: no soft limit.
• Now
• GOGC=-1
• MemoryLimit: soft limit은 어플리케이션의 메모리 사용 패턴과 특성을 고려하여
container 스펙의 60~80%정도로 적용
42
43. 2023.08.05 | Go 도입 후, 4년 간 기록 | Gophercon Korea 2023 | 변규현
메모리 사용 개선하기
> GC 튜닝 결과 CPU(약 40% -> 약 25%)
43
44. 2023.08.05 | Go 도입 후, 4년 간 기록 | Gophercon Korea 2023 | 변규현
메모리 사용 개선하기
> GC 튜닝 결과 GC Frequency(400회 -> 8회)
44
45. 2023.08.05 | Go 도입 후, 4년 간 기록 | Gophercon Korea 2023 | 변규현
메모리 사용 개선하기
> GC 튜닝 결과 CPU Time 30% -> 1%
45
46. 2023.08.05 | Go 도입 후, 4년 간 기록 | Gophercon Korea 2023 | 변규현
메모리 사용 개선하기
> GC 튜닝 결과 Pod count 245개 -> 120개
46
47. 2023.08.05 | Go 도입 후, 4년 간 기록 | Gophercon Korea 2023 | 변규현
이 뿐만 아니라 업무생산성을 위한
다양한 노력을 기울이고 있어요
47
48. 2023.08.05 | Go 도입 후, 4년 간 기록 | Gophercon Korea 2023 | 변규현
CPU/Memory 관리를 위한 Autopprof
• https://github.com/daangn/autopprof
48
49. 2023.08.05 | Go 도입 후, 4년 간 기록 | Gophercon Korea 2023 | 변규현
Fluentbit Plugin by Go
Plugin Description
Out bigquery_storage_write
Send record to BigQuery using Storage
Write API.
Out s3_gzipped_multipart Amazon S3 Gzipped Multipart Upload.
Filter ml_feature_logging_extract_example Extract examples from ML Feature Logging.
Filter ml_feature_logging_extract_context Extract context from ML Feature Logging.
49
50. 2023.08.05 | Go 도입 후, 4년 간 기록 | Gophercon Korea 2023 | 변규현
다양한 오픈소스 및 이슈 모음
• Kinesumer: kinesis consumer for Go
https://github.com/daangn/kinesumer
• Autopprof: https://github.com/daangn/autopprof
• Minimemcached: https://github.com/daangn/minimemcached
• DynamoDB HTTP client tracer for Datadog
• Ketama consistent hashing for Memcached
• Go library for Apache Kafka
… 절찬리 생성중…!
50
51. 2023.08.05 | Go 도입 후, 4년 간 기록 | Gophercon Korea 2023 | 변규현
오늘 다루지 않은 내용들
• 도메인 복잡도가 올라가면서 변화하는 코드 변화
• gRPC 서비스 최적화하기
• Error를 다루는 방법
• 로깅을 효과적으로 하는 시스템 디자인
• 마이크로 서비스를 나누는 기준
• K8s 환경에서 네트워크 이슈 트래킹
... 그 밖에 다양한 케이스들
51
52. 2023.08.05 | Go 도입 후, 4년 간 기록 | Gophercon Korea 2023 | 변규현
서비스 신뢰성을 위한 Test case
https://news.kbs.co.kr/data/news/2013/05/30/2667778_70.jpg
52
53. 2023.08.05 | Go 도입 후, 4년 간 기록 | Gophercon Korea 2023 | 변규현
에서 함께
재밌는 문제를 해결할 분을 찾고 있어요!
👆👆채용 보러가기👆👆
53
54. 2023.08.05 | Go 도입 후, 4년 간 기록 | Gophercon Korea 2023 | 변규현
도움을 준 사람들
• 메모리 튜닝 이야기를 공유해준 Lani
• 함께 고생해온 채팅팀
• Go 마스터하기 역자 Lambert
• Head first go 역자 Mingrammar
• 리뷰해준 Gopher들
경험한 일을 아낌없이 공유해준 분들!
54
55. 2023.08.05 | Go 도입 후, 4년 간 기록 | Gophercon Korea 2023 | 변규현
감사합니다.
• Email: novemberde1@gmail.com
• Blog: novemberde.github.io
• Github: github.com/novemberde
55