Trong bài này, mình sẽ giới thiệu về Caching, một kỹ thuật tăng hiệu suất của máy tính được sử dụng rộng rãi. Đây là loạt bài viết gồm 2 phần, phần 1 mình sẽ giải thích nguyên lý cơ bản của cache và cách áp dụng cache trong thực tế. Phần 2, mình sẽ giải thích về việc CPU sử dụng cache như thế nào.
Cache là gì?
Caching, hay lưu cache là một kỹ thuật nhằm tăng hiệu suất của một hệ thống máy tính. Nó hoạt động dựa trên một cơ chế: lưu trữ một bản sao của dữ liệu thường xuyên được truy xuất ở một nơi có tốc độ truy xuất nhanh hơn so với vị trí gốc, nhờ đó, tốc độ hoạt động chung của hệ thống được tăng lên. Vị trí gốc được gọi là backing store, còn vị trí có tốc độ truy xuất nhanh hơn gọi là cache (tiếng Việt hay gọi là bộ nhớ đệm).
Vì sao kỹ thuật này lại được sử dụng? Mọi thứ đều có lý do của nó. Trong cuộc sống thực tế, chúng ta thường gặp những tình huống tổng quát như thế này:
Bạn có 10 tệp dữ liệu, được đánh số từ 1 đến 10. Lần đầu tiên bạn truy cập vào tệp số 3, thì khả năng cao trong vài lần truy cập tiếp sau đó, bạn tiếp tục truy cập vào tệp số 3 hoặc một vài tệp lân cận (2 hoặc 4)
Một ví dụ gần gũi nhất đó là việc lập trình. Giả sử bạn là lập trình viên front-end Angular, source code dự án của bạn có hàng trăm file nhưng trong quá trình làm việc thực tế, bạn hiếm khi mở rải rác các file ở các thư mục khác nhau, mà bạn thường xuyên truy cập vào các files trong cùng một thư mục nhất định (ví dụ azo-detail).

Các tình huống như thế được gọi là Tính cục bộ (Locality of reference).
Dưới đây là một số ví dụ để bạn dễ hình dung:
- Khi người dùng truy cập Internet để tải một bức ảnh (logo / banner), sau khi tải xong, có khả năng cao bức ảnh đó sẽ được truy cập để xem.
- Ví dụ khác, khi bạn có một cuốn sách tiểu thuyết dày, dự định đọc 1 tiếng mỗi ngày, từ ngày thứ 2 trở đi, khả năng bạn sẽ tiếp tục đọc cuốn sách đã bắt đầu là cao hơn so với các cuốn sách khác.
- Khi bạn vào Mytour và xem một bài trong một danh mục, sau khi đọc xong, có khả năng cao bạn sẽ chọn xem tiếp một bài khác trong cùng danh mục.
Nếu hệ thống sử dụng cache, khi có yêu cầu dữ liệu lần đầu (cache miss), hệ thống sẽ tải dữ liệu từ bộ nhớ chính, đồng thời lưu một bản sao vào cache. Các yêu cầu sau đó sẽ được tải từ cache (cache hit).

Do đó, kích thước của bộ nhớ cache càng lớn thì hiệu suất càng cao, nhưng chi phí sản xuất cũng tăng theo. Việc quyết định kích thước cache là một bài toán cân nhắc giữa hiệu suất và chi phí. Tuy nhiên, dù bộ nhớ cache có lớn đến đâu, nó cũng sẽ đầy sau một thời gian. Để tiếp tục sử dụng, chúng ta phải làm cho nó trống bằng cách loại bỏ những dữ liệu ít được truy cập nhất. Có 2 thuật toán phổ biến để quyết định dữ liệu nào sẽ bị loại bỏ khỏi cache:
LRU (Least Recently Used), tức là dữ liệu được truy xuất gần đây nhất sẽ được ưu tiên giữ lại. Ví dụ, nếu bộ cache đã đầy và hiện đang lưu trữ 3 trường dữ liệu là data1, data2, data3. Lần truy xuất gần nhất tương ứng là 5 phút trước, 2 phút trước và 3 phút trước. Khi muốn lưu thêm data4 vào cache, ta sẽ giữ lại data2 và data3, và loại bỏ data1.
TLRU (Time-aware LRU), khác biệt so với thuật toán trên ở chỗ mỗi trường dữ liệu trong cache đều có thông tin thời gian hết hạn, khi hết hạn, dữ liệu đó sẽ tự động bị loại bỏ khỏi cache.

Ví dụ, nếu cache đang chứa dữ liệu và thời gian hiện tại (theo UNIX time) là 1500000100, thì dữ liệu có key là 431 sẽ được loại bỏ khỏi cache.
Ưu điểm của cách này:
Đảm bảo rằng một loại dữ liệu cụ thể sẽ được cập nhật đúng chu kỳ, mà chu kỳ này được quyết định bởi người dùng. Ví dụ, trang thương mại điện tử quốc tế cần cập nhật tỉ giá tiền tệ theo giờ.
Khi gặp nhiều truy xuất nội bộ đối với một tập dữ liệu, có thể điều chỉnh thời gian hết hạn để quyết định dữ liệu nào cần lưu lâu hơn và dữ liệu nào cần loại bỏ sớm hơn.
Cách cập nhật dữ liệu khi sử dụng cache
Trong thực tế, khi cần cập nhật dữ liệu, có nhiều phương pháp khác nhau phụ thuộc vào cấu trúc hệ thống. Nhìn chung, có 2 nhóm phương pháp:
Cập nhật dữ liệu ở cả cache và backing store.
Nhóm này chia làm 2 cách:
Ghi lại sau: Cập nhật dữ liệu trong cache trước, sau đó mới cập nhật dữ liệu ở backing store. Cách này tối ưu hiệu năng nhưng có thể mất dữ liệu nếu xảy ra sự cố trước khi cập nhật backing store.
Ghi qua: Cập nhật dữ liệu đồng thời trong cả cache và backing store. Đảm bảo dữ liệu luôn đồng bộ nhưng có thể ảnh hưởng đến hiệu năng hệ thống.
Chỉ cập nhật dữ liệu ở backing store
Vô hiệu hóa cache: Hệ thống sẽ gửi yêu cầu vô hiệu hóa dữ liệu trong cache, khiến dữ liệu tiếp theo sẽ được tải từ backing store mới nhất.
Phiên bản hóa: tạo ra một phiên bản mới khác so với phiên bản trong cache. Trong việc lập trình web, lập trình viên thường thêm một tham số vào đường dẫn của các tệp css hoặc hình ảnh tĩnh như logo. Khi sửa đổi tệp css hoặc thay đổi logo, lập trình viên chỉ cần thay đổi biến $version (bằng cách thủ công hoặc bằng lệnh) để người dùng nhận được phiên bản cập nhật mới nhất. Dữ liệu cũ trong cache vẫn được lưu trữ, nhưng ở đây, chúng ta yêu cầu dữ liệu với một khóa khác không tồn tại trong cache.

Các ứng dụng phổ biến của cache
Bộ nhớ cache trang
Khi một chương trình máy tính được mở, máy tính có thể tải toàn bộ hoặc một phần mã nguồn (đã biên dịch) vào bộ nhớ RAM để truy xuất dữ liệu một cách nhanh chóng. Bởi vì tốc độ truy xuất dữ liệu từ RAM luôn nhanh hơn từ ổ đĩa cứng. Ở đây, RAM là bộ nhớ cache và ổ đĩa cứng là backing store.
Bộ nhớ cache của trình duyệt web
Khi bạn truy cập vào một trang web lần đầu, các tài nguyên tĩnh của trang web như tệp css, tệp js, hình ảnh tĩnh (logo, biểu tượng) sẽ được lưu trữ trong máy của bạn. Trong những lần truy cập sau, máy của bạn sẽ tải những tài nguyên này từ bộ nhớ trong máy thay vì từ máy chủ, giúp tiết kiệm băng thông và tăng tốc độ tải trang.
Bộ nhớ cache dữ liệu sau quá trình tính toán phức tạp
Backing store thường là nơi có khả năng lưu trữ dữ liệu lớn nhưng có tốc độ truy xuất thấp. Tuy vậy, nó cũng có thể là những tác vụ tính toán phức tạp, mất nhiều thời gian để hoàn thành.
Ví dụ, bạn phát triển một trò chơi trực tuyến cho hàng nghìn người tham gia. Trước khi bắt đầu một ván, mỗi người chơi được thông báo về thời gian trung bình để hoàn thành ván đấu. Con số này được tính dựa trên số trung vị của thời gian hoàn thành ván đấu của người chơi trước. Để tính được con số này, hệ thống phải sắp xếp mảng thời gian và tìm trung vị. Tác vụ sắp xếp này có độ phức tạp là O(n log n).
Để tối ưu hiệu suất hệ thống, kết quả này có thể được lưu vào cache và gửi cho người chơi, vì nó chỉ mang tính chất tham khảo và không quá cần thiết cho trải nghiệm của người chơi. Cập nhật kết quả này có thể thực hiện một lần vào cuối ngày.
CDN – Mạng phân phối nội dung
Mytour, một trang tin điện tử hàng đầu Việt Nam, có hàng triệu lượt đọc mỗi tháng từ khắp cả nước. Nếu server đặt tại Hà Nội, thì tốc độ truy cập từ Tp.Hồ Chí Minh sẽ thấp hơn so với từ Đà Nẵng. Vì vậy, việc lưu một bản sao của Mytour tại Bình Dương sẽ làm cho việc truy cập từ Tp.Hồ Chí Minh nhanh hơn nhiều. Đây chính là cơ chế hoạt động của các công ty CDN. Khi người dùng truy cập sản phẩm load từ CDN, dịch vụ sẽ phản hồi với các tài nguyên từ các máy chứa cache gần nhất với nơi yêu cầu truy cập.
