Tìm kiếm một mô hình khóa phân tán


10

Tôi cần đưa ra một cơ chế khóa đối tượng đệ quy tùy chỉnh \ mẫu cho một hệ thống phân tán trong C #. Về cơ bản, tôi có một hệ thống nhiều nút. Mỗi nút có quyền ghi độc quyền đối với các phần trạng thái n- số. Trạng thái tương tự cũng có sẵn ở dạng chỉ đọc trên ít nhất một nút khác. Một số ghi / cập nhật phải là nguyên tử trên tất cả các nút, trong khi các cập nhật khác cuối cùng sẽ trở thành các quy trình sao chép nền, hàng đợi, v.v ... nhất quán

Đối với các bản cập nhật nguyên tử, tôi đang tìm kiếm một mẫu hoặc mẫu cho phép tôi đánh dấu một đối tượng là bị khóa để ghi mà sau đó tôi có thể phân phối, cam kết, khôi phục, v.v ... Vì hệ thống có mức độ đồng thời cao, tôi Tôi cho rằng tôi sẽ cần có khả năng xếp chồng các khóa sẽ hết thời gian chờ hoặc không được kiểm soát sau khi khóa được giải phóng.

Các phần giao dịch hoặc nhắn tin không phải là trọng tâm của câu hỏi này, nhưng tôi đã cung cấp chúng cho một số bối cảnh bổ sung. Như đã nói, hãy thoải mái nói rõ những thông điệp bạn nghĩ sẽ cần nếu bạn muốn.

Đây là một mẫu mơ hồ về những gì tôi đã hình dung mặc dù tôi cởi mở với bất kỳ ý tưởng mới nào ngoài việc thực hiện toàn bộ sản phẩm mới

thing.AquireLock(LockLevel.Write);

//Do work

thing.ReleaseLock();

Tôi đã nghĩ đến việc sử dụng các phương thức mở rộng, có thể trông giống như thế này

public static void AquireLock(this IThing instance, TupleLockLevel lockLevel)
{ 
    //TODO: Add aquisition wait, retry, recursion count, timeout support, etc...  
    //TODO: Disallow read lock requests if the 'thing' is already write locked
    //TODO: Throw exception when aquisition fails
    instance.Lock = lockLevel;
}

public static void ReleaseLock(this IThing instance)
{
    instance.Lock = TupleLockLevel.None;
}

Để làm rõ một vài chi tiết ...

  • Tất cả các thông tin liên lạc là TCP / IP sử dụng giao thức yêu cầu / phản hồi nhị phân
  • Không có công nghệ trung gian như hàng đợi hoặc cơ sở dữ liệu
  • Không có nút chủ trung tâm. Trong trường hợp này, sự sắp xếp khóa được xác định bởi người khởi tạo khóa và đối tác sẽ tôn trọng yêu cầu với một số hình thức hết thời gian để điều chỉnh hành vi của nó

Bất cứ ai có bất kỳ đề nghị?


Khóa nói chung là một tính năng tiêu chuẩn trong hầu hết các hệ thống. Tôi đoán nó cũng có cho C #. (Kết quả tìm kiếm của google: albahari.com/threading/part2.aspx ) Bạn đang cố gắng đạt được điều gì đó ngoài Mutex hoặc semaphores cơ bản?
Dipan Mehta

2
@DipanMehta Xin lỗi, tôi nên giải quyết vấn đề này rõ ràng hơn. Các nút tôi đã đề cập là các máy trên một mạng. Sự hiểu biết của tôi về Mutex và Semaphores là chúng là các khóa toàn máy ( ví dụ như xử lý chéo ) và không phải là các khóa có thể mở rộng giữa các máy trên mạng.
JoeGeeky

@JoeGeeky Câu hỏi của bạn thuộc chủ đề ở đây và có thể quá lý thuyết cho Stack Overflow . Nếu bạn muốn hỏi lại ở đó, bạn có thể, nhưng bạn sẽ muốn một cụm từ tập trung nhiều mã hơn.
Adam Lear

Câu trả lời:


4

Cảm ơn đã làm rõ.

Trong trường hợp đó, những gì tôi khuyên bạn nên sử dụng mô hình xuất bản / đăng ký. Giao thức khóa phân tán Chubby của Google (triển khai Paxos )

Tôi chưa bao giờ sử dụng Paxos (hoặc Chubby), nhưng dường như có một triển khai nguồn mở ở đây .

Nếu điều đó không hiệu quả, bạn có thể triển khai phiên bản Paxos của riêng mình bằng cách sử dụng, ví dụ, một trong những nghi phạm thông thường về thư viện nhắn tin: thư viện hàng đợi tin nhắn bằng không , RabbitMQ hoặc ActiveMQ .


Trả lời trước:

Hầu hết các đề xuất về SO ( [A] , [B] ) đều sử dụng hàng đợi tin nhắn để đạt được khóa máy chéo.

AcquireLockPhương pháp của bạn sẽ đẩy một cái gì đó xác định đối tượng khóa vào hàng đợi, kiểm tra các trường hợp khóa trước đó trước khi thành công. ReleaseLockPhương pháp của bạn sẽ loại bỏ đối tượng khóa khỏi hàng đợi.

Người dùng SO atlantis gợi ý, trong bài đăng này , bài đăng của Jeff Key cho một số chi tiết.


Cảm ơn, nhưng những giải pháp này sẽ không phù hợp vì tôi không có chủ trung tâm, cơ sở dữ liệu hoặc hàng đợi. Tôi đã cập nhật câu hỏi với một số chi tiết bổ sung để làm rõ một số chi tiết này.
JoeGeeky

Tôi sẽ không thể sử dụng trực tiếp các sản phẩm này vì đã có giao thức được xác định rõ ràng mà tôi phải sử dụng cho tất cả các giao tiếp giữa các nút, nhưng Chubby và Paxos có thể có các mẫu được xác định rõ mà tôi có thể học hỏi. Tôi sẽ xem qua một chút.
JoeGeeky

@JoeGeeky Có, liên kết Paxos có sơ đồ trình tự có thể cho phép bạn thực hiện bằng liên kết truyền thông ưa thích của mình.
Peter K.

Mặc dù không phải là một câu trả lời trực tiếp, nhưng việc đọc qua tất cả những thứ Chubby và Paxos đã giúp tôi xác định giải pháp của riêng mình. Tôi đã không sử dụng những công cụ đó, nhưng đã có thể xác định một mô hình hợp lý dựa trên một số khái niệm của họ. Cảm ơn.
JoeGeeky

@JoeGeeky: Thật tốt khi nghe nó là một số trợ giúp, ít nhất. Cảm ơn đã đánh dấu.
Peter K.

4

Có vẻ như tôi có một vài công nghệ hỗn hợp ở đây:

  • thông tin liên lạc (mà về cơ bản bạn dựa vào là đáng tin cậy 100% ... có thể gây tử vong)

  • khóa / loại trừ lẫn nhau

  • hết giờ (vì mục đích gì)?

Một lời cảnh báo: Hết giờ trong các hệ thống phân tán có thể đầy nguy hiểm và khó khăn. Nếu được sử dụng, chúng phải được thiết lập và sử dụng rất cẩn thận vì việc sử dụng thời gian chờ bừa bãi không khắc phục được vấn đề, nó chỉ làm chậm lại thảm họa. (Nếu bạn muốn xem cách timeout nên được sử dụng, đọc và hiểu các tài liệu HDLC giao thức truyền thông. Đây là một ví dụ điển hình của việc sử dụng hợp lý và thông minh, kết hợp với một hệ thống bit mã hóa thông minh cho phép phát hiện những thứ như dòng IDLE) .

Trong một thời gian, tôi đã làm việc trong các hệ thống phân tán đa bộ xử lý được kết nối bằng các liên kết giao tiếp (không phải TCP, một cái gì đó khác). Một trong những điều tôi học được là như một sự khái quát hóa thô sơ, có một số nơi đa lập trình nguy hiểm sẽ xảy ra:

  • sự phụ thuộc vào hàng đợi thường kết thúc trong nước mắt (nếu hàng đợi đầy, bạn gặp rắc rối. KHÔNG GIỚI HẠN bạn có thể tính kích thước hàng đợi sẽ không bao giờ lấp đầy, trong trường hợp đó bạn có thể sử dụng giải pháp không xếp hàng)

  • phụ thuộc vào khóa là đau đớn, hãy thử và suy nghĩ nếu có một cách khác (nếu bạn phải sử dụng khóa, hãy xem tài liệu, khóa phân tán đa bộ xử lý đã là chủ đề của nhiều bài báo acedemia trong 2-3 thập kỷ qua)

Tôi phải tiến hành khóa, sau đó:

Tôi sẽ ĐÁNH GIÁ rằng bạn sẽ chỉ sử dụng thời gian chờ như một phương tiện phục hồi của biện pháp cuối cùng - tức là để phát hiện lỗi của hệ thống liên lạc cơ bản. Tôi sẽ tiếp tục giả định rằng hệ thống truyền thông TCP / IP của bạn có băng thông cao và có thể được coi là độ trễ thấp (lý tưởng là 0, nhưng điều này không bao giờ xảy ra).

Điều tôi muốn đề xuất là mỗi nút có một danh sách kết nối của các nút khác mà nó có thể kết nối. (Các nút sẽ không quan tâm đến việc kết nối đến từ đâu.) Dân số của các bảng mà nút mà một nút có thể kết nối được để lại như một thứ riêng biệt để sắp xếp, bạn không nói nếu đó sẽ được đặt tĩnh hay không. Cũng bị bỏ qua một cách thuận tiện là những thứ như phân bổ số cổng IP nơi các kết nối sẽ đến một nút - có thể có lý do chính đáng để chấp nhận yêu cầu chỉ trên một cổng hoặc trên nhiều cổng. Điều này cần phải được xem xét cẩn thận. Các yếu tố sẽ bao gồm xếp hàng ngầm, đặt hàng, sử dụng tài nguyên, loại hệ điều hành và khả năng.

Khi các nút biết họ kết nối với ai, họ có thể gửi cho nút đó một yêu cầu khóa và phải nhận lại từ phản hồi khóa từ nút từ xa đó. Bạn có thể đóng gói hai thao tác đó vào một trình bao bọc để làm cho nó trông nguyên tử. Hiệu quả của việc này là các nút muốn có được khóa sẽ thực hiện cuộc gọi giống như:

if (get_lock(remote_node) == timeout) then
  {
    take some failure action - the comms network is down
  }

/* Lock is now acquired - do work here */

if (release_lock(remote_node) == timeout) then
  {
    take some failure action - the comms network is down
  }

các lệnh gọi get_lock và release_lock phải giống như (về nguyên tắc):

send_to_remote_node(lock_request)
get_from_remote_node_or_timeout(lock_reply, time)
if (result was timeout) then
  return timeout
else
  return ok

Bạn sẽ phải hết sức cẩn thận với một hệ thống khóa phân tán mà các đơn vị công việc đã thực hiện trong khi khóa được giữ rất nhỏ và nhanh vì bạn sẽ có nhiều nút từ xa có khả năng bị giữ chờ để lấy khóa. Đây thực sự là một hệ thống đa bộ xử lý / truyền thông dừng và chờ mạnh mẽ nhưng không có hiệu suất cao nhất có thể.

Một gợi ý là thực hiện một cách tiếp cận hoàn toàn khác. Bạn có thể sử dụng một cuộc gọi thủ tục từ xa trong đó mỗi cuộc gọi RPC mang một gói thông tin mà người nhận có thể xử lý và loại bỏ các nhu cầu về khóa không?


Khi đọc lại câu hỏi, có vẻ như bạn không thực sự muốn quan tâm đến khía cạnh giao tiếp của mọi thứ, bạn chỉ muốn giải quyết vấn đề khóa của mình.

Do đó, câu trả lời của tôi có vẻ hơi lạc đề, tuy nhiên, tôi tin rằng bạn không thể giải quyết vấn đề khóa của mình mà không nhận được các phần bên dưới nó. Tương tự: Xây dựng một ngôi nhà trên nền móng xấu khiến nó sụp đổ ... Cuối cùng.


1
Các ngữ nghĩa hết thời gian chủ yếu ở đó để xử lý các nút biến mất khỏi mạng hoặc để xử lý các tồn đọng lớn trong ngăn xếp khóa ... Điều này sẽ hạn chế thời gian bị chặn trong khi chờ để lấy khóa và sẽ cung cấp cho những người yêu cầu khóa cơ hội để khởi động các quá trình khác ở giữa những sự chậm trễ, thất bại bất ngờ, v.v ... Ngoài ra, điều này sẽ ngăn chặn một cái gì đó bị khóa mãi mãi trong trường hợp một cái gì đó không thành công. Tôi đánh giá cao sự lo lắng của bạn mặc dù tại thời điểm này, tôi không thấy bất kỳ giải pháp thay thế nào được đưa ra rằng cuối cùng sẽ có điều gì đó thất bại
JoeGeeky

Để nói với một số ý kiến ​​khác của bạn, tôi không sử dụng hàng đợi mỗi lần (theo nghĩa giao tiếp không đồng bộ), mặc dù tôi hy vọng rằng các khóa được xếp chồng lên nhau và phát hành dựa trên mô hình FIFO. Tôi đã không hoàn toàn hòa giải làm thế nào điều này sẽ hoạt động theo mô hình yêu cầu / phản hồi được yêu cầu khác với điều này sẽ cần phải chặn theo một cách nào đó và là một phần của một cái bắt tay lớn hơn. Hiện tại, tôi đang làm việc thông qua cơ chế khóa xếp chồng trong một nút và sau đó nó sẽ hoạt động như thế nào thông qua kịch bản phân tán. Tôi sẽ đọc thêm một chút như bạn đề nghị. Cảm ơn
JoeGeeky

@JoeGeeky - một FIFO là một hàng đợi. Cẩn thận với hàng đợi. Nghĩ rằng bên đó rất cẩn thận. Nghe có vẻ như bạn sẽ không nhận được một cái gì đó "ngoài giá" mà sẽ phải suy nghĩ kỹ về vấn đề và giải pháp của bạn.
quick_now

Tôi hiểu ... Tôi đã cố gắng làm rõ sự khác biệt btwn một hàng đợi FIFO được sử dụng trong các quy trình không đồng bộ ( ví dụ: một quy trình xử lý và sau đó là một công cụ khác ). Trong trường hợp này, mọi thứ sẽ cần phải được quản lý theo thứ tự, nhưng quá trình vào hàng đợi sẽ không rời đi cho đến khi (a) họ nhận được khóa, (b) bị từ chối khóa, hoặc (c) họ hết thời gian và rời khỏi dòng. Giống như đứng xếp hàng tại ATM. Điều này hoạt động giống như một mô hình FIFO trong trường hợp thành công, nhưng các quy trình có thể rời khỏi trật tự trước khi đến phía trước của dòng. Còn đối với giá ngoài? Không, nhưng đây không phải là vấn đề mới
JoeGeeky

0

Câu hỏi của bạn có thể được thực hiện dễ dàng bằng cách sử dụng bộ đệm phân tán như NCache. Những gì bạn yêu cầu là một cơ chế Khóa bi quan trong đó bạn có thể có được một khóa bằng cách sử dụng một đối tượng. Sau đó thực hiện các nhiệm vụ và hoạt động của bạn và giải phóng khóa cho các ứng dụng khác để sử dụng sau này.

Hãy xem mã sau đây;

Tại đây, bạn sẽ có được một khóa trên một Khóa cụ thể và sau đó thực hiện các tác vụ (từ một hoặc nhiều thao tác) rồi cuối cùng giải phóng khóa khi bạn hoàn tất.

// Instance of the object used to lock and unlock cache items in NCache
LockHandle lockHandle = new LockHandle();

// Specify time span of 10 sec for which the item remains locked
// NCache will auto release the lock after 10 seconds.
TimeSpan lockSpan = new TimeSpan(0, 0, 10); 

try
{
    // If item fetch is successful, lockHandle object will be populated
    // The lockHandle object will be used to unlock the cache item
    // acquireLock should be true if you want to acquire to the lock.
    // If item does not exists, account will be null
    BankAccount account = cache.Get(key, lockSpan, 
    ref lockHandle, acquireLock) as BankAccount;
    // Lock acquired otherwise it will throw LockingException exception

    if(account != null && account.IsActive)
    {
        // Withdraw money or Deposit
        account.Balance += withdrawAmount;
        // account.Balance -= depositAmount;

        // Insert the data in the cache and release the lock simultaneously 
        // LockHandle initially used to lock the item must be provided
        // releaseLock should be true to release the lock, otherwise false
        cache.Insert("Key", account, lockHandle, releaseLock); 
        //For your case you should use cache.Unlock("Key", lockHandle);
    }
    else
    {
        // Either does not exist or unable to cast
        // Explicitly release the lock in case of errors
        cache.Unlock("Key", lockHandle);
    } 
}
catch(LockingException lockException)
{
    // Lock couldn't be acquired
    // Wait and try again
}

Lấy từ liên kết: http://bloss.alachisoft.com/ncache/distribution-locking/

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.