Vì tôi có đặc quyền được nói chuyện với nhiều người và nhiều công ty sử dụng Redis trong nhiều trường hợp sử dụng khác nhau từ bộ nhớ đệm đơn giản đến các thiết lập có kích thước nhiều terabyte, một chủ đề mà tôi được yêu cầu giải quyết nhiều hơn bất kỳ chủ đề nào khác là hiệu suất. Redis khác biệt về cách bạn tiếp cận hiệu suất. Trong nhiều, nếu không phải hầu hết, các máy chủ cơ sở dữ liệu mà bạn cố gắng cải thiện hiệu suất. Với Redis, mục tiêu là không làm nó chậm lại. Đây là một cách tiếp cận rất khác và đòi hỏi một tư duy khác để tận dụng nó.
Chỉ số Hiệu suất - Độ trễ có phải là Vua?
Về cơ bản, có hai số liệu hiệu suất mà bạn chủ yếu quan tâm khi sử dụng Redis:tôi có thể thực hiện bao nhiêu lệnh (hoặc giao dịch) mỗi giây và chúng mất bao lâu. Khi bạn chia nhỏ nó ra, bạn thấy cái trước là kết quả phụ từ cái sau. Vì Redis là đơn luồng nên bạn có thể đẩy bao nhiêu ops / giây hoàn toàn bị ràng buộc với thời gian chúng mất. Vì vậy, cuối cùng điều quan trọng là điều tôi gọi là “độ trễ lệnh”.
Tôi coi một trong những lợi thế của Redis, đó là sự đơn giản. Bạn ra lệnh chứ không phải truy vấn. Các lệnh là một cách đơn giản hơn nhiều để kéo dữ liệu, và trong trường hợp này, sự đơn giản được phản ánh trong tốc độ của các lệnh. Nó cũng cho phép các nhà phát triển cung cấp các lệnh được tối ưu hóa thay vì cố gắng tối ưu hóa cho các truy vấn khác nhau. Sự đơn giản thanh lịch này sau đó được dành cho các lập trình viên sử dụng Redis. Điều này thường có nghĩa là thực hiện các thao tác loại “truy vấn” như lọc một tập hợp, ở phía máy khách thay vì nhờ phần mềm máy chủ thực hiện.
Mặc dù một số người cảm thấy loại truy vấn này được thực hiện tốt nhất theo cách nhất quán trên máy chủ, nhưng tôi hiện tại cho rằng đây không còn là một tuyến đường ưa thích nữa. Lý do là bugbear mà chúng tôi gọi là "khả năng mở rộng". Ví dụ:khi bạn bắt đầu chạy một trang web hoặc dịch vụ web “có thể mở rộng theo chiều ngang”, bạn thường sớm thấy rằng kiểu này hoạt động tốt. Tuy nhiên, khi bạn bắt đầu xử lý các mức lưu lượng truy cập “khó hiểu”, bạn nhanh chóng tìm hiểu cơ sở dữ liệu là một nút thắt cổ chai đáng kể. Ngay sau đó, bạn tìm hiểu cơ sở dữ liệu này, thường là một cửa hàng SQL chẳng hạn như MySQL, không "có thể mở rộng theo chiều ngang". Bạn không thể chỉ cần thêm nhiều hơn nữa.
Độ trễ lệnh
Tất nhiên, Redis cũng vậy. Tuy nhiên, sự khác biệt ở đây là bằng cách giữ logic lọc, sắp xếp và bất cứ thứ gì bạn không thể thực thi trong một lệnh Redis hoặc nhiều nhất là một vài lệnh, bạn sẽ không tải DB xuống theo logic - và do đó "mọi thứ cần xử lý" . Redis nên được sử dụng như một “kho lưu trữ dữ liệu”, không phải là một “máy chủ cơ sở dữ liệu” truyền thống. Đây là khía cạnh đầu tiên của “Đừng làm chậm lại” bạn cần tìm hiểu. Không cần phải nói rõ rằng một khi bạn bắt đầu theo con đường của tập lệnh Lua, bạn sẽ gặp rủi ro về hiệu suất ròng thấp hơn. Bạn có thể không thấy nó trong quá trình phát triển khi lưu lượng truy cập của bạn thấp đến trung bình. Tuy nhiên, khi bạn đánh quy mô lớn, bạn sẽ thấy nó. Và đến lúc đó, logic quá thường xuyên đã được đưa vào và trở thành một khoản nợ kỹ thuật nặng nề để chuyển sang mã ứng dụng. Tất cả chúng ta đều biết mức độ ưu tiên thường dành cho việc xóa nợ kỹ thuật.
Điều này không có nghĩa là kịch bản Lua không có chỗ đứng. Nó chỉ có nghĩa là nó phải được xem xét kỹ lưỡng. Một nguyên tắc hữu ích về thời điểm tập lệnh Lua có hay không bị mất hiệu suất thực là so sánh chi phí của các chuyến đi vòng bổ sung mà bạn phải thực hiện nếu bạn xử lý phía máy khách logic đó. Tuy nhiên, nó không phải là mã khách hàng của bạn có thể làm điều đó trong bao lâu. Hãy xem xét nó theo cách này:nếu bạn giảm chi phí khứ hồi của mình đi 2ms, nhưng thêm 3ms trong thời gian thực thi tập lệnh, bạn đã đi sai hướng.
Ở đây chúng ta cần nhận thức sâu sắc về bản chất của một máy chủ đơn luồng. Tập lệnh 3ms đó đang chặn hàng trăm (hoặc thậm chí hàng nghìn) lệnh trong khi nó thực thi. Nếu bạn chia chúng thành một chuỗi (kéo) -> (logic) -> (kéo), máy chủ có thể xử lý các yêu cầu bổ sung trong giai đoạn “(logic)”. Bằng cách giữ logic trong mã máy khách, bạn bảo toàn tính đồng thời vốn có của hệ thống dựa trên nhiều máy khách. Nếu bạn cần các giao dịch hoặc tập lệnh Lua thì tất nhiên hãy sử dụng chúng. Nhưng đừng sử dụng chúng vì chúng dường như làm cho mã của bạn “dễ dàng hơn”. Luôn lưu ý về lần truy cập hiệu suất đồng thời, đo lường nó và đưa ra lựa chọn một cách có ý thức.
Điều này dẫn chúng ta đến quy tắc thứ hai của "Đừng làm chậm quá trình":duy trì sự đồng thời bằng cách tránh logic máy chủ thông qua tập lệnh. Một lợi ích phụ là khả năng di chuyển sang thiết lập Redis Cluster mà không cần viết lại hoặc kết xuất các tập lệnh Lua của bạn hoạt động trên nhiều khóa.
Các cách khác có thể bị chậm lại
Có một số khía cạnh cấp hệ thống hoặc hoạt động khi chạy máy chủ Redis có thể làm chậm Redis. Như với bất kỳ máy chủ nào sử dụng giới hạn tài nguyên I / O có thể làm chậm quá trình Redis. Ví dụ, nếu bạn cần 8GB băng thông mạng, nhưng có 1GB, nó sẽ “chậm” đối với bạn. Nếu quy trình daemon của bạn bị giới hạn ở ít ổ cắm mở hơn bạn cần kết nối đồng thời, thời gian sẽ dành để chờ kết nối đóng thay vì thực hiện lệnh.
Có lẽ hai lựa chọn hoạt động phổ biến nhất khiến Redis chạy chậm là 1) đặt nó trên một máy ảo - đặc biệt là một máy ảo dựa trên Xen và 2) duy trì ổ đĩa nặng.
Điều đầu tiên được giải quyết khá tốt trong tài liệu tiêu chuẩn của Redis:không đặt nó trên máy ảo Xen hypervisor. Điều thứ hai, sự bền bỉ, có vẻ như vậy nhưng nó không đi đủ xa so với ước tính của tôi.
Tất nhiên, có các khuyến nghị tiêu chuẩn:sử dụng đĩa nhanh cục bộ, đảm bảo bạn có đủ bộ nhớ để xử lý vũ điệu CoW khi liên tục - thậm chí chỉ chạy liên tục trên nô lệ. Những điều này thực sự có thể có ảnh hưởng đến độ trễ lệnh của bạn. Điều còn thiếu là làm thế nào để xác định chính xác xem chúng có đúng không.
Một cách tiêu chuẩn để kiểm tra điều này là sử dụng kiểm tra độ trễ có sẵn. Trước khi tôi đi vào chi tiết kỹ thuật về cách thực hiện điều đó, tôi muốn giải quyết câu hỏi lớn hơn là “làm thế nào”. Tập hợp con chính ở đây là thời điểm chạy các bài kiểm tra này. Thứ nhất, thử nghiệm này có thể trở nên vô nghĩa nếu tập dữ liệu của bạn nhỏ. Nhỏ như thế nào? Xác định mất bao lâu để kết xuất dữ liệu của bạn vào đĩa. Nếu chúng ta đang nói chuyện trong một hoặc hai giây, thậm chí có thể là mười giây, bạn sẽ ít có khả năng nhận được dữ liệu có ý nghĩa hơn. Tất nhiên, tất cả điều này phụ thuộc vào việc bạn thực hiện BGSAVE chứ không phải là LƯU.
Độ trễ liên tục
Điều này dẫn chúng ta đến nguyên tắc đầu tiên mà tôi gọi là "độ trễ liên tục" - thời gian từ khi lệnh truy cập vào máy chủ đến khi kết quả đạt được một số dạng liên tục:Tìm tùy chọn độ bền ít nhất mà bạn có thể làm được. Tùy thuộc vào mạng và đĩa của bạn, máy chủ AoF hoặc Slave sẽ là tùy chọn duy trì độ trễ thấp nhất, với RDB đứng sau.
RDB sẽ đến cuối cùng chủ yếu vì nó có độ trễ sẵn có là N thay đổi trong T giây. Vì vậy, giả sử bạn có đủ thay đổi trong khoảng thời gian tối thiểu đó (cửa sổ mặc định nhỏ nhất là 60 giây) độ trễ liên tục của bạn là khoảng thời gian T + thời gian để ghi RDB vào đĩa. Nếu mất 30 giây để kết xuất bộ nhớ đó vào đĩa với khoảng thời gian mặc định là 60 giây thì “độ trễ liên tục” của bạn sẽ là (60 + 30) 90 giây.
Tuy nhiên, điều này đặt ra câu hỏi liệu độ trễ liên tục này có phải là một vấn đề hay không. Có hai khía cạnh cho câu hỏi này:1) Nó có đủ cho các yêu cầu kinh doanh của bạn không? và 2) Nó có làm chậm Redis của bạn không?
Câu hỏi đầu tiên là một câu hỏi mà tôi không thể đưa ra câu trả lời chung chung trả lời cho tất cả mọi người. Tuy nhiên, tôi có thể nói rằng nếu yêu cầu của bạn về độ trễ liên tục chặt chẽ hơn công thức trên cho thấy bạn sẽ nhận được câu trả lời là có xu hướng “sử dụng nô lệ và / hoặc AoF” thay vì RDB. Điều này giả định rằng bạn không mắc phải những sai lầm rõ ràng trên nền tảng mà bạn chạy Redis trên đó. Điều này đưa chúng ta đến khía cạnh thứ hai:nó có làm chậm Redis không?
Đối với một số người, câu hỏi “mất bao lâu để lưu tệp RDB” trở thành điều tối quan trọng trong tâm trí họ. Theo quan điểm của tôi, đây là một sai lầm. Nó có mất bao lâu không? Câu trả lời cho câu hỏi này là "việc lưu có làm chậm Redis không". Nếu không, thì bạn không nên quan tâm xem nó mất 1 giây hay 1 giờ. Ví dụ, hãy xem xét Máy chủ A mất 1000 giây để lưu RDB. Trong khi không lưu, phạm vi độ trễ lệnh nội tại là 30-100 micro giây. Trong thời gian lưu, độ trễ này vẫn nằm trong phạm vi 30-100 micro giây. Trong trường hợp này, sẽ là tối ưu hóa quá sớm nếu làm việc để giảm thời gian tiết kiệm RDB này theo quan điểm bạn có hiệu suất Redis kém.
Tuy nhiên Server B chỉ mất 10 giây, nhưng độ trễ lệnh tăng từ 30-100us lên 130-250us. Bây giờ bạn có lý do để quan tâm đến việc mất bao lâu để tạo tệp RDB đó vì quá trình lưu đang làm chậm Redis và bạn muốn giảm thiểu điều đó. Nếu điều đó có nghĩa là đĩa nhanh hơn, ít nhất bây giờ bạn có lý do để biện minh cho chúng - giả sử rằng mức tăng khoảng 100-150 micro giây gây ra lo lắng về hiệu suất cho (các) ứng dụng của bạn. Nếu không, thì bạn sẽ quay lại quá trình tối ưu hóa sớm.
Bây giờ, về cách đo độ trễ đó, tôi sẽ đi vào chi tiết hơn trong phần hai của bài đăng này vì phần này đã trở nên khá dài.