2009-03-20 11 views
5

Tôi đang chạy một công việc khoa học chuyên sâu về mặt tính toán, tạo ra kết quả mỗi lúc rồi. Công việc này về cơ bản là chỉ mô phỏng cùng một chuỗi toàn bộ thời gian, vì vậy nó được phân chia giữa một số máy tính, sử dụng các hệ điều hành khác nhau. Tôi muốn chỉ đạo đầu ra từ tất cả các cá thể này đến cùng một tệp, vì tất cả các máy tính có thể thấy cùng một hệ thống tệp qua NFS/Samba. Dưới đây là các ràng buộc:Khóa tệp độc lập trên nền tảng?

  1. Phải cho phép nối thêm đồng thời an toàn. Phải chặn nếu một số cá thể khác trên máy tính khác hiện đang thêm vào tệp.
  2. Hiệu suất không không phải là số. I/O cho mỗi cá thể chỉ là một vài byte mỗi phút.
  3. Tính đơn giản không được tính. Toàn bộ vấn đề này (bên cạnh sự tò mò thuần khiết) là vì vậy tôi có thể dừng việc ghi từng tệp vào một tệp khác và kết hợp các tệp này theo cách thủ công với nhau.
  4. Không được phụ thuộc vào chi tiết của hệ thống tệp. Phải làm việc với một hệ thống tập tin không xác định trên một NFS hoặc Samba gắn kết.

Ngôn ngữ tôi đang sử dụng là D, trong trường hợp quan trọng. Tôi đã nhìn, không có gì trong lib tiêu chuẩn mà dường như làm điều này. Cả hai câu trả lời D-cụ thể và nói chung, ngôn ngữ-thuyết bất khả tri là hoàn toàn chấp nhận được và đánh giá cao.

Trả lời

7

Trên NFS, bạn gặp phải một số sự cố với lưu vào bộ đệm phía máy khách và dữ liệu cũ. Tôi đã viết một mô-đun khóa độc lập hệ điều hành để làm việc trên NFS trước đây. Ý tưởng đơn giản về việc tạo một tệp tin [datafile] .lock không hoạt động tốt trên NFS. Ý tưởng cơ bản để làm việc xung quanh nó là tạo một tệp khóa [datafile] .lock nếu hiện tại có nghĩa là tệp KHÔNG bị khóa và quá trình muốn lấy lại khóa đổi tên tệp thành một tên khác như [datafile] .lock. [ tên máy chủ]. [pid]. Việc đổi tên là một hoạt động đủ nguyên tử hoạt động tốt trên NFS để đảm bảo tính độc quyền của khóa. Phần còn lại về cơ bản là một loạt các thất bại an toàn, vòng lặp, kiểm tra lỗi và khóa truy xuất trong trường hợp quá trình chết trước khi phát hành khóa và đổi tên tệp khóa trở lại [datafile] .lock

1

Tôi không biết D, nhưng tôi sử dụng một tệp mutex để thực hiện công việc có thể hoạt động. Dưới đây là một số mã giả bạn có thể thấy hữu ích:

do { 
    // Try to create a new file to use as mutex. 
    // If it's already created, it will throw some kind of error. 
    mutex = create_file_for_writing('lock_file'); 
} while (mutex == null); 

// Open your log file and write results 
log_file = open_file_for_reading('the_log_file'); 
write(log_file, data); 
close_file(log_file); 

close_file(mutex); 
// Free mutex and allow other processes to create the same file. 
delete_file(mutex); 

Vì vậy, tất cả các quá trình sẽ cố gắng tạo tệp mutex nhưng chỉ người thắng sẽ có thể tiếp tục. Một khi bạn viết đầu ra của bạn, đóng và xóa các mutex để các quá trình khác có thể làm như vậy.

+0

Bạn phải bỏ lỡ phần mà anh ấy nói anh ấy cần đồng bộ hóa giữa các máy tính khác nhau. –

+0

Và giải pháp này sẽ không hoạt động trên NFS như ông yêu cầu. –

+0

Tại sao lại không làm việc này? Tôi không có nghĩa là viết một tập tin cục bộ trong mỗi máy tính nhưng ở một vị trí duy nhất cho tất cả chúng. – Seb

2

Giải pháp cổ điển là sử dụng khóa tệp hoặc thư mục khóa chính xác hơn. Trên tất cả các HĐH phổ biến tạo ra một thư mục là một hoạt động nguyên tử nên thường xuyên là:

  • cố gắng để tạo ra một thư mục khóa với một tên cố định ở một vị trí cố định
  • nếu Create thất bại, chờ một giây hoặc lâu hơn và thử lại - lặp lại cho đến khi thành công
  • ghi dữ liệu của bạn vào file dữ liệu thực tế
  • xóa các thư mục khóa

này đã được sử dụng bởi các ứng dụng như CVS trong nhiều năm qua nhiều nền tảng. Vấn đề duy nhất xảy ra trong những trường hợp hiếm hoi khi ứng dụng của bạn gặp sự cố khi viết và trước khi xóa khóa.

2

Khóa tập tin với một twist

Giống như câu trả lời khác đã đề cập, phương pháp đơn giản nhất là để tạo ra một tập tin khóa trong cùng thư mục với các datafile.

Vì bạn muốn có thể truy cập cùng một tệp trên nhiều PC, giải pháp tốt nhất tôi có thể nghĩ là chỉ bao gồm số nhận dạng của máy hiện đang ghi vào tệp dữ liệu.

Vì vậy, trình tự cho văn bản cho các tập tin dữ liệu sẽ là:

  1. Kiểm tra nếu có một tập tin khóa hiện

  2. Nếu có một tập tin khóa, xem nếu tôi là một trong những sở hữu nó bằng cách kiểm tra xem nội dung của nó có nhận dạng của tôi hay không.
    Nếu đúng như vậy, chỉ cần ghi vào tệp dữ liệu, sau đó xóa tệp khóa.
    Nếu đó không phải là trường hợp, chỉ cần chờ một giây hoặc một khoảng thời gian ngẫu nhiên nhỏ và thử lại toàn bộ chu kỳ.

  3. Nếu không có tệp khóa, hãy tạo một tệp có mã định danh của tôi và thử lại toàn bộ chu kỳ để tránh tình trạng cuộc đua (kiểm tra lại xem tệp khóa thực sự là của tôi).

Cùng với số nhận dạng, tôi sẽ ghi lại dấu thời gian trong tệp khóa và kiểm tra xem nó có lớn hơn giá trị thời gian chờ nhất định hay không.
Nếu dấu thời gian quá cũ, hãy giả sử rằng tệp khóa cũ và chỉ xóa nó vì nó sẽ là một trong những PC ghi vào tệp dữ liệu có thể đã bị lỗi hoặc kết nối của nó có thể bị mất.

Một giải pháp khác

Nếu bạn đang ở trong kiểm soát các định dạng của tập tin dữ liệu, có thể là để dự trữ một cấu trúc ở phần đầu của tập tin để ghi lại cho dù đó là bị khóa hay không.
Nếu bạn chỉ đặt một byte cho mục đích này, bạn có thể giả định rằng 00 có nghĩa là tệp dữ liệu không bị khóa và các giá trị khác sẽ đại diện cho số nhận dạng của máy hiện đang ghi vào đó.

Các vấn đề với NFS

OK, tôi thêm một vài điều vì Jiri Klouda một cách chính xác chỉ ra rằng NFS uses client-side caching rằng sẽ cho kết quả trong file khóa thực tế là trong tình trạng không xác định.

Một vài cách để giải quyết vấn đề này:

  • gắn kết thư mục với noac hoặc sync tùy chọn NFS. Điều này là dễ dàng nhưng không hoàn toàn đảm bảo tính nhất quán dữ liệu giữa máy khách và máy chủ mặc dù vậy vẫn có thể có vấn đề mặc dù trong trường hợp của bạn nó có thể là OK.

  • Mở tệp khóa hoặc tệp dữ liệu bằng các thuộc tính O_DIRECT, O_SYNC hoặc O_DSYNC. Điều này là nghĩa vụ phải vô hiệu hóa bộ nhớ đệm hoàn toàn.
    Điều này sẽ giảm hiệu suất nhưng sẽ đảm bảo tính nhất quán.

  • Bạn thể có thể sử dụng flock() để khóa các tập tin dữ liệu nhưng việc thực hiện của nó là đốm và bạn sẽ cần phải kiểm tra xem hệ điều hành cụ thể của bạn thực sự sử dụng các dịch vụ khóa NFS. Nó có thể không làm gì cả.
    Nếu tệp dữ liệu bị khóa, khi đó một ứng dụng khách khác mở tệp để ghi sẽ không thành công.
    Ồ vâng, và nó dường như không hoạt động trên cổ phiếu SMB, vì vậy tốt nhất nên quên nó đi.

  • Không sử dụng NFS và chỉ sử dụng Samba thay vào đó: có good article on the subject và lý do NFS có thể không phải là câu trả lời hay nhất cho kịch bản sử dụng của bạn.
    Bạn cũng sẽ tìm thấy trong bài viết này các phương pháp khác nhau để khóa tệp.

  • Giải pháp của Jiri cũng là giải pháp tốt nhất.

Về cơ bản, nếu bạn muốn giữ mọi thứ đơn giản, không sử dụng NFS cho các tệp được cập nhật thường xuyên được chia sẻ giữa nhiều máy.

Something khác nhau

Sử dụng một máy chủ cơ sở dữ liệu nhỏ để lưu dữ liệu của bạn vào và bỏ qua các vấn đề khóa NFS/SMB hoàn toàn hoặc giữ nhiều hệ thống tập tin dữ liệu hiện tại của bạn và chỉ cần viết một tiện ích nhỏ để nối kết quả.
Nó vẫn có thể là giải pháp an toàn và đơn giản nhất cho vấn đề của bạn.

+1

Giải pháp này, trong khi làm việc tốt trên máy tính duy nhất, sẽ chạy vào điều kiện chủng tộc vì bộ nhớ cache phía máy khách NFS. –

+0

Lưu ý rằng NFSv4 khắc phục nhiều sự cố với các phiên bản cũ của giao thức. – janneb

2

Tại sao không chỉ xây dựng một máy chủ đơn giản nằm giữa tệp và các máy tính khác?

Sau đó, nếu bạn muốn thay đổi định dạng dữ liệu, bạn sẽ chỉ phải sửa đổi máy chủ chứ không phải tất cả các máy khách.

Theo ý kiến ​​của tôi, việc xây dựng một máy chủ sẽ dễ dàng hơn nhiều so với việc cố gắng sử dụng hệ thống tệp Mạng.

+0

Hoặc chỉ sử dụng cơ sở dữ liệu và lưu trữ dữ liệu trong cơ sở dữ liệu thích hợp và giải quyết các vấn đề về khóa. –

+0

Tôi không có một cấu hình cơ sở dữ liệu và tôi không muốn cấu hình một cái để giải quyết một vấn đề đơn giản như vậy. – dsimcha