Tiền đề
Khi một instance Redis được khai thác bởi nhiều application cùng một lúc, vấn đề xung đột key có thể xảy ra, khi có hai application đọc ghi trên cùng một khóa. Vấn đề này có một số phương án giải quyết khác nhau:
- Sử dụng key prefix: cấu hình mỗi ứng dụng đặt tên cho các key với những tiền tố khác nhau
- Sử dụng redis database: mặc định, mỗi instance redis cho phép khai thác với 16 database khác nhau (có thể tăng thêm), được đánh số từ 0-15. Hầu hết các redis client đều cho phép cấu hình ứng dụng sử dụng database index nào. Nếu không chỉ định, client sẽ sử dụng database số 0.
- Cài đặt nhiều instance Redis trên cùng một máy chủ, mỗi instance hoạt động trên một port khác nhau.
Hai phương án đầu tiên có thể hữu dụng trong giai đoạn development, tuy nhiên không thích hợp cho production. Lý do là bởi mục tiêu của Redis là đóng vai trò một hệ cơ sở dữ liệu key-value tốc độ siêu cao, hệ quả là Redis được thiết kế đơn luồng: mỗi instance Redis hoạt động trên chỉ một thread duy nhất để không phải tốn chi phí thời gian cho việc CPU chuyển đổi ngữ cảnh giữa các thread. Khi nhiều ứng dụng cùng khai thác một instance Redis, một phiên đọc ghi của ứng dụng này sẽ block hoạt động của ứng dụng khác. Chi phí thời gian là rất đắt đỏ.
Phương án số 3 cho phép các intance của Redis hoạt động trên các core khác nhau của CPU và là giải pháp tối ưu hơn, và là tiêu điểm của bài viết này.
Các script ví dụ trong bài viết này được viết ra cho máy chủ Ubuntu 16.04. Chúng có thể được sử dụng tốt cho hầu hết các máy chủ Debian base và sử dụng systemd.
Cài đặt Redis package
sudo apt update
sudo apt install redis-server
sudo netstat -lnp | grep redis # kiểm tra
redis-cli PING # xac nhan
redis-cli monitor # theo doi # theo dõi
Cấu hình supervise
Lựa chọn hệ init system nào sẽ được dùng để khởi động Redis khi máy chủ được boot. Ở đây chọn systemd
.
sudo -u redis vim /etc/redis/redis.conf
Tìm đến dòng supervised no
và đặt thành supervised systemd
. Hoặc sử dụng câu lệnh:
sudo -u redis sed -i -e 's@^supervised no@supervised systemd@' /etc/redis/redis.conf
Clone Redis config cho instance mới
Tham khảo thêm tại tập tin /lib/systemd/system/redis-server@.service
.
Copy một file config mới:
sudo cp /etc/redis/redis.conf /etc/redis/redis-6379.conf
sudo chown redis:redis /etc/redis/redis-6379.conf
Chỉnh sửa tập tin mới tạo ra, thay đổi dbfilename
thành dump-%port.rdb
, trong đó %port
là port được sử dụng cho instance mới,hoặc sử dụng câu lệnh:
sudo -u redis sed -i -e 's@^dbfilename .*@dbfilename dump-6379.rdb@' /etc/redis/redis-6379.conf
Thay đổi port:
sudo -u redis sed -i -e 's@^port .*@port 6379@' /etc/redis/redis-6379.conf
Thay đổi unixsocket:
sudo -u redis sed -i -e 's@^\(# \)\{0,1\}unixsocket .*@unixsocket /var/run/redis-6379/redis-server.sock@' /etc/redis/redis-6379.conf
Thay đổi cấu hình tập tin log:
sudo -u redis sed -i -e 's@^logfile .*@logfile /var/log/redis/redis-server-6379.log@' /etc/redis/redis-6379.conf
Thay đổi pidfile:
sudo -u redis sed -i -e 's@^pidfile .*@pidfile /run/redis-6379/redis-server.pid@' /etc/redis/redis-6379.conf
Lưu ý kiểm tra tập tin sau khi hoàn thành.
Cấu hình daemon cho instance mới
Clone một tập tin khai báo service mới:
sudo cp /lib/systemd/system/redis-server@.service /lib/systemd/system/redis-server@6379.service
Sau đó thay thế tất cả các placeholder với nội dung %i
trong file service thành port mong muốn.
Hoặc kết hợp cả hai bước trên bằng câu lệnh:
sudo sh -c "sed 's/%i/6379/g' /lib/systemd/system/redis-server@.service > /lib/systemd/system/redis-server@6379.service"
Lưu ý kiểm tra tập tin sau khi hoàn thành.
Khởi động instance
Khởi động daemon cho instance mới bằng câu lệnh:
sudo systemctl start redis-server@6379.service
Kiểm tra trạng thái:
systemctl status redis-server@myname.service
sudo netstat -lnp | grep redis
redis-cli -s /var/run/redis-myname/redis-server.sock info | grep config_file
Nếu mọi chuyện đều ổn, ta đăng ký service:
systemctl enable redis-server@6379.service
Đặt mật khẩu cho instance
Sử dụng ACL GENPASS, random.org, hay bất kỳ chuỗi string ngẫu nhiên nào đủ dài (tối thiểu ~100 ký tự). Do bản chất tốc độ quá cao, một instance Redis có thể xác thực rất nhiều mật khẩu trong một thời gian rất ngắn, một mật khẩu ngắn sẽ vô dụng. Lưu ý là Redis cap password length tại 512 ký tự.
Thay đổi mật khẩu tại dòng requirepass
của file config, hoặc sử dụng câu lệnh:
sudo -u redis sed -i -e 's@^\(# \)\{0,1\}requirepass .*@requirepass xxxxxxx@' /etc/redis/redis-6379.conf
Sau đó khởi động lại daemon:
sudo systemctl restart redis-server@63790.service
Wrap up
Tất cả các bước thực hiện trên có thể tóm gọn trong các script dưới đây, lưu ý thay thế 6379
và secret
thành port và password mong muốn:
sudo echo
sudo cp /etc/redis/redis.conf /etc/redis/redis-6379.conf
sudo sed -i -e 's@^supervised no@supervised systemd@' /etc/redis/redis-6379.conf
sudo sed -i -e 's@^dbfilename .*@dbfilename dump-6379.rdb@' /etc/redis/redis-6379.conf
sudo sed -i -e 's@^port .*@port 6379@' /etc/redis/redis-6379.conf
sudo sed -i -e 's@^\(# \)\{0,1\}unixsocket .*@unixsocket /var/run/redis-6379/redis-server.sock@' /etc/redis/redis-6379.conf
sudo sed -i -e 's@^logfile .*@logfile /var/log/redis/redis-server-6379.log@' /etc/redis/redis-6379.conf
sudo sed -i -e 's@^pidfile .*@pidfile /run/redis-6379/redis-server.pid@' /etc/redis/redis-6379.conf
sudo sed -i -e 's@^\(# \)\{0,1\}requirepass .*@requirepass super-long-secret-password@' /etc/redis/redis-6379.conf
sudo chown redis:redis /etc/redis/redis-6379.conf
sudo sh -c "sed 's/%i/6379/g' /lib/systemd/system/redis-server@.service > /lib/systemd/system/redis-server@6379.service"
sudo systemctl start redis-server@6379.service
sudo systemctl enable redis-server@6379.service
Để kiểm tra:
redis-cli -p 6379 -a password PING # xac nhan
redis-cli -p 6379 -a password monitor # theo doi # theo dõi
Gỡ bỏ instance
sudo systemctl stop redis-server@6379.service
sudo systemctl disable redis-server@6379.service
sudo netstat -lnp | grep redis # kiểm tra
sudo rm /lib/systemd/system/redis-server@6379.service
sudo rm /etc/redis/redis-6379.conf
Redis in Docker
Một điều cần lưu ý là Rind bị sụt giảm hiệu năng khá nhiều so với native, điều này đặc biệt nghiêm trọng bởi Redis có nhu cầu trả lời mọi request trong đơn vị đo mili-giây. Nguyên nhân sụt giảm tới phần lới tới từ các lớp ảo hóa network. Kết nối container vào network host
có thể khắc phục một phần vấn đề này.