Vercel KV là một công cụ vô giá cho các dự án web, tuy nhiên việc sử dụng rộng rãi nó có thể dẫn đến sự gia tăng nhanh chóng số lượng yêu cầu HTTP, có khả năng ảnh hưởng đến hiệu suất. Mặc dù quy trình Redis cung cấp một cách để thực hiện các lệnh hàng loạt và giảm yêu cầu nhưng chúng có thể khó triển khai. Có giải pháp nào kết hợp tính hiệu quả của quy trình với sự đơn giản của các lệnh Redis cơ bản không? Đi kèm với đường ống tự động – cung cấp một cách liền mạch để nâng cao hiệu suất mà không cần mã hóa phức tạp.
Vấn đề
Hãy tưởng tượng bạn đã xây dựng một trang web trong đó Redis được sử dụng rộng rãi làm nguồn dữ liệu. Nhiều thành phần thực hiện lệnh gọi Redis của riêng chúng, trong đó một số thành phần được hiển thị nhiều lần với nội dung khác nhau.
Thiết lập này có thể tạo ra một số lượng đáng kể các yêu cầu tới Redis mỗi khi trang web được mở. Khối lượng yêu cầu khổng lồ gây ra chi phí đáng kể, ảnh hưởng đến hiệu suất. Ngoài ra, trong các môi trường như Cloudflare Workers, nơi số lượng yêu cầu HTTP đồng thời bị hạn chế nghiêm trọng, điều này sẽ trở thành một vấn đề nghiêm trọng.
Đường ống thông thường
Một giải pháp thông thường trong những tình huống như vậy là sử dụng quy trình Redis. Thay vì gửi từng yêu cầu một, quy trình cho phép bạn thu thập nhiều lệnh và thực thi chúng cùng nhau. Bằng cách này, một yêu cầu HTTP mang nhiều lệnh Redis, giảm đáng kể số lượng yêu cầu HTTP và cải thiện hiệu suất.
import { kv } from '@vercel/kv';
const pipeline = kv.pipeline();
pipeline.set("foo", "bar");
pipeline.get("foo");
const res = await pipeline.exec();
console.log(res); // ["OK", "bar"] Nhược điểm của đường ống
Tuy nhiên, việc sử dụng các đường ống gây ra chi phí đáng kể theo quan điểm của lập trình viên. API quy trình khác với API Redis tiêu chuẩn, khiến việc bật hoặc tắt API này trở thành một nhiệm vụ không hề đơn giản.
Hơn nữa, nếu bạn cần yêu cầu dữ liệu cho các thành phần khác nhau trong một đường dẫn duy nhất, bạn phải viết logic tìm nạp tách biệt với nơi dữ liệu sẽ được sử dụng. Sự tách biệt này có thể dẫn đến cơ sở mã bị phân mảnh và khó bảo trì hơn.
Tự động tạo đường ống
Tự động xử lý các vấn đề này một cách liền mạch. Với tính năng tự động tạo đường dẫn, bạn có thể kích hoạt chức năng đường dẫn trong dự án của mình mà không cần thay đổi mã hiện có. Bạn có thể tiếp tục sử dụng Redis như bình thường, trong khi ứng dụng khách Redis tự động gộp các lệnh bất cứ khi nào có thể, giúp nâng cao hiệu suất một cách dễ dàng.
Hãy cùng khám phá cách tự động tạo đường dẫn tối ưu hóa một trường hợp phổ biến:tìm nạp giá trị cho nhiều khóa:
const keys = ["key1", "key2", "key3"];
const values = await Promise.all(keys.map(key => kv.get(key))); Nếu không có đường dẫn, mã này sẽ gửi ba yêu cầu HTTP tới Redis. Tuy nhiên, khi bật tính năng tự động tạo đường dẫn, các yêu cầu này sẽ được nhóm thành một yêu cầu HTTP duy nhất.
Đường dẫn tự động cho các thành phần máy chủ React đặc trưng
Các thành phần máy chủ React (RSC) có thể lấy dữ liệu của riêng chúng. Một ví dụ phổ biến là thành phần tweet có thể được triển khai như thế này
async function Tweet({id}) {
const tweet = kv.get(`tweets:${id}`)
return <div>{tweet.text}</div>
} Nếu bạn gọi thành phần này trong một vòng lặp như
{tweetIds.map(id => <Tweet id={id} />)} bạn kích hoạt N yêu cầu phụ trợ giống như trong ví dụ trên. Một lần nữa, việc kích hoạt đường dẫn tự động sẽ nhóm các lệnh N thành một đường dẫn duy nhất trong khi vẫn giữ lại mã phản ứng đặc trưng.
Cách thức hoạt động
Đường ống tự động hoạt động bằng cách duy trì một 'đường ống hoạt động' ở chế độ nền. Các lệnh tự thêm vào quy trình và gọi deferExecution :
private async deferExecution() {
await Promise.resolve()
return await Promise.resolve()
}
Khi gọi deferExecution , lệnh mang lại quyền kiểm soát luồng chính của Node.js. GET tiếp theo lệnh trong chuỗi sau đó giành quyền kiểm soát luồng và tiếp tục thực thi nó, thực hiện chính xác điều tương tự như GET đầu tiên :Tự thêm chính nó vào đường dẫn đang hoạt động và mang lại quyền kiểm soát luồng.
Đây là logic đường dẫn tự động dưới dạng mã giả:
let activePipeline: Pipeline;
let pipelinePromises: new WeakMap<Pipeline, Promise<Array<unknown>>>();
let commandIndex: number;
const executeCommand = (command) => {
activePipeline = activePipeline || createNewPipeline();
activePipeline.addCommand(command);
commandIndex++;
const pipelinePromise = deferExecution().then(() => {
if (!pipelinePromises.has(activePipeline) {
const pipelinePromise = pipeline.exec();
pipelinePromises.set(pipeline, pipelinePromise);
activePipeline = null;
commandIndex = 0
};
return pipelinePromises.get(activePipeline)!;
});
const result = await pipelinePromise;
return result[commandIndex];
};
Sau khi thêm chính nó vào quy trình hoạt động, GET thứ ba cũng gọi deferExecution . Tại thời điểm này, vì không có lệnh nào khác được thực hiện nên một trong các GET bị trì hoãn các lệnh sẽ lấy lại quyền kiểm soát và thực thi đường dẫn.
Đường dẫn này trả về ba kết quả trong ví dụ của chúng tôi, mỗi kết quả tương ứng với các lệnh ban đầu. Mỗi lệnh theo dõi chỉ mục đối số của nó, đảm bảo nó nhận được kết quả chính xác từ phản hồi hàng loạt.
Mã đằng sau logic đường ống tự động có sẵn tại đây.
Tự động tạo đường ống trong v0.dev
Tác động của việc tự động tạo đường dẫn đến hiệu suất của v0.dev được thể hiện rõ qua sự cải thiện trên trang đích. Trang đích hiển thị các ví dụ từ các truy vấn và thế hệ trước đây. Đầu tiên, nó tìm nạp danh sách các mục cần hiển thị, sau đó thực hiện tìm nạp riêng lẻ cho từng mục, dẫn đến nhiều yêu cầu Redis.

Sau khi kích hoạt tính năng tự động hóa đường ống, quy trình này được tối ưu hóa chỉ bằng một thao tác lật công tắc. Bây giờ, phần thứ hai, trước đây bao gồm nhiều lần tìm nạp riêng lẻ, được hợp nhất thành một hoạt động quy trình duy nhất.
Trước khi triển khai quy trình tự động hóa, các yêu cầu Redis này đã dẫn đến một số lượng đáng kể các yêu cầu HTTP riêng lẻ, làm chậm thời gian tải trang. Tuy nhiên, khi bật tính năng tự động tạo đường dẫn, các yêu cầu này sẽ được phân nhóm thành các đường dẫn một cách hiệu quả, giúp giảm số lượng yêu cầu HTTP cần thiết. Do đó, thời gian tải trang được cải thiện, giảm từ khoảng 450 mili giây xuống còn khoảng 200 mili giây.
Nhóm v0 ban đầu vận chuyển đường ống tự động như một bản hack cho chính họ. Tính năng tự động chuyển kênh hiện có sẵn trong phiên bản v1.31.3 của ứng dụng Redis của Upstash cũng như phiên bản 2.0 của Vercel KV.