sonar報錯500 Packet for query is too large

記錄一下自己的踩坑血淚史,昨天,金融組的項目經理問我是不是自己搭了一套自動化平臺,有代碼質量檢測功能,給他做一下代碼質量檢測。我跟他說,沒問題,我給你配置一下持續集成都行。

然後,我找他要了SVN地址,配置到jenkins,修改他的項目配置文件,配置了gradle的sonar插件,然後5分鐘不到,全部配好,開掃。

瞟了眼日誌,5000個java文件,有點愣,他說這項目做了好多年了,頭一次做代碼質量檢測。

等了10分鐘,終於掃描完畢,然後報了個500錯誤,失敗了。

我的項目一直在自動構建,從來沒失敗過啊,心裏有點慌,是不是自動構建環境哪裏出問題了,趕緊構建了一下我自己的項目,2分鐘後,我自己的項目成功構建完成。

那估計就是他的項目引發的問題了,shell中的日誌被頂不見了,無奈又跑了一次他的項目,10分鐘又過去了。

看到錯誤信息

INFO: Analysis report generated in 5163ms, dir size=86 MB

INFO: Analysis reports compressed in 8786ms, zip size=28 MB

ERROR: Error during SonarQube Scanner execution

ERROR: Failed to upload report - 500: An error has occurred. Please contact your administrator

沒有詳細信息,不知道什麼問題,於是 -x又跑了一遍……10分鐘又過去了

沒啥特別有用的信息,還是說上傳報告出錯,500

想了想,500那就是sonarqube報錯了,服務端應該有日誌,於是去到sonarqube/logs/web.log找到具體的錯誤信息

2019.03.19 08:42:37 ERROR web[AWlGy9kW/lhOnmA/AAUn][o.s.s.w.WebServiceEngine] Fail to process request http://localhost:9000/api/ce/submit?projectKey=dfcwpc&projectName=dfcwpc
java.lang.IllegalStateException: Fail to insert data of CE task AWmTZm4R6CYg244CjrN5
    at org.sonar.db.ce.CeTaskInputDao.insert(CeTaskInputDao.java:56)

Caused by: com.mysql.jdbc.PacketTooBigException: Packet for query is too large (34143478 > 4194304). You can change this value on the server by setting the max_allowed_packet' variable.
 

原來是mysql的數據包大小限制問題,趕緊查一下現在是多少

mysql> show variables like '%max_allowed_packet%';
+--------------------------+------------+
| Variable_name            | Value      |
+--------------------------+------------+
| max_allowed_packet       | 4194304    |
| slave_max_allowed_packet | 1073741824 |
+--------------------------+------------+
---------------------  

才4M……話說剛纔我們的包是多大來着,28M吧,怪不得報錯,趕緊修改mysql設置

vim /etc/my.cnf,根據實際情況進行參數調整:
[mysqld]
max_allowed_packet = 100M 

重啓mysql,這下改好了吧(一個小時已經過去了,同事已經向我投來了懷疑的眼光……而且,馬上就要下班了)

重新運行掃描,10分鐘又過去了,又報錯了,客戶端報錯信息跟之前一樣,還是500

趕緊看一眼服務端日誌,內容如下:

Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Row size too large (> 8126). Changing some columns to TEXT or BLOB or using ROW_FORMAT=DYNAMIC or ROW_FORMAT=COMPRESSED may help. In current row format, BLOB prefix of 768 bytes is stored inline. 

還是那一行代碼,換了個錯誤信息。

行數據大於8126?查閱mysql相關文檔,瞭解到

  • 一個16KB的InnoDB數據Page必須至少包含兩行數據。此外,每個Page都有一個頁眉和一個包含頁面校驗和和日誌序列號的頁腳,依此類推。這就是你的每行限制小於8KB的地方。
  • 固定大小的數據類型(如INTEGER,DATE,FLOAT,CHAR)存儲在此主數據Page上,並計入行大小限制。
  • 可變大小的數據類型(如VARCHAR,TEXT,BLOB)存儲在溢出頁面上,因此它們不會完全計入行大小限制。在Antelope中,除了存儲在溢出頁面上之外,在主數據頁面上還存儲多達768個字節的此類列。Barracuda支持  動態行格式,因此它可能只在主數據頁面上存儲一個20字節的指針。
  • 可變大小的數據類型也以1個或多個字節爲前綴來編碼長度。而InnoDB行格式也有一個字段偏移數組。因此,他們的wiki中或多或少都記錄了內部結構。

因此,我們要把問題所在的表的 ROW_FORMAT改成COMPRESSED或者DYNAMIC,應該就能解決問題。

於是,再次修改mysql設置

[mysqld]

#服務器發送和接受的最大包長度,當單行數據較大時,需要調整該參數。

max_allowed_packet = 100M 

#開啓page獨立空間

innodb_file_per_table = 1

#innodb的文件格式更改爲Barracuda
innodb_file_format = Barracuda

Antelope是innodb-base的文件格式,Barracude是innodb-plugin後引入的文件格式,同時Barracude也支持Antelope文件格式。兩者區別在於:

文件格式 支持行格式 特性
Antelope

(Innodb-base)

ROW_FORMAT=COMPACT

ROW_FORMAT=REDUNDANT

 

Compact和redumdant的區別在就是在於首部的存存內容區別。

compact的存儲格式爲首部爲一個非NULL的變長字段長度列表

redundant的存儲格式爲首部是一個字段長度偏移列表(每個字段佔用的字節長度及其相應的位移)。

在Antelope中對於變長字段,低於768字節的,不會進行overflow page存儲,某些情況下會減少結果集IO.

Barracuda

(innodb-plugin)

ROW_FORMAT=DYNAMIC

ROW_FORMAT=COMPRESSED

 

這兩者主要是功能上的區別功能上的。 另外在行裏的變長字段和Antelope的區別是隻存20個字節,其它的overflow page存儲。

另外這兩都需要開啓innodb_file_per_table=1

(這個特性對一些優化還是很有用的)

重啓數據庫

然後需要修改問題所在表的行格式,然而,到底是哪張表出問題了呢?

沒辦法,開始翻看sonarqube的源碼https://github.com/SonarSource/sonarqube

終於找到了

  public void insert(DbSession dbSession, String taskUuid, InputStream data) {
    long now = system.now();
    Connection connection = dbSession.getConnection();
    try (PreparedStatement stmt = connection.prepareStatement(
      "INSERT INTO ce_task_input (task_uuid, created_at, updated_at, input_data) VALUES (?, ?, ?, ?)")) {
      stmt.setString(1, taskUuid);
      stmt.setLong(2, now);
      stmt.setLong(3, now);
      stmt.setBinaryStream(4, data);
      stmt.executeUpdate();
      connection.commit();
    } catch (SQLException e) {
      throw new IllegalStateException("Fail to insert data of CE task " + taskUuid, e);
    }
  }

問題所在的表就是 ce_task_input,於是執行SQL

DROP TABLE ce_task_input;
      
CREATE TABLE `ce_task_input` (
  `task_uuid` VARCHAR(40) COLLATE utf8_bin NOT NULL,
  `input_data` LONGBLOB,
  `created_at` BIGINT(20) NOT NULL,
  `updated_at` BIGINT(20) NOT NULL,
  PRIMARY KEY (`task_uuid`)
) ENGINE=INNODB DEFAULT CHARSET=utf8 COLLATE=utf8_bin ROW_FORMAT=DYNAMIC;

這個時候已經晚上7點多了,同事已經要放棄了,叫我別折騰了,我說弄好了,這次肯定能成,然後讓他跟我一起見證奇蹟。

接着在大家的注視下,我執行了掃描命令,然而這次讓我更加尷尬了,還是500,錯誤日誌變了

Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Row size too large (> 8126). Changing some columns to TEXT or BLOB may help. In current row format, BLOB prefix of 0 bytes is stored inline.

字面上的意思是讓我把某些字段改成TEXT或者BLOB……WTF?特麼就這4個字段,還有啥好改的

同事已經回家了,我已經忘記了晚飯的事,開始繼續折騰……

谷歌,百度各種搜索,各種查,基本都是說上面的改innodb文件類型的方案,完全沒有用……不知不覺就快9點了,家裏的電腦壞了,兒子學不了英語,老婆火氣特別大,趕緊關電腦回家。

今天早上剛到公司,繼續磕mysql論壇,突然看到有人說設置innodb_log_file_size,日誌文件大小,突然想到,sql日誌裏面是包含完整的sql內容的,日誌文件大小也可能影響插入。

趕緊查一下,默認的sql日誌文件是500M,果斷改成1G

[mysqld]

#服務器發送和接受的最大包長度,當單行數據較大時,需要調整該參數。

max_allowed_packet = 100M 

#開啓page獨立空間

innodb_file_per_table = 1

#innodb的文件格式更改爲Barracuda
innodb_file_format = Barracuda

#日誌文件大小

innodb_log_file_size=1024M 

重啓mysql,開始掃描,10分鐘過去,終於成功了!

INFO: Analysis report generated in 5163ms, dir size=86 MB

INFO: Analysis reports compressed in 8786ms, zip size=28 MB

INFO: Analysis report uploaded in 2366ms INFO: ANALYSIS SUCCESSFUL, you can browse http://192.168.95.45:9000/dashboard/index/ly.mp:dfcwpc

INFO: Note that you will be able to access the updated dashboard once the server has processed the submitted analysis report

INFO: More about the report processing at http://192.168.95.45:9000/api/ce/task?id=AWmVAuVJVEKL64HKj-4e INFO: Task total time: 6:23.107 s

INFO: ------------------------------------------------------------------------

INFO: EXECUTION SUCCESS

INFO: ------------------------------------------------------------------------

INFO: Total time: 6:24.156s INFO: Final Memory: 24M/1434M

INFO: ------------------------------------------------------------------------ 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章