현재 진행하고 있는 프로젝트에서 Github Actions을 통해 CI를 구축했다. Travis CI처럼 유료 전환이 되는 것도 아니고, 젠킨스처럼 별도의 젠킨스 서버를 구축하지 않아도 된다는 점이 Github Actions의 큰 장점이라고 생각한다. 무엇보다 사용하기가 매우 간편하다. 오늘은 Github Actions에서 Gradle을 캐싱해서 사용하는 방법에 대해 공유하고자 한다.
왜 Gradle을 캐싱해서 사용해야 하는가
Gradle은 빌드할때 의존성 패키지들을 모두 다운받는다. 이때 Gradle은 빌드 시간과 네트워크 통신을 줄이기 위해 의존성 패키지를 캐싱해서 재사용하는 방법을 사용한다.
하지만 Github Actions의 workflow는 매 실행하다 새로운 환경을 구축하고, 매번 새롭게 의존성 패키지들을 가지고 와야 한다. 이는 전체 빌드 시간의 증가로 이어진다. workflow의 작업들이 늘어나고 CI 과정 중 테스트 케이스가 많아질수록 조금이라도 CI 시간을 줄이기 위한 노력이 필요하다고 생각한다.
빌드 시간의 단축을 위해서 우리는 Github Actions의 actions/cache를 사용해서 gradle의 의존성을 캐싱할 수 있다.
- name: Gradle Caching
uses: actions/cache@v3
with:
path: |
~/.gradle/caches
~/.gradle/wrapper
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
restore-keys: |
${{ runner.os }}-gradle-
- name: Grant execute permission for gradlew
run: chmod +x ./gradlew
shell: bash
- name: Build with Gradle
run: ./gradlew build
shell: bash
- path : 캐시의 저장과 복원에 사용되는 runner 내 파일 경로다.
- key : 캐시를 저장, 복원에 사용되는 키. 여러 값들을 조합해서 512자 제한으로 생성할 수 있다.
- restore-keys : 내가 설정한 key로 cache miss가 발생할때 사용할 수 있는 후보군 키들이다.
action/cache를 사용할때의 성능 최적화
workflow의 .yml 파일에 action/cache를 어떻게 작성하는지 살펴봤으니 이번에는 실제 얼마만큼의 성능 최적화가 있는지 살펴보자.
우선 Gradle 캐싱을 하지 않았을때의 소요시간이다. 아직 비교 대상이 없으니 시간이 얼마나 걸린건지 판단할 수 없다.
이번에는 Gradle 캐싱을 적용했을때의 소요시간이다.
2분 23초가 소요되던 전체 CI 시간이 1분 11초로 감소된걸 알 수 있다. 1~2분이라는 작은 시간에서는 별 차이가 나지 않겠지만 테스트 케이스를 추가하면서 CI 시간이 증가할수록 빌드 캐시를 사용한 최적화는 더 크게 체감될 것이다.
첫번째 빨간 줄을 보면 Cache가 정상적으로 복원된 것을 알 수 있다. 두번째 빨간 줄을 보면 Cache hit이 잘 발생한 것도 알 수 있다.
결론
백엔드 개발자로서의 역량은 얼마나 클린 코드를 잘 작성하고 테스트와 클린 아키텍처에 대한 이해가 있는냐로도 판단할 수 있겠지만, 개발 전반의 성능 최적화를 시키는 능력도 매우 중요하다고 생각한다.
DB의 인덱스나 버퍼를 통한 성능 튜닝, 캐시를 사용한 조회 성능 최적화 등 잘 돌아가는 어플리케이션을 만들기 위해 개발자는 끊임 없이 성능 최적화에 대해 고민해야 한다.
이번 기회를 통해 성능 최적화를 할 수 있는 또 하나의 방법을 알게 되어서 좋았고, 이 글을 다른 사람이 본다면 CI/CD 과정에 꼭 빌드 캐시를 도입하는 계기가 되었으면 좋겠다.