이미지 카드 변환에 쓰던 ImageMagick을 Skia로 바꾸기 위해 C++ 라이브러리를 파이썬에 바인딩한 1주일짜리 작업 기록이다. 착수 전에 실패 조건을 스스로 정해두고 시작하며, 빌드 도구와 브랜치 관례, 메모리 누수, 포팅 옵션까지 막힌 지점을 순서대로 짚는다. 결과는 변환 성능 약 4배, 이미지 서버 CPU 사용률 30~40% 감소다.
핵심 포인트- 문서가 빈약하고 바인딩 경험도 없으니 1주일 안에 못 끝내면 포기한다는 조건을 먼저 정했다.
- jpeg 인코딩이 안 되던 이틀은 그 프로젝트가 master를 개발 브랜치로 쓰기 때문이었다. 릴리스 태그로 체크아웃하니 해결됐다.
- 40만 줄이 넘는 코드를 다 볼 수 없어 가장 단순한 예제 파일을 골라 그것을 기반으로 개발했다.
- 성능은 평균 약 4배, 빠를 때는 5배 이상 차이가 났다.
- 변환이 업로드 전체에서 차지하는 비중은 10% 정도라 체감 속도보다 CPU 사용률 감소가 컸다.
- 이미지 변환 서버의 CPU 사용률이 기존 대비 약 30~40% 줄어 그대로 비용 절감으로 이어졌다.
상세 정리- 배경: 서버가 파이썬과 Flask로 구성돼 있고 카드 생성은 Celery와 ImageMagick 계열로 처리하고 있었다. 서비스 오픈 후 1년 6개월 동안 약 4억 장이 올라왔다.
- 착수 계기: 다른 회사가 같은 라이브러리로 4배 성능 개선을 이뤘다는 글을 보고 자극을 받아 이슈로 남겨뒀다가 시간이 생겨 시작했다.
- 규칙 세 가지: 문서가 부족하니 1주일 안에 못 끝내면 포기, 바인딩 경험이 없으니 마찬가지로 1주일 기준, 완성하면 코드를 공개한다.
- 첫 벽 빌드 도구: 익숙한 도구 대신 처음 보는 빌드 시스템 두 가지가 등장해 시작부터 헤맸고, IDE 빌드와 커맨드라인 빌드를 오가며 프로젝트에 익숙해졌다.
- 두 번째 벽 인코딩: 로컬 이미지 로딩과 크롭, 리사이즈는 금방 됐는데 jpeg 인코딩이 아무리 해도 안 돼 이틀을 썼다.
- 원인: 그 프로젝트는 master를 develop처럼 쓰고 있었다. master가 최신 릴리스일 것이라는 익숙한 브랜치 모델의 가정이 틀렸던 것이다.
- 개발 기반: 잘 정의된 문서 없이 40만 줄을 분석하는 것은 불가능하다고 보고, 가장 간단한 예제 파일을 찾아 그 위에 API 인터페이스를 명세하고 코드를 얹었다.
- 바인딩 선택: 파이썬은 C와 접착성이 좋다고 하지만 C++ 라이브러리를 붙이는 것은 다르다. 여러 대안 중 boost-Python을 골랐다.
- 바인딩 난관: jpeg 바이너리 중간에 널 문자가 들어가는 경우가 있어 전체 데이터를 파이썬 객체로 넘기는 부분에서 헤맸고 공식 문서로 해결했다.
- 빌드 난관: 원본이 다른 빌드 시스템으로 만들어져 컴파일 옵션을 알 수 없었다. IDE의 빌드 메시지를 한 줄씩 분석해 설정 파일에 옮겼다.
- 추가 문제: 설정하지 않은 컴파일 옵션이 계속 붙어 알아보니 표준 빌드 유틸리티의 알려진 동작이었고, 약간의 트릭으로 옵션을 커스터마이징해 빌드에 성공했다.
- 성능 측정: 이미지 크기가 크지 않아 차이가 없으면 어쩌나 걱정했지만 평균 4배, 최대 5배 이상 빨랐다.
- 메모리 검증: 회사에서 쓰는 언어가 모두 관리형이라 직접 검증이 필요했다. 무한 루프로 변환을 반복시키며 점유율을 보니 누수가 심해 모두 잡았다.
- 마지막 난관 최적화: 안티 얼라이싱 옵션을 줘도 이미지에 적용되지 않았고 관련 문서도 없었다. 오래된 코드에서 단서를 얻어 필터 품질 값을 조정해 해결했다.
- 기한 관리: 이 시점에 스스로 정한 1주일이 됐고, 8부 능선은 넘었다고 판단해 이틀만 더 하고 안 되면 접기로 했다.
- 포팅: 우분투로 옮기는 데 꼬박 하루가 걸렸다. 위치 독립 코드 옵션을 어디에 넣어야 할지 알 수 없었고, 공유 라이브러리 빌드 정의를 주는 방식으로 겨우 성공했다.
- 배포: 목요일 저녁에 작업을 마치고 금요일 오후에 서버에 반영했다.
- 결과 해석: 변환 비중이 10%라 업로드 전체 성능에는 큰 영향이 없지만 CPU 사용률이 크게 떨어졌고, 모니터링 그래프에서도 여유가 확인됐다.
- 성능의 출처: 이 라이브러리의 성능은 CPU 인스트럭션 수준 최적화에서 오며 코드를 뜯어보면 어셈블리가 많이 나온다고 덧붙인다.
- 마무리: 참고 문서가 없어 벽에 부딪힐 때마다 이름 모를 개발자들에게 기대어 왔다는 생각이 들었다며 약속대로 코드를 공개했다.
왜 읽나성능 때문에 C++ 라이브러리를 직접 파이썬에 붙여야 하는 상황이라면, 실패 조건을 먼저 정하는 방식과 실제로 시간을 잡아먹는 지점들이 어디인지 미리 알 수 있다.