简介SonarQube 7.4 面向软件开发团队、代码质量管理与静态扫描实践者是一款用于多语言项目漏洞、代码异味和复杂度分析的开源工具安装包支持 Java、Python、C#、JavaScript 等语言可服务本地质量检测环境搭建、历史版本研究及持续集成质量门禁验证也适合需要复现旧版行为、测试插件兼容性或准备教学演示环境的人员对中小团队建立代码质量基线、梳理技术债务亦有参考意义。RAR 压缩包约 161.38MB文件总数及类型明细暂无从包体组成看涵盖启动脚本、核心配置、插件扩展、运行库、Web 前端资源与说明文档等模块便于按配置、扩展和运行环境分层查阅。已有 643 人学习或下载具备一定社区关注度。其价值在于提供较完整的 7.4 版本分发内容可用于离线部署、插件适配和规则分析实践也方便与 Jenkins、GitLab CI/CD 等工具联动验证代码质量检查流程为团队排查质量问题和降低维护成本提供参考。1. sonarqube-7.4 这个包到底解决什么问题接手一个跑了三年的老系统交接文档只有一句“代码质量看板在 9000 端口”。点开一看SonarQube 7.4 还跑着规则库停在两年前覆盖率永远是 0。sonarqube-7.4 这个包真正的价值不在版本新旧而在于它是一套可以完全离线部署的静态代码分析平台自带 Elasticsearch、规则引擎、Web 看板和技术债统计一台 4 核 8G 的机器就能撑住几十万行代码。sonar 这套体系之所以在内网还有生命力是因为很多团队不愿意把源码结构和缺陷清单一并上传到外部服务。适合需要本地保存历史快照、想做质量卡点又不想改动技术栈的团队。下面按部署、接入、质量门禁、避坑、升级五段拆。2. 部署 sonarqube-7.4JVM、数据库、内核参数三件事sonarqube-7.4 的安装包解压完只有 200MB 左右看起来一副“解压即用”的样子实际上直接sonar.sh start之后三秒退出的情况非常普遍。原因不复杂7.x 开始它把 Elasticsearch 内嵌进来了Web、Compute Engine、Search 三个组件由同一个启动脚本拉起任何一个的环境检查不过整个实例就起不来。这一章把启动链路拆开说清每个参数动了会发生什么。2.1 为什么 7.4 的启动失败大多死在 Java 和数据库上先看进程结构。执行sonar.sh start后脚本会依次拉起三个 JVMWeb 进程负责 HTTP 和 API默认监听 9000Compute Engine 负责把扫描上报的原始数据算成指标也就是常说的“报告一直 Pending”就是它没跑完Search 进程就是内嵌的 Elasticsearch负责看板上的检索和聚合。三者共用conf/sonar.properties但各自有独立的内存参数和日志文件logs/web.log、logs/ce.log、logs/es.log排错时必须分开看只盯sonar.log会漏掉真正的报错。Java 版本是第一个门槛。7.4 的服务端和 Scanner 都跑在 JDK 8 上java -version出来是 1.8.0_xxx 才算合格。机器上装了 JDK 11 并且JAVA_HOME指向它症状往往是启动脚本一闪而过或者 Web 起来了但访问 502日志里出现Unsupported class file major version。我一般会在conf/wrapper.conf里显式钉死wrapper.java.command/usr/local/jdk8/bin/java不让它去猜 PATH这比改全局环境变量稳妥得多尤其在同一台机器上还有别的服务跑 JDK 11 的时候。第二个门槛是数据库。7.4 内嵌的 H2 只用于试用日志里会明确提示Embedded database is not supported for production一旦并发上去或者数据量超过几百 MB经常出现锁表、看板打不开。正式环境必须换外部库。官方支持的组合里PostgreSQL 9.6/10 是最省心的MySQL 5.6/5.7 也能用但要盯两件事库的字符集必须是 utf8不是 utf8mb4以及 5.7 默认的sql_mode含ONLY_FULL_GROUP_BY时部分统计查询会直接报错通常由 DBA 给 sonar 这个库单独放开该选项。MySQL 8.0 在 7.4 上不是稳妥选项驱动和语法差异带来的坑足以让人放弃能换 PostgreSQL 就换。2.2 sonar.properties 里必须改的六个参数解压后进conf/sonar.properties文件里每一项都有注释但默认全是注释掉的。真正需要动的就下面这些其余保持默认即可。# 数据库连接PostgreSQL 示例库名和账号由 DBA 预建 sonar.jdbc.urljdbc:postgresql://10.0.0.21:5432/sonar sonar.jdbc.usernamesonar sonar.jdbc.password改成你的密码 # 连接池几十人团队默认 60 够用扫描高峰期可调到 80 sonar.jdbc.maxActive60 # Web 进程内存4C8G 机器给 1G 起步项目多、看板查询重时给 2G sonar.web.javaOpts-Xmx1G -Xms512m -XX:HeapDumpOnOutOfMemoryError -XX:HeapDumpPath/data/sonar/dump # Compute Engine 内存这是最容易被忽略的一项 sonar.ce.javaOpts-Xmx1G -Xms512m -XX:HeapDumpOnOutOfMemoryError # 内嵌 Elasticsearch 内存官方建议不超过 2G且不超过物理内存一半 sonar.search.javaOpts-Xmx512m -Xms512m # 数据与日志落盘位置别放在解压目录里升级时会覆盖 sonar.path.data/data/sonar/data sonar.path.logs/data/sonar/logs sonar.path.temp/data/sonar/tempsonar.web.javaOpts和sonar.ce.javaOpts分开配是这套部署里最值得强调的一点。很多环境 Web 给到 2G 却让 CE 用默认的 512m结果大批量项目并发扫描时任务是排队状态点进去显示 Pendingce.log里能看到 OOM 或者 GC 频繁人却一直以为是数据库慢。CE 的内存跟“一次性要处理多少个项目的报告”正相关CI 高峰期同时提交三四个扫描任务时1G 是底线。sonar.path.data必须落在独立分区或者至少独立目录上因为这个目录里既有数据库的补丁记录也有es5索引数据。升级时新版本会往data目录里写新 schema回滚靠的就是这个目录的备份放在解压目录下等于把备份和数据一起覆盖掉。临时目录同理sonar.path.temp在分析大项目时会有几百 MB 的临时文件放在/tmp被系统清理策略盯上就会莫名其妙分析中断。如果要把看板挂到已有域名的子路径下比如http://tools.internal/sonar再补一项sonar.web.context/sonar。这个参数改完要重启且已经在用的项目配置里的sonar.host.url都要跟着改否则 Scanner 上报会 404。第一次部署时若不确定就别加后面改的成本比一开始就规划好要高。2.3 首次启动与自检从内核参数到 /api/system/status参数配好之后先别急着 start把系统层的东西处理掉能省下后面至少半天。# 1. 专用用户Elasticsearch 拒绝以 root 身份启动 useradd -r -s /sbin/nologin sonar chown -R sonar:sonar /opt/sonarqube-7.4 /data/sonar # 2. vm.max_map_count 是 ES 的 bootstrap check 硬指标 sysctl -w vm.max_map_count262144 echo vm.max_map_count262144 /etc/sysctl.conf # 3. 文件描述符与进程数写进 limits.conf 永久生效 echo sonar - nofile 65536 /etc/security/limits.conf echo sonar - nproc 4096 /etc/security/limits.conf # 4. 用 sonar 用户启动首次建议用 console 模式看完整输出 su - sonar -c /opt/sonarqube-7.4/bin/linux-x86_64/sonar.sh consolesysctl -w只是临时生效重启机器就没了所以必须落到/etc/sysctl.conf。这一项漏掉的典型表现是sonar.sh start显示 started但 9000 端口死活连不上es.log里写着max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144]。整段日志在sonar.log里是看不到的这也是很多人第一次部署卡住的地方。console模式会前台输出第一次启动务必用它看到SonarQube is up再CtrlC换成start后台跑。启动完成后做三项自检# 看服务状态返回 UP 才代表三个进程都健康 curl -s -u admin:admin http://127.0.0.1:9000/api/system/status # 确认没有退化到内嵌数据库 grep -i embedded database /data/sonar/logs/sonar.log # 看 Compute Engine 是否正常起来了 curl -s -u admin:admin http://127.0.0.1:9000/api/ce/activity_status/api/system/status返回的是整体状态UP之外还会出现STARTING和DB_MIGRATION_NEEDED。看到DB_MIGRATION_NEEDED说明数据库版本比程序新通常是回滚过二进制包但没恢复数据库备份别硬启先恢复备份。/api/ce/activity_status会返回pending、inProgress、failing三个计数如果failing一直涨基本就是 CE 内存不够或者某个项目的报告数据有问题。第一件事是改掉 admin 默认密码第二件事是去 Marketplace 装中文语言包7.x 时代的中文包是社区维护的装完重启生效第三件是创建专用分析账号而不是一直用 admin 的 token。这三步做完平台侧就基本可用了剩下的工作全在“怎么让项目接进来”。3. 接入第一个项目sonar-scanner 与 Maven 两条路平台起来只是空壳真正决定这套东西好不好用的是接入方式。sonar 的接入原则很统一无论什么语言最终都是把一个叫sonar-project.properties的配置或者等价的命令行参数交给 ScannerScanner 采集源码和报告打包上报给服务端。差别只在于是手工调 Scanner还是让构建工具帮你调。3.1 Scanner 方式sonar-project.properties 逐项拆解Scanner 是独立分发包下载解压后bin/sonar-scanner即可用前提是 JDK 8。适合前端、Python、Go 这类没有强构建体系的栈也适合把分析从 CI 里单独剥出来跑的场景。# 项目唯一标识一旦定下不要再改改了等于新建项目历史全部丢失 sonar.projectKeyorder-center sonar.projectName订单中心 sonar.projectVersion2.3.0 # 源码根目录多个模块用逗号分隔相对路径以本文件所在目录为基准 sonar.sourcessrc/main/java sonar.testssrc/test/java # 源码编码Windows 上开发的项目不写这行会先给你几百个编码类缺陷 sonar.sourceEncodingUTF-8 # 排除规则第三方代码、生成代码、前端产物一律排掉 sonar.exclusions**/generated/**,**/node_modules/**,**/dist/** # 覆盖率与单测报告的导入路径 sonar.coverage.jacoco.xmlReportPathstarget/site/jacoco/jacoco.xml sonar.junit.reportPathstarget/surefire-reports几个参数的实际影响值得说清楚。sonar.projectKey是服务端的唯一键命名只允许字母、数字和-_.:且不能以数字开头。改 key 的后果不是“重命名”而是所有历史、质量门禁状态、技术债曲线都断掉所以项目多的时候我一般按“业务域-服务名”统一规范比如trade-order-center避免后期撞名。sonar.exclusions支持的语法是 Ant 风格通配**跨目录、*单层。这里最容易踩的是把生成的 mapper 或者 protobuf 产物算进去重复率指标立刻爆表然后团队开始怀疑工具不准。生成代码的正确处理是排掉不是加//NOSONAR注释去压。sonar.coverage.jacoco.xmlReportPaths指向的是 JaCoCo 的 XML 报告不是.exec二进制文件。7.4 配套的 Java 插件版本已经不再推荐二进制格式很多人从老教程抄来sonar.jacoco.reportPaths配完覆盖率永远是横杠就是这个原因。Scanner 的调用方式# 先取一个 token别把账号密码写进 CI 脚本 curl -s -u admin:admin -X POST \ http://127.0.0.1:9000/api/user_tokens/generate?nameci-order-center \ | python -c import sys,json;print(json.load(sys.stdin)[token]) # 用 token 跑分析-D 参数优先级高于配置文件 sonar-scanner \ -Dsonar.host.urlhttp://127.0.0.1:9000 \ -Dsonar.login上一步拿到的token \ -Dsonar.projectVersion$(git rev-parse --short HEAD)sonar.login用 token 而不是用户名密码这是必须遵守的底线因为 token 可以单独吊销且不泄露账号。sonar.projectVersion在 CI 里传 Git 短哈希是个好习惯服务端的事件时间线上能看到每次分析对应的提交出问题回溯非常直观。3.2 Maven 与 Gradle把分析挂进构建生命周期Java 项目基本都走构建工具插件好处是 classpath、依赖、编译产物全都现成不用手写一堆路径。!-- pom.xml 里固定插件版本不要靠 latestCI 上版本漂移是灾难 -- plugin groupIdorg.sonarsource.scanner.maven/groupId artifactIdsonar-maven-plugin/artifactId version3.6.0.1398/version /plugin properties sonar.host.urlhttp://127.0.0.1:9000/sonar.host.url sonar.coverage.jacoco.xmlReportPaths ${project.build.directory}/site/jacoco/jacoco.xml /sonar.coverage.jacoco.xmlReportPaths /properties# 关键点先 verify 再 sonarjacoco 报告要有字节码也要有 mvn -B clean verify sonar:sonar \ -Dsonar.login$SONAR_TOKEN \ -Dsonar.projectKeytrade-order-center # Gradle 侧2.x 插件写法在 build.gradle 里配置 # plugins { id org.sonarqube version 2.7 } # sonarqube { properties { property sonar.host.url, http://127.0.0.1:9000 } } gradle clean build sonarqube -Dsonar.login$SONAR_TOKENmvn clean verify sonar:sonar中verify不能省也不要用mvn sonar:sonar单独跑。原因是 Java 分析需要字节码插件会去target/classes找只有sonar:sonar而没编译时分析会直接失败并提示Please provide compiled classes of your project with sonar.java.binaries property。这个提示本身就是答案要么加compile要么在手工场景下显式指定sonar.java.binariestarget/classes和sonar.java.test.binariestarget/test-classes。多模块项目里路径是列表漏写子模块就会漏分析最终表现为“某个 module 零缺陷”很容易被当成好消息。Maven 多模块还需要注意sonar.modules在新版 Java 插件里已经不需要手写插件会自动根据 pom 结构拆分。如果手工写了sonar.modules又和实际模块对不上症状是分析报Module ... not found或者模块被合并到一个项目里指标全糊在一起。3.3 覆盖率与单测报告不要让 0% 变成常态覆盖率是质量门禁里最容易失守的指标因为它的失败往往是静默的。JaCoCo 与 sonar 的对接要点只有三个版本对得上、报告确实生成了、路径写对了。!-- jacoco 的 prepare-agent 必须挂到 surefire 之前否则 exec 文件是空的 -- plugin groupIdorg.jacoco/groupId artifactIdjacoco-maven-plugin/artifactId version0.8.2/version executions executiongoalsgoalprepare-agent/goal/goals/execution execution idreport/id phaseverify/phase goalsgoalreport/goal/goals !-- 必须生成 xmlhtml 报告 sonar 读不了 -- configurationformatsformatXML/format/formats/configuration /execution /executions /plugin验证方式很直接跑完mvn verify之后target/site/jacoco/jacoco.xml必须存在且大小不为 0再去服务端看项目概览里的 Coverage。如果 XML 在但服务端是横杠就是sonar.coverage.jacoco.xmlReportPaths的路径问题如果是 0.0%那是 XML 里本身没数据问题在测试没跑或者 agent 没挂上跟 sonar 无关。还有一种常见情况覆盖率数字比本地 IDE 里低一截。这通常是 exclusions 没配好测试类被算进了“可覆盖代码”。正确做法是让sonar.tests明确指向测试目录同时把 DTO、常量类、自动生成的代码放进sonar.coverage.exclusions指标才反映真实的有效覆盖。4. 质量门禁与规则配置让 sonarqube-7.4 真正挡住人装完不配门禁这套平台三个月内必然沦为“没人看的看板”。7.4 的门禁体系分两层Quality Gate 决定“合不合得过”Quality Profile 决定“用哪些规则查”。两层都配对了才能把分析结果变成流水线里一个会失败的步骤。4.1 Quality Gate 的判定逻辑与 API 取值Quality Gate 的本质是一组“指标 比较符 阈值”的条件集合且 7.x 已经全面转向“新代码”模式门禁只盯本次提交引入的问题历史存量不参与判定。这一点很重要否则老项目第一次接入就是几千个缺陷门禁永远红着团队很快就会要求关掉。# 建一个门禁新代码覆盖率低于 70% 直接失败 curl -s -u admin:admin -X POST \ http://127.0.0.1:9000/api/qualitygates/create?nameJava-Standard # 拿到 gateId 后加条件op 可用 LT / GTerror 是阈值 curl -s -u admin:admin -X POST \ http://127.0.0.1:9000/api/qualitygates/create_condition?gateId1metricnew_coverageopLTerror70 curl -s -u admin:admin -X POST \ http://127.0.0.1:9000/api/qualitygates/create_condition?gateId1metricnew_bugsopGTerror0 curl -s -u admin:admin -X POST \ http://127.0.0.1:9000/api/qualitygates/create_condition?gateId1metricnew_duplicated_lines_densityopGTerror3 # 把门禁绑到项目上 curl -s -u admin:admin -X POST \ http://127.0.0.1:9000/api/qualitygates/select?gateId1projectKeytrade-order-centernew_bugs的error0意味着新代码里只要引入一个 bug 级别问题就红团队初期可以放宽到 12跑稳了再收紧。new_duplicated_lines_density设 3 是比较务实的值Java 项目里实体的 getter/setter、异常分支很容易重复卡到 1 会让大量正常提交被拦。new_coverage用 70 而不是 80是留给“本次提交主要是改配置和文档”这类情况的缓冲。CI 里判断门禁结果用/api/qualitygates/project_status# ceTaskId 从 scanner 输出里拿或直接查最近一次分析 curl -s -u $SONAR_TOKEN: \ http://127.0.0.1:9000/api/qualitygates/project_status?projectKeytrade-order-center \ | python -c import sys,json djson.load(sys.stdin)[projectStatus] print(d[status]) for c in d.get(conditions,[]): if c[status]!OK: print(FAIL:, c[metricKey], actual, c.get(actualValue), threshold, c.get(errorThreshold)) 这段脚本的用处是把“哪个条件没过、实际值多少”打出来。只打印ERROR的话开发看到红色但不知道为什么红沟通成本立刻上去。actualValue在覆盖率这类百分比指标上是数字字符串别直接做数值比较容易踩到类型问题。4.2 规则与质量配置从 Sonar way 复制而不是直接改Quality Profile 是规则集合。7.4 自带Sonar way直接改它是最常见的错误做法因为插件升级时内置配置会被重置改了半天全白费。正确做法是Copy一份命名为Java-内部规范在副本上加规则、调参数然后把项目绑到副本上。常见需要动的几类规则把Cognitive Complexity of methods should not be too high的阈值从默认 15 调到 20老系统的长方法太多了卡 15 会淹没真正的问题把String literals should not be duplicated从 Blocker 降到 Major否则日志里的固定文案会刷屏关掉对测试代码的重复率检测测试方法名长是常态。7.4 还支持自定义 XPath 规则基于 SSLR 语法树适合写内部框架的约束比如“禁止在 Controller 层直接调用 DAO”“禁止使用某个已废弃的工具类”。做法是在 Java 插件提供的模板规则上新建填 XPath 表达式然后在 Profile 里激活。这条路能用但不要指望它做复杂语义分析XPath 只能看到语法树拿不到类型信息和控制流把复杂的架构约束压给它规则会误报得没法用。团队里更实际的做法是把这类约束交给单元测试或 ArchUnit 之类的工具sonar 只负责已经内置的那一千多条规则。4.3 新代码周期7.4 里叫 Leak Period这是门禁能不能落地的关键设置。7.4 的界面里叫 Leak Period配置粒度是项目级可选previous_version、previous_analysis、daysN、dateYYYY-MM-DD四种取值语义适用场景previous_version与上一个版本比较有明确版本号的发布制项目previous_analysis与上一次分析比较每次提交都触发分析的 CI 项目daysN最近 N 天内没有固定版本的持续迭代项目date某个固定日期之后规范推行日切分历史包袱previous_analysis是最严格也最有效的它让“新代码”等于“这次提交”配合 CI 每次 PR 触发分析门禁就变成了真正的合入卡点。代价是要求扫描足够频繁、足够稳定否则一次失败的分析会导致下次比较基准错位。days30适合还没上 CI、靠定时任务每天跑一次的团队先用滚动窗口把存量隔离开。一个容易忽略的细节切换 Leak Period 方式之后门禁结果会立刻变化历史曲线也会断点。所以切换动作本身应该在团队内公告最好挑版本发布后做避免开发以为是自己代码出了问题。5. 避坑sonarqube-7.4 上线后最常见的五类排查下面这几条都来自真实环境里反复出现的场景现象、原因、解决三件套照着对能省掉大量“重启试试”的时间。5.1 启动与环境两个占坑率最高的硬门槛现象一sonar.sh start返回 started但 9000 端口连不上sonar.log里没有任何明显错误es.log里写着can not run elasticsearch as root。原因内嵌 Elasticsearch 出于安全策略拒绝以 root 用户启动而很多部署脚本图省事直接用 root 执行sonar.sh脚本本身不报错Search 进程静默退出Web 因为没有后端检索也就起不来。解决建专用账号整个目录chown给它长期用su - sonar -c ...sonar.sh start或 systemd 的Usersonar。不要用ES_JAVA_OPTS之类的环境变量去绕过检查那是把问题藏起来。现象二非 root 启动后es.log报max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144]进程反复重启。原因Elasticsearch 5.x 的 bootstrap check 会在启动时校验vm.max_map_count容器化和最小化安装的系统默认值是 65530不够用。解决sysctl -w vm.max_map_count262144并写入/etc/sysctl.conf。如果跑在容器里需要在宿主机上设容器内设不生效同时确认ulimit -n至少 65536否则下一轮会换成文件描述符报错。5.2 分析结果看着成功其实什么都没算现象三Java 项目扫描显示ANALYSIS SUCCESSFUL但项目里 Bug、漏洞全是 0代码行数也对得上。原因只执行了mvn sonar:sonar而没有先编译Java 分析器拿不到字节码只能做语法层面的检查语义规则全部跳过。这在日志里有一条Please provide compiled classes of your project with sonar.java.binaries property的警告很容易被淹没在几百行输出里。解决改成mvn clean verify sonar:sonar确实只想分析不编译时显式传-Dsonar.java.binariestarget/classes -Dsonar.java.test.binariestarget/test-classes。多模块项目要确认每个子模块的路径都被覆盖别用一个大而全的路径糊过去。现象四jacoco.xml明明生成了服务端覆盖率还是横杠或者 0.0%。原因有两层一是用了已废弃的sonar.jacoco.reportPaths配二进制.exec文件7.4 配套的 Java 插件已经不支持这种格式二是sonar.coverage.jacoco.xmlReportPaths写成了相对于仓库根目录的路径但 Scanner 的工作目录不在根目录导致文件找不到且不报错。解决统一换成 XML 报告 sonar.coverage.jacoco.xmlReportPaths路径优先用构建工具变量如${project.build.directory}而不是硬编码相对路径。排查时先手工确认 XML 里有counter typeLINE数据再去看服务端。5.3 运行期任务一直 Pending 的真凶现象五扫描早就结束了页面上的分析任务一直是 Pendingce.log里出现index [analysis] blocked by: [FORBIDDEN/12/index read-only之类的内容。原因内嵌 Elasticsearch 的磁盘水位保护被触发。默认低水位 85%、高水位 95%一旦数据目录所在分区超过高水位索引会被置为只读Compute Engine 写入失败任务就永远排队。这个报错藏在es.log里从 Web 界面完全看不出来。解决先清磁盘或扩容然后手动解除只读PUT _settings把index.blocks.read_only_allow_delete置为 false再重启服务让积压的任务重跑。长期方案是把sonar.path.data放到独立分区并加磁盘监控阈值设在 80% 报警——等它自己触发只读就晚了。另外提醒一句7.4 社区版不支持分支分析。多个分支用同一个sonar.projectKey提交结果是互相覆盖看到“缺陷数忽高忽低”别怀疑工具先看 key 是不是重了。需要分支隔离只能靠不同 key 模拟或者上商业版。6. 升级与长期维护从 7.4 走向 7.9 LTS 的路径7.4 不是 LTS长期停在这个版本上的问题是插件生态和安全补丁都停了。真要往上走目标应该是 7.9 LTS但这条路有个硬拐点7.9 彻底移除了 MySQL 支持。也就是说7.4 MySQL 的组合必须先迁到 PostgreSQL 才能升级这一步不能跳过。我的顺序是这样的先在 7.4 上完成数据库迁移用 PostgreSQL 建库、导出导入、改sonar.jdbc.url、启动验证、重跑一次全量分析确认指标一致再备份data目录和数据库然后停止服务、替换二进制包、保留原conf与data、启动、观察web.log里的 schema 迁移日志最后用/api/system/status和/api/ce/activity_status双确认。检查项迁移后要看什么不合格的表现数据库sonar.jdbc.url指向新库schema 迁移日志无 ERROR启动即DB_MIGRATION_NEEDED数据目录data/es5保留完整权限归属 sonar 用户看板空白、检索报错插件旧插件与目标版本兼容不兼容的先卸载Web 启动卡住、类冲突扫描链路用同一份代码重跑缺陷数与升级前对比数量级差异说明规则集变了CI 凭据token 是否仍有效sonar.host.url是否变更401 或 404重跑对比这一步别省。升级会带来插件和规则集变化缺陷数从 800 跳到 1500 是正常的新规则上线但如果从 800 跳到 80基本说明某类规则没加载或者字节码没读到别急着庆祝质量提升。我当时就吃过这个亏升级后指标一片大好两天后才发现 Java 插件没装全语义规则全没跑。从那以后我每次升级都强制走一遍“同代码双跑对比”把升级前后的指标快照存成两份 JSON逐项 diff 完才允许生产环境接 CI。希望帮到你。本文还有配套的精品资源点击获取