ケース12は、マルチスレッドデータベースのバックアップシェル

シェルスクリプトは、それが名前付きパイプによって達成されるので、理解するのは難しいビットを実装するために、マルチスレッド。いわゆるマルチスレッドはもともと複数のスレッドで完了するために、今何が起こっているかの方法により行われます。彼らに分業を与え、今、物事を完了するために、10個のスレッドを割り当てを10時間かかり、同時にこれらすべてのことを行う過程した場合、最終的には1時間が必要な場合があります。

次のようにこの場合、特定の要件は次のとおりです。

1より大きい)、同社の事業、100個のデータベースは完全バックアップが必要がある、とまでGB〜数十データベースあたりのデータ量は、(各ライブラリは別々のIPを持っている別のインスタンスであることに注意してください:ポート) 。

2)約30分で、各ライブラリのバックアップ時間を推定しました。

3)バックアップが5時間で完了される必要です。


ヒント:5時間でデータベース100のバックアップを完了させるためには、マルチスレッド機能は、スクリプト、一回開いて10件のスレッド10の同時バックアップデータベースのシェルを使用する必要があります。


知識ポイント1:xtrabackupを使用してバックアップMySQLデータベース

データベーステーブルをエクスポートするmysqldumpをまたは数Gのいくつかは、良いです。データは、Gの数百数十、元のライブラリや輸出実績の両方の圧力が、かなりのないラインナップをmysqldumpを達します。最良の選択オンラインMySQLのホットバックアップジョブが増分、単一テーブルのバックアップの完全な量であることと、復元することができます達成するために、Percona-Xtrabackupバックアップツール。


xtrabackupコマンドのみデータベースのバックアップをノンブロッキングInnoDBストレージエンジンXtraDBをサポートし、Perlの、読み取りロックテーブルを添加することによって達成バックアップMYISAM xtrabackup層によって封入innobackupex。


Percona-XtrabackupはそうCentOS7に取り付けられました:

#RPMの-ivh https://www.percona.com/downloads/percona-release/redhat/0.1-3/percona-release-0.1-3.noarch.rpm //ソースはyumをマウント
#yumを-y percona-xtrabackupをインストール-24 // yumのバージョン2.4をインストールします

xtrabackupでフルバックアップを実行するコマンドは次のとおりです。

#innobackupex --default-ファイル=は/ etc / my.cnfの--host = 10.100.100.100 --port = 3333 --user = bakuser --password = your_pass /データ/バックアップ/ MySQLの

説明:バックアップ操作を実行する前に、ユーザーbakuser(カスタムユーザ名)を作成し、リロード、ロックテーブル、複製クライアント、プロセス、スーパーやその他の権限を付与する必要があります。バックアップデータは、例えば2019-08-10_09_56_12のために、自動的にディレクトリの名前に現在の日付と時刻を生成するために、中/データ/バックアップ/ mysqlディレクトリに配置されます。


知識ポイント2:ファイルディスクリプタ

非負の整数の形でファイルディスクリプタ(略称FD)。実際には、ファイルリストによって維持レコードを開くために、各プロセスを処理するためにカーネルを指し示す指標値です。プログラムは、既存のファイルを開くか、新しいファイルを作成すると、カーネルはプロセスにファイル記述子を返します。すべてのUNIXプロセスは、3つの異なるストリームに対応する3つの標準的なファイルディスクリプタを持っています。

ファイルディスクリプタの名前
0標準入力
正しい標準出力
2標準エラー出力

上記の3つの標準記述子に加えて、あなたは、ファイルディスクリプタなどの他の番号へのプロセスをカスタマイズすることができます。それぞれが同じファイルを開くと同時に、ファイルをオープンし、また別のファイル記述子に対応することができるファイル記述子に対応し、ファイルが別のプロセスで開くことができ、同様の処理を複数回開くことができます。


テストスクリプトを書く、を/ tmp / test.sh、コンテンツ:

#!/ binに/ bashの
"$$のためのプロセスのpid"エコー
Execの1> /tmp/test.log 2>&1つの
LS -l / procの/ $$ / FD /

スクリプトを実行し、その後/tmp/test.logを表示

#猫test.log 
0の合計量
。LRWXルート1 ------ルート8は10:24 0 10 64日付- >は/ dev / PTS / 1。
.. 1 ------ L-WX 8ルートルート64。 。1 10:24 5月10日- > /tmp/test.log 
ルート1 ------ L-WX 8ヶ月ルート64 2 10:24 10 - 。。。> /tmp/test.log 
LR-X ---- - 。1つのルートルート64の8日付け10 10:24 255 - > /tmp/test.sh

説明:スクリプトの右と/tmp/test.log後続の命令にリダイレクト間違った出力をexecし、あなたが上記のファイルの内容を表示したときに表示されます。EXECコマンドについて、視覚的な例を見て:

#幹部>を/ tmp /テスト[WBS 12.sh @ルート] 
[WBS @ルート12.sh]#は"123123"をエコー
#エコー$ PWD [WBS 12.sh @ルート] 
[WBS @ルート12.sh]#ラララを
-bash:ラララ:未找到命令
#幹部>は/ dev / ttyの[WBS 12.sh @ルート] 
#猫の/ tmp /テスト[WBS 12.sh @ルート] 
123123 
/root/20shell/12.sh

説明:上記の例として、それが実行されたときExecの、右その背後にあるコマンドの標準出力は、すべての/ tmp /テスト・ファイルに書き込まれ、そしてエラーは、設定を終了するために、現在の端末上に表示されることがわかりました、 / dev / ttyの標準出力を再定義するには、exec必要。


知識ポイント3:コマンドパイプライン

シェルスクリプトの前で繰り返し使用パイプ記号は、「|」、これは、匿名パイプと呼ばれ、ここで言及したパイプは、基本的には同じ名前付きパイプ、匿名パイプと機能と呼ばれます。

名前付きパイプは、英語まず最初にアウトでは、FIFOと呼ばれます。名前付きパイプの機能:

1)ファイルシステムでは、FIFOは、名前を持ち、デバイス特殊ファイルの形式です。

2)任意のプロセスは、FIFOを介してデータを共有することができます。

3)FIFOの両端ながら読み書きのプロセスない限り、そうでなければFIFOデータフローがブロックされます。

4)匿名パイプシェルによって自動的に作成され、それがカーネル内に存在し、FIFOは、例えばはmkfifoコマンドとしてプログラム()によって作成されたファイルシステム内に存在します。

5)匿名パイプは、バイトの一方向の流れであり、FIFOは、双方向バイトストリームです。


mkfifoコマンドを使用して、名前付きパイプを作成します。

画面#の
#は123.fifoはmkfifo 
#は我々だけでパイプラインの内容を書き込み、このコンテンツを読むための他のプロセスが存在しないため、「121212」は> // 123.fifoは、この時点でブロックされているエコー。
CTRL + D //画面の終了
121212は//この時点で、あなたが内容を確認して、ちょうどそのコマンドが終了したエコーを参照するには、画面を入力することができます123.fifo#のCATを。

名前付きパイプとファイルディスクリプタを組み合わせることができます。

[root@wbs ~]# mkfifo test.fifo
[root@wbs ~]# exec 100<>test.fifo  //这样可以把fd100的读和写全部指定到test.fifo中
[root@wbs ~]# ls -l /dev/fd/100  //可以看到fd100已经指向到了/root/test.fifo
lrwx------. 1 root root 64 8月  10 11:41 /dev/fd/100 -> /root/test.fifo


知识点四:read命令

在shell脚本中,read命令使用还是比较多的,最典型的用法是,和用户交互,如下:

# read -p "Please input a number:" n
Please input a number:3
# echo $n
3

如果不使用-p选项,也可以这样使用:

# read name
1234
# echo $name
1234

read的-u选项后面可以跟fd,如下:

# read -u 10 a  //这样会把fd 10里面的字符串赋值给a

注意,这里的fd 10就是前面定义的test.fifo,如果你的fd 10里还没有任何的内容写入,那么你执行上面这条命令会卡着不动。因为fd 10是一个命名管道文件,只有写入了东西,read才会读到,否则就一直卡着,等待写入内容。当然,这个命名管道文件可以写入多行,先储存起来,然后等着read去读。

# echo "123" >& 10
# echo "456" >& 10  //连续在fd10中写入两次内容
# read -u 10 a  //第一次读取fd10里的第一行
# echo $a
123
# read -u 10 a  //第二次读取fd10里的第二行
# echo $a
456


知识点五:wait命令

wait命令:等待的意思,即等待那些在没有完成的任务(主要是后台的任务),直到所有任务完成后,才会继续执行wait以后的指令,常用于shell脚本中。以下是关于wait指令的示例:

# sleep 5 &
# wait   //此时会卡死不动,直到上面的后台指令执行完,才会有反应。


知识点六:结合命名管道和read实现多线程

命名管道有两个很明显的特点:

1)先进先出,比如上例中我们给fd10写入了两行内容,则第一次read第一行,第二次read第二行。

2)有内容read则执行,没有则阻塞,例如上例中,read完两次后,如果你再执行一次read,则它会一直卡着,直到我们再次写入新的内容它才会read到。


利用这两个特点,就可以实现shell的多线程了,先看个例子:

#!/bin/bash
#创建命名管道123.fifo文件
mkfifo 123.fifo
#将命名管道123.fifo和文件描述符1000绑定,即fd1000的输入输出都是在123.fifo中
exec 1000<>123.fifo

#连续向fd1000中写入两次空行
echo >&1000
echo >&1000

#循环10次
for i in `seq 1 10`
do
    #每循环一次,读一次fd1000中的内容,即空行,只有读到空行了,才会执行{ }内的指令
    #每次循环都需要打印当前的时间,休眠1秒,然后再次向fd1000中写入空行,这样后续的read就有内容了
    #read指令不仅可以赋值,也可以跟一个函数,用{ }括起来,函数中是多条指令
    read -u1000
    {
        date +%T
        echo $i
        sleep 1
        echo >&1000
    } &  //丢到后台去,这样10次很快就循环完,只不过这些任务是在后台跑着。由于我们一开始就向fd1000里写入了两个空行,所以read会一次性读到两行。
done
#等待所有后台任务执行完成
wait
#删除fd1000
exec 1000>&-
#删除命名管道
rm -f 123.fifo

执行结果:

08:54:11
1
08:54:11
2
08:54:12
3
08:54:12
4
08:54:13
5
08:54:13
6
08:54:14
08:54:14
7
8
08:54:15
9
08:54:15
10

可以看到,原本需要10秒完成的事情,现在5秒就完成了,这说明并发量为2,即两个线程同时执行任务,要想5个线程,那么在一开始的时候,直接向fd1000写入5个空行即可。


本案例参考脚本

#!/bin/bash
#多线程备份数据库
#作者:
#日期:
#版本:v1.0

##假设100个库的库名、host、port以及配置文件路径存到了一个文件里,文件名字为/tmp/databases.list
##格式:db1 10.10.10.2 3308 /data/mysql/db1/my.cnf
##备份数据库使用xtrabackup(由于涉及到myisam,命令为inoobackupex)

exec &> /tmp/mysql_bak.log

if ! which innobackupex &>/dev/nll
then
    echo "安装xtrabackup工具"
    rpm -ivh http://www.percona.com/downloads/percona-release/redhat/0.1-3/percona-release-0.1-3.noarch.rpm  && \ 
    yum install -y percona-xtrabackup-24
    if [ $? -ne 0 ]
    then
        echo "安装xtrabackup工具出错,请检查。"
        exit 1
    fi
fi

bakdir=/data/backup/mysql
bakuser=vyNctM
bakpass=99omeaBHh

function bak_data {
    db_name=$1
    db_host=$2
    db_port=$3
    cnf=$4
    [ -d $bakdir/$db_name ] || mkdir -p $bakdir/$db_name
    innobackupex --defaults-file=$4  --host=$2  --port=$3 --user=$bakuser --password=$bakpass  $bakdir/$1
        if [ $? -ne 0 ]
        then
            echo "备份数据库$1出现问题。"
        fi
}

fifofile=/tmp/$$
mkfifo $fifofile
exec 1000<>$fifofile


thread=10
for ((i=0;i<$thread;i++))
do
    echo >&1000
done

cat /tmp/databases.list | while read line
do
    read -u1000
    {
        bak_data `echo $line`
        echo >&1000
    } &
done

wait
exec 1000>&-
rm -f $fifofile


おすすめ

転載: blog.51cto.com/13576245/2429077