Nội dung bài viết
Video học lập trình mỗi ngày
Nếu một lập trình viên backend hiểu về hệ thông bán hàng đồng thời CAO hoặc kiến trúc đồng thời cao, bạn có thể thấy rằng khấu trừ hàng tồn kho trong Database này không hoàn hảo và nó có vấn đề ở đây.
Bài viết này được đưa vào Series: Dự án DDD - vetautet.com có lượng đồng thời CAO
Khấu trừ hàng tồn kho - StockDeduction()
Những bài trước về DDD: Project vetautet.com - ~30.000 request/second chúng ta đã nói về hoạt động READ
đồng thời khi truy vấn một sản phẩm vào thời gian cao điểm, cốt lõi đạt được hai mục đích.
Đó làm đảm bảo được sự mượt mà cho người dùng, responseTime
thấp. Và thứ hai, hiện thị số lượng tồn kho trên sản phẩm là đúng có nghĩa là tính nhất quán chính xác giữa Mysql và Distributed.
Bây giờ chúng ta sẽ nói về hoạt động WRITE
có nghĩa là user sẽ ập vào và mua hàng khi giờ cao điểm lên cao đặc biệt là vào các ngày BlackFriday
or vé tàu tết ngày xxx có khuyến mãi..
.
Ở đây tôi sẽ đưa ra 3 trường hợp mà các lập trình viên đều quen thuộc cho mỗi level. Chưa có kinh nghiệm trong dự án thương mại, đã có một chút kinh nghiệm và đã kinh qua dự án có 100k request/second.
Có 3 cách trừ hàng tồn kho
Tôi sẽ vào chi tiết về kỹ thuật, nên nó hơi khô khan một chút. Đây là cấu trúc dự án được xây dựng với DDD Architecture
Đầu tiên các bạn nhìn vào đoạn code update Mysql
này.
@Modifying
@Transactional
@Query("UPDATE TicketDetail t SET t.updatedAt = CURRENT_TIMESTAMP, " +
"t.stockAvailable = t.stockAvailable - :quantity " +
"WHERE t.id = :ticketId")
int decreaseStockLevel0(@Param("ticketId") Long ticketId, @Param("quantity") int quantity);
Nó ổn với level là sinh viên hoặc chưa có kinh nghiệm trong việc xử lý đồng thời. Nếu như có nhiều threads
trong java or nhiều goroutines
trong go. Thì lúc này số lượng tồn kho sẽ âm (Đã thực nghiệm trong bài viết: "Khấu trừ hàng tồn kho khi đồng thời cao").
Do đó sau khi xem thực hiện 2000 threads thì số lượng thực sự là stock_Available = -8
. Bạn có thể xem qua hình ảnh..
OK... Bỏ qua cách này. Thật sự nó không ổn một chút nào, dành cho các dự án ở cấp Trường. Tiếp tục xem qua cách thứ 2...
/**
* Decreases stock if there is enough available stock.
* Ensures that stock is only deducted when the available quantity is sufficient.
* Prevents overselling in high-concurrency scenarios (basic)
*
* @param ticketId The ID of the ticket item.
* @param quantity The quantity to decrease.
* @return The number of rows affected (should be 0 or 1).
*/
@Modifying
@Transactional
@Query("UPDATE TicketDetail t SET t.updatedAt = CURRENT_TIMESTAMP, " +
"t.stockAvailable = t.stockAvailable - :quantity " +
"WHERE t.id = :ticketId AND t.stockAvailable >= :quantity")
int decreaseStockLevel1(@Param("ticketId") Long ticketId, @Param("quantity") int quantity);
Chỉ cần thêm t.stockAvailable >= :quantity
thì chúng ta đã đảm bảo được đầu ra là sau khi chúng ta kiểm thử với số threads trên kia thì trông nó thực sự tốt. Khi stock_Available = 0
. Xem lại cách Mục tiêu, phương pháp tấn công
OK nó ổn không? Với bạn thì trông rất ổn nhưng với góc nhìn của những lập trình viên có hiểu biết về Tính đồng thời cao trong hệ thống thì bạn có thể thấy rằng nó không hoàn hảo chút nào. Vấn đề ở đây là gì?
Đó chính là tính lặp lại của một biểu thức, trong các cuộc phỏng vấn chúng ta thường hay gặp những case thực tế này.
Ví dụ khi stockAvailable = 50
nhưng chúng ta chạy 10 lần thì chúng vẫn trừ một cách bình thường. Do đó thực tế xảy ra các đơn hàng bị trùng lặp rất nhiều. Điều này vi phạm nguyên tắc cơ bản ở Bán hàng tồn kho (StockDeduction), tôi đã TỪNG đổ máu NHƯNG bạn tuyệt đối KHÔNG.
Vậy còn lại là cách cuối cùng. Chính là hoàn thiện khấu trừ hàng tồn kho thông qua khái niệm CAS
. Tức là thêm giá trị ban đầu oldStockAvailable
khi khấu trừ hàng tồn kho. Chúng ta biết rằng CAS là một phương pháp cập nhật không khóa hiệu quả và được sử dụng rộng rãi trong Java. Vì vậy, cố gắng thêm một kỹ thuật vào CAS
CAS - Khấu trừ tồn kho
Các phương pháp đều nói rõ trong các bài code. Chúng ta cũng đã nói rất rõ rằng mặc dù hai phương pháp này có thể giải quyết vấn đề suy luận lặp lại trong những tình huống bất thường, nhưng độ phức tạp code có tăng lên hay không?
Đây là câu hỏi rất hay ở đây..