이전 게시물에서 doka에 대한 간략한 설명을 했다.
금요일날 배포를 했고, MSK/Kinesis에 문제가 없어서 퇴근을 했다. 그리고 주말이 지났는데..
월요일날 확인해보니 MSK에서 Offset은 업데이트가 되고 있었는데 Kinesis에는 데이터가 안들어오는 문제가 발생했다.
그리고 로그를 확인하면 아래와 같이 Put record fail + ExpireToken을 확인할 수 있었다.
- 로그만 보면 CrossAccount Sts Token Expire로 인해 Kinesis Put Record가 실패한것 같다.
Expire Token 문제가 뭘까?
CrossAccountSts를 획득하는 코드를 보면 아래와 같다. Sts Token을 만드는것 자체에는 문제가 없다.
찾아보니 Sts는 Expire Time이 존재한다고 한다! 기본값이 1시간이고, 최대 12시간까지 늘릴 수 있는것 같다.
코드에서 별도의 Expire Time 인자가 없기 때문에 기본값을 사용하고 1시간이 지나 Expire Token 에러와 함께 Put Record Fail이 발생한것으로 추정한다.
// Get CrossAccoutn Sts Token
func createCrossSession(session aws.Config) aws.CredentialsProviderFunc {
conf := configs.GetConfig()
stsClient := sts.NewFromConfig(session)
roleSessionName := fmt.Sprintf("doka-%s-%s", viper.GetString("ENV"), uuid.NewString())
stsInput := &sts.AssumeRoleInput{
RoleArn: aws.String(conf.GetString("aws.crossAccountArn")),
RoleSessionName: aws.String(roleSessionName),
}
stsOutput, err := stsClient.AssumeRole(context.TODO(), stsInput)
if err != nil {
loggers.GlobalLogger.Fatal(err)
}
//
crossAccountSts := aws.CredentialsProviderFunc(func(ctx context.Context) (aws.Credentials, error) {
return aws.Credentials{
AccessKeyID: *stsOutput.Credentials.AccessKeyId,
SecretAccessKey: *stsOutput.Credentials.SecretAccessKey,
SessionToken: *stsOutput.Credentials.SessionToken,
Source: conf.GetString("aws.crossAccountArn"),
}, nil
})
return crossAccountSts
}
Sts 갱신 문제 어떻게 수정할까?
그렇다면 어떻게 해야할까? 여러가지 옵션이 있을것 같다.
- Sts Expire Time을 늘린다.
- 하지만 이는 시간만 늘릴뿐 원인 해결이 되지 않는다.
- Get CrossAccount Sts Token을 주기적으로 진행한다.
- Put Record를 하는 시점에 Sts Token 유효값을 확인한 다음에 유효하지 않는다면 Token을 다시 만든다.
- Expire 되기 이전에 특정 시간마다 Token을 다시 만든다.
"Expire 되기 이전에 특정 시간마다 Token을 다시 만드는 방법"을 선택했다. 왜냐하면 Sts Token 유효값을 확인하는 조건을 넣는것보다는 특정시간마다 재생성하는것이 코드 관점에서 더 깔끔하고/로직상 단순하게 갈 수 있다고 생각했기 때문이다.
하지만, 또 생각을 해보니.. 특정 시간마다 Token을 다시 만드는데, 이때 Put Record 작업이 동시에 일어난다면 Race Contidion 문제가 발생할 수 있을것 같았다. 그래서 작업간 Mutex Lock을 걸어서 동일 리소스에 대한 동시 작업을 피하기로 했다.
// CrossAccount Role을 30분마다 갱신하기 위함
// kinesisClient 변수가 경합이 발생할 수 있으므로, 작업 간에 mutex 추가
func (s *Streamer) RenewClient() {
ticker := time.NewTicker(30 * time.Minute)
defer ticker.Stop()
for {
loggers.GlobalLogger.Println("crossaccount session renew after 30 minute")
select {
case <-ticker.C:
s.mutex.Lock()
session, _ := getOriginalSession()
newCrossAccount := createCrossSession(session)
newKinesisClient, _ := createCrossKinesisSession(newCrossAccount)
s.kinesisClient = newKinesisClient
loggers.GlobalLogger.Println("renew crossaccount session")
s.mutex.Unlock()
}
}
}
처음에는 time.Sleep으로 구현했었는데, 주기적으로 실행하는 작업일 경우네는 Ticker를 예시가 많아서 Ticker로 구현했다.
Sts Token이 1시간 Expire Time이므로, 30분마다 Ticker 틱이 만들어지도록 했다. 그리고 select/case로 Ticker 채널에 값이 들어오면 Sts를 새로 갱신하는 식으로 구현했다.
- 이때 kinesisClient를 값을 변경해야 하므로 RenewClient를 포인터 리시버로 구현했다.
30분마다 Sts Token을 갱신하도록 하는 것은 이해했다. 그럼 이제 이걸 어떻게 실행할까?가 중요한 포인트이다.
기존의 Msk Consume, Kinesis Produce는 그대로 진행되야 하므로, Sts Token은 병렬적으로 실행되어야 하고 이때를 위하 고루틴을 사용했다.
고루틴을 사용할 때 중요한건 무분별하게 고루틴이 실행되면 안되는것이다. 그래서 최초 1회만 실행되는 Instance를 만드는 함수에 추가했다.
// NewConsumer는 1번만 실행
func NewConsumer(streamer *streamers.Streamer) *Consumer {
conf := configs.GetConfig()
consumer := &Consumer{
streamer: streamer,
conf: conf,
}
go consumer.streamer.RenewClient()
return consumer
}
그럼 로그가 아름답지는 않지만, 아래와 같이 30분마다 Sts Token이 갱신되고 Put Record에 문제가 발생하지 않는다.
야호
조금만 생각해보면 Sts Token Expire Time이 있는것은 당연하다. 현재 Okta를 통해 Sts Token을 발급받고 AWS를 사용하는데, 여기에도 Expire Time이 있기 때문에 몇시간마다 다시 로그인을 해주고 있다. 당연한데, 개발을 할 때 생각하지 못했다. 왜냐? Service Account에 할당된 Role을 쓸때는 Expire Time이 따로 없기 때문이다.
Service Account의 역할을 사용하는 것도 실제로는 Sts Token을 발급받아서 사용하는 방식이다. 물론 Expire Time도 존재한다.
하지만 이는 EKS에서 자동 갱신해주기 때문에 사용자가 따로 Expire Time을 관리할 필요가 없는것이다.
이번에 Mutex, Expire Time, 고루틴에 대해 Go 공부를 할 때 가장 다른 언어와 다른 점이 고루틴이라고 생각한다.
병렬적으로 처리한다. 말은 쉽지만 고루틴을 잘못쓰면 Mem Leak이 발생하고, 어떤 경우에 고루틴을 사용해야 하는지 아직 감이 안온다.
문제는 있었지만, 해결되었고 이로써 한단계 또 발전했다!!
끝!
'개발 이모저모 > Golang' 카테고리의 다른 글
[go] Prometheus Metric 만들고, 모니터링하는 방법 (1) | 2024.01.01 |
---|---|
[go] 내가 만든 kafka-connector to kinesis, 통칭 doka-connector (0) | 2023.12.21 |
[go] Golang 개발을 시작하자! (0) | 2023.11.26 |