Tạm thời lưu trữ và ghi bộ đệm một thư mục (để tăng tốc quá trình xây dựng trên chia sẻ NFS)


7

Tổng quat

Câu hỏi này được cấu trúc như sau:
Trước tiên tôi đưa ra một số nền tảng về lý do tại sao tôi quan tâm đến chủ đề này và cách nó sẽ giải quyết vấn đề mà tôi đang giải quyết. Sau đó, tôi hỏi câu hỏi độc lập thực tế liên quan đến bộ nhớ đệm hệ thống tệp, vì vậy nếu bạn không quan tâm đến động lực (một số thiết lập xây dựng dự án C ++), chỉ cần bỏ qua phần đầu tiên.

Vấn đề ban đầu: Liên kết các thư viện dùng chung

Tôi đang tìm cách để tăng tốc thời gian xây dựng dự án của chúng tôi. Thiết lập như sau: Một thư mục (hãy gọi nó workarea) được đặt trong một chia sẻ NFS. Nó ban đầu chỉ chứa mã nguồn và tệp thực hiện. Sau đó, quá trình xây dựng trước tiên tạo các thư viện tĩnh trong workarea/libvà sau đó tạo các thư viện dùng chung workarea/dll, sử dụng các thư viện tĩnh trong workarea/lib. Trong quá trình tạo các thư viện dùng chung, chúng không chỉ được viết mà còn được đọc lại bằng cách sử dụng, vdnmđể xác minh tại thời điểm liên kết mà không có biểu tượng nào bị thiếu. Sử dụng song song nhiều công việc, (ví dụ: make -j 20 hoặc make -j 40), thời gian xây dựng nhanh chóng bị chi phối bởi thời gian liên kết. Trong trường hợp này, hiệu suất liên kết bị giới hạn bởi hiệu suất hệ thống tệp. Ví dụ: liên kết với 20 công việc song song mất khoảng 35 giây trong chia sẻ NFS, nhưng chỉ 5 giây trong ổ RAM. Lưu ý rằng việc sử dụng rsync để sao chép dlllại vào chia sẻ NFS mất thêm 6 giây, do đó, làm việc trong ổ RAM và đồng bộ hóa với NFS sau đó nhanh hơn nhiều so với làm việc trực tiếp trong chia sẻ NFS. Tôi đang tìm cách để đạt được hiệu suất nhanh mà không cần sao chép / liên kết rõ ràng các tệp giữa chia sẻ NFS và ổ RAM.
Lưu ý rằng chia sẻ NFS của chúng tôi đã sử dụng bộ đệm, nhưng bộ đệm này chỉ có thể lưu trữ truy cập đọc.
AFAIK, NFS yêu cầu mọi máy khách NFS không được xác nhận ghi cho đến khi máy chủ NFS xác nhận hoàn thành ghi, do đó máy khách không thể sử dụng bộ đệm ghi cục bộ và thông lượng ghi bị giới hạn bởi tốc độ mạng. Điều này giới hạn hiệu quả thông lượng ghi kết hợp đến khoảng 80MB / s trong thiết lập của chúng tôi.
Hiệu suất đọc, tuy nhiên, tốt hơn nhiều, vì bộ đệm đọc được sử dụng. Nếu tôi thực hiện liên kết (tạo nội dung dll) với workarea/libtrong NFS và workarea/dlllà liên kết tượng trưng cho ổ RAM, hiệu suất vẫn tốt - khoảng 5 giây. Lưu ý rằng quá trình xây dựng là bắt buộc để kết thúc với việc workarea/*cư trú trong chia sẻ NFS: libcần phải ở trong phần chia sẻ (hoặc bất kỳ gắn kết liên tục nào) để cho phép các bản dựng gia tăng nhanh vàdllcần phải có trong NFS để được truy cập bởi các máy tính bắt đầu công việc bằng cách sử dụng các dll này.
Do đó, tôi muốn áp dụng một giải pháp cho vấn đề bên dưới workarea/dllvà cũng có thể workarea/lib(cách sau để cải thiện thời gian biên dịch). Yêu cầu về thời gian thiết lập nhanh dưới đây là do sự cần thiết phải thực hiện các bản dựng gia tăng nhanh, chỉ sao chép dữ liệu nếu được yêu cầu.

Cập nhật

Tôi có lẽ nên có một chút cụ thể hơn về thiết lập xây dựng. Dưới đây là một số chi tiết: Các đơn vị biên dịch được biên dịch thành các tệp .o trong một thư mục tạm thời (in / tmp). Chúng sau đó được hợp nhất vào các thư viện tĩnh trong libviệc sử dụng ar. Quá trình xây dựng hoàn chỉnh là gia tăng:

  • Các đơn vị biên dịch chỉ được biên dịch lại nếu chính đơn vị biên dịch (tệp .C) hoặc một tiêu đề đi kèm đã thay đổi (sử dụng các tệp phụ thuộc do trình biên dịch tạo vào make).
  • Thư viện tĩnh chỉ được cập nhật nếu một trong các đơn vị biên dịch của nó đã được biên dịch lại.
  • Thư viện dùng chung chỉ được xem lại nếu một trong những thư viện tĩnh của nó đã thay đổi. Biểu tượng của các thư viện dùng chung chỉ được kiểm tra lại nếu các biểu tượng được cung cấp bởi các thư viện dùng chung, nó phụ thuộc vào sự thay đổi nếu chính thư viện chia sẻ đã được cập nhật.

Tuy nhiên, việc xây dựng lại hoàn chỉnh hoặc gần hoàn thành là khá thường xuyên, vì nhiều trình biên dịch ( gcc, clang), phiên bản trình biên dịch, chế độ biên dịch ( release, debug), tiêu chuẩn C ++ ( C++97, C++11) và sửa đổi bổ sung (ví dụ libubsan) có thể được sử dụng. Tất cả các kết hợp sử dụng hiệu quả các thư mục libdllthư mục khác nhau , do đó, người ta có thể chuyển đổi giữa các thiết lập và xây dựng tăng dần dựa trên bản dựng cuối cùng cho chính thiết lập đó. Ngoài ra, đối với các bản dựng gia tăng, thường chỉ cần biên dịch lại một vài tệp, mất rất ít thời gian, nhưng kích hoạt lại các thư viện chia sẻ (có thể lớn), mất nhiều thời gian hơn.

Cập nhật 2

Trong thời gian chờ đợi, tôi đã tìm hiểu về noctotùy chọn gắn kết NFS, có vẻ như có thể giải quyết vấn đề của tôi về cơ bản tất cả các triển khai NFS ngoại trừ Linux, vì Linux luôn xóa bộ đệm close(), ngay cả với nocto. Chúng tôi đã thử một số thứ khác: Ví dụ: chúng tôi có thể sử dụng một máy chủ NFS cục bộ khác asyncđược kích hoạt làm bộ đệm ghi và xuất khung gắn NFS chính, nhưng thật không may, máy chủ NFS không có bộ đệm ghi trong trường hợp này. Có vẻ như điều đó asyncchỉ có nghĩa là máy chủ không buộc hệ thống tệp bên dưới của nó chuyển sang lưu trữ ổn định và bộ đệm ghi được sử dụng ngầm trong trường hợp hệ thống tệp bên dưới sử dụng bộ đệm ghi (vì rõ ràng đó là trường hợp của hệ thống tệp trên ổ đĩa vật lý).
Chúng tôi thậm chí đã nghĩ về tùy chọn sử dụng máy ảo không phải Linux trên cùng một hộp gắn kết chia sẻ NFS chính bằng cách sử dụng nocto, cung cấp bộ đệm ghi và cung cấp bộ đệm này thông qua một máy chủ NFS khác, nhưng chưa thử nghiệm và muốn tránh một giải pháp như vậy.
Chúng tôi cũng tìm thấy một số FUSEtrình bao bọc hệ thống tập tin dựa trên bộ đệm, nhưng không có bộ đệm ghi nào được triển khai.

Bộ nhớ đệm và đệm một thư mục

Hãy xem xét một số thư mục, hãy gọi nó orig, nằm trong một hệ thống tệp chậm, ví dụ như chia sẻ NFS. Trong một khoảng thời gian ngắn (ví dụ giây hoặc phút, nhưng dù sao thì điều này cũng không quan trọng), tôi muốn tạo một chế độ xem được lưu trữ và lưu vào bộ đệm đầy đủ của origviệc sử dụng một thư mục cache, nằm trong một hệ thống tệp nhanh, ví dụ như ổ cứng cục bộ hoặc thậm chí là một Ổ đĩa RAM. Bộ nhớ cache phải được truy cập thông qua ví dụ một mount cached_viewvà không yêu cầu quyền root. Tôi giả sử rằng trong suốt vòng đời của bộ đệm, không có quyền truy cập đọc hoặc ghi trực tiếp orig(tất nhiên bên cạnh bộ đệm). Bằng cách lưu trữ đầy đủ và được lưu vào bộ đệm, tôi có nghĩa như sau:

  1. Các truy vấn đọc được trả lời bằng một lần chuyển tiếp truy vấn đến hệ thống tệp orig, lưu vào kết quả đó và sử dụng nó từ đó trở đi và
  2. Các truy vấn ghi được ghi vào cachevà xác nhận khi hoàn thành trực tiếp, tức là bộ đệm cũng là bộ đệm ghi. Điều này thậm chí sẽ xảy ra khi close()được gọi trên tập tin bằng văn bản. Sau đó, trong nền, ghi được chuyển tiếp (có thể sử dụng hàng đợi) đến orig. Đọc các truy vấn đến dữ liệu bằng văn bản được trả lời bằng cách sử dụng dữ liệu trong cache, tất nhiên.

Hơn nữa, tôi cần:

  1. Bộ đệm cung cấp một chức năng để tắt bộ đệm, giúp xóa tất cả ghi vào orig. Thời gian xả chỉ nên phụ thuộc vào kích thước của tệp được viết chứ không phải tất cả các tệp. Sau đó, người ta có thể truy cập một cách an toàn orig.
  2. Thời gian thiết lập nhanh, ví dụ: khởi tạo bộ đệm chỉ có thể phụ thuộc vào số lượng tệp trong orig, chứ không phụ thuộc vào kích thước tệp orig, vì vậy sao chép origvào cachemột lần không phải là một tùy chọn.

Cuối cùng, tôi cũng sẽ ổn với một giải pháp không sử dụng hệ thống tệp khác làm bộ đệm, mà chỉ lưu trữ trong bộ nhớ chính (các máy chủ có nhiều RAM). Lưu ý rằng việc sử dụng bộ đệm dựng sẵn của ví dụ NFS không phải là một tùy chọn, vì AFAIK NFS không cho phép ghi bộ đệm (phần đầu tiên của cf).

Trong thiết lập của mình, tôi có thể mô phỏng một hành vi tồi tệ hơn một chút bằng cách liên kết nội dung của origđến cache, sau đó làm việc với cache(vì tất cả các thao tác ghi thực sự thay thế các tệp bằng các tệp mới, trong trường hợp đó, các liên kết tượng trưng được thay thế bằng các phiên bản cập nhật) và kết nối sửa đổi tập tin để origsau đó. Điều này không đáp ứng chính xác các yêu cầu ở trên, ví dụ: việc đọc chỉ được thực hiện một lần và các tệp được thay thế bằng liên kết tượng trưng, ​​điều này tất nhiên sẽ tạo ra sự khác biệt cho một số ứng dụng.
Tôi cho rằng đây không phải là cách chính xác để giải quyết vấn đề này (ngay cả trong cài đặt đơn giản hơn của tôi) và có thể ai đó biết về giải pháp sạch hơn (và nhanh hơn!).


ccache không trả lời câu hỏi của bạn, nhưng tôi nghĩ nó giải quyết vấn đề của bạn.
Gilles 'SO- ngừng trở nên xấu xa'

1
ccache chỉ ảnh hưởng đến việc biên dịch. Nút thắt của tôi là thông lượng hệ thống tập tin trong khi liên kết, trong đó ccache không giúp đỡ.
jasilvan

1
Ồ, tôi hiểu rồi. Những gì bạn thực sự muốn không chỉ là bộ đệm mà còn ghi đệm - báo cáo rằng một lần ghi đã thành công trước khi nó được truyền đến máy chủ NFS. Bộ nhớ đệm ghi chỉ giữ một bản sao cục bộ của dữ liệu được ghi nhưng không trả về từ yêu cầu ghi cho đến khi máy chủ nhận được dữ liệu và đó là nút cổ chai bạn muốn phá vỡ.
Gilles 'SO- ngừng trở nên xấu xa'

À được rồi. Tôi không quá quen thuộc với thuật ngữ phổ biến trong lĩnh vực này, cảm ơn bạn đã chỉ ra điều này. Tôi sẽ cập nhật câu hỏi cho phù hợp.
jasilvan

Tôi cũng muốn nghe câu trả lời. lớp phủ âm thanh quá thủ công, có lẽ cachefilesdcó thể làm tốt hơn?
Anton

Câu trả lời:


2

Wow, ngạc nhiên không ai trả lời "lớp phủ" chưa.

Thật ra tôi có hai gợi ý. Đầu tiên là sử dụng các lớp phủ, về cơ bản chính xác là những gì bạn đang mô tả, với một cảnh báo. Lớp phủ (tiêu chuẩn từ Linux 3.18 trở lên) cho phép bạn đọc từ hai cây thư mục gần như được hợp nhất trong khi chỉ viết cho một trong số chúng. Những gì bạn sẽ làm là lấy bộ lưu trữ nhanh (như tmpfs) và phủ nó lên khối lượng NFS, sau đó thực hiện việc biên dịch của bạn trong sự hợp nhất lớp phủ của cả hai. Khi bạn đã hoàn tất, đã không có ghi vào bất kỳ tệp nào trên NFS và hệ thống tệp khác đang giữ tất cả các thay đổi của bạn. Nếu bạn muốn giữ các thay đổi, bạn chỉ có thể đưa chúng trở lại NFS. Bạn thậm chí có thể loại trừ các tệp mà bạn không quan tâm hoặc chỉ chọn thủ công một vài tệp trong kết quả.

Bạn có thể thấy một ví dụ tương đối đơn giản về lớp phủ trong một dự án nhỏ của tôi: https://github.com/nrdvana/squash-portage/blob/master/squash-portage.sh Tập lệnh đó cũng cho biết cách sử dụng UnionFS trong trường hợp bạn Đang sử dụng kernel cũ hơn không có lớp phủ.

Trong trường hợp của tôi, lệnh rsync được Gentoo sử dụng để cập nhật thư viện phần mềm của nó mất một thời gian cực kỳ dài vì nó có hàng triệu đĩa ghi nhỏ. Tôi sử dụng lớp phủ để viết tất cả các thay đổi vào tmpfs, và sau đó tôi mksquashfs để xây dựng một hình ảnh nén của cây. Sau đó, tôi ném các tmpfs đi và gắn hình ảnh nén vào vị trí của nó.

Đề nghị thứ hai của tôi là một bản dựng "ngoài cây". Ý tưởng là bạn có mã nguồn và tệp tạo tệp trong một cây và bạn bảo tự động tạo tất cả các tệp trung gian của nó trong một cây riêng biệt phản chiếu đầu tiên.

Nếu bạn may mắn, công cụ xây dựng của bạn (tự động hoặc không có gì) có thể đã làm điều này. Nếu bạn không may mắn, bạn có thể phải trải qua một số cơn đau đầu mày mò với các bộ trang điểm của bạn.


Tôi đang biên dịch Julia-lang trong một thư mục riêng và trong khi nó giúp, 25 phút so với 8 phút cho bản sao cục bộ là sự khác biệt quá lớn. overlayfs là tốt nhưng rsync thủ công không phải là những gì tôi thực sự muốn ở đây, tôi cần cả đọc và ghi bộ đệm. Bất kỳ ý tưởng khác để chia sẻ?
Anton

@Anton Nếu bạn đang sử dụng đề xuất lớp phủ của tôi, nó không thể nhanh hơn được nữa. Lớp phủ dừng tất cả ghi vào NFS, do đó bạn bị giới hạn bởi tốc độ đọc của NFS. Bạn có thể làm việc để điều chỉnh các lần đọc NFS, nhưng nếu bạn muốn một số cách để lưu trữ cục bộ các tệp NFS mà không cần kiểm tra máy chủ mỗi khi chúng được truy cập, thì bạn hoàn toàn không sử dụng nó như một "hệ thống tệp mạng" và nên xem xét lại mục tiêu của bạn. tức là nếu ai đó thay đổi một trong các tệp từ xa, bạn sẽ không thấy thay đổi trong bản dựng của mình nếu bạn hoàn toàn lưu vào bộ đệm.
M Conrad

25 phút và 8 phút cả hai âm thanh cực đoan. Bạn đang chạy bản dựng song song? Hệ thống của bạn có đủ RAM còn lại để cung cấp bộ đệm không?
M Conrad

Cảm ơn. Đối với các dự án khác, tôi sử dụng chia sẻ để sửa đổi nguồn từ các máy khác nhau. Đối với Julia-lang, nó có thể được xem là sao lưu tự động hoặc rsync. Vâng, nó song song trong một số phần nhưng thời gian chạy ngôn ngữ là một điều rất lớn, nó bao gồm việc biên dịch LLVM và nhiều thư viện khác, và một phần nối tiếp của việc lắp ráp hình ảnh Julia và kiểm tra giới hạn khả năng mở rộng. Ccache hoạt động tốt BTW, nó thậm chí còn giảm 8 phút này thành 5 trên bản dựng cục bộ và gần như giải quyết được vấn đề 25 phút đó
Anton

1
Nghe có vẻ như bạn đã sửa nó với ccache, nhưng nếu NFS chỉ dành cho lưu trữ không liên tục, bạn có thể xem xét một tập lệnh xây dựng chạy rsync để làm mới một bản sao cục bộ, sau đó chạy make, sau đó chạy rsync để lưu kết quả trở lại NFS. Đó chỉ là "thủ công" cho đến khi bạn tự động hóa nó ;-)
M Conrad
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.