전화위복

2024년 8월 21일 수요일

Today I Learned

날짜

2024년 8월 21일 수요일

내용

전화위복

대참사도 이런 대참사가 따로 없다! 결국 매일 오전 정기 업데이트는 작동하지 않았다.

추가로, 정기 업데이트가 같은 네이버 API를 사용해서 발생하는 문제인 것으로 확인했습니다. 따라서 현재 같은 광고계정 간의 동시처리 금지 정책을 같은 관리자 계정 간의 동시처리 금지 정책으로 변경해야 할듯 합니다. 이렇게 되면 사용성이 많이 떨어져서 현재 진행 로직을 좀 변경할 계획입니다. 현재

  1. 최근 50일치 데이터 생성 및 다운로드(네이버 API 사용)
  2. 데이터 전처리(네이버 API 사용 X)
  3. 50일전~ 100일전 데이터 생성 및 다운로드(네이버 API 사용)
  4. 전처리(네이버 API 사용 X)

…400일치 누적되면 구글 API를 이용해 삽입하는 모양새를 취하고 있는데, 각각 2,4번이 꽤 작업이 오래걸립니다(전체 시간 중 약 70~80%).따라서 일괄 생성 및 다운로드 방식으로 변경할 계획입니다.

  1. 최근 50일치 생성 및 다운로드
  2. 50일전~ 100일 전 데이터 생성 및 다운로드
  3. 400일치 다운로드가 완성되면 데이터처리 시작

이렇게 되면 데이터 전처리 시간 동안 다른 로우데이터가 네이버 API를 사용하기 때문에, 다수의 작업이 빠르게 처리도힐 수 있고 API 사용이 겹쳐 발생하는 문제도 어느정도 해소할 수 있을 듯합니다.

< ‘사실 내가 멍청하게 만들었어요’를 숨기기 위해 개선을 위한 의견인 척하는 slack 중 일부>

쉽게 말하면 뒤집어 엎어야 한다!

  1. 네이버 API는 관리자 계정 당 한 명만 사용해야 한다.

현재는 광고계정 별로 따졌지만 이제는 관리자 계정마다 따져야 한다. 더 정확히는, customer id 마다 따져야 한다. 같은 회사에서 근무하는 두 유저가 같은 네이버 api 키를 사용할 수도 있으니까! 그렇다고 로직이 시작할때마다 모든 유저를 탐색할 순 없는 노릇이다. 그래서 새로운 테이블을 만들었다.

1
2
3
4
5
6
7
8
9
10
11
12
class NaverApiUsageStatus(Base):
    __tablename__ = "naver_api_usage_status"

    id = Column(Integer, primary_key=True, index=True)
    naver_customer_id = Column(String, index=True, unique=True)
    is_using = Column(Boolean, default=False)
    created_at = Column(DateTime(timezone=True), default=datetime.now(tz=timezone.utc))
    updated_at = Column(
        DateTime(timezone=True),
        default=datetime.now(tz=timezone.utc),
        onupdate=datetime.now(tz=timezone.utc),
    )

naver_customer_id가 uniuque하게 저장되어 관리된다. 만약 누가 API를 쓰려고 하면 naver_customer_Id로 데이터를 찾아 is_using 을 True로 바꿔준다. 이 때 똑같은 API 키를 사용하는 다른 쪽은 사용할 수 없게된다.API를 더이상 사용하지 않으면 저 데이터를 찾아 다시 False로 바꿔주면 된다. 대기열일 때 연관된 다른 것들을 모두 찾아 상태를 살필 필요 없이 저 데이터 하나만 참조하면 되니 편하다. 멀티쓰레드를 공부할 때 본 락이나 세마포어를 이런 느낌으로 쓰일줄은 몰랐다..

이 로직이 제대로 작동하기 위해선 각각이 API 사용을 최대한 빨리 끝마쳐야 한다. 지금은

1
2
3
4
5
6
7
8
 1. 50일치 보고서 생성(1분, 네이버 API 사용)
 2. 50일치 보고서 다운로드(2분, 네이버 API 사용)
 3. 50일치 데이터 처리(12분) ⇒ 하지만 언제 4로 넘어갈지 모르니 네이버 API 권한 필요)
 4. 그 다음 50일치 보고서 생성(1분, 네이버 API 사용) ⇒
 …
 로직 종료(120분)
 
 15분 X 8 = 120분 내내 API 사용에 대한 권한 필요!

이 반복된다. 보고서 생성, 다운로드떄마다 API를 사용하는데 결국 로직이 끝날때 까지 네이버 API 사용 권한을 들고있어야 한다. 그럼 꼼짝없이 다른 친구들은 2시간을 기다려야 하는 문제가 생기고 하루에 많아야 24개밖에 처리를 못한다.

그래서 사용을 몰아뒀다.

1
2
3
4
5
6
7
8
9
10
11
1. 50일치 보고서 생성(1분) ⇒ 
2. 50일치 보고서 다운로드(2분) ⇒ 
3. 그다음 50일치 생성(1분) ⇒ 
4. 다운로드(2분) ⇒ 
… 
17. 다운로드 끝(네이버 API 사용 끝) => 더이상 쓸 일 없음

400일치 데이터 처리 시작(96분, 네이버 API와 전혀 무관)

3분 X 8 = 24분만 API 사용 권한을 들고 있으면 된다!
 

로 바꿨다. 사실 데이터처리가 대부분의 시간을 잡아먹으니 생성과 다운로드만 따로 하면 시간이 그렇게까지 오래걸리진 않는다. 400일치 다운로드가 끝나는 순간 “난 이제 데이터 처리하러 가볼테니 네이버 API 쓸 사람 쓰셈~” 하면 된다. 두 번째 순서의 작업도 다쓰면 넘겨주면 되고. 데이터 처리 자체는 동시에 발생해도 된다. ecs 크론으로 처리하니 별도의 컨테이너에서 처리되어 서로 리소스가 낭비되지 않는다. 오히려 돈을 많이 쓰면 겁나 빨라질 수도..?

이 작업을 위해서, 각 처리 과정을 잘게 쪼갰고 각 다운로드 받은 파일의 이름도 정확하게 처리했다. 대충 만들고 덮어쓰고 하면 안되니까… 상당히 복잡한 작업이라 걱정이 됐는데 막상 해보니 코드가 깔끔해지고 있다. 그동안 내가 작동하게 만든다고 얼마나 중복이 가득하고 비효율적인 코드만 써댔는가… 심지어 보고서 생성을 요청하면 반환값으로 보고서 다운로드 링크를 보내주는데, 굳이 보고서 다운로드 링크를 조회하는 API를 또 쓰고 있었다. 2번만 보내면 되는 요청을 3번 보내고 있었던 건가?

그외에도 그동안 데이터 생성, 데이터 수동 업데이트, 첫번째 연동 실패 시 재연동, 수동 업데이트 실패 시 재연동 등 로직이 복잡했다. 이제보니 굳이 안나눠도 될 것 같다!

이참에 다시 깔끔하게 잘 만들어보자. 오히려 좋을 지도..?

회고

정신승리 on