AWS를 사용하다보면 API 제한에 걸릴 수 있다. AWS의 서비스 품질을 안정화하기 위한 조치 중 하나이다. 스핀에커(Spinnaker)에서는 AWS에 생성한 자원의 상태를 알기 위해서 주기적으로 AWS API(Application Programming Interface)를 호출하는데, AWS 자원이 많아 지면 호출 수는 꽤 많아진다. 그렇게 되면 어느 순간 AWS에서 지정한 제한선에 도달하게 된다. 그러면 일부 인스턴스들의(Instances)의 현재상태를 알 수 없게된다. 이러한 문제를 해결하기 위해서 AWS의 제한을 늘려달라고 요청할 수 있다. 하지만 AWS에서 항상 높여 주는 것은 아니다. 여유가 되는 범위안에서 높여 줄 수 있다. 그래서 다른 한 편으로는 스핀에커의 설정을 변경하여 AWS를 호출하는 빈도를 줄이는 것이 필요하다. 아래는 호출 빈도를 지정하는 설정이다. 아래 예시에서 로드발란서(ELB, Elastic Load Balancer)에 지정한 숫자는 한창 문제가 발생할 당시에 스핀에커에서 AWS를 호출하는 빈도를 극도로 낮춘 값이다. 지금은 스핀에커에서 인스턴스의 상태를 확인하는 방식이 개선되었고, 스핀에커에서 로드발란서를 잘 못 부르는 문제를 해결했기 때문에 아래 예시에서 설정한 값보다 높은 값을 설정해도 괜찮다.
아래 예시의 숫자는 1초마다 몇 번의 호출을 할 것인지 결정하는 것이다. AmazonElasticLoadBalancing 밑에 rateLimit 값이 1이면 1초당 1번 부르겠다는 뜻이된다. 이 값을 조정하는 것에 따라 AWS API 호출 수 제한을 넘지 않도록 조정할 수 있을 것이라고 판단해서 15였던 값을 3으로 바꾸어 보았다. 그래도 여전히 문제가 발생해서 1로 바꾸어보았다. 약간 나아지기는 했지만 문제를 완전히 해결하지는 못했다.
당시에 AWS 담당자에게 문제의 원인파악을 위하여 일시적으로나마 호출 수 제한을 올려 볼 수 있는 지 문의하였다. 그러나 AWS 담당자는 AWS 문제라고 단정할 수 없기 때문에 API 호출 수 제한을 쉽게 늘려줄 수 없다고 말했다. 결국 하는 수 없이, 스핀에커에서 인스턴스 상태가 알 수 없음(Unknown)으로 나오는 것이 API 호출 수 제한 때문이라는 것을 직접 증명해야 했다. 그러나 스핀에커의 rateLimit 설정 값을 퍼최소 값이라고 생각한 1로 변경했지만 상태가 나아지지 않았고 원인을 뚜렷하게 단정지을 수 없었다. 그러다가 문득, 예제의 값 중에 소수점이 있다는 것을 발견하고, 숫자를 0.1로 변경해 보았다. 그러자 스핀에커에서 오류가 나지 않았다. 심지어 알 수 없음으로 나오던 인스턴스의 상태가 정상을 회복했다. 그래서 상황을 설명하기 위해 가설을 세웠다. 스핀에커가 필요이상으로 AWS API를 많이 호출했든, 또는 인스턴스가 많아져서 AWS API를 많이 호출했든, 문제의 원인은 API 호출 수 제한에 걸렸기 때문이었던 것 같았다. 최대 1초당 한 번 호출하던 빈도를 10초에 한 번 호출하는 설정으로 바꾼 것이 API 호출 수 제한을 피할 수 있었던 결정적인 판단이었다. 그래서 AWS와 다시 이야기를 시작했고 AWS에서는 API 호출 제한 값을 올려주었다.
serviceLimits:
cloudProviderOverrides:
aws:
rateLimit: 15.0
implementationLimits:
AmazonAutoScaling:
defaults:
rateLimit: 0.5
AmazonElasticLoadBalancing:
defaults:
rateLimit: 0.1
당시 스핀에커에서는 일부 로드발란서의 버전을 제대로 구분하지 못하고 다른 세대의 API를 호출하는 오류가 있었다.
AWS의 ELB는 현재 클래식 로드발란서(CLB, Classic Load Balancer), 어플리케이션 로드발란서(ALB, Application Load Balancer), 네트워크 로드발란서(NLB, Network Load Balancer)가 있다. 클래식 로드발란서는 1세대(V1), 어플리케이션 로드발란서와 네트워크 로드발란서는 2세대(V2)로 구분한다. 두 가지 버전의 로드발란서의 가장 큰 차이점으로 타겟그룹(Target Group)의 사용여부다. 2세대 로드발란서들은 타겟그룹을 사용한다. 그래서 로드발란서에 연결된 인스턴스의 상태를 조회하기 위해서는 서로 다른 AWS API를 구분해서 호출해야 했다. 그런데 당시 스핀에커에서는 어플리케이션 로드발란서에 연결된 인스턴스의 상태를 조회하기 위해 어플리케이션 로드발란서를 위한 API와 클래식 로드발란서를 위한 API를 모두 호출하는 문제가 있었다. 물론 이렇게 호출하면 HTTP 400 오류를 반환했고, 그렇게 되면 스핀에커에서는 예외처리를 하고 그냥 넘어갔다. 그래서 처음에는 크게 문제가 되지 않았다. 스핀에커에서 다루는 인스턴스의 수가 감당할 만한 수준이었기 때문이었다. 그래서 엉뚱한 버전의 로드발란서를 찾는 API를 호출해도 눈에 띄는 문제는 없었다. 그러나 인스턴스의 수가 늘어남에따라 API 호출이 비례하여 늘어났고 곧 AWS API 제한에 도달했다. 인스턴스의 수가 늘어난 것이 API 제한에 도달한 직접적인 원인이었지만, 엉뚱한 AWS API를 호출함으로써 무의미하게 호출 기회를 날려버린 것도 API 제한에 도달하는 시간을 줄이는 일에 한 몫 했다.
우리가 먼저 이러한 일을 겪은 후 다른 여러 곳에서도 비슷한 일이 일어났다. 결국 넷플릭스(Netflix) 담당자에게도 전달이 되었다. 그리고 문제가 되는 부분이 수정되었다. 넷플릭스는 오픈소스(Open Source) 스핀에커와 달리 AWS의 정보를 주기적으로 보관하는 캐시(Cache) 서비스인 Edda를 사용하기 때문에 이러한 문제상황을 늦게 알았다고 말했다. 지금은 API 제한과 관련해서는 문제가 없다. 대신 ECS(Elastic Container Service)를 사용할 경우 기존 인스턴스보다 훨씬 많은 인스턴스의 상태를 수시로 확인해야 하기 때문에 AWS API를 자주 부를 가능성이 있다. 그래서 많은 양의 컨테이터 인스턴스를 생성해서 동일한 문제가 발생하는 지 점검하고 있다.