[ruby-list:50887] Net::SSH を使ったパイプ処理

From: emo@...
Date: 2020-05-31 11:22:05 UTC
List: ruby-list #50887
BASH のスクリプトで書いているディスクの
バックアップの処理を Ruby に書き換えようとして苦戦しています。

BASH  で以下の様な処理をしている箇所があります。

 > btrfs send -p $PREVIOUS $CURRENT | ssh $REMOTEHOST "btrfs receive 
$TARGETDIR"


このコマンドを説明すると、二つのディレクトリ(Btrfs のスナップショット)
$PREVIOUS と $CURRENT の差分を標準出力を
ssh で $REMOTEHOST に送ります。
リモートホスト側では、差分情報を標準入力から読み込み、
これをディレクトリ $TARGETDIR に反映します。

この時の差分情報のデータは ~数十 GB 程度です。

これを Ruby で Net::SSH を使って以下のように書き換えました。
(ホスト名等は *** に替えています)

 > #!/usr/bin/ruby
 > # -*- coding: utf-8 -*-
 >
 > require 'open3'
 > require 'net/ssh'
 > BUF_SIZE=100*1024
 >
 > CURRENT="*****"
 > PREVIOUS="******"
 > REMOTE_HOST='******'
 > TARGET_DIR='*****'
 >
 > sender_in, sender_out, sender_thread = Open3.popen2("btrfs send -p 
#{PREVIOUS} #{CURRENT}")
 >
 > Net::SSH.start(REMOTE_HOST, 'root', :keys => '/root/.ssh/id_rsa'  ) 
do |ssh|
 >   cmd="btrfs receive #{TARGET_DIR}"
 >   ssh.open_channel do |channel|
 >     channel.exec(cmd) do |ch, success|
 >       raise 'file to execute remote command' unless success
 >       channel.on_data do |ch, data|
 >         puts data
 >       end
 >
 >       while (data=sender_out.read(BUF_SIZE)) do
 >         channel.send_data(data)
 >         channel.process()
 >       end
 >     end
 >   end
 >   ssh.loop
 > end


これを実行すると以下の例外で失敗してしまします。

 > /usr/share/gems/gems/net-ssh-2.9.1/lib/net/ssh/buffer.rb:143:in 
`append': failed to allocate memory (NoMemoryError)
 >         from 
/usr/share/gems/gems/net-ssh-2.9.1/lib/net/ssh/connection/channel.rb:251:in 
`send_data'
 >         from ./test_backup.rb:25:in `block (3 levels) in <main>'
 >         from 
/usr/share/gems/gems/net-ssh-2.9.1/lib/net/ssh/connection/channel.rb:608:in 
`call'
 >         from 
/usr/share/gems/gems/net-ssh-2.9.1/lib/net/ssh/connection/channel.rb:608:in 
`do_success'
 >         from 
/usr/share/gems/gems/net-ssh-2.9.1/lib/net/ssh/connection/session.rb:591:in 
`channel_success'
 >         from 
/usr/share/gems/gems/net-ssh-2.9.1/lib/net/ssh/connection/session.rb:465:in 
`dispatch_incoming_packets'
 >         from 
/usr/share/gems/gems/net-ssh-2.9.1/lib/net/ssh/connection/session.rb:221:in 
`preprocess'
 >         from 
/usr/share/gems/gems/net-ssh-2.9.1/lib/net/ssh/connection/session.rb:205:in 
`process'
 >        from 
/usr/share/gems/gems/net-ssh-2.9.1/lib/net/ssh/connection/session.rb:169:in 
`block in loop'
 >         from 
/usr/share/gems/gems/net-ssh-2.9.1/lib/net/ssh/connection/session.rb:169:in 
`loop'
 >         from 
/usr/share/gems/gems/net-ssh-2.9.1/lib/net/ssh/connection/session.rb:169:in 
`loop'
 >         from ./test_backup.rb:30:in `block in <main>'
 >         from /usr/share/gems/gems/net-ssh-2.9.1/lib/net/ssh.rb:210:in 
`start'
 >        from ./test_backup.rb:15:in `<main>'


差分の情報が極小さい場合は、正常に実行できているようなのですが、
差分データが大きい場合は、send_data ではデータが実際には送られず、
バッファーに溜まって行き、本体のメモリが足らなくなって
失敗しているようです。

どのようにプログラムを書き換えれば良いでしょうか?


実行環境:

OS : CentOS Linux release 7.7.1908 (Core)
Ruby : 2.0.0p648 (2015-12-16) [x86_64-linux]
Net::SSH 2.8.1



江本


In This Thread

Prev Next