0

Tối ưu CI/CD cho Hệ thống Microservices - Bài 3 - Nghệ thuật Caching trong CI Pipeline

I. Tại sao Pipeline của bạn lại "rùa bò"?

Trong môi trường CI/CD, mỗi khi một luồng (pipeline) được kích hoạt, các CI Runner (như GitLab Runner, GitHub Actions, Bitbucket Pipelines) thường sẽ khởi tạo một môi trường hoàn toàn mới và trống rỗng (clean state) để đảm bảo tính chính xác.

Điều này dẫn đến một sự lãng phí khổng lồ:

  • Với một service viết bằng Node.js, Runner phải tải lại hàng trăm MB node_modules từ đầu bằng npm install.

  • Với một service Go, Runner phải chạy lại go mod download để kéo toàn bộ package về. Nếu một ngày team bạn push code 50 lần, thời gian chết chờ đợi việc tải đi tải lại các thư viện này cộng dồn lại có thể lên tới hàng giờ.

II. Giải cứu Pipeline với Dependency Caching

Caching (bộ nhớ đệm) trong CI/CD là kỹ thuật lưu lại các file dependencies ở một lần chạy thành công, và tái sử dụng chúng cho các lần chạy sau.

Bí quyết để caching hiệu quả nằm ở Cache Key (Khóa cache). Bạn không thể dùng chung một cache vĩnh viễn vì thư viện sẽ được cập nhật. Nguyên lý hoạt động như sau:

  1. Tạo Khóa bằng Hash: Khóa cache được tạo ra dựa trên mã băm (hash) của file quản lý thư viện (ví dụ: package-lock.json của Node.js hoặc go.sum của Go).

  2. Kiểm tra (Cache Hit/Miss): Khi pipeline chạy, nó sẽ băm file package-lock.json hiện tại. Nếu mã băm trùng với một Cache Key đã lưu, nó tải node_modules từ cache ra trong vài giây (Cache Hit).

  3. Làm mới Cache: Nếu ai đó vừa thêm một thư viện mới, mã băm thay đổi -> Cache Miss. Pipeline sẽ tự động chạy npm install để tải mới, sau đó lưu lại một bản Cache mới tương ứng với Khóa mới.

III. Tối ưu Docker Layer Caching - Tốc độ ở khâu Đóng gói

Microservices thường đi kèm với Docker. Việc build Docker image cho hàng chục services cũng là một nút thắt lớn. Docker hoạt động theo cơ chế từng lớp (layers). Thay vì build mọi thứ từ đầu, bạn có thể thiết kế Dockerfile để tận dụng cache:

  • Tách biệt việc copy thư viện và copy source code: Code thay đổi liên tục, nhưng thư viện thì hiếm khi. Hãy copy package.json và chạy npm install (hoặc go mod download) TRƯỚC khi thực hiện lệnh COPY . . (copy toàn bộ source code).

  • Bằng cách này, nếu bạn chỉ sửa logic code (Controller, Route), Docker sẽ tái sử dụng lại layer đã cài đặt thư viện trước đó, bỏ qua bước install tốn thời gian. Thời gian build Docker image sẽ giảm từ vài phút xuống chỉ còn dưới 10 giây.

  • External Cache: Tích hợp tính năng --cache-from trong luồng CI để kéo cache từ một Docker Registry về trước khi build, đảm bảo Runner luôn có layer cache từ các lần build trước.

IV. Tổng kết bài học

Dependency Caching giải quyết tốc độ ở khâu chuẩn bị (Integration), còn Docker Layer Caching giải quyết tốc độ ở khâu đóng gói (Delivery). Áp dụng triệt để hai kỹ thuật này cho các service backend, bạn sẽ thấy CI/CD nhanh như một cái chớp mắt, giúp team giữ vững nhịp độ Trunk-based Development đã bàn ở Bài 2.


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí