Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

13-6 [BE] [Fix] Request batcher 로직 수정 #89

Merged
merged 6 commits into from
Dec 6, 2022
Merged

Conversation

leesungbin
Copy link
Member

@leesungbin leesungbin commented Dec 5, 2022

개요

  1. GitHub Actions Fail 오류 수정
  2. Request batcher에 대한 로직을 수정
  • 파란 상자 안에 있는 부분이 추가되었습니다.
    image
  • 키워드로 검색한 논문별로 reference까지 하나씩 탐색하던 로직을 삭제했습니다.
  • 사용자로부터 reference에 대한 doi를 직접 검색요청받았을 때, doiQueue에 검색 요청이 들어가며 해당 논문의 reference까지 탐색합니다.
    image

작업사항

  • Dockerfile BE / FE 수정 (npm i -> npm ci) [CI/CD] BE 이미지 Docker build시 Fail 하는 현상 #87
  • Too many request를 최대한 방지하기 위해 batch 설정 변경
    • default TIME_INTERVAL 을 3초에서 1초로 줄이고, batch 한 단위가 끝나야만 다음 batch를 실행할 수 있도록 함
    • Too many request 발생시, RESTART_INTERVAL 만큼 요청을 보내지 않음 (Batcher 내부에 block 변수를 static하게 선언)
    • crossref에 요청을 보낼 때, 1분 정도가 걸릴 때도 있고, 재요청 보냈을 때 요청이 빨리 올 것이라는 기대를 할 수 없어서, axios timeout 시간을 1분으로 변경 (+ sort=is-referenced-by-count 쿼리를 제외해야하나 고민 중 이지만, 해당 keyword에 대해 너무 많은 검색결과가 나올 수 있는 경우, 1개의 키워드에 대한 결과를 수집하는데만 4-5시간 정도 걸릴 것으로 예상되어, 우선 순위가 높은(많이 인용당한) 논문 순으로 우리 DB로 가져오는 것은 필요한 작업이 아닐까하는 생각이 됨)
  • redis에 검색했던 keyword를 설정할 때 소문자로 변경하여 저장 / 조회
  • /search/stat에서 서버의 batch queue 상태와, elasticsearch db 상태를 확인할 수 있음 (debug 용)

리뷰 요청사항

  • doi로 논문을 조회할 때, 해당 논문의 reference에 대한 정보를 가져오기위해, 총 2번의 get 요청(1. doi에 해당하는 논문 보내줘, 2. referenceList에 있는 논문들의 doi들로 multiGet operation을 만들었으니 여기 해당하는거 다 보내줘)을 elasticsearch에 보냅니다. 이게 N+1 문제에 해당할까요?

sort할 경우 요청 당 너무 많은 시간이 소요된다.
http timeout 60초로 변경(crossref가 결과를 주기까지 꽤 오랜 시간이 걸림, 재요청했을 때 빠를 것임을 기대할 수 없음), keyword set과 queue에
push하는 로직을 분리(doi도 keyword로 취급하는 중)
too many request가 너무 자주 발생 -> batch 단위 절반으로 수정, 428 발생시, RESTART_INTERVAL 만큼 batch 중지
@leesungbin leesungbin marked this pull request as ready for review December 5, 2022 07:04
@github-actions github-actions bot requested review from JunYupK and Palwol December 5, 2022 07:04
@leesungbin leesungbin linked an issue Dec 5, 2022 that may be closed by this pull request
Copy link
Collaborator

@JunYupK JunYupK left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

제가 이해한 것이 맞다면 현재 setInterval을 통해 runBatch를 주기적으로 실행하고, Batcher라는 클래스에 내부적으로 blocked와 실행 여부를 변수로 관리하는 듯 합니다.

이를 통해 실행할 때마다 blocked와 running 여부를 체크 하고 실행을 하는 것으로 보입니다.
(blocked와 running 이 true이면 return)
이는 큐에서 전의 요청이 정상적으로 response를 받고 Too Many Request를 피하기 위한 방법으로 이해를 했는데
blocked와 running 여부를 매번 확인하는 것이 아니라 그냥 외부 api를 요청하고 await 후 response를 받은 후에 해당 response의 유효성을 검증하는 방식을 적용할 수 없나요?

리뷰 요청 사항

일반적인 DB라면 N+1 문제에 해당한다고 생각합니다.
그러나 엘라스틱서치에서는 해당하는지는 좀 더 학습이 필요하다 생각되네요
inverted index의 특징을 생각하면 apple이라는 키워드로 단순히 get 요청을 했을때는 apple이 들어간 데이터의 인덱스를 모두 가지고 있으니, N+1의 문제가 발생하지 않지만,
한 논문에 대한 ref목록의 doi 들로 get 요청을 하면 n개의 doi 키워드로 검색을 하면 당연히 n번의 get요청이 들어갈 것이라 생각합니다.
=> N+1이 발생하겠네요
하지만 elasticsearch의 multi math query를 사용하면 성능이 향상된다는 글이 있네요.
https://stackoverflow.com/questions/62318268/multi-match-query-and-the-scoring-calculation-in-elasticsearch
https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-multi-match-query.html

this.doiBatcher.pushToQueue(0, v.depth + 1, -1, false, v.doi);
});
batchSearchQueue(batchSize = SEARCH_BATCH_SIZE) {
this.searchBatcher.runBatch(batchSize);
}

@Interval(TIME_INTERVAL)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이 부분의 경우 없어도 Interval 이 정상 작동하긴 했었는데, 이렇게 명시하는 이유가 있나요?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

혹시 batchSearchQueue 가 있는 이유를 물어보신걸까요??

@leesungbin
Copy link
Member Author

제가 이해한 것이 맞다면 현재 setInterval을 통해 runBatch를 주기적으로 실행하고, Batcher라는 클래스에 내부적으로 blocked와 실행 여부를 변수로 관리하는 듯 합니다.

이를 통해 실행할 때마다 blocked와 running 여부를 체크 하고 실행을 하는 것으로 보입니다. (blocked와 running 이 true이면 return) 이는 큐에서 전의 요청이 정상적으로 response를 받고 Too Many Request를 피하기 위한 방법으로 이해를 했는데 blocked와 running 여부를 매번 확인하는 것이 아니라 그냥 외부 api를 요청하고 await 후 response를 받은 후에 해당 response의 유효성을 검증하는 방식을 적용할 수 없나요?

가끔씩 crossref가 응답을 빠르게 해주는 경우가 있어서요, 이 친구가 빠른 속도로 응답해버릴 때, 응답이 올 때마다 다음 요청을 보내는 식으로 하면 rate limit이 걸릴 수 있겠더라구요. (ex doi로 검색할 때)
물론 대부분의 경우 응답속도가 매우 느리기 때문에 말씀하신대로 할 수 있을 것 같습니다.
crossref에 찌르는 최소한의 시간 단위를 지정하기 위해 이렇게 구현했습니다!

@leesungbin leesungbin merged commit f522fc3 into dev Dec 6, 2022
@leesungbin leesungbin deleted the feature/batcher branch December 8, 2022 15:00
# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[CI/CD] BE 이미지 Docker build시 Fail 하는 현상
3 participants