Logo
性能优化常用策略

性能优化常用策略 #

简介 #

DBPlusEngine 本身在代码、参数等方面已对通用场景的性能进行过大量优化,默认参数的情况下启动 DBPlusEngine 即可达到较优性能。对性能要求更高的用户,可以针对场景、环境进行进一步的优化。

Java 相关优化 #

Java 版本 #

目前 DBPlusEngine 最低支持 Java 8。截至本文编写,最新的 LTS(Long term support,长期支持版本) 为 Java 17。

新版本的 Java 相比旧版本 Java 在 JDK 类库、JIT、GC 等方面会有一定的性能提升。

JVM 参数 #

设置合适的 -Xmx #

JVM 堆内存参数需要结合业务与环境设置,不能太小也不宜过大。堆内存太小可能会导致 GC 次数增加,堆内存过大可能会增加 GC 停顿时长,具体表现为某些 SQL 的执行延时增加。

对于 OLTP 场景,在所有 SQL 都能够下推到数据库执行的情况下,堆内存一般不超过 16 GB。

对于使用联邦查询的场景,由于部分计算需要在 DBPlusEngine 进程的内存中进行,堆内存可以根据实际数据量适当增加,避免发生 OOM。

-Xss 设置 #

-Xss 在一般场景下无须专门设置。以下情况可能需要考虑调整:

  • 使用 jOOQ

在 jOOQ 类加载过程中,类加载相关调用栈会比较深,-Xss 过小(例如少于 512k)可能会发生 java.lang.StackOverflowError,一般 -Xss 不小于 1m 即可。

  • SQL 特别长或参数特别多

当 SQL 较长或参数非常多时,SQL 解析可能会存在较深的调用栈。例如以下 SQL:

insert into some_table values (1,'foo'), (2,'bar'), ..., (100000,'baz')

在 values 数量非常多的情况下,SQL 解析所需的调用栈会比较深,此时如果 -Xss 过小就可能会发生java.lang.StackOverflowError。

-XX:+AggressiveHeap #

适用于:Java 10 及更高版本

启用该选项,JVM 会为长时间运行的内存密集型应用程序优化堆,在高并发场景对 DBPlusEngine 性能提升有帮助。

NUMA 环境相关参数 #

-XX:+UseNUMA #

在 NUMA 环境下,使用该参数可以优化 JVM 的内存分配。由于 JVM 会启动时会检测当前是否 NUMA 环境,即使在非 NUMA 环境下启动了该参数,也不会产生任何影响。

JIT 相关参数 #

-XX:+SegmentedCodeCache #

适用于:Java 9 及更高版本

该参数会启用分段代码缓存,对 DBPlusEngine 性能提升有帮助。

-XX:+UseJVMCICompiler #

适用于:OpenJDK 11

使用 JVMCI 作为默认编译器。启用该选项对 DBPlusEngine 性能峰值有提升效果。

使用该参数要求先启用以下参数:

-XX:+UnlockExperimentalVMOptions

DBPlusEngine 优化 #

DBPlusEngine 参数优化 #

max-connections-size-per-query #

默认值:1

该参数控制每次执行查询时,在每个数据源上允许获取的最大连接数量。当存在路由到多库/多表的查询请求时,适当增加该参数可以提高查询的并发执行度。

proxy-backend-query-fetch-size #

适用于:Proxy

默认值:-1。

该参数控制 Proxy 向存储节点查询数据时,每次网络交互所传输的数据行数。

使用默认值 -1 的情况下,Proxy 向 MySQL 存储节点查询数据时会尽量使用流式查询,能够减少 Proxy 内存使用,避免在结果集非常大的情况下发生 OOM。

如果结果集行数可控,可以适当增加该参数,可能会减少 Proxy 与数据库的交互次数以减少 SQL 执行延时,但会增加 Proxy 的内存使用。

proxy-frontend-executor-size #

适用于:Proxy

该参数控制 Proxy 中 Netty 的线程数量,默认值为 Proxy 所在 JVM 进程可用的逻辑 CPU 数量 * 2。

在 Proxy 承受一定负载的情况下,通过 top -H 可以查看 JVM 中线程的资源使用情况。其中,命名以 epollEventLoopGroup 为前缀的线程是 Netty 线程。

在 Proxy 吞吐量达到瓶颈的情况下:如果 Netty 线程的平均 CPU 使用率较低,可以适当减少线程数量,以减少线程切换等存在性能开销的情况;反之,则需要适当增加线程数量,以增加网络 I/O 处理能力。

DBPlusEngine 第三方依赖参数优化 #

关闭 Netty 泄漏检测 #

适用于:Proxy

Netty 具备泄漏检测能力,存在 4 种检测等级:

  • DISABLED:关闭。
  • SIMPLE:(默认)简单采样,对性能开销较小。
  • ADVANCED:在简单采样的基础上,同时记录泄漏资源的近期访问代码路径,开销会相对较大。
  • PARANOID:(仅适用于测试)检测所有资源是否存在泄漏,性能开销非常大。

Netty 泄漏检测默认是 SIMPLE 级别,性能开销较低。

但对于稳定版本的 Proxy,可以完全关闭泄漏检测以消除泄漏检测逻辑自身的性能开销。

-Dio.netty.leakDetection.level=DISABLED

DBPlusEngine Proxy 客户端优化 #

MySQL Connector/J 参数建议 #

启用 Server 端 Prepared Statement #

参数名MySQL Connector/J 默认值连接 DBPlusEngine Proxy 建议值描述
cachePrepStmtstruetrue在驱动内部缓存 Prepared Statement。
useServerPrepStmtsfalsetrue使用服务端 Prepared Statement。
prepStmtCacheSize258192驱动内部每个数据库连接的 Prepared Statement 缓存大小。
prepStmtCacheSqlLimit2562048允许缓存的 SQL 语句长度限制。

在 DBPlusEngine Proxy 内部会对 Server 端 Prepared Statement 的语句进行 SQL 解析、SQL 上下文进行缓存,能够减少 SQL 执行的开销与延时。

TCP 缓冲区配置 #

默认情况下,MySQL Connector/J 的 TCP 缓冲区会使用操作系统的默认值。如果需要调整为特定的值,可以通过以下两个参数配置。

  • tcpRcvBuf
  • tcpSndBuf

合并批量操作 #

当使用 PreparedStatement 的 addBatch/executeBatch 等方法时,由于 MySQL 协议本身的局限性,批量操作无法直接通过 MySQL 协议实现。可以通过以下参数启用 MySQL Connector/J 的批量操作改写:

  • rewriteBatchedStatements=true
  • allowMultiQueries=false(MySQL Connector/J 默认值)

当开启批量操作改写后:

  • insert SQL 会自动被改写成多组 values 的形式;
  • update/delete 语句会自动改写成多语句的形式。

DBPlusEngine Proxy 内部会自动识别 MySQL COM_SET_OPTIONS 指令,因此使用批量操作的同时需要保持 allowMultiQueries=false 参数设置。

避免长时间网络等待 #

可以通过设置 socketTimeout 减少异常连接的等待时间,建议最小设置为 SQL 最大执行时间加上一个 RTT (Round-Trip Time),实际业务场景考虑网络波动和数据库高峰压力需要设的大一些。

PostgreSQL/openGauss JDBC Driver 参数建议 #

TCP 缓冲区配置 #

默认情况下,PostgreSQL/openGauss JDBC Driver 的 TCP 缓冲区会使用操作系统的默认值。如果需要调整为特定的值,可以通过以下两个参数配置。

  • receiveBufferSize
  • sendBufferSize

环境优化 #

CPU 亲和性 #

在一些用户环境下,机器上某些 CPU 核心可能有专门用途。

例如在某 128 核的环境下,CPU 0-15 核被专门用于处理网络中断,此时如果 DBPlusEngine 在所有 CPU 上运行,网络处理能力、DBPlusEngine 最大吞吐量可能会受到影响。

此时可以为 DBPlusEngine 所在 JVM 执行可用的 CPU。例如,使用 numactl,指定 CPU 16-127 核可用于 DBPlusEngine,则将启动命令修改为:

numactl -C 16-127 java ...# 省略其他参数

排除网卡性能瓶颈 #

DBPlusEngine 属于网络 I/O 密集的应用,尤其是 Proxy,会同时与数据库客户端、存储节点交互,网络收发频繁。此时需要避免网络中断的处理成为 DBPlusEngine 的性能瓶颈,尤其在网卡队列较少的情况下,网卡中断处理达到瓶颈会限制 DBPlusEngine 的最大吞吐量。

如果网卡只有单队列,网络中断处理达到上限(通常表现是某个 CPU 核心的 hi/si 使用率接近 100%,其他 CPU 核心使用率相对较低),可以考虑通过启用 irqbalance 等方式在多个 CPU 核心分摊网络中断处理。

场景建议 #

为分片键配置索引 #

在数据分片场景下,分片键如果不是主键,建议增加索引,以减少通过分片键为条件的 SQL 执行延时。

分页修正与分页查询优化 #

对于能够路由到单库/单表的分页查询 SQL,DBPlusEngine 会直接将 SQL 下推到存储节点执行。

当分页查询的 SQL 路由到多个库或者多个表时,为确保查询的正确性,DBPlusEngine 会对语句的分页参数进行改写。尤其在大偏移量查询的情况下,经过分页修正的 SQL 查询效率会明显降低。对于可能涉及大偏移量查询的情况,建议不使用 LIMIT 方式进行分页。可以考虑构建行记录数量与行偏移量的二级索引、使用上次分页数据结尾 ID 作为下次查询条件的等分页方式,避免 SQL 执行延时过高。

避免在 SQL 中包含不需要的数据 #

用户在编写 SQL 时,建议精准控制所需的列、查询条件,可以有效减少 SQL 执行开销、网络 I/O 开销。与传统直接连接数据库情况相比,DBPlusEngine Proxy 的网络拓扑更为复杂,传输不必要的数据所带来的网络 I/O 开销会更明显。