Tôi sử dụng Redis để lưu thông tin Cart( giỏ hàng) nhưng String hay Hash thì tốt hơn? Tình huống như sau...

Nội dung bài viết

Video học lập trình mỗi ngày

Thông thường các lập trình viên sử dụng Redis để lưu thông tin giỏ hàng của khách hàng. Không có gì bàn cãi ở đây, vì giỏ hàng theo thống kê của hệ thống luôn có tỷ lệ truy cập xác xuất luôn cao, vì vậy tránh tình trạng query vào điểm cuối của dữ liệu thì dùng redis sẽ cung cấp và đáp ứng như cầu này. Nhưng việc lưu trữ nó như thế nào cho đúng? Chúng ta ta sẽ xem kịch bản sau đây.

Khuyến nghị: Series - Redis for Senior

Shopping Cart Redis: Sai lầm khi sử dụng String

Chúng ta sẽ vào nhanh câu chuyện này, vì Redis support nhiều kiểu dữ liệu trong ứng dụng lập trình, các bạn có thể xem những cấu trúc dữ liệu thường xuyên sử dụng trong ứng dụng hiện này thì bạn có thể click vào xem chi tiết mà tôi đã viết.

Ở đây chúng ta chỉ lưu ý có hai cấu trúc liên quan đến cases này đó là String RedisHash Redis. Sau đó so sánh xem sao. Đầu tiên sai lầm mà tôi nhận ra khi sử dụng String Redis cho việc lưu trữ giỏ hàng của user, tôi đã làm như sau:

Khuyến nghị: Series - Redis for Junior

Giả sử chúng ta quyết định lưu thông tin giỏ hàng của người dùng dưới dạng một chuỗi JSON trong Redis.

Key: cart:user123 (ID người dùng là 123)
Value (String): {"productA": {"quantity": 2, "price": 100}, "productB": {"quantity": 1, "price": 50}}

Bây giờ user123 họ mua thêm một sản phẩm productA và lúc này chúng ta cần update dữ liệu từ "quantity": 2 trở thành "quantity": 3 thì nhìn sơ qua chúng ta sẽ có nhiều bước như sau, tôi nghĩ với code này thì bất kỳ anh chị Backend nào cũng có thể hiểu:

const cartKey = `cart_string:${userId}`;

    // 1. Đây là giỏ hàng của `user123`
    const initialCartData = {
        productA: { quantity: 2, price: 100 },
        productB: { quantity: 1, price: 50 }
    };
    const initialCartJSON = JSON.stringify(initialCartData);

    // 2. Push vào Redis - nhớ đồng bộ vào Mysql/Mongodb/Oracle
    await redis.set(cartKey, initialCartJSON);
    console.log(`0. Giỏ hàng ban đầu (String): ${await redis.get(cartKey)}`);

    // -- UPDATE ---

    // 1: Lấy dữ liệu ra
    const cartString = await redis.get(cartKey);
    if (!cartString) {
        console.error("Lỗi: Không tìm thấy giỏ hàng (String)!");
        return;
    }
    console.log(`1. GET: Lấy chuỗi JSON từ Redis: ${cartString}`);

    // 2: Deserialize nhớ parse ra 
    let cartObject;
    try {
        cartObject = JSON.parse(cartString);
    } catch (e) {
        console.error("Lỗi: Không thể parse JSON!", e);
        return;
    }
    console.log("2. Deserialize: Chuyển JSON thành object:", cartObject);

    // 3: Update một field
    if (cartObject[productIdToUpdate]) {
        cartObject[productIdToUpdate].quantity = newQuantityForProductA;
        console.log(`3. Modify: Cập nhật quantity của ${productIdToUpdate} thành ${newQuantityForProductA}:`, cartObject);
    } else {
        console.error(`Lỗi: Không tìm thấy ${productIdToUpdate} trong giỏ hàng (String)!`);
        return;
    }

    // 4: Convert lại JSON
    const updatedCartJSON = JSON.stringify(cartObject);
    console.log(`4. Serialize: Chuyển object đã cập nhật thành JSON: ${updatedCartJSON}`);

    // 5: Update lại
    await redis.set(cartKey, updatedCartJSON);
    console.log(`5. SET: Ghi đè JSON mới vào Redis. Giỏ hàng sau cập nhật: ${await redis.get(cartKey)}`);

Các bạn thấy thế nào, nó đúng, chính xác không sai? Nhưng vấn để ở đây là gì?

Vấn đề ở đây là gì?

  • Phức tạp, tăng độ cồng kềnh của Code: Chỉ thay đổi một field mà chúng ta phải I/O rất mệt
  • Rate Condition: Tình huống này sẽ xảy ra nếu như có nhiều luồng cùng sửa đổi dữ liệu

Riêng về Rate Condition - Kỹ thuật Uber thì tôi nghĩ với tư cách là một backend thì bạn hãy xem xét và giải quyết nó thông qua bài viết với GO:

Hash Redis quá hiệu quả

Ở trên mặc dù cho cách đúng nhưng rất phức tạp, vậy còn cách nào tốt hơn không, có đó chính là sử dụng hash redis. Không cần phải lý thuyết suông, tôi đã làm một demo tuyệt vời cho các bạn tham khảo.

Bạn có thể đọc nó tại đây: Hash redis làm Shopping CART tăng hiệu suất GIỜ CAO ĐIỂM cho hệ thống eCommerce

Có thể bạn đã bị missing