이 포스트는 2023년에 진행된 GopherCon Korea의 강연 내용을 정리한다.
영상에서의 텍스트 추출은 Voice2Text를 사용했으며, 텍스트의 정리는 ChatGPT의 도움을 받았다.
강연이 많기에 여러 포스트로 분리하여 작성할 예정이다.
Golang 도입, 그리고 4년 간의 기록
https://youtu.be/75X_eBW0mog?si=aQ5z4nlri_0EgbTh
1. 발표 개요
- 발표자: 변교현 (당근마켓 채팅팀 엔지니어링 리드)
- 주제: 당근마켓에서 Golang을 도입하고 4년 동안 운영하면서 겪은 경험 공유
- 핵심 내용:
- Golang 도입 배경 및 초기 고려사항
- Golang 활용 사례 및 주요 이슈
- Golang 성능 최적화 (뮤텍스, CPU 스로틀링, GC 튜닝)
2. 당근마켓에서의 Golang 활용 현황
- Golang을 사용하는 레포지토리: 200개 이상
- Golang을 사용하는 엔지니어: 50명 이상
- 트래픽 규모
- 최대 초당 8만 개 요청 처리 (2코어 10GB 컨테이너 200개 운영)
- 일반적인 서비스는 초당 3만 5천 개 요청 (1코어 1GB 컨테이너 25개)
3. Golang 도입 배경
- 기존에는 Ruby on Rails 사용
- 트래픽 증가로 인해 RDB 부하의 60%가 채팅 서비스에서 발생 → 해결이 필요
- 후보군 비교
- Java (Spring), Kotlin, TypeScript (NestJS), Golang
- Golang이 가장 적합하다고 판단
4. Golang의 장점과 단점
✅ 장점
- 빠른 컴파일 및 앱 실행 속도
- 동시성 처리(고루틴) 지원
- 언어가 단순하여 빠르게 학습 가능
- 성능 최적화가 용이
❌ 단점
- 에러 핸들링이 번거로움 (매번 처리 필요)
- **GC(가비지 컬렉션)**가 대규모 힙 사용 환경에서 성능 저하 가능
- 초기에는 제네릭이 미지원
- 강제된 패턴이 부족하여 개발자별로 코드 스타일 차이 발생
5. Golang 운영 중 발생한 주요 이슈와 해결 방법
✅ 1) 뮤텍스 이슈 (메모리 폭주 문제)
🔍 문제점:
- 특정 시점에서 10분 만에 메모리가 2GB → 8GB로 급증
- sync.Mutex의 스타베이션(Starvation) 모드로 인해 메모리 사용량 증가
- 트래픽이 높아질 때 뮤텍스가 해제되지 않고 계속 대기
🛠 해결 방법:
- 뮤텍스 그룹을 2,000개로 나눠 사용하여 병렬 처리
- Go 벤치마크를 활용해 최적의 그룹 개수(2,000) 선정
✅ 2) 컨테이너 환경에서 CPU 스로틀링 발생
🔍 문제점:
- 컨테이너의 CPU 사용률은 30% 이내로 낮았음에도 CPU 스로틀링 발생
- GOMAXPROCS 값이 호스트 머신의 전체 코어 수(16) 로 자동 설정됨
- 스케줄링 문제로 인해 불필요한 CPU 대기 발생
🛠 해결 방법:
- Uber의 automaxprocs 라이브러리 적용
- import _ "go.uber.org/automaxprocs"
- 컨테이너에 할당된 CPU 개수에 맞게 GOMAXPROCS 자동 조정
- 결과: CPU 스로틀링 완전히 해결
✅ 3) GC 튜닝 (메모리 최적화)
🔍 문제점:
- GC(Garbage Collection) 빈도가 분당 400회 이상 → CPU 사용률 증가
- GC Stop-the-world로 인해 P99 레이턴시 증가
- CPU 사용량의 30%가 GC 처리에 사용
🛠 해결 방법:
- GOGC 비활성화 (GOGC=-1)
- 메모리 리밋 기반 GC 동작 (GOMEMLIMIT 설정)
- 결과:
- GC 실행 횟수: 분당 400회 → 8회로 감소
- CPU 사용량: 15% 절감
- GC 작업 CPU 소모율: 30% → 1%로 감소
- 인프라 비용 절감 (컨테이너 개수 245개 → 120개로 감소)
6. Golang 기반 내부 도구 개발
✅ 1) Auto Pprof (CPU/메모리 모니터링)
- 자동으로 CPU/메모리 이상 감지 후 Slack 알림
- Pprof 분석을 간편하게 수행 가능
- 실시간 트래픽 감시 및 성능 저하 방지
✅ 2) Fluent Bit용 Golang 플러그인 개발
- 고성능 로그 수집기 (C 기반)인 Fluent Bit에 Golang 플러그인 추가
- ML팀, 피드팀 등의 로그 변환 & 적재 최적화
7. Golang을 활용한 오픈소스 및 기술 공유
- 당근마켓에서 Golang 기반 오픈소스 적극 개발 & 공유
- 쿠버네티스 환경에서의 네트워크 이슈 트래킹 기법
- gRPC 최적화 및 마이크로서비스 설계 가이드
- 에러 핸들링 패턴 및 로깅 시스템 구축 사례
8. 결론 & 느낀 점
- “운영 중인 서비스는 항상 달리는 차와 같다” 🚗
→ 새로운 기술 도입 시, 기존 시스템에 영향을 주지 않도록 신중히 진행해야 함 - Golang 도입을 통해 성능 & 비용 최적화 성공
- ✅ 트래픽 급증에도 안정적인 성능 유지
- ✅ CPU 스로틀링, 메모리 누수, GC 이슈 해결
- ✅ 인프라 비용 절감 (컨테이너 개수 절반 감소)
- 기술 공유 & 협업의 중요성
- Golang 전문가들과 협력하며 성능 개선 진행
- Golang 생태계 발전을 위해 적극적인 경험 공유
📌 최종 요약
✅ Golang 도입 후 트래픽 급증을 효과적으로 처리
✅ 뮤텍스 문제 해결 & CPU 스로틀링 방지
✅ GC 튜닝으로 CPU 사용량 절감 & 인프라 비용 절약
✅ Auto Pprof & Fluent Bit 플러그인 개발로 운영 효율성 향상
✅ Golang 기반 기술 공유 & 오픈소스 기여 지속
Golang과 함께 서버 레이턴시를 500배 개선한 후기
https://youtu.be/NVqVS64qClk?si=LGegu9-jc5TozDcR
1. 발표 개요
- 발표자: 박세현 (소프트원 코리아 소프트 엔지니어)
- 주제: Golang을 활용하여 서버 레이턴시를 최대 500배 개선한 과정과 결과 공유
2. 기존 시스템의 문제점
- 기술 스택: PHP, 단일 DB, 블로킹 IO, MVC 기반 서버
- 트래픽 증가: 2014년 대비 4만 배 이상 증가 예상
- IO 바운드 문제: 전체 요청 시간의 99.8%가 서버-결제 제공사 간 통신 대기 시간
- PHP의 한계: 동적 타입 언어의 유지보수 어려움 + 고성능 요구 증가
3. 해결 전략
- 아키텍처 개선
- 마이크로서비스 아키텍처(MSA) 도입 (가능한 부분)
- 기능을 Golang으로 재구현 (분리가 어려운 부분)
- 주요 접근법: 파워로우(Power Law) 활용
- 전체 코드 중 1%의 코드가 99%의 요청을 처리
- 핵심 1% 코드만 Golang으로 재작성하여 성능 개선 극대화
4. Golang을 선택한 이유
- 쉽고 빠른 학습 곡선
- 정적 타입 지원 → 안정성 향상
- 고루틴 활용 가능 → IO 바운드 작업을 효율적으로 처리
- 빠른 콜드 스타트 → 결제 트래픽 급등 시 유연한 대응 가능
- Golang의 강력한 암호화 라이브러리
5. 서버 개선 및 최적화 과정
- 기술 스택 변경
- 웹 서버: PHP → Golang + Fiber (FastHTTP 기반 웹 프레임워크)
- DB 드라이버: 기본 SQL 패키지 (database/sql) + go-mysql
- 캐싱: Redis (go-redis)
- 통신: gRPC 클라이언트 사용
- 테스트: Testcontainers (MySQL 컨테이너 기반) & Mockery (인터페이스 목킹)
- HTTP 요청 최적화 (Fiber)
- 기존 PHP 프레임워크 대비 제로 할당(Zero Allocation) 방식 사용
- HTTP 버퍼 복사 없이 데이터 활용 → 성능 개선
- I/O 병렬 처리 개선 (zipPar 함수)
- 요청 간 의존성이 없으면 고루틴 & 채널 기반 병렬 처리
- 지연 실행 (Lazy Evaluation) 적용 → 필요한 시점에만 실행
- gRPC 요청을 제너릭 인터페이스로 추상화하여 효율적인 호출 처리
- ORM 최적화
- 기존 ORM에서 불필요한 데이터까지 조회하는 문제 해결
- 필요한 정보만 SQL 쿼리로 직접 가져오도록 개선
- 서버 사이드 템플릿 변환
- PHP에서 사용하던 템플릿을 Golang의 템플릿 엔진으로 변환
- 트랜스파일러(Transpiler) 개발 → 자동 변환 및 휴먼 에러 감소
- 무중단 배포 (Blue-Green Deployment)
- ALB의 L7 라우팅 활용 → 특정 엔드포인트만 점진적으로 신규 서버로 이동
- 웨이트 기반 트래픽 분배 → 점진적 배포 & 즉각적인 롤백 가능
- E2E 테스트 및 QA
- 레거시 서버와 신규 서버의 응답이 완벽히 동일한지 검증
- Bug-to-Bug 매칭: 기존 버그까지 그대로 유지하여 예상치 못한 문제 방지
6. 성능 개선 결과
✅ 레이턴시 60배~500배 개선 → 결제창 로딩 속도 대폭 향상
✅ 서버 효율성 14.3배 개선 → 트래픽 증가에도 적은 자원으로 대응
✅ 빠른 오토 스케일링 가능 → 콜드 스타트 속도 향상
✅ CPU 사용량 절감 → 동일 요청 대비 서버당 CPU 사용량 감소
✅ 서버 비용 절감 → 오버 프로비저닝 해소 & 적정한 서버 수 유지
7. 결론
- Golang 도입을 통해 서버 성능과 유지보수성을 극적으로 향상
- 파워로우 법칙을 활용한 효율적인 코드 재작성 전략
- 고루틴과 병렬 처리를 통한 IO 최적화로 서버 부하 감소
- 점진적 배포 전략(L7 라우팅)으로 안정적인 전환 수행
- 결과적으로 서버 비용 절감 + 사용자 경험 향상
- 💡 "포트원의 고(Golang) 사랑이 더욱 커졌다!" 😆
컨텍스트를 이용한 상태 관리
https://youtu.be/o844Ghyjfnw?si=HqaV_P-_NThYFk8_
1. 발표 개요
- 발표자: 권용민 (아프리카TV)
- 주제: Golang의 context 패키지를 활용한 상태 관리 방법 소개
- 대상: Golang 초보자 및 context 사용법을 잘 모르는 개발자
2. context 패키지란?
context 패키지는 API 경계를 넘어 작업 간에 데드라인, 취소 신호, 요청 스코프의 값 전달을 위한 기능을 제공한다.
주요 역할:
- 데드라인 설정 (WithDeadline)
- 취소 기능 (WithCancel, WithTimeout)
- 값 전달 (WithValue)
- 함수 간 context 전파
모든 context 객체는 기본 인터페이스를 구현해야 한다.
Deadline() | context가 만료되는 시간 반환 |
Done() | context가 취소될 때 닫히는 채널 반환 |
Err() | context 취소 시 에러 반환 |
Value(key) | context에서 특정 키의 값 반환 |
3. 기본적인 context 종류
- context.Background()
- 가장 기본적인 context.
- 프로그램의 최상위 부모 context로 사용됨.
- context.TODO()
- 아직 context가 필요할지 모를 때 임시로 사용.
- context.WithCancel(parentCtx)
- 취소 가능한 context 생성.
- cancel() 함수 호출 시, Done() 채널이 닫히고 모든 하위 context에 취소 신호가 전파됨.
- context.WithTimeout(parentCtx, duration)
- 지정된 시간 이후에 자동으로 cancel() 호출됨.
- WithDeadline()과 유사하지만, 상대적인 시간(duration)으로 설정.
- context.WithValue(parentCtx, key, value)
- 요청 스코프 내에서 데이터를 전파하는 context.
- 예: JWT 토큰, 사용자 정보 등을 저장하여 핸들러 간 공유 가능.
4. 예제 코드 및 사용 사례
✅ 예제 1: 작업 영역 정의 및 제한 설정
- 웹 서버 전체를 제어할 수 있는 context 생성 (notify.Context())
- 웹 서버 종료 시 모든 핸들러도 함께 종료되도록 context 전파
- 각 요청마다 timeout 적용 (WithTimeout())
- Shutdown()을 사용하여 graceful 종료 처리
✅ 예제 2: 요청 범위 내 데이터 전파
- JWT 인증 미들웨어에서 클레임을 context에 저장 (WithValue())
- 이후 핸들러에서 context에서 사용자 정보를 꺼내어 활용
- Value() 메서드 호출 시 타입 안정성을 위해 key에 type alias 사용
✅ 예제 3: 작업 종료 시 리소스 정리 (소멸자 역할)
- TCP 서버의 연결 관리
- 싱크풀(sync.Pool) 활용하여 메모리 재사용 최적화
- 연결이 종료될 때, context의 AfterFunc()를 활용하여 헤더 반환
✅ 예제 4: 같은 작업 영역 내 에러 전파
- P2P TURN 서버에서 Sender와 Receiver 간의 연결 관리
- WithCancelCause()를 사용하여 context가 왜 취소되었는지 원인(Error)까지 전파
- 기존 코드에서는 별도의 채널 및 전파 로직이 필요했으나, context 하나로 해결 가능
5. Golang 1.21에서 새롭게 추가된 기능
- context.AfterFunc(ctx, func())
- context가 종료될 때 자동으로 특정 함수 실행 가능
- ex) 연결 종료 시 리소스 정리 자동화
- context.WithCancelCause(ctx, error)
- cancel() 호출 시 취소 이유를 함께 저장 가능
- 이후 ctx.Err() 대신 ctx.Cause()를 호출하면 취소 원인 반환
6. 결론 및 활용 포인트
- 작업 흐름 제어: WithCancel()을 사용해 취소 신호를 전파
- 데이터 전파: WithValue()를 활용하여 요청 범위 내에서 JWT, 사용자 정보 전파
- 리소스 관리: AfterFunc()를 통해 연결 종료 시 자동 리소스 반환
- 에러 전파: WithCancelCause()를 통해 취소 원인(Error) 전파 가능
📌 최종 정리
✅ context 패키지는 취소 신호 전파, 데이터 공유, 작업 제한 설정을 쉽게 해줌
✅ 기존 코드에서 복잡한 상태 관리 로직을 단순화할 수 있음
✅ Golang 1.21에서 추가된 기능을 활용하면 더 효과적인 리소스 관리 가능
✅ context를 잘 활용하면 웹 서버, TCP 서버, P2P 네트워크 등에서 더욱 효율적인 상태 관리 가능
AWS Lambda in Go (with Kafka)
https://youtu.be/l42VTNbWKaI?si=CjLf1JCAyb8G4ie9
1. 발표 개요
- 발표자: 김수빈 (비바 리퍼블리카)
- 주제: AWS Lambda를 활용하여 슬랙 웹훅 이벤트를 안정적으로 처리하는 아키텍처 구축
- 핵심 내용:
- 기존 아키텍처의 문제점
- 새로운 아키텍처 설계 및 Golang 도입
- AWS Lambda, Kafka(MSK) 활용 경험
- 성능 최적화 및 현재 고민
2. 기존 아키텍처와 문제점
✅ 기존 아키텍처
- 슬랙 웹훅 요청을 Python 기반 서비스에서 직접 처리
- Kubernetes(K8s) 기반 API 서버에서 처리
- 트래픽이 많을 경우 API 서비스에도 장애 발생
❌ 문제점
- 슬랙 웹훅 트래픽 급증 시 API 서비스까지 영향을 줌
- DB 부하 증가 (최대 분당 2만 건)
- 모놀리식 구조로 인해 장애 전파 위험
- 임시적인 CPU/메모리 증설로 해결 → 비용 증가
3. 새로운 아키텍처 (AWS Lambda + MSK)
✅ 개선 목표
- 서버리스(AWS Lambda) 도입 → 트래픽 폭증에 안정적으로 대응
- 이벤트 큐(MSK) 활용 → 메시지 기반 아키텍처로 DB 부하 분산
- 고루틴을 활용한 경량 프로세스 처리
✅ 새로운 아키텍처 구성
- AWS API Gateway → 슬랙 웹훅 요청 수신
- AWS Lambda (Go 기반) → 이벤트 전처리 및 Kafka(MSK)로 전달
- Amazon MSK (Managed Kafka) → 메시지 큐 기반 이벤트 처리
- EKS 내 Python 컨슈머 → Kafka에서 메시지를 가져와 최종 처리
4. 주요 기술 스택 및 경험
✅ 1) AWS Lambda 개발 환경 (SAM CLI)
- AWS SAM(Serverless Application Model) CLI 활용
- Lambda 환경 설정, 로컬 개발 및 배포 용이
- sam local invoke로 이벤트 테스트 가능
✅ 2) Golang을 선택한 이유
- 단일 바이너리 배포 가능 → 종속성 관리가 쉬움
- 빠른 실행 속도 & 낮은 메모리 사용량
- 서버리스 환경에서 작은 패키지 크기 유지 (최종 빌드: 6.8MB)
✅ 3) Kafka 프로듀서 라이브러리 선택
- IBM Sarama (과거 Shopify Sarama → IBM에서 유지보수)
- 순수 Go(Pure Go) 구현 → C 바인딩이 없어 크로스 플랫폼에서 문제 없음
- Confluent Kafka Go 대신 사용 (C 라이브러리 의존성을 피하기 위해)
✅ 4) AWS Lambda 핸들러 구현
- AWS Lambda Go SDK (aws-lambda-go) 활용
- 다양한 이벤트 소스를 쉽게 처리 가능 (API Gateway, EventBridge 등)
5. 새로운 아키텍처 적용 후 결과
✅ Lambda 실행 시간: 평균 500ms, 최대 3000ms
✅ 처리량: 시간당 최대 20만 건
✅ 비용 절감:
- API Gateway: $170/월
- Lambda: $30/월 (추가 최적화 가능)
- 총 비용 $200/월로 기존 대비 절감
6. 현재 고민 및 최적화 방향
❗ 1) Lambda 실행 시간 단축
- ARM 기반 프로세서(Graviton2) 사용 검토
- Kafka REST Proxy 도입 검토 (그러나 SPOF 우려)
- Kafka Flush 최적화 (이벤트 배치 처리)
❗ 2) 슬랙 웹훅 응답 최적화
- 현재는 Lambda가 Kafka로 이벤트 전달 후 바로 200 응답
- 슬랙 UI에 즉각적인 응답이 필요한 경우 처리 방안 고민
📌 최종 요약
✅ AWS Lambda + Kafka(MSK)로 서버리스 아키텍처 구축
✅ Python → Golang 전환으로 성능 & 배포 최적화
✅ Lambda 패키지 크기 최소화 (6.8MB) → 빠른 배포 & 실행 속도
✅ Kafka 도입으로 안정적인 메시지 처리 및 장애 격리
✅ 비용 절감 (기존 대비 더 저렴한 운영 가능)
✅ 추가 최적화 필요 (Lambda 실행 시간 & Kafka 최적화)
'컨퍼런스 정리' 카테고리의 다른 글
GopherCon Korea 2024 Day 1 정리 (0) | 2025.03.22 |
---|---|
GopherCon Korea 2023 정리 4편(최종) (0) | 2025.03.18 |
GopherCon Korea 2023 정리 3편 (0) | 2025.03.18 |
GopherCon Korea 2023 정리 2편 (0) | 2025.03.18 |