Có phải REST chỉ giới hạn trong kiểm soát tương tranh lạc quan?


9

Bối cảnh

Do tính phi trạng thái của kiểu kiến ​​trúc REST liên quan đến việc mỗi yêu cầu đứng hoàn toàn một mình, máy chủ hàng đầu không bao giờ lưu trữ bất kỳ thông tin nào về máy khách.

Do đó, kiểm soát đồng thời bi quan không phù hợp bởi vì nó sẽ yêu cầu máy chủ lưu trữ máy khách nào có khóa trên tài nguyên. Kiểm soát đồng thời lạc quan sau đó được sử dụng, với sự trợ giúp của Etagtiêu đề. (btw, như tôi đã hỏi ở đó /programming/30080634/concurrency-in-a-rest-api )

Vấn đề

Vấn đề chính với cơ chế kiểm soát đồng thời lạc quan là bạn cho phép mọi lúc, mọi khách hàng, thực hiện bất kỳ hoạt động nào.

Và tôi muốn tránh điều đó mà không phá vỡ nguyên tắc không quốc tịch của REST. Tôi có nghĩa là tất cả các khách hàng không thể thực hiện bất kỳ hoạt động bất cứ lúc nào.

Câu hỏi

Trong tâm trí của tôi, nó có thể với một cơ chế kiểm soát tương tranh bán lạc quan , như thế:

  • Khách hàng có thể yêu cầu mã thông báo
  • Chỉ một mã thông báo có thể được tạo và có thời hạn hiệu lực hạn chế
  • Để thực hiện các hoạt động trên các tài nguyên (như POST hoặc PUT ), khách hàng phải cung cấp mã thông báo này như một phần của phần thân (hoặc tiêu đề?) Của yêu cầu. Khách hàng không có mã thông báo không thể thực hiện các hoạt động này.

Nó rất giống với điều khiển đồng thời lạc quan, ngoại trừ việc chỉ có một khách hàng có thể thực hiện một số thao tác (một hoạt động có mã thông báo) ... ngược lại với "tất cả các khách hàng có thể thực hiện tất cả các hoạt động".

Cơ chế này có tương thích với phong cách kiến ​​trúc REST không? Liệu nó có phá vỡ bất kỳ ràng buộc của nó? Tôi đã suy nghĩ để hỏi về SO, nhưng đây có vẻ là một câu hỏi cấp cao hơn, liên quan đến thiết kế phần mềm.


1
Thật ra nó khá đơn giản: bạn phải mô hình hóa một Transactioncách rõ ràng như một Tài nguyên.
Jörg W Mittag

Nó thay đổi cái gì? Không chắc chắn để hiểu bình luận của bạn. Tôi không thực hiện kiểm soát đồng thời cho giao dịch, mà là nói với khách hàng "ok ngay bây giờ, bạn hoàn toàn chắc chắn rằng không ai sẽ thay đổi tài nguyên" (vì nó có một mã thông báo duy nhất).
AilurusFulgens

1
Sự khác biệt là gì? Một mặt, bạn sử dụng Etag để kiểm tra, người được phép cập nhật phiên bản "hiện tại"; nếu nó đụng độ, bạn phải cập nhật phiên bản của mình và thực hiện cập nhật sau đó. Mặt khác, bạn có cơ chế "khóa" của mình: một cái được cho phép, những cái khác phải chờ. Âm thanh khá giống nhau. Nhược điểm của phương pháp thứ hai: 2 yêu cầu - 1 cho khóa và 1 cho cập nhật. Trong trường hợp tối ưu, bạn chỉ có một bản cập nhật thông qua phương pháp Etag.
Thomas Junk

Chà, nói chung là về kiểm soát đồng thời ... thứ hai "thua cuộc đua" sẽ luôn phải chờ đợi (chỉ vì những lý do khác nhau, tôi đồng ý với điều đó). Khác biệt với Etag? Với Etagbạn không bao giờ chắc chắn rằng các hoạt động của bạn sẽ được hoàn thành, bạn có thể có một tình huống mà bạn sẽ không bao giờ thực hiện bất kỳ hoạt động. Với một khóa, bạn chắc chắn ít nhất để thực hiện hoạt động của bạn. Vì vậy, có một khóa đơn giản chỉ là một trung gian giữa một môi trường nơi "xung đột cao" và "xung đột hiếm" có thể xảy ra.
AilurusFulgens

Câu trả lời:


3

Bạn không bao giờ nên (như chưa bao giờ EVER) khóa bất kỳ tài nguyên nào trong khi chờ tương tác của người dùng.

Tại một số điểm, một số người dùng của bạn sẽ cất cánh trong một ngày cuối tuần dài để lại một số hồ sơ quan trọng bị khóa.

À nhưng bạn sẽ không để điều đó xảy ra vì bạn có sơ đồ giải quyết hết thời gian / bế tắc thông minh; sau đó, tại một thời điểm nào đó, điều này sẽ trở nên sai lầm khủng khiếp và một người dùng nhận được thông báo "tiện ích của bạn đã được yêu cầu" sẽ được hét lên tại bàn trợ giúp để biết lý do tại sao tiện ích của anh ta không được gửi.

Hầu hết mọi người có thể đối phó với thông báo "xin lỗi người dùng khác vừa đặt hàng phần này".


Bạn giải thích nó độc đáo. Mặc dù tôi không hoàn toàn bị thuyết phục bởi câu đầu tiên của bạn: đến một lúc nào đó bạn sẽ đảm bảo rằng không ai khác ngoài bạn có thể thực hiện một đơn đặt hàng. Nhưng tốt, câu cuối cùng của bạn là một bản tóm tắt tốt, trong 99% đó là trường hợp.
AilurusFulgens 8/07/2015

1
Nếu bạn cần khóa một bản ghi cho một người dùng cụ thể thì hãy thực hiện nó ở cấp ứng dụng. Hoặc là một thuộc tính "KhóaBy" đơn giản, hoặc, với một số cơ chế luồng công việc và phiên bản phức tạp hơn.
James Anderson

Bạn có ý nghĩa gì bởi "ở cấp ứng dụng"? Nếu bạn thêm thuộc tính "KhóaBy" trên tài nguyên của mình, thì bạn sẽ lưu trữ thông tin về máy khách trên máy chủ của mình. Hoặc có lẽ tôi đã không hiểu bình luận của bạn. Nếu bạn có thể cung cấp một số chi tiết, nó sẽ là tuyệt vời!
AilurusFulgens 10/07/2015

1
@AilurusFulgens - Bạn thêm một thuộc tính LockBy (và có thể là dấu thời gian của LockOn) vào cơ sở dữ liệu của bạn. Trong mã ứng dụng của bạn, bạn đặt tên người dùng và thời gian bất cứ khi nào khách hàng bắt đầu tương tác cập nhật. Bạn không đặt nó khi khách hàng kết thúc - sau đó bạn cần đưa ra một số quy tắc kinh doanh để giải quyết xung đột và thời gian chờ, v.v.
James Anderson

2

Sử dụng mã thông báo rất phổ biến trong API, các mã thông báo này thường được gửi dưới dạng tiêu đề và có vòng đời rõ ràng. Hãy suy nghĩ ví dụ OAuth.

Bất kể ngôn ngữ lập trình hoặc khung của bạn, API REST đều tương tự nhau.

Tôi có thể nghĩ ra một số tình huống mà bạn muốn hạn chế đồng thời, hai trong số đó là:

  1. Nhiều khách hàng cập nhật cùng một tài nguyên như một hàng cơ sở dữ liệu. Ví dụ: hai yêu cầu đồng thời, một yêu cầu xóa một bản ghi và một yêu cầu khác cố gắng cập nhật cùng một bản ghi. Tùy thuộc vào cơ sở dữ liệu của bạn và cách bạn đã thiết lập nó, bạn có thể khóa các bản ghi hoặc hoạt động không hợp lệ vì dữ liệu sẽ khác nhau hoặc sẽ không tồn tại.

  2. Một siêu người dùng hoặc quản trị viên thực hiện các hành động đặc biệt với API.


Làm gì trong những trường hợp này?

  1. Sử dụng các giao dịch trong cơ sở dữ liệu, singletons, khóa và các cơ chế tương tự để đồng bộ hóa quyền truy cập vào tài nguyên.

  2. Mã thông báo có thể hoạt động, tôi nghĩ sẽ tốt hơn nếu bạn không lưu trữ thông tin về khách hàng, chỉ về chính mã thông báo. Trên một bước, bạn có thể xác thực người dùng và gán mã thông báo. Sau đó, chỉ cần xác thực rằng mã thông báo còn sống và hợp lệ. Sử dụng mã thông báo có thể được giải mã để có thêm thông tin. Bạn có thể lưu trữ nếu đây là mã thông báo đặc biệt và chỉ cho phép bật tại một thời điểm. Bằng cách này, bạn xác thực mã thông báo, không phải người dùng.

Tôi hi vọng cái này giúp được.


Vâng, tôi đã mong đợi một phản hồi về tính tương tự của mã thông báo và cơ chế OAuth. Mặc dù cái cuối cùng được dành riêng để xác thực. Tôi đã không hiểu được kịch bản của bạn 1. Phần khó khăn để giải quyết vấn đề đồng thời trong API REST là giữ cho ràng buộc không trạng thái ... có nghĩa là máy chủ không lưu trữ thông tin về máy khách. Kịch bản 2 của bạn chính xác là những gì tôi đang làm hiện tại! :)
AilurusFulgens 7/07/2015

Tôi đã trả lời câu hỏi của bạn chưa nhỉ?
Pablo Granados

Không xin lỗi. Tôi nêu lên câu trả lời của bạn bởi vì nó cung cấp một cái nhìn tổng quan tốt về vấn đề nhưng thật không may, imo, nó không thực sự giải quyết nó.
AilurusFulgens

0

REST một mình là quá nguyên thủy, thực sự. Bạn có thể bắt đầu với REST, nhưng cuối cùng, ứng dụng phong phú của bạn sẽ cần truy vấn với các phép nối và cập nhật với các giao dịch. Mỗi nhà phát triển cố gắng tự thêm những thứ này sẽ dễ bị lỗi và không nhất quán. May mắn thay, có một tiêu chuẩn mới nổi gọi là OData thực hiện điều đó. Nó xếp chồng lên trên REST và cung cấp (1) ngôn ngữ truy vấn cho phép các phép nối đơn giản sử dụng các thuộc tính điều hướng (mà không phải lộ các khóa ngoại) và, (2) xử lý hàng loạt bao gồm các bộ thay đổi nguyên tử.

Xem tại đây để (1) https://stackoverflow.com/a/3921423/471129 , và,

Xem tại đây và cho (2) https://stackoverflow.com/a/21939972/471129

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.