Tại sao rsync không sử dụng chuyển delta cho một tệp trên toàn mạng?


15

Tôi đã xem xét câu hỏi này và câu hỏi này , nhưng dường như chúng không giải quyết được các triệu chứng tôi đang thấy.

Tôi có một tệp nhật ký lớn (khoảng 600 MB) mà tôi đang cố gắng chuyển qua mạng di động. Bởi vì nó là một file log nó chỉ được nối vào (mặc dù nó thực sự là một cơ sở dữ liệu SQLite với chỉ INSERT được thực hiện, vì vậy nó không phải là khá đơn giản như vậy, nhưng với ngoại lệ của người cuối cùng 4k trang (hoặc có thể là một vài lần) tập tin giống hệt nhau mỗi lần. Điều quan trọng là chỉ những thay đổi (và bất kỳ tổng kiểm tra nào cần được truyền) thực sự được gửi, bởi vì kết nối dữ liệu được đo.

Tuy nhiên, khi tôi thực hiện kiểm tra qua kết nối không được đáp ứng (ví dụ: điểm phát wifi miễn phí), tôi không thấy việc truyền dữ liệu tăng tốc hoặc giảm tốc độ được quan sát hoặc báo cáo. Qua kết nối WiFi chậm, tôi thấy đơn hàng từ 1MB / s trở xuống, báo cáo rằng việc chuyển tiền sẽ mất gần 20 phút. Qua kết nối WiFi nhanh, tôi thấy tốc độ nhanh hơn đồng đều, nhưng không có báo cáo về tốc độ và lần thử thứ hai để chuyển (mà bây giờ sẽ nhanh hơn vì hai tệp giống hệt nhau) hiện không có sự khác biệt.

Lệnh (được khử trùng để xóa thông tin nhạy cảm) tôi đang sử dụng là:

rsync 'ssh -p 9999' --progress LogFile michael@my.host.zzz:/home/michael/logs/LogFile

Đầu ra tôi nhận được ở cuối trông như thế này:

LogFile
    640,856,064 100%   21.25MB/s   0:00:28 (xfr$1, to-chk=0/1)

Không có đề cập đến bất kỳ loại tăng tốc.

Tôi nghi ngờ vấn đề có thể là một trong những điều sau đây:

  • Tôi đang thiếu một số tùy chọn dòng lệnh. Tuy nhiên, đọc lại trang man dường như gợi ý rằng chuyển delta được bật theo mặc định: Tôi chỉ thấy các tùy chọn để vô hiệu hóa chúng.
  • Tôi đang sử dụng rsync trên ssh (trên một cổng không chuẩn) do máy chủ đứng sau tường lửa chỉ cho phép ssh. Tôi chưa thấy bất cứ điều gì rõ ràng nói rằng chuyển delta sẽ không hoạt động nếu daemon rsync không chạy. Tôi đã thử sử dụng ký hiệu "::" thay vì ":" nhưng trang man không rõ lắm về "mô-đun" là gì và lệnh của tôi bị từ chối vì chỉ định mô-đun không hợp lệ.

Tôi đã loại trừ những điều sau đây:

  • chuyển delta không được thực hiện trên một mạng cục bộ. Loại trừ vì tôi đang cố gắng thực hiện chuyển tiền qua internet
  • chi phí do tính toán tổng kiểm tra. Tôi đã thấy hành vi này trên cả kết nối Wifi nhanh và chậm và tốc độ truyền tải dường như không bị ràng buộc.

1
but with the exception of the last 4k page (or maybe a few) the file is identical each time. Bạn đã thực sự xác minh rằng với cmp? Hoặc tốt hơn, với xdeltahoặc một cái gì đó? Nếu bạn thực sự muốn giảm thiểu kích thước chuyển, hãy giữ các phiên bản cũ và mới cục bộ, để bạn có thể tính toán một nhị phân nhị phân tối thiểu cục bộ (với thứ gì đó không phải là rsync) và chỉ cần gửi mà không phải gửi tổng kiểm qua kết nối được đo. Làm điều này ở mức bản ghi cơ sở dữ liệu thay vì mức tệp nhị phân có lẽ còn tốt hơn, như derobert gợi ý.
Peter Cordes

1
Ngoài ra, bạn có thể đã sử dụng rsync --statsvà cũng -v -vđể có được số liệu thống kê dài hơn. Rsync sẽ cho bạn biết có bao nhiêu dữ liệu trùng khớp với dữ liệu chưa từng có.
Peter Cordes

Câu trả lời:


27

Tóm lược

Cơ sở dữ liệu có xu hướng giữ nhiều siêu dữ liệu, dữ liệu tổ chức, v.v. Một phần chèn rất khó có thể là một phần bổ sung đơn giản, giống như nó sẽ có trong một tệp văn bản. Kiểm tra SQLite cho thấy nó hoạt động theo cách đó, trong cả chế độ WAL và không WAL. Điều này dẫn đến rsync phải đồng bộ hóa nhiều dữ liệu hơn bạn mong đợi. Bạn có thể giảm chi phí này một chút bằng cách sử dụng mức thấp --block-size(với chi phí tính toán chi phí cao hơn và chuyển tổng kiểm).

Một cách tiếp cận tốt hơn có lẽ là loại bỏ các bản ghi mới dưới dạng kết xuất SQL, nén nó và chuyển nó. Ngoài ra, dường như có một số giải pháp sao chép cho SQLite, bạn có thể sử dụng một trong những giải pháp đó.

roaima đề xuất ở mức tối thiểu bạn có thể thực hiện một kết xuất SQL đầy đủ, nén nó bằng cách sử dụng gzip --rsyncablevà sau đó rsync nó. Đáng để thử nghiệm, tôi cho rằng, để xem đó có phải là một đồng bằng đủ nhỏ không.

Chi tiết

Những gì bạn đang cố gắng nên làm việc. Cá nhân tôi muốn thêm --partialvào các tùy chọn rsync của bạn, chỉ trong trường hợp nó bằng cách nào đó phát hiện tệp đang phát triển dưới dạng chuyển một phần. Bạn cũng có thể nhận được số liệu thống kê chuyển tốt hơn với --stats.

Điều thứ hai cần kiểm tra là nếu SQLite thực sự chỉ chạm vào một vài trang mà thành thật, tôi sẽ không ngạc nhiên nếu nó viết các trang trên toàn bộ tệp. Một cách nhanh chóng để kiểm tra là sử dụng cmp -ltrên hai phiên bản mà xem nếu có thay đổi đối với các trang khác với các trang cuối cùng. Hãy nhớ rằng rsyncý tưởng về "trang" / khối khác với SQLite; bạn có thể thay đổi rsync thông qua --block-size. Giảm nó có thể giúp đỡ.

Chỉnh sửa: Tôi đã làm một bài kiểm tra nhanh với SQLite. Ngay cả với 32k trang, việc thêm một loạt các mục nhật ký được viết nguệch ngoạc trên mỗi trang. Chi tiết bên dưới.

Chỉnh sửa 2 : Nó có vẻ tốt hơn trong chế độ WAL, mặc dù bạn vẫn mất một lượng lớn chi phí, có thể là từ trạm kiểm soát.

Chỉnh sửa 3 : Nó cũng tốt hơn khi bạn thêm nhiều dữ liệu cho mỗi lần chuyển nhượng Tôi đoán nó có thể viết nguệch ngoạc một số khối nhất định nhiều lần. Vì vậy, bạn đang chuyển cùng một nhóm các khối bất kể nó được viết cho chúng một lần hay một trăm lần.

BTW: Để giảm thiểu chuyển khoản, có lẽ bạn có thể làm tốt hơn nhiều so với rsync. Ví dụ: kết xuất SQL của các bản ghi mới kể từ lần chuyển cuối cùng chạy qua xz --best(hoặc thậm chí gzip) có thể sẽ nhỏ hơn một chút.

Kiểm tra SQLite nhanh

Lược đồ:

CREATE TABLE log (id integer primary key not null, ts integer not null, app text not null, message text not null);
CREATE INDEX log_ts_idx on log(ts);
CREATE INDEX log_app_idx on log(app);

Chương trình Perl:

use 5.022;
use DBI;

my $DBH = DBI->connect('dbi:SQLite:test.db', '', '', {RaiseError => 1, AutoCommit => 0})
    or die "connect...";

my @apps = (
    '[kthreadd]',        '[ksoftirqd/0]',
     # there were 191 of these
    '[kworker/5:0H]',
);

my @messages = <DATA>;

(my $curr_time) = $DBH->selectrow_array(<<QUERY);
    SELECT COALESCE(MAX(ts),978307200) FROM log
QUERY

my $n_apps = @apps;
my $n_msgs = @messages;
say "Apps: $n_apps";
say "Messages: $n_msgs";
say 'Start time: ', scalar gmtime($curr_time), ' UTC';

my $sth = $DBH->prepare(<<QUERY);
    INSERT INTO log(ts, app, message) VALUES (?, ?, ?)
QUERY

for (my $i = 0; $i < 10_000; ++$i) {
    $sth->execute(int($curr_time), $apps[int rand $n_apps], $messages[int rand $n_msgs]);
    $curr_time += rand 0.1;
}
$DBH->commit;

__DATA__
microcode: CPU0 microcode updated early to revision 0x19, date = 2013-06-21
Linux version 4.5.0-2-amd64 (debian-kernel@lists.debian.org) (gcc version 5.3.1 20160528 (Debian 5.3.1-21) ) #1 SMP Debian 4.5.5-1 (2016-05-29)

Có rất nhiều thông điệp nhật ký ví dụ (2076).

Kiểm tra xem trang nào đã thay đổi:

cp test.db test.db.old
perl test.pl
cmp -l test.db.old test.db | perl -n -E '/^\s*(\d+) / or die "wtf"; $bucket{int $1/32768} = 1; END { say join "\n", sort( { $a <=> $b } keys %bucket) }'
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.