티스토리 뷰

A의료인공지능 기업 AITRICS에서 backend와 frontend 개발을 하고 있는 윤소영입니다.

새로운 것을 배우는 것에 관심이 많습니다.

 

Web service 구현 시 속도 최적화는 모든 개발자들이 마주하는 필수적인 부분입니다. 딥러닝을 이용한 서비스가 점점 늘고, 처리해야 하는 데이터의 양이 점점 늘어나면서 많은 양의 데이터 처리 성능 최적화의 중요성도 점점 늘고 있습니다. 제가 현재 일하고 있는 의료 인공지능 회사에서도 역시, Django로 대용량의 의료 정보 데이터를 실시간으로 받아 빠르게 저장하고 업데이트를 해줘야 하는 경우가 많습니다. 저는 먼저 Django ORM이 무엇인지에 대해 설명하고, 이러한 데이터를 처리할 때 마주했던 문제점들을 소개한 후, 이 문제점들을 어떻게 해결했는지를 발표하여 많은 개발자들이 비슷하게 고민하는 문제들의 해결 방안을 공유해드리고 싶습니다.

발표를 계획하게 된 이유
    대용량 데이터 처리 시 성능을 개선하기 위해서는 Query Optimization이 필수적입니다. 이러한 상황에서 개발하면서 먼저 알았으면 도움이 되었을 것이라고 느꼈던 점을 공유하고자 합니다. 이 발표를 통해 Django를 이용해 많은 양의 데이터를 처리하고 가공하는 상황에서 생기는 여러 개발 이슈를 해결한 사례를 공유하여, 자신의 상황에 맞는 Django의 기능이 어떤 것인지 알고, 더 유용하게 Django를 쓸 수 있을 것이라고 기대합니다.

대상 청중

Django를 사용하여 대용량의 데이터를 빠르게 처리해야 하는 개발자
Django ORM만으로는 원하는 기능이 되지 않아 고통받는 개발자
현재 구현한 코드에서 최적화할 수 있는 부분을 최적화하여 데이터 처리 속도를 높이고 싶은 개발자
발표를 통해 얻을 수 있는 것
이 발표를 통해 청중들은 Django ORM이 어떻게 작동하는지, 현재 한계점으로 어떤 것이 있는지, 그것을 극복하기 위해 어떻게 SQL 쿼리를 최적화해야 하는지 등을 알 수 있고, 더 나아가 그런 것들을 현재 구현에 적용하여 데이터 처리 성능을 개선하기를 기대합니다.

 

https://www.pycon.kr/program/talk-detail?id=42

 

 


 

 

실시간 인공지능을 위한 장고 쿼리!

카이스트 출신.

 

순서

1. 회사에서 개발중인 장고 서비스 문제

2. 문제 개선점 개선 쿼리 ORM

3. 쿼리 프로파일링

4. 대용량 db를 빠르게 

5. DB에서 빠르게 ML로 전달

 

 

 

장고를 이용한 서비스

현 서비스

 

병원 입원 한 환자의 질병 확률 예측 

그런데 이 환자들이 폐혈증에 걸릴 확률이 높음.

빠르게 환자 건강정보를 업데이트하여 감시하는 것이 관건.

 

 

병원데이터 처리

장고 ORM을 이용해빠르게 저장(예를 들어 하루정 맥박, 심박수 등등)

매분 수백명 환자 정보 저장하는데 많은 시간 소모하고 있음

이렇게 저장한 데이터를 머신러닝 모델에 전송

현재 시간단위로 이루어짐.

측정하여 병에 걸릴 확률을 저장.

 

ml모델에 넣고 예측값을 산출

예측값을 받아 저장해야 한다.

그래서 빠르게 저장하기 위해 쿼리 옵티마이저 필요.

 

Django ORM

객체 지향적인 방법으로 SQL쿼리를 관리.

 

 

 

get은 selet를 수행, save는 obj를 생성하거나 업데이트

 

 

get_or_create() 검색후 리턴 없으면 만들어서 반환.

bulk_create()는 여러개를 생성. 단 save()가 불리지 않음

 

장고 ORM의 특징

 

 

lazy_load : 접근하는 시점에 쿼리가 발생. 바로 실행이 아니라 특정한 지점에서만 이루어짐.

실제로 접근할 때 그제서야 obj를 가져옴.

그런데 이런 것 떄문에 N+1 문제가 발생. N번 쿼리를 시행.

 

 

 

프로파일링

실제보고 싶다. str()을 사용하여 쿼리문을 볼 수 있다.

또는 connetion.qureies[-1]을 실해하면 마지막 명령을 출력

실제로 실행되는 valid sql이 아니라 어댑터에 query와 파라미터를 보내는 것일 뿐.

 

 

프로파일링 툴

 

DJDT

 

세팅과 urls에 추가함. 그러면 새로운 아이콘이 생김.

그런데 로컬에서만 돌아감. POST로 들어오는 것은 프로파일링 안됨.

 

SILK

과거 이용 내역도 저장됨. 한눈에 보기 용이.

디비에 저장하기 때문에 마이그레이션도 해줘야함.

원하는 곳에 데코를 붙여서 사용함.

 

접속 정보, 쿼리문, 트랙백, 프로필 그래프도 볼 수 있음

 

 

장단점 정리

- 라이브 환경, 여러개를 비교 가능

- 느리다. 실제 실행시간도 오래 걸림.

 

----

 

대용량 빠르게 

 

API로 들어온 대용량 데이터 저장

병원에서 수백개의 리스트가 들어옴.

환자마다 고유 아아디가 있으며 각 칼럼별로 저장하고 있음.

환자 하나씩 저장하기 때문에 느려.

 

방법1. Bulk Create

 

그럼 일괄 저장하면?

한 오브젝트씩 처리하는 방법에서 나중에 일괄 저장하는 방식으로 변경.

하지만 이미 존재하는 것은 다시 생성 불가 . 실패

 

방법2. 지우고 생성

 

delte _crete으로 기존의 값을 지우고 새로 생성

Raw query : 자율적으로 조절하는능. 성능 극대화 가능.

커스텀 가능

 

 

이 기능을 코딩으로 수정.

모두 지우고 한번에 벌크 생성.

역시 실패

 

 

그런데 환자 사망할 경우. 사망 정보가 들어옴.

업데이트 할 때마다 모든 정보를 보내지 않는다. 

그러면 기존 정보중 삭제되는 것이 있다.

 

그래서 한계가 있다.

기존 정보가 날아감. 연결관계도 깨짐.

삭제하고 생성하는데 어떤 일이 일어나는지 몰라.

 

 

업설트를 해줘야 한다.

장고로는 지원 안해.

 

업데이트 크리에이트는 있지만 벌크는 없다.

특정 필드를 다른 값으로 표현하는 기능이 필요.

제한된 기능만 가능.

 

 

 

마지막 방법. 로우쿼리

 

parse.py에서 테이브를 가져오고, 인설트해야하는 필드를 가져옴, value의 람다로 대응되는 값을 넣어줌.

업데이트 필드를 선택적으로 정함.

 

silk로 확인

기존쿼리 1838ms

한 환자에 대해 3개의 쿼리 발생.

 

delete_and_crate() 쿼리 : 263ms

쿼리하나로 모든 동작이 수행

 

delete_cretae() 쿼리 수행 

같은 쿼리를 한번에 수행

시간이 줄어듬

 

 

벌크는 72ms

DJDT로 확인결과 쿼리가 잘 들어감을 확인.

 

정리

총 25배 이상 단축.

쿼리도 302개에서 1개로 줄어듬.

기능상의 문제도 없고 속도도 최적화에도 성공.

 

 

BD데이터를 ML로

환자 정보를 시간별로 검색해서 분석.

빠르게 가져오는 방법은 인덱싱

 

selecte_related는 n+!문제를 해결

prefetch_realteed는 쿼리 2번이 필요. 셀렉트하고 관련 데이터를 패칭

해당 쿼리를 가져옴

코딩 수정으로 DB접근을 최소화

 

 

인덱싱 

인덱스 파일로 검색하여 검색속도를 빠르게 함.

 

입원일에 대한 인덱싱을 함.

해당 테이블을 전부 스캔하는 것이 아닌 인덱싱 테이블을 저장. 

하지만 인덱싱을 김으로 하면 성이 김인 사람이 많아 시간이 오래 걸림.

 

정리

자주 사용하는 칼럼에 사용하면 좋아.

하지만 쿼리가 많이 일어남.  데이터가 중복되면 효과가 없음

 

 

그런데 데이터는 시계열데이터

시간기준 많이 사용하는 것으로 인덱싱에 적절.

인데싱은 여러 칼럼을 묶어서 지정 가능

 

 

배칭 

n개 이상의 obj를 생성할 때 하나씩 저장하는 것보다 효율적.

IO시간을 줄임.

 

 

댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함