Загружаем каталог…
Загружаем каталог…
이전에는 주문 생성기를 사용하다 CPU 이상을 발견해 원인을 찾던 중 라이더의 배차에 속도와 관련된 문제를 발견해서 수정해 보았습니다. 이번에는 관리자 콘솔을 확인하던 중 가게는 정상적으로 영업중인데 주문건수가 없는 가게들이 눈에 보였습니다. 그래서 이번에는 랜덤으로 주문을 생성하지만 전혀 랜덤하지 않은, 균등하지 않은 문제를 확인하고 해결해 보려고 합니다. 생성기로 생성된 주문 테이블 확인 이때까지 생성된 주문테이블에서 가게의 분포를 확인해 보았습니다. SELECT merchant_id, COUNT(*) AS cnt FROM orders GROUP BY merchant_id ORDER BY cnt DESC 확인해 보았을 때 특정 가게에 주문이 비정상적으로 몰리는 가게가 있으며, 수백건의 주문이 생성된 가게가 있는 반면 주문이 1건만 생성된 가게도 있어 주문 생성 자체가 고르게 생성되고 있지 않다는 것을 확인했습니다. 주문시 가게를 선정하는 코드는 다음과 같습니다. ## 기본 서치 SELECT * FROM merchants WHERE business_status_code = '01' AND id >= (SELECT FLOOR(RAND() * (SELECT MAX(id) FROM merchants)) + 1) ORDER BY id LIMIT 1 ## 기본 서칭 후 null일 경우 폴백 쿼리 SELECT * FROM merchants WHERE business_status_code = '01' ORDER BY id LIMIT 1 이전 라이더 쿼리에도 동일하지만 단순 MySQL의 RAND() 함수로는 테이블 풀 스캔으로 인하여 속도가 느린 문제가 있어 위와 같이 특정 랜덤한 수를 기준으로 데이터를 뽑아내어 속도 문제를 해결했습니다. 난수로 인해 어느정도 값이 균등할 거라고 예상했지만 실상은 id > RAND() 쿼리로 낮은 id 값이 우선적으로 뽑히는 쿼리라 균등하다고 할 수 없는 결과가 나오게 되었습니다. 코드로 랜덤하게 뽑아내면 어떨까..? RAND() 쿼리를 ORDER BY 절에 바로 사용하는 것은 속도가 문제 WHERE 절에 사용하면 균등성의 문제 현재의 문제는 위와 같은 문제가 발생해 속도, 균등성 두 가지 모두 깔끔하게 해결되지 않고 있습니다. 그래서 쿼리가 아닌 코드로 랜덤한 값을 뽑아내도록 하면 어떨까? 라는 생각이 들었습니다. 이때까지는 데이터 처리는 되도록 쿼리에서 처리하는 방식을 고수했지만 쿼리를 잘 모르는 신입 시절에는 코드로 랜덤 값을 뽑아내서 결과 쿼리와 합치는 방식을 사용했던 경험도 있어 한번 시도해 보았습니다. ## 영업중인 전체 가게 추출 SELECT id FROM merchants WHERE business_status_code='01' ## 인메모리 저장 후 랜덤 추출 findActiveIds(): List<Long> return [Random.nextInt(snapshot.size)] 코드를 수정 전과 후를 주문생성기로 1만건을 생성하는 것으로 비교해 보았습니다. 코드 수정 후 수정되기 전 마지막 주문 id(2198647)이후 주문 건들에 대해 가게 분포도를 확인해보면 SELECT cnt as '주문 건수', COUNT(*) as '가게 수' FROM ( SELECT merchant_id, COUNT(*) AS cnt FROM orders where id > 2198647 GROUP BY merchant_id) AS orders_tb group by cnt 이전보다는 균등하게 주문이 배치된 것을 볼 수 있습니다. 전/후를 생성기 결과 화면과 표로 비교하면 코드 수정 전 주문 생성 결과 코드 수정 후 주문 생성 결과 비교 표 항목 수정 전 수정 후 소요 시간 115초 101초 처리량 87건/초 99건/초 가게 분포 1,818곳 9,552곳 한 가게 최다 주문 19건 3건 코드로 수정했을 때 생각되는 문제 쿼리에서의 속도, 균등성 두가지 모두가 만족스럽게 해결이 되지 않아 코드로 해결을 해 보았습니다. 하지만, 이렇게 하면 쿼리에서 사용되는 CPU, 메모리와 같은 자원을 애플리케이션에서 사용하게 되니 그만큼 애플리케이션 자원에 부담이 가지 않을까 생각 했습니다. 메모리 사용량 계산 현재 인메모리 저장은 long 타입으로 선언됩니다. long 타입은 64bit(8Byte) 입니다. 단순, long 타입이 8Byte이니 현재 전체 데이터를 인메모리에 저장하게 되면 대략 아래와 같이 계산됩니다. 대상 데이터 수 크기 가게(영업 중) 129,132 961,072Byte 인메모리 저장을 long이 아닌 int로 지정하면 계산상 메모리는 줄어들 수 있겠지만 주문이 지속적으로 발생하고 그로 인해 Id값의 상승으로 타입이 커버되지 못할 수 있기 때문에 long 타입은 유지하는게 좋을 것으로 생각됩니다. 메모리 사용량 실측 단순 계산도 좋지만 실제로 메모리가 얼마나 사용되는지도 측정해 보았습니다. 메모리를 체크하는 쉘(mem_check.sh)을 만들어서 비교해 보았고 다음과 같았습니다. 대략 적인 적재량 계산과 비슷하게 약 961,400Byte가 이용되었습니다. 약 0.92MiB로 실제 힙 메모리를 미미하게 사용한다고 볼 수 있습니다. 이전 쿼리가 사용하는 메모리와 비교했을 때에도 개선이 되었다고 생각됩니다. 데이터 수 크기 메모리 문장당 약 2MiB 앱 상시 약 0.92MiB 시간 약 342ms(약35만행) 0초 (인메모리 적재) 느낀점 항상 뭔가를 개선할 때는 속도를 빠르게 하기 위해 반복문과 같은 알고리즘에 문제가 없는지, 슬로우 쿼리가 없는지에 대해서만 확인을 했던 것 같습니다. 무작정 코드로 개선을 해볼까? 라고 생각해서 진행했지만 생각보다 좋은 결과가 나왔고, 쿼리보다 코드로 처리하여 보다 적은 자원으로 높은 효율을 낼 수 있는 방법도 있다는 것을 알게 되었습니다.
То, что RADAR обнаружил и классифицировал для этой возможности. Это опубликованный источником текст, а не подтверждение, что предложение ещё действует.
[토이프로젝트] [order-simulator] 주문 생성기 성능 측정 - 가게 주문 배치 최적화. 이전에는 주문 생성기를 사용하다 CPU 이상을 발견해 원인을 찾던 중 라이더의 배차에 속도와 관련된 문제를 발견해서 수정해 보았습니다. 이번에는 관리자 콘솔을 확인하던 중 가게는 정상적으로 영업중인데 주문건수가 없는 가게들이 눈에 보였습니다. 그래서 이번에는 랜덤으로 주문을 생성하지만 전혀 랜덤하지 않은, 균등하지 않은 문제를 확인하고 해결해 보려고 합니다. 생성기로 생성된 주문 테이블 확인 이때까지 생성된 주문테이블에서 가게의 분포를 확인해 보았습니다. SELECT merchant_id, COUNT(*) AS cnt FROM orders GROUP BY merchant_id ORDER BY cnt DESC…
Открыть источник