記Linux服務器磁盤空間不足解決之路

1. 前言

在我登錄我自己開發的產品血玉鑽的時候,我發現接口沒有數據返回,遠程登錄發現服務器也並沒有掛掉。因為我是通過pm2管理我的應用的,於是乎,我日常pm2 restart 項目,發現接口還是數據沒有返回,也沒有報錯,於是我沒有用pm2啟動項目,直接node main.js啟動項目,發現MySql Lock wait timeout exceeded 這個錯誤。

然後我又進行萬能重啟操作,重啟mysql,先systemctl stop mysqld,然後再systemctl start mysqld,這問題就出來了,啟動失敗,報如下錯誤。

<code>Starting mysqld (via systemctl): Job for mysqld.service failed because the control process exited

with

error

code. See

"systemctl status mysqld.service"

and

"journalctl -xe"

for

details. [

FAILED

] /<code>

然後我就看我之前寫的記錄mysql的文章雲服務器Mysql安裝配置 和linux安裝mysql啟動不起來總結 這兩篇文章,果然安裝記錄的文章,發現了mysql啟動不起來的原因,如下:

<code>

Disk

is

full

writing

'./binlog.000039'

(OS

errno

28

-

No

space

left

on

device).

Waiting

for

someone

to

free

space...

Retry

in

60

secs.

Message

reprinted

in

600

secs

/<code>

2. linux命令查看磁盤使用情況

通過上面我們已經知道,mysql啟動不成功的原因是因為磁盤不足。 這裡我們就先來學習下,怎麼查看linux服務器磁盤空間使用情況。

2.1 使用df -h命令查看磁盤空空間

使用df -h命令查看磁盤空間,若磁盤空間不足則清理(當然這是我解決之後的截圖,之前的磁盤滿的情況忘了截圖)。

2.2 du的用法

du命令用來查看目錄或文件所佔用磁盤空間的大小。常用選項組合為:du -sh

du常用的選項:   -h:以人類可讀的方式顯示   -a:顯示目錄佔用的磁盤空間大小,還要顯示其下目錄和文件佔用磁盤空間的大小   -s:顯示目錄佔用的磁盤空間大小,不要顯示其下子目錄和文件佔用的磁盤空間大小   -c:顯示幾個目錄或文件佔用的磁盤空間大小,還要統計它們的總和   --apparent-size:顯示目錄或文件自身的大小   -l :統計硬鏈接佔用磁盤空間的大小   -L:統計符號鏈接所指向的文件佔用的磁盤空間大小 du -lh --max-depth=1: 查看當前目錄下一級子文件和子目錄佔用的磁盤容量。 du -h -x --max-depth=1:查看哪個目錄佔用過高 du -sh * | sort -n 統計當前文件夾(目錄)大小,並按文件大小排序 du -sk filename 查看指定文件大小

3. 查看佔用空間大的文件

然後用du命令查看linux文件佔用磁盤大小情況。

然後我們查到原因了,是mysql文件夾裡面就佔用了25G磁盤,總共磁盤才40G,然後在進入mysql文件夾查看

發現binglog之類的文件竟然達到了20多G。

binlog是什麼呢?

Mysql Binlog是二進制格式的日誌文件,但是不能把binlog文件等同於OS系統某目錄下的具體文件,這是狹隘的。Binlog是用來記錄Mysql內部對數據庫的改動(只記錄對數據的修改操作),主要用於數據庫的主從複製以及增量恢復。

然後我們知道這寫文件主要是記錄對數據的修改操作,主要用於數據庫的主從複製,但是我的應用並沒有用到主從複製,所以是可以刪除的。

4. mysql的binlog安全刪除

默認情況下mysql會一直保留mysql-bin文件,這樣到一定時候,磁盤可能會被撐滿,這時候是否可以刪除這些文件呢,是否可以安全刪除,是個問題。

首先要說明一下,這些文件都是mysql的日誌文件,如果不做主從複製的話,基本上是沒用的,雖然沒用,但是不建議使用rm命令刪除,這樣有可能會不安全,正確的方法是通過mysql的命令去刪除。

我們登錄mysql之後,使用命令

<code>

mysql>

reset

master;

Query

OK,

0

rows

affected

(3

min

37.65

sec)

/<code>

其實關鍵的命令就是reset master;這個命令會清空mysql-bin文件。

另外如果你的mysql服務器不需要做主從複製的話,建議通過修改my.cnf文件,來設置不生成這些文件,只要刪除my.cnf中的下面一行就可以了。

<code>

log-bin

=mysql-bin /<code>

如果你需要複製,最好控制一下這些日誌文件保留的天數,可以通過下面的配置設定日誌文件保留的天數:

<code>

expire_logs_days

=

7

/<code>

表示保留7天的日誌,這樣老日誌會自動被清理掉。

另外的方法

4.1 手動清理binlog

① 查看主庫和從庫正在使用的binlog是哪個文件

<code>

show

master

status

\G

show

slave

status

\G \ /<code>

② 在刪除binlog日誌之前,首先對binlog日誌備份,以防萬一 開始動手刪除binlog:

<code>

purge

master

logs

before

'2016-09-01 17:20:00'

; //刪除指定日期以前的日誌索引中binlog日誌文件 /<code>

<code>

purge

master

logs

to

'mysql-bin.000022'

; //刪除指定日誌文件的日誌索引中binlog日誌文件 /<code>

注意: 時間和文件名一定不可以寫錯,尤其是時間中的年和文件名中的序號,以防不小心將正在使用的binlog刪除!!!

切勿刪除正在使用的binlog!!!

使用該語法,會將對應的文件和mysql-bin.index中的對應路徑刪除。

4.2 通過設置binlog過期的時間,使系統自動刪除binlog文件

這種就是類似上面的expire_logs_days = 7

<code>mysql> show variables like

'expire_logs_days'

; +------------------+-------+

| Variable_name |

Value

| +------------------+-------+ |

expire_logs_days

| 0 |

+------------------+-------+ mysql> set global expire_logs_days =

30

; ———————————————— /<code>

注意: 過期時間設置的要適當,對於主從複製,要看從庫的延遲決定過期時間,避免主庫binlog還未傳到從庫便因過期而刪除,導致主從不一致!!!

通過上面的方法之後,我們再一次查看磁盤使用情況,發現刪除binlog之後,足足多出了一半以上的磁盤空間,開心。

5. mysql擴展

5.1 innodb_file_per_table 的簡要說明

在很久很久以前也就是說還沒有innodb_file_per_table 的那個年代,所有的innodb表的數據都是保存在innodb系統表空間中的,

在有了innodb_file_per_table參數後innodb可以把每個表的數據單獨保存。單獨保存有兩方面的優勢一個是方便管理,二個是提長性能。

5.2 mysql 引用innodb_file_per_table是為了解決什麼問題

在沒有innodb_file_per_table之前所有的innodb表的數據都是統一保存到,innodb系統表空間文件中的,如果想讓mysql的行為

與innodb_file_per_table還沒有引入時的行為一致,那麼把innodb_file_per_table設置為OFF就行。

1、由於數據都統一保存到innodb系統表空間文件中,在drop table ,truncate table後表空間文件並不會進行收縮,也就是說表空間文件所佔的磁盤空間並不會因為drop table , truncate table 而釋放。

2、對於mysql來說alter table 的過程大概可以概括為 1)根據alter table 的指示創建出一張新的表 . 2)把老表的數據插入表新表中3)刪了老表. 4)把新表的表名字重命名成老表的名字;當然如今的mysql已經有inplace對上面的過程進行優化了,不過並不是所有的alter table 都支持inplace,更多關於inplace的問題在此不表了。還是回到alter table 的第2)步 由這裡可以看出系統表空間是要增大的(理由是:創建了新的表,又在向新的表中插入數據) 所以啊alter table 會導致系統表空間的進一步加大。

3、在linux系統中不允許並行的對一個文件進行寫入(innodb_flush_method=O_DIRECT的情況下是這樣的),這可能成為一個性能問題

4、對於使用innodb_file_per_table=ON的情況下,默認創建出來的ibd文件的格式是Barracuda,在這個文件格式下innodb數據行的格式就可以設置為compressed 或 dynamic 格式了。compressed 提供壓縮功能節約空間,dynamic能優化對blob,text這樣的數據類型的存儲以提升性能。

5.3 Mysql刪除數據後磁盤空間未釋放的解決辦法

官方推薦使用 OPTIMIZE TABLE命令來優化表,該命令會重新利用未使用的空間,並整理數據文件的碎片。

語法如下:

OPTIMIZE [LOCAL | NO_WRITE_TO_BINLOG] TABLE tbl_name [, tbl_name] ...

注:該命令將會整理表數據和相關的索引數據的物理存儲空間,用來減少佔用的磁盤空間,並提高訪問表時候的IO性能。但是,具體對錶產生的影響是依賴於表使用的存儲引擎的。該命令對視圖無效。

執行語句:show table status like 'table_name'查看錶信息

查詢結果中:

<code>

Index_length

代表索引的數量

Data_free

代表碎片數量

/<code>

然後執行下面命令進行優化整理:

<code>mysql > optimize

table

table_name /<code>

如果之前的碎片數量多,執行時間可能會久一點,執行結束後出現下面框內的數據則優化成功。

注意事項: 由於命令optimize會進行鎖表操作,所以進行優化時要避開表數據操作時間,避免影響正常業務的進行。

MySQL5.7已經推薦對於InnoDB的table使用 alter table table_name engine=innodb;語句的方式來進行表碎片優化。

6. 相關文章