mysql|筆記|設計|資料|資料庫
以下是使用MYSQL服務的一些經驗,主要從以下幾個方面考慮的MYSQL服務規劃設計。
1 MYSQL服務的安裝/配置的通用性;
2 系統的升級和資料移轉方便性;
3 備份和系統快速恢複;
MYSQL伺服器的規劃
為了以後維護,升級備份的方便和資料的安全性,最好將MYSQL程式檔案和資料分別安裝在“不同的硬體”上。
/
/usr <== 作業系統 }==> 硬碟1
/home/mysql <== mysql應用程式
...
/data/app_1/ <== 應用資料和指令碼 }==> 硬碟2
/data/app_2/
/data/app_3/
mysql服務的安裝和服務的啟動:
MYSQL一般使用當前STABLE的版本,盡量不使用--with-charset=選項,我感覺with-charset只在按字母排序的時候才有用,這些選項會對資料的遷移帶來很多麻煩。
configure --prefix=/home/mysql
make
make install
服務的啟動和停止
1 複製預設的mysql/var/mysql到 /data/app_1/目錄下
2 MYSQLD的啟動指令碼:
start_mysql.sh
#!/bin/sh
rundir=`dirname "$0"`
echo "$rundir"
/home/mysql/bin/safe_mysqld --user=mysql --pid-file="$rundir"/mysql.pid --datadir="$rundir"/var "$@"\
-O max_connections=500 -O wait_timeout=600 -O key_buffer=32M --port=3402 --socket="$rundir"/mysql.sock &
注釋:
--pid-file="$rundir"/mysql.pid --socket="$rundir"/mysql.sock --datadir="$rundir"/var
目的都是將相應資料和應用臨時檔案放在一起;
-O 後面一般是伺服器啟動全域變數最佳化參數,有時候需要根據具體應用調整;
--port: 不同的應用使用PORT參數分布到不同的服務上去,一個服務可以提供的串連數一般是MYSQL服務的主要瓶頸;
修改不同的服務到不同的連接埠後,在rc.local檔案中加入:
/data/app_1/start_mysql.sh
/data/app_2/start_mysql.sh
/data/app_3/start_mysql.sh
注意:必須寫全路徑
3 MYSQLD的停止指令碼:stop_mysql.sh
#!/bin/sh
rundir=`dirname "$0"`
echo "$rundir"
/home/mysql/bin/mysqladmin -u mysql -S"$rundir"/mysql.sock shutdown
使用這個指令碼的好處在於:
1 多個服務啟動:只需要修改指令碼中的--port=參數。單個目錄下的資料和服務指令碼都是可以獨立打包的。
2 所有服務相應檔案都位於/data/app_1/目錄下:比如:mysql.pid mysql.sock,當一台伺服器上啟動多個服務時,多個服務不會互相影響。但都放到預設的/tmp/下則有可能被其他應用誤刪。
3 當硬碟1出問題以後,直接將硬碟2放到一台裝好MYSQL的伺服器上就可以立刻恢複服務(如果放到my.cnf裡則還需要備份相應的設定檔)。
服務啟動後/data/app_1/下相應的檔案和目錄分布如下:
/data/app_1/
start_mysql.sh 服務啟動指令碼
stop_mysql.sh 服務停止指令碼
mysql.pid 服務的進程ID
mysql.sock 服務的SOCK
var/ 資料區
mysql/ 使用者庫
app_1_db_1/ 應用庫
app_2_db_2/
...
/data/app_2/
...
查看所有的應用進程ID:
cat /data/*/mysql.pid
查看所有資料庫的錯誤記錄檔:
cat /data/*/var/*.err
個人建議:MYSQL的主要瓶頸在PORT的串連數上,因此,將表結構最佳化好以後,相應單個MYSQL服務的CPU佔用仍然在10%以上,就要考慮將服務拆分到多個PORT上運行了。
服務的備份
盡量使用MYSQL DUMP而不是直接備份資料檔案,以下是一個按weekday將資料輪循備份的指令碼:備份的間隔和周期可以根據備份的需求確定
/home/mysql/bin/mysqldump -S/data/app_1/mysql.sock -umysql db_name | gzip -f>/path/to/backup/db_name.`data +%w`.dump.gz
因此寫在CRONTAB中一般是:
* 6 * * * /home/mysql/bin/mysqldump -S/data/app_1/mysql.sock -umysql db_name | gzip -f>/path/to/backup/db_name.`data +\%w`.dump.gz
注意:
1 在crontab中'%'需要轉義成'\%'
2 根據日誌統計,應用負載最低的時候一般是在早上6點
先備份在本地然後傳到遠端備份伺服器上,或者直接建立一個Database Backup帳號,直接在遠端伺服器上備份,遠程備份只需要將以上指令碼中的-S /path/to/msyql.sock改成-h IP.ADDRESS即可。
資料的恢複和系統的升級
日常維護和資料移轉:在資料盤沒有被破壞的情況下硬碟一般是系統中壽命最低的硬體。而系統(包括作業系統和MYSQL應用)的升級和硬體升級,都會遇到資料移轉的問題。只要資料不變,先裝好伺服器,然後直接將資料盤(硬碟2)安裝上,只需要將啟動指令碼重新加入到rc.local檔案中,系統就算是很好的恢複了。
災難恢複:資料本身被破壞的情況下確定破壞的時間點,然後從備份資料中恢複。
應用的設計要點
1.非用資料庫不可嗎?
資料庫的確可以簡化很多應用的結構設計,但本身也是一個系統資源消耗比較大的應用。所以很多應用如果沒有很高的即時統計需求的話,完全可以先記錄到檔案日誌中,週期性匯入到資料庫中做後續統計分析。如果還是需要記錄2維表結構,結構足夠簡單的話可以使用DBM結構。即使需要使用資料庫的,應用如果沒有太複雜的資料完整性需求的化,完全可以不使用那些支援外鍵的商務資料庫。
2.資料庫服務的主要瓶頸:單個服務的串連數對於一個應用來說,如果資料庫表結構的設計能夠按照資料庫原理的範式來設計的話,並且已經使用了最新版本的MYSQL,並且按照比較最佳化的方式運行了,那麼最後的主要瓶頸一般在於單個服務的串連數,即使一個資料庫可以支援並發500個串連,最好也不要把應用用到這個地步,因為並發串連數過多資料庫服務本身用於調度的線程的開銷也會非常大了。所以如果應用允許的話:讓一台機器多跑幾個MYSQL服務分擔。將服務均衡的規划到多個MYSQL服務連接埠上:比如app_1 ==> 3301 app_2 ==> 3302...app_9 ==> 3309。一個1G記憶體的機器跑上10個MYSQL是很正常的。讓10個MYSQLD承擔1000個並發串連效率要比讓2個MYSQLD承擔1000個效率高的多。當然,這樣也會帶來一些應用編程上的複雜度;
3.使用單獨的資料庫伺服器(不要和前台WEB服務搶記憶體),MYSQL擁有更多的記憶體就可能能有效進行結果集的緩衝;
4.應用盡量使用PCONNECT和polling機制,用於節省MYSQL服務建立串連的開銷;
5.表的橫向拆分:讓最常被訪問的10%的資料放在一個小表裡,90%的曆史資料放在一個歸檔表裡,資料中間通過定期“搬家”和定期刪除無效資料來節省。這樣對於應用來說總是在10%資料中進行選擇,比較有利於資料的緩衝,不要指望MYSQL中對單表記錄數在10萬級以上還有比較高的效率。
6.表的縱向拆分(過渡範化):將所有的定長欄位(char, int等)放在一個表裡,所有的變長欄位(varchar,text,blob等)放在另外一個表裡,2個表之間通過主鍵關聯,這樣,定長欄位表可以得到很大的最佳化(甚至可以使用HEAP表類型,資料完全在記憶體中存取),這裡也說明另外一個原則,對於我們來說,盡量使用定長欄位可以通過空間的損失換取訪問效率的提高。MYSQL之所以支援多種表類型,實際上是針對不同應用提供了不同的最佳化方式;
7.仔細的檢查應用的索引設計,甚至在服務啟動中加入 --log-slow-queries[=file]用於跟蹤分析應用瓶頸。