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: ------------------------------------------------------------------------ 

 

 

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值