pile·
백엔드·엔라이즈엔라이즈·

Skia Python 적용기

이미지 카드 변환에 쓰던 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++ 라이브러리를 직접 파이썬에 붙여야 하는 상황이라면, 실패 조건을 먼저 정하는 방식과 실제로 시간을 잡아먹는 지점들이 어디인지 미리 알 수 있다.
엔라이즈
엔라이즈 블로그
원문은 여기서 이어서 읽을 수 있어요
원문 읽기
읽음 (0)

이 글과 비슷한

  1. 백엔드·twilio-engTwilio Engineering·

    Programmable Messaging에서 Verify API로 마이그레이션하기

    Twilio의 Programmable Messaging API로 자체 OTP 솔루션을 운영하던 서비스가 Verify API로 전환하는 방법을 코드 예시와 함께 설명한다. Verify는 OTP 전송·검증을 위한 전용 API로, 전화번호 구매, 토큰 생성, DB 저장·만료 관리를 내부에서 처리해 개발자가 직접 구현할 코드를 크게 줄인다.

    요약 이어보기
    #authentication#twilio#sms+2
  2. 백엔드·포스타입포스타입·

    포스타입이 개인화 추천을 하는 방법 2부

    포스타입 백엔드 엔지니어가 벡터 기반 개인화 추천 시스템을 실제 운영하며 맞닥뜨린 성능 장애와 용량 문제를 해결한 과정을 담은 2부다. 수백만 개의 벡터 KNN 검색이 피크 시간대에 전체 Elasticsearch 검색 성능을 흔드는 문제부터 클러스터 OOM 사태까지, 쿼리 최적화와 인프라 분리 두 가지 경로로 근본 해결에 이른다.

    요약 이어보기
    #elasticsearch#vector-search#recommendation-system+2
  3. 백엔드·포스타입포스타입·

    포스타입이 개인화 추천을 하는 방법 1부

    포스타입이 태그 기반 추천의 한계를 극복하고 벡터 임베딩 기반 개인화 추천 시스템을 구축한 과정을 담은 1부다. 유사한 콘텐츠가 다른 용어를 쓰거나 동일한 태그가 전혀 다른 톤의 콘텐츠를 가리키는 문제를 임베딩 벡터로 해결하고, OpenSearch의 HNSW ANN 검색으로 수백만 벡터를 실시간 검색하는 시스템을 구축해 구매율 15% 향상을 달성했다.

    요약 이어보기
    #opensearch#vector-search#recommendation-system+2