언어별 이미지 처리 벤치마크

[원본 링크]

이미지 처리 전문 시스템을 구축해볼 필요를 느껴서 조사를 좀 해봤다.

HTTP 서버와 통합해서 테스트한 것이기 때문에, 이미지 라이브러리 자체의 성능만은 아니다.
비교 대상은 Python의 Pillow, Node.js의 sharp(libvips), Go의 내장모듈, Rust의 image-rs 정도다.

자료가 충분하고 비교적 널리 사용되는 것들만 후보로 추렸다.




속도 차이 비교: PNG => JPG 변경, 리사이즈

일단 png를 jpg로 바꾸는 단순한 사용사례부터 비교해봤다.
결론부터 말하자면, 언어/라이브러리별 성능 차이는 유의미하지 않았다.

3MB짜리 하나 넣어서 쏴봤는데

Python의 경우

golang도 비슷했다.

nodejs도 비슷했다.

Rust도 비슷했다.

대부분 300ms 내에서 처리되었고, 차이가 나는 것처럼 보이는 것도 돌릴때마다 다르다.
성능 차가 눈에 띄지 않는 것은 resize-image도 마찬가지였다.




속도 비교: 이미지 회전

단순 연산 비교에서 성능이 의미있게 벌어진 경우는 rotate였다.
이건 구현체마다 성능 수준 차이가 좀 벌어지는 것 같더라.

파이썬의 경우에는 1초가 넘게 걸렸고

go도 제법 걸렸다.

짬밥이 좀 있어서인지 nodejs-sharp는 꽤 빨랐다.

그리고 이 경우에는 Rust가 가장 빨랐다.

다른 것들도 이것저것 조금 돌려봤는데, Python이나 Golang이 부분적으로 느린 모습들을 좀 보여주는 것 같고, 처리 속도만 보면 sharp와 image-rs가 가장 안정적인 것 같았다.




처리량, 리소스 사용량 테스트

서버를 띄워서 장기적으로 운영을 한다면, 사실 단순 처리 속도보다는 잘 유지가 되는지가 중요하다.
얼마나 막 때려넣을 수 있는지, 때려넣을때 얼마나 부하가 가는지를 봐보겠다.

서버는 공통적으로 코어/메모리 제한을 두고 때렸다.

동시 유저 제한은 15개를 기준으로 했다.



Python

파이썬부터 한번 때려봤다.

확실히 리소스를 좀 많이 먹긴 한다. 다른 언어들과 비교했을때 가장 높았다.

이렇게 돼지처럼 리소스를 먹는다.
근데 생각외로 OOM이 나서 터지거나 하는 사태는 잘 없었다. CPU 병목으로 스로틀링이 걸려서 메모리를 쌓는 것 자체를 잘 못하기 때문인 것 같다.


응답 시간 (밀리초)


RPS와 실패율



Golang

이것도 User 15 기준이다.

CPU를 많이 쓰는데 반해 메모리 사용량이 아주 높지는 않았다.


응답 시간 (밀리초)
파이썬보다는 미미하게 빨랐다.




Node.js

이것도 User 15 기준이다.

리소스 사용량은 생각보다 적었다.
코어가 좋아서 그런가? 아니면 스레드를 잘 못써서 그런가?


응답시간 (밀리초)


실패율이 조금 높긴 하다.



Rust

이것도 User 15 기준이다.

리소스 사용량은 가장 적은 편이다.


처리량/응답시간도 대개는 비슷한듯...


생각보다 처리량에서 현격한 차이가 나지는 않았다.




정리

Go와 Python은 성능 안정성이 그닥 좋다고 하긴 어렵고, 특히나 Python은 선택할 이유가 없어보인다.

성능 측면에서는 nodejs/sharp와 rust/image-rs가 꽤 좋은 편에 속하는 것 같다. 리소스 사용량과 성능 양쪽을 전부 다 본다면 Rust가 가장 낫긴 하나, 아주 극적인 정도의 차이는 아니다.

멀티코어 활용/확장이 더 순진하게 잘 된다는 점, 리소스 사용량이 적다는 점에 꼽힌다면 Rust를 쓸만도 한데, 그렇게 크리티컬하지 않다면 sharp로도 충분한 것 같기도 하다.
애초에 sharp란 것도 꽤 성숙한 C 구현체인 libvips 기반인지라.



벤치마크에 사용한 전체 코드/구성은 다음 레포에 있다.
https://github.com/myyrakle/benchmarks/tree/master/image-processing