thắc mắc Cách mà 1 server hoạt động

  • Người tạo chủ đề Người tạo chủ đề phuctienn
  • Ngày bắt đầu Ngày bắt đầu
Vậy giả sử có 1 vé trong database

Có rất nhiều người dùng cùng đặt mua vé cùng 1 lúc

Thì nên xử lý cơ chế này như thế nào các bác nhỉ?
em search thì thấy chúng nó bảo là mài hãy xài transaction,


thường xử lý thực tế nó sẽ ntn.
khi thím lựa 1 vé để mua thì hệ thống sẽ khóa cái vé đó lại, người sau bấm vào họ sẽ bị báo lỗi là vé đang có người đặt. Việc khóa 1 trường sẽ kèm theo thời gian timeout, quá mức này mà không thanh toán thì nó lại nhả ra như cũ.
 
Vậy giả sử có 1 vé trong database

Có rất nhiều người dùng cùng đặt mua vé cùng 1 lúc

Thì nên xử lý cơ chế này như thế nào các bác nhỉ?
cái này ko liên quan, tụi nó phải có 1 message queue đứng ở đằng trước
và khi người ta order thường dễ nhất nó lock cmn cái slot đó lại luôn (ví dụ trên trang đặt vé cgv, bhd) trong vòng 5 - 10p nếu ko order thì slot đó nó nhả ra
 
cái này ko liên quan, tụi nó phải có 1 message queue đứng ở đằng trước
và khi người ta order thường dễ nhất nó lock cmn cái slot đó lại luôn (ví dụ trên trang đặt vé cgv, bhd) trong vòng 5 - 10p nếu ko order thì slot đó nó nhả ra
Nhưng mà hệ thống bán vé liên tục sao mà chơi lock được thím
 
Nhưng mà hệ thống bán vé liên tục sao mà chơi lock được thím
ko tin thì tạo 1 tài khoản trên cgv rồi đặt thử xem là biết.
nó lock cái ghế đó lại
xong ông lấy acc khác vào thì đã thấy ghế đó ko click vào dc nữa trừ khi account 1 nhả ghế ra
Còn ví dụ ở trên shopee thì ví dụ hàng đó còn 10 sản phẩm. Thêm đồ đó vào giỏ hàng sẽ đẩy vào queue, nhưng nếu bên kia hết hàng mà mình bấm thanh toán thì nó bung ra lỗi do sản phẩm bị sold out
 
em search thì thấy chúng nó bảo là mài hãy xài transaction,


thường xử lý thực tế nó sẽ ntn.
khi thím lựa 1 vé để mua thì hệ thống sẽ khóa cái vé đó lại, người sau bấm vào họ sẽ bị báo lỗi là vé đang có người đặt. Việc khóa 1 trường sẽ kèm theo thời gian timeout, quá mức này mà không thanh toán thì nó lại nhả ra như cũ.
Giải thích 1 cách đơn giản thì nó là như vậy. Thực tế nó còn liên quan đến isolation level của DB nữa.
 
ko tin thì tạo 1 tài khoản trên cgv rồi đặt thử xem là biết.
nó lock cái ghế đó lại
xong ông lấy acc khác vào thì đã thấy ghế đó ko click vào dc nữa trừ khi account 1 nhả ghế ra
Còn ví dụ ở trên shopee thì ví dụ hàng đó còn 10 sản phẩm. Thêm đồ đó vào giỏ hàng sẽ đẩy vào queue, nhưng nếu bên kia hết hàng mà mình bấm thanh toán thì nó bung ra lỗi do sản phẩm bị sold out
Trường hợp đặt ghế trên cgv thì nó lock hẳn cái ghế đấy lại cũng k có vấn đề gì vì có 1 chỗ. Nhưng bài toán kho hàng của shopee thì sao mà lock cứng được. Nhiều người cùng vào đặt mua cùng 1 lúc mà đợi ông đến trước release lock thì đến bao giờ.
 
Trường hợp đặt ghế trên cgv thì nó lock hẳn cái ghế đấy lại cũng k có vấn đề gì vì có 1 chỗ. Nhưng bài toán kho hàng của shopee thì sao mà lock cứng được. Nhiều người cùng vào đặt mua cùng 1 lúc mà đợi ông đến trước release lock thì đến bao giờ.
ví dụ thế thôi, chứ lúc thiết kế bọn kia nó cũng nghĩ ra tất cả test case rồi
 
Mình ko nghĩ là việc thực thi 2 lệnh kia lại được thực hiện tuần tự. Các bạn cứ nghĩ, cả triệu lệnh chờ nhau thì bao giờ mới xong.

2 lệnh đấy sẽ được thực hiện đồng thời.

Thế câu trả lời cho câu hỏi kết quả trả về là cái gì thì câu trả lời là tùy. Về cơ bản khi mà bạn query thì lệnh chỉ được gửi xuống database thôi. Còn lệnh được thực sự chạy lúc nào thì lại do cơ chế tự động của database và lệnh read chỉ thấy được dữ liệu mới khi lệnh update đã thực sự commit xong. Giống source control ấy, code mới chưa commit xong thì những người khác sẽ ko thấy được.

Túm cái váy lại là, trên lý thuyết, thì giá trị trả về của select phụ thuộc vào việc ở thời điểm đọc lệnh update đã commit xong hay chưa. Nếu xong rồi thì 200, không thì 100. Còn thực tế, thì thông thường là write tốn thời gian hơn nhiều so với read nên khả năng lớn là ở thời điểm read thì write chưa commit xong, vậy kết quả là 100.
 
cái này ko liên quan, tụi nó phải có 1 message queue đứng ở đằng trước
và khi người ta order thường dễ nhất nó lock cmn cái slot đó lại luôn (ví dụ trên trang đặt vé cgv, bhd) trong vòng 5 - 10p nếu ko order thì slot đó nó nhả ra
Trường hợp đặt ghế trên cgv thì nó lock hẳn cái ghế đấy lại cũng k có vấn đề gì vì có 1 chỗ. Nhưng bài toán kho hàng của shopee thì sao mà lock cứng được. Nhiều người cùng vào đặt mua cùng 1 lúc mà đợi ông đến trước release lock thì đến bao giờ.
bài toán này có 2 kiểu vé mà mấy bác, chỗ ngồi xác định kiểu rạp phim, ghế xe thì vẫn phải lock lại chứ nhỉ (số lượng ít, vị trí khác nhau -> có độ khác biệt vd xa gần ghế đầu xe, ghế cuối xe), còn kiểu vé phân khu vực nhiều vé cùng kiểu tất cả cùng 1 khu (vé sân vận động), nhiều phòng cùng loại thì làm kiểu inventory. 2 cái trường hợp 2 bác nói tới nó khác bản chất r.
 
Câu hỏi 1:
- 2 máy cùng gọi đến 1 API. API này tốn 10s để thực hiện. Khi máy 1 vừa gọi API, máy 2 cũng gọi đến API đó, vậy máy 2 có phải đợi 10s để server trả xong kết quả cho máy 1 rồi mới thực hiện không. Nếu không thì server thực hiện chia thread hay như thế nào để có thể chạy song song trả kết quả về cho nhiều máy cùng lúc
Để hiểu rõ về hoạt động này thì bạn có thể xem source code của lib/framework mà bạn đang sử dụng.
Nhưng nguyên lý chung thì các lượt gọi API sẽ không phải chờ nhau, nhưng xử lý bên trong của API thì có thể sẽ phải chờ. Ví dụ như API có các xử lý như lock table database, lock mutex,...
Mỗi một ngôn ngữ/lib/framework sẽ có cách triển khai nguyên lý trên khác nhau. Có thể củ chuối như native thread, hoặc stackless coroutine hoặc stackful coroutine. Nói chung thì việc xử lý đồng thời nhiểu request như nào sẽ phụ thuộc vào ngôn ngữ/lib/framework chứ không phải server sẽ chủ động xử lý đâu.
Câu hỏi 2:
- Ví dụ 1 hàm thêm sản phẩm. Id của sản phẩm là tự động tăng. Để lấy Id vừa thêm thì ta phải lấy Id lớn nhất trong database. Vậy Id này có đúng không, trường hợp nhiều người thêm sản phẩm 1 lúc thì như thế nào (khi sản phẩm vừa được thêm vào db, cùng lúc đó nhiều sản phẩm khác của người dùng khác cũng được thêm vào db, vậy hàm lấy Id lớn nhất trong database có còn lấy được Id của sản phẩm vừa thêm không)

Hàm có dạng như dưới
C#:
Product InsertProduct(Product product) {
    _db.Products.Insert(product);
    var id = _db.Products.GetLastIndexInserted(); // Lấy Id mới nhất vừa được thêm
    product.Id = id;
    return product;
}
- Câu hỏi em thấy tương tự câu trên: Trong 1 hàm, gọi 2 lần hàm GetNewProducts để lấy danh sách sản phẩm mới nhất, 2 kết quả này có khác nhau không. Nếu giống nhau thì server thực hiện theo cơ chế nào
Mục đích của việc gọi func GetLastIndexInserted() để làm gì? Trong khi kết quả trả về của func Insert() đã có thông tin ID của product mà bạn vừa insert rồi. Nếu mục đích là lấy ID của product thì GetLastIndexInserted() theo mình là không cần thiết.
Chưa code C# bao giờ nên nếu có hiểu sai thì ae nhẹ tay nhé.
 
DB nó xử lý đồng thời luôn đấy các thím, chứ ko có queue quéo gì đâu :LOL:
Ví dụ bảng Product có data như sau:

ProductId | Price
1 | 100

Giả sử có 1 lệnh select
select * from Product where ProductId = 1

Và 1 lệnh update
update Product set Price = 200 where ProductId = 1

Trong trường hợp 2 lệnh cùng 1 thời điểm, không lệch một chút nào thì kết quả trả ra là gì?
Fen tìm hiểu thêm về isolation level trong transaction đi sẽ hiểu được câu trả lời dưới đây.
- cùng 1 thời điểm như fen nói thì thg select thấy price là 100

Còn về nếu chệch nhau 1 chút thì sẽ có 2 kiểu như sau:
  • nếu thằng select mở transaction với isolation level là REPEATABLE READ VÀ NÓ ĐÃ ĐỌC CÁI RECORD NÀY TRƯỚC ĐẤY thì cho dù select sau thằng update VÀ THG UPDATE ĐÃ COMMIT RỒI thì thg select cũng chỉ thấy price là 100 giống với lúc ban đầu nó thấy.
  • nếu thằng select mở transaction với isolation level là READ UNCOMMITTED thì select nó sẽ thấy dữ liệu mới nhất mặc cho thg update có commit hay chưa, tức là thấy 200 đấy.

Note: lâu rồi ko đụng vào DB nên có thể sai sót các bác chỉnh giúp e nhé :D
 
mình thiết kế cột
id là guid = new guid(), 1 cột là id_no là int, lúc insert bằng last-id++
rồi gói trong transaction
có thể insert 1 list mà ko cần quan tâm nếu trước kia để cột id là int identity
 
Em cảm ơn bác ạ, câu 1 dễ hiểu lắm, còn câu 2 em tìm hiểu như thế nàyXem tệp đính kèm 2691460
  • Theo em hiểu: khi gọi 2 lần hàm GetNewProducts thì sẽ viết 2 câu query xuống db, mỗi câu query lại trong 1 transaction khác nhau nếu mình không gói vào 1 transaction => 2 dữ liệu nhận được có thể khác nhau.
  • Tương tự nếu không gói 2 transaction Insert và lấy LAST_INSERT_ID thì khi transaction của câu query _db.Products.Insert(product) thành công, trong quá trình chạy xuống transaction của câu query LAST_INSERT_ID có thể sẽ có nhiều user khác thêm product, và dẫn tới lấy sai Id của product vừa thêm

Không biết em hiểu vầy có đúng không ạ, hay còn cơ chế gì để gói các câu query trong 1 hàm vào 1 transaction to hơn để đảm bảo tính đúng đắn không ạ
Theo em tìm hiểu thêm thì khi lấy dữ liệu EF sẽ có tracking - tương tự như first-level-cache. Nên với 1 phiên bản dbcontext, dù gọi 2 lệnh GetNewProducts thì cũng sẽ chỉ viết 1 câu query xuống database thôi, còn dữ liệu của hàm sau sẽ lấy từ cache. Còn nếu dùng asNoTracking, thì dữ liệu lấy được sẽ là dữ liệu mới nhất.

Các bác confirm giúp em với, nhờ các bác mà các kiến thức của em liên kết lại, học 1 mà hiểu ra bao nhiêu:beauty:
 
Mình ko nghĩ là việc thực thi 2 lệnh kia lại được thực hiện tuần tự. Các bạn cứ nghĩ, cả triệu lệnh chờ nhau thì bao giờ mới xong.

2 lệnh đấy sẽ được thực hiện đồng thời.

Thế câu trả lời cho câu hỏi kết quả trả về là cái gì thì câu trả lời là tùy. Về cơ bản khi mà bạn query thì lệnh chỉ được gửi xuống database thôi. Còn lệnh được thực sự chạy lúc nào thì lại do cơ chế tự động của database và lệnh read chỉ thấy được dữ liệu mới khi lệnh update đã thực sự commit xong. Giống source control ấy, code mới chưa commit xong thì những người khác sẽ ko thấy được.

Túm cái váy lại là, trên lý thuyết, thì giá trị trả về của select phụ thuộc vào việc ở thời điểm đọc lệnh update đã commit xong hay chưa. Nếu xong rồi thì 200, không thì 100. Còn thực tế, thì thông thường là write tốn thời gian hơn nhiều so với read nên khả năng lớn là ở thời điểm read thì write chưa commit xong, vậy kết quả là 100.
Em đang hơi bị conflict, nếu để đồng thời thì id sẽ không tự động tăng được nên em nghĩ phải lock id lại, mà lock lại thì lại không đồng thời được
 
Bạn phải xem cụ thể database của bạn là database gì, hoạt động thế nào. Rồi monitor database, xem xem ở lower level query EF generate ra là cái gì. Mọi thứ phải cụ thể, môi trường ko giống thì kết quả ko giống. Ví dụ như bạn trên nói về isolation level READ Uncommitted chẳng hạn, Postgre SQL ko support nhưng MS SQL thì có, chẳng hạn vậy.
 
Em đang hơi bị conflict, nếu để đồng thời thì id sẽ không tự động tăng được nên em nghĩ phải lock id lại, mà lock lại thì lại không đồng thời được
Đúng vậy bạn, nếu bạn để database generate ID dạng int tự động tăng thì đương nhiên database nó phải lock. Đó là 1 trong nhiều lý do tại sao người ta dùng unique identifier làm key dù type này tốn space hơn hẳn integer, đã vậy còn ko quick view được muốn xem data là phải viết query select
 
ID generation hay dùng sequence, SQL query sequence.next_val luôn lấy được value mới và không bao giờ bị trùng. Cách design database server nó vậy rồi :LOL:.
Ví dụ docs của postgresql
Mã:
Advances the sequence object to its next value and returns that value. This is done atomically: even if multiple sessions execute nextval concurrently, each will safely receive a distinct sequence value

Còn nếu bạn query max(id) của 1 table thì thế nào cũng có lúc bị trùng :LOL:
 
trên github không biết có repo nào implement mấy cái system booking/order này mà high perf/concurrency ko các bác nhỉ, để tham khảo chút.
 

Thống kê chủ đề

Ngày tạo
phuctienn,
Người trả lời cuối
seoitsystem,
Trả lời
49
Lượt xem
11.290
Quay lại
Lên đầu trang