Chào các bạn, hôm nay mình sẽ đề cập đến một chủ đề khá quen thuộc trong lập trình, đặc biệt là lập trình web. Đó là Cache.

Nhắc đến cache chắc cũng nhiều bạn đã từng nghe đến cache google. Nhiều khi có các bài báo trên mạng đăng tin sai lệch hoặc nội dung không phù hợp hoặc gì đó mà nhà xuất bản tự xoá bài viết, nếu sau khi xoá chưa lâu thì đôi khi ta vẫn có thể tìm được bài đó trong google cache. Hay khi cắt template HTML, sau khi sửa CSS, javascript mà thấy chưa được “ăn code mới” thì ta hay làm động tác bấm phím Ctrl+F5 để xoá cache của trang đó trên trình duyệt và tải lại trang. Ngay cả hệ điều hành Window cũng có thư mục cache để lưu dữ liệu cần xử lý.
Đó!, với web thì đi đâu ta cũng bắt gặp cache, loanh quanh chúng ta chỗ nào cũng thấy cache. Vậy tóm lại cache là cái gì, được cài đặt ở đâu và tại sao ta lại cần đến cache trong lập trình?

Cache là một bộ nhớ đệm hoặc một nơi lưu trữ tạm thời các dữ liệu tĩnh thường xuyên sử dụng.

Cache lưu dữ liệu trong ổ cứng, hoặc ram, hoặc bộ nhớ flash.

Trong môi trường mạng thì cache có thể được cài đặt ở gateway, proxy, web browser

Lợi ích của cache

  • Giúp tăng tốc truy xuất dữ liệu
  • Giảm thiểu request tới bộ nhớ chính và cơ sở dữ liệu chính
  • Giảm thiểu ảnh hưởng hiệu năng máy chủ do không mất thời gian cho việc tạo connection và truy vấn vào cơ sở dữ liệu

Hạn chế của cache

  • Nói đến cache thì luôn nhắc đến cache invalidation. Cache out-of-date thì chỉ là dữ liệu vô dụng.
  • Cache chỉ là một bộ nhớ lưu các dữ liệu tạm chứ không phải toàn bộ dữ liệu của hệ thống, vì vậy thường phải có thao tác đồng bộ dữ liệu từ bộ nhớ chính (cơ sở dữ liệu) vào cache. Cũng chính vì lý do này mà đôi khi google chưa kịp đồng bộ cache thì ta vẫn có thể xem được các bài báo đã bị xoá trên website nhưng vẫn tồn tại trên google cache.
    Và để giải quyết vấn đề đồng bộ dữ liệu trên thì nhiều trường hợp ta cần thêm một tiến trình chạy ngầm để thực hiện đồng bộ, từ đó lại phát sinh việc giám sát tiến trình chạy ngầm này xem còn hoạt động ổn định không… Một mớ bòng bong =)))

Với cache thì thông thường sẽ lưu trữ theo dạng key-value, nghĩa là khi lưu dữ liệu vào cache ta sẽ phải gắn dữ liệu đó với 1 key làm định danh, để khi cần lấy dữ liệu ra ta cũng phải sử dụng key định danh đó lấy dữ liệu.

Vậy bình thường người ta sẽ lưu cái gì vào cache?

  • Lấy nhược điểm hóa ưu điểm, lấy thực tế hóa giải nhược điểm. Chính vì vấn đề out-of-date của cache nên thông thường người ta chỉ lưu các dữ liệu ít thay đổi ví dụ như danh sách địa bàn tỉnh thành, quốc gia.
  • Hay khai thác lợi ích to lớn của cache là khả năng truy vấn dữ liệu nhanh, nên người ta có thể lưu trữ các dữ liệu có tần suất sử dụng cao để giảm thiểu số lượng truy vấn vào cơ sở dữ liệu chính.

Đến đây thì các bạn đã hiểu cơ bản về cache, vậy nếu thấy nó hay và cần thiết rồi thì làm thế nào để triển khai được cache vào hệ thống của mình! Tiếp theo mình sẽ hướng dẫn các bạn cách cài đặt một cache server để sử dụng trong phần mềm Java.

Hiện nay có khá nhiều cache server nổi tiếng và mạnh mẽ có thể kể đến như RedisMemcached, cả 2 đều cài đặt và sử dụng rất dễ dàng, mỗi cái lại có những ưu điểm riêng, nhưng với các hệ thống lớn thì khuyên dùng Redis (mặc dù nó ngốn nhiều Ram hơn Memcached) bởi vì khả năng lưu trữ đa dạng nhiều kiểu dữ liệu và cấu trúc đối tượng phức tạp chứ không đơn thuần là String như Memcached, và nổi trội hơn là Redis hỗ trợ khả năng replication/cluster để triển khai trong hệ thống yêu cầu cân bằng tải (loadbalancing), cài đặt được trên nhiều node master-master hoặc master-client mà không gặp vấn đề mất đồng bộ dữ liệu. Vì vậy ở bài viết này mình sẽ sử dụng Redis làm ví dụ.

Vì phần lớn các phần mềm Java đi triển khai cho khách hàng đều cài đặt trên server chạy Linux như Centos/Red Hat vì vậy mình khuyên các bạn nên cài Redis trên 1 hệ điều hành nào đó nhân *nix như Centos/Red Hat/Ubuntu/Fedora/… hay kể cả MacOS cũng tốt, ngoại trừ Windows. Tất nhiên Windows vẫn cài được và làm việc bình thường, nhưng khi vào dự án thật thì bạn sẽ phải mất thêm thời gian để tìm lại cách cài đặt/cấu hình/sử dụng trên hệ điều hành mới.
Nhất là bây giờ Windows 10 đã hỗ trợ WSL (Window Subsystem for Linux) cho phép cài đặt Centos/Ubuntu/… hay bất kỳ distribution nào của Linux ngay trên Windowskhông cần cài đặt máy ảo. Việc sử dụng WSL để thực thi các câu lệnh của Linux trên Windows nhẹ nhàng như việc gõ lệnh trong CMD của Windows vậy. Nên dù bạn có đang sử dụng Windows thì cũng không quá khó khăn để sử dụng thêm Linux cho các công việc khác cần Linux như cài Redis cache

Về vấn đề này thì các bạn có thể tìm từ khóa trên Google “Install WSL Ubuntu on Windows 10”, “Install WSL Centos on Windows 10” sẽ ra các hướng dẫn cài đặt WSL từ Window Store dễ dàng như cài Google Chrome vậy :D. Khá nhiều WSL free để lựa chọn, còn nếu bạn muốn cài các WSL khác không có trên Store hoặc không muốn trả tiền thì tìm trên Github cũng có khá nhiều bản cài đặt offline.

Thôi, quay lại vấn đề chính, khi bạn đã chuẩn bị được 1 hệ điều hành Linux thì việc tiếp theo là thực hiện cài đặt Redis. Vì mỗi hệ điều hành lại có lệnh cài đặt khác nhau nên mình sẽ tổng hợp một số cách của các hệ điều hành thông dụng cho bạn sử dụng.

MacOS

Cài đặt rất đơn giản bằng 1 lệnh duy nhất như sau

brew install redis

Sau khi đã hoàn tất việc cài đặt, bạn có thể start hoặc stop dịch vụ của redis bằng lệnh dưới

brew services start redis
brew services stop redis

Ubuntu / Linux Mint

Ví dụ này mình đang thực hiện bằng bản Ubuntu WSL trên Windows 😀

Trước tiên, bạn cần phải update kho dữ liệu của apt-get để lấy các gói cài đặt mới nhất

sudo apt-get update
sudo apt-get upgrade

Sau đó tiến hành cài đặt Redis

sudo apt-get install redis-server

Start stop redis bằng lệnh

sudo service redis-server start
sudo service redis-server stop

Centos / Red Hat 7

Vì mặc định trong yum không có gói cài đặt redis nên phải lấy bộ cài từ kho dữ liệu EPEL

sudo yum install epel-release

Sau đó mới có thể sử dụng lệnh cài đặt như bình thường

sudo yum install redis

Start và Stop Redis bằng lệnh

sudo systemctl start redis
sudo systemctl stop redis

Cách sử dụng Redis Cache

Sau khi đã cài đặt và start dịch vụ của Redis, ta thử kiểm tra xem nó đã chạy thành công chưa
Đầu tiên là truy cập vào server redis

redis-cli

Màn hình dòng lệnh sẽ đổi sang dạng 127.0.0.1:6379>, và ta thử gõ lệnh PING, nếu thấy server phản hồi PONG thì nghĩa là start thành công
Giờ ta test thử việc lưu trữ 1 cặp key-value vào redis

set MY_NAME "Tung Huynh"

Sau đó thử lấy ra để kiểm tra kết quả

get MY_NAME

Hoặc nếu muốn đặt thời gian hết hạn cho dữ liệu, nghĩa là sau một khoảng thời gian nào đó dữ liệu tự động bị xóa khỏi redis thì các bạn thêm tham số EX (tính theo giây), PX (tính theo mili giây) để đặt thời gian hết hạn.
Tham số này sẽ được gợi ý ngay khi bạn đang gõ lệnh
Để chắc chắn hơn về tính bảo toàn dữ liệu của Redis, bạn thử stop Redis đi và start lại, sau đó get MY_NAME để kiểm tra xem dữ liệu còn không. Tất nhiên là vẫn còn rồi 😀
Để xóa một key dữ liệu bất kỳ, các bạn có thể sử dụng lệnh del <tên key>
Để xóa sạch dữ liệu trong Redis, các bạn có thể dùng lệnh flushall

Ngon tuyệt, bước đầu thành công quá dễ dàng và dễ hiểu. Nhưng vấn đề là phải sử dụng được Redis Cache trong ứng dụng Java của bạn, mời các bạn theo dõi tiếp phần dưới.
Để ứng dụng Java của bạn có thể kết nốiđọc ghi dữ liệu từ Redis Cache thì cần phải sử dụng thư viện xử lý của Redis, các bạn có thể tải gói .jar hoặc import maven tại địa chỉ: https://mvnrepository.com/artifact/redis.clients/jedis/3.1.0
Sau đó import vào project và viết thử 1 hàm Main để test

package net.tunghuynh.redis;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import redis.clients.jedis.Jedis;

/**
* File net.tunghuynh.redis.Main
* by Tùng Huynh
* date 22/08/2019
*/

public class Main {
        static Logger logger = LogManager.getLogger(Main.class);

        public static void main(String[] args) {
              Jedis jedis = new Jedis("localhost");
              logger.info("Connected");
              logger.info("PING to server: " + jedis.ping());

              // Set/Get String value
              jedis.set("MY_NAME_2", "Tung Huynh, set from Java Application");
              logger.info("MY_NAME_2's value: " + jedis.get("MY_NAME_2"));

              // Set/Get List value
              jedis.lpush("packages", "logging");
              jedis.lpush("packages", "reflect");
              jedis.lpush("packages", "shallowcopy");
              jedis.lpush("packages", "listcollection");
              logger.info("Items of packages: " + jedis.lrange("packages", 0, 4));
        }
}

Ở đây, ngoài khả năng lưu trữ key-value dạng String, thì Redis hỗ trợ khá nhiều kiểu object khác như Hash, List, Set,…. thông dụng của Java
Chạy thử chương trình và xem kết quả ở màn hình log

2019-08-22 23:40:01 PM INFO [main]n.t.r.Main.main: Connected
2019-08-22 23:40:01 PM INFO [main]n.t.r.Main.main: PING to server: PONG
2019-08-22 23:40:01 PM INFO [main]n.t.r.Main.main: MY_NAME_2's value: Tung Huynh, set from Java Application
2019-08-22 23:40:01 PM INFO [main]n.t.r.Main.main: Items of packages: [listcollection, shallowcopy, reflect, logging]

Giờ thử trở lại cửa sổ dòng lệnh, kiểm tra bằng tay thì cũng có thể lấy được key MY_NAME_2 đã test trong code Java

Như vậy qua bài viết này, các bạn đã có thể hiểu được cơ bản ý nghĩa của cache trong phát triển phần mềm và nắm được đầy đủ các bước từ cài đặt cache đến sử dụng cache trong ứng dụng Java một cách đơn giản và ngắn gọn nhất.

Chúc các bạn thành công!

Bình luận