2020.03.06 EC2에서 계산작업을 돌리는데 속도가 매우 느리다면?

최근에 ec2에서 계산 작업 돌릴 일이 있어 사이즈가 있었다.
AWS RDS + AWS EC2를 사용하고 사이즈는 둘 다 거의 최소 사이즈였다.

EC2에서 명령어를 실행하면 실시간으로 콘솔에 로깅을 하면서 실시간으로 작업 현황을 보여주도록 해놨는데 어떨 때는 잘 되다가 또 어떨때는 엄청나게 느려지는 경우가 있었다.

어제는 실행을 시켰더니 속도가 매우매우 느렸었는데 원인은 swap 메모리 사용이었다.
RDS의 메모리 사이즈가 작아서 내가 불러오려는 쿼리의 총 메모리 용량보다 작았고 그로 인해 SWAP 메모리를 20메가 이상으로 사용한 흔적이 있었다.

이 때 RDS의 사이즈를 늘려주는것도 방법이지만, 그게 여의치 않을 때는 쿼리를 수정해야한다.

SQLALCHEMY를 사용한다는 가정하에, 쿼리 수정은 아래와 같은 방법으로 할 수있다.

먼저 query를 호출하면 .all()을 호출하던 그렇지 않던 메모리에 한꺼번에 result set을 올려두는 듯하다. 그러면 당연히 메모리를 많이 차지하는데 어차피 한번에 계산을 하지도 못하기 때문에 필요한만큼만 불러와서 사용할 수 있도록 한다.

간단한 방법은 Query.yield_per() API를 사용하는 것. yield_per()의 인자로 받는 integer가 한번에 불러올 레코드의 갯수다. 총 레코드가 10만개였는데 만약 yield_per(1000)로 1000개씩만 불러오면 당연히 메모리 사용량은 감소할 것이다.

단 yield_per()를 사용할때는 주의할 점이 있다. eager_loading이 된 object들은 yield_per()를 사용할 수 없다. 따라서 joinedload 옵션을 사용하는 쿼리는 바로 사용할 수가 없고,  selectinload로 변경해서 사용해야 yield_per()를 사용할 수 있다고 한다. 왜인지는 좀 더 찾아봐야 하고 일단은 메모만 해놓는다.

댓글

이 블로그의 인기 게시물

로컬 Tomcat 서버 실행속도 개선

2019.05.23 - SQLAlchemy 의 객체 상태 관리 (expire, refresh, flush, commit) 에 관한 이해

2020.02.17 Python의 multiprocessing 중 Pool.map(), chunksize에 관한 내용