원래는 하나의 서버에서 하나의 채점 프로그램을 돌려 여러 개의 서버를 두려고 했다. 왜냐하면 채점은 하나의 채점이 다른 채점에 영향을 주거나 받지 않는 독립적인 환경에서 이루어져야하기 때문이었다.
그런데, Docker를 공부하던 와중에 docker run 옵션에 cpu와 memory제약을 걸 수 있는 옵션이 있는 것을 발견했다. 그래서 이 실험 일지는 해당 옵션을 활용하면 CPU가 여러 개 있는 서버에서 도커를 활용해 여러 개의 채점 프로그램 도커를 돌릴 수 있지 않을까?에서 시작되었다.
CPU 코어별로 사용률을 확인하기 위해 nmon
설치
sudo apt install nmon
sudo docker build -t judger:latest -f ./Dockerfile .
로 빌드 후
sudo docker run --rm judger:latest
로 실행
⇒ 아무런 옵션을 주지 않고 채점 실행
결과 → 실행마다 랜덤으로 CPU를 사용하는 것을 확인할 수 있음
GIF입니다. 눌러서 확인해보세요!
<aside> 🤔 애초에 하나의 CPU밖에 사용을 안하는데?? 굳이 CPU 개수를 지정을 해야할까?
</aside>
sudo docker run --cpuset-cpus=20 --cpus=1 --rm judger:latest
⇒ 20번째 CPU 1개를 사용하는 제약을 걸어봄
결과 → 지정한 CPU만 사용하는 것을 확인할 수 있음
GIF입니다. 눌러서 확인해보세요!
<aside> 🤔 2번이랑 크게 차이가 없는데.. 정해진 거 하나만 쓰긴 하네.. 그런데 왜이렇게 채점이 빠르게 되는거지..?? CPU가 아무것도 안해서 채점이 빨리 되는건가? 부하를 걸어보자!
</aside>
부하를 걸어보자!
sudo docker run -d --cpuset-cpus=0 --cpus=1 alicek106/stress stress --cpu 1
0번째 CPU에 부하가 걸린 것을 확인할 수 있다.
<aside> 🤔 그러면 부하가 걸린 CPU에 채점을 보내면 어떻게 될까?
</aside>
GIF입니다. 눌러서 확인해보세요!
부하가 걸린 0번째 CPU에 채점을 보낸 것과 부하가 없는 1번째 CPU에 채점을 보낸 것의 차이가 생각했던 것과 다르게 채점 시간에 드라마틱한 차이가 없었다. 왜 그럴까?
<aside> 🤣 테케가 하나여서 채점이 빨랐던 것이다! 테케 개수를 늘려보자!
</aside>
테케 개수를 늘려서 다시 실험해보자!
GIF입니다. 눌러서 확인해보세요!
위와 동일한 조건에서 테케 개수만 20개로 늘려서 실험
→ 시간 차이가 확실하게 나는 것을 확인할 수 있었음
그런데 부하 자체가 채점 하는 행위의 결과에는 영향을 주지 않고 채점을 모두 완료하는 시간에만 영향을 준다는 것을 확인할 수 있었음.
채점 프로그램의 시간 측정 방식이 CPU가 대기 상태일 때도 포함되는 것이 아닌 진짜로 사용자가 제출한 프로그램이 실행하는 시간만 측정되기 때문임.
<aside> 🤔
그렇다면 이제 동일한 채점 프로그램을 병렬로 서로 다른 CPU에게 실행을 시키면 서로 영향을 주지 않는가?
</aside>
서로 다른 CPU에 동시에 동일한 코드를 채점하도록 실행해보자!
GIF입니다. 눌러서 확인해보세요!
4, 5, 6번 CPU에 동시에 동일한 코드를 채점하도록 실행시켜봤을 때 총 실행시간이나 메모리, 최대 채점시간이 크게 차이나지 않는 것으로 확인했다. (위에 보이는 차이는 문제의 정/오답에 영향을 줄 수치가 아니다. by 알고리즘 고수 장효석)
여러 개의 CPU를 가진 하나의 서버에서 컨테이너 여러 개에 각각의 CPU를 할당해준다면 서로에게 영향을 미치지 않고 채점을 할 수 있다!!
메모리 제한을 1mb 단위로 수정하면서 채점 프로그램이 측정한 메모리의 근처로 테스트를 해보았다. 하지만 메모리 제한을 채점 프로그램의 측정보다 낮게 설정을 해도 정상적으로 컨테이너가 동작을 마치는 신기한 현상을 겪었다. 이것은 메모리의 종류가 워낙 다양하고 측정 방식도 다양하기 때문에 측정 방식에 따른 차이라고 보고 메모리 제한은 너무 커지지 않도록 넉넉하게 2GB 정도로 제한하는 것으로 결정하였다.