本文介绍在高并发场景下,如何通过 DashScope Java SDK 高效调用 Sambert 语音合成服务。
Sambert 语音合成服务使用 WebSocket 协议,在高并发场景下,频繁创建 WebSocket 连接会增加连接耗时并消耗大量资源。
在使用 DashScope Java SDK 时,您可以根据服务器的实际情况,通过合理设置连接池和对象池的大小来降低运行开销。
连接池和对象池不是越多越好,过少或过多都会导致程序运行变慢。建议您根据自己服务器的实际规格进行配置。
在服务器上只运行 Sambert 语音合成服务的情况下,进行测试后得到了如下推荐配置供您参考:
单机并发数指的是同一时刻正在运行的 Sambert 语音合成任务的数量,也可以理解为工作线程数。
DashScope Java SDK 使用了 OkHttp3 提供的连接池来复用 WebSocket 连接,从而减少频繁创建 WebSocket 连接的耗时和资源开销。
连接池是 DashScope SDK 默认开启的优化项,您需要根据使用场景配置连接池的大小。
请在运行 Java 服务前,通过环境变量的方式提前按需配置好连接池的相关参数。连接池配置参数如下:
推荐使用对象池的方式来复用
关于如何配置环境变量,可参考配置 API Key 到环境变量。
以下为使用资源池的示例代码。其中,对象池为全局单例对象。
前提条件
- 已开通服务并获取 API Key。请配置 API Key 到环境变量,而非硬编码在代码中,防范因代码泄露导致的安全风险。
- 安装最新版 DashScope SDK。
推荐配置
连接池和对象池不是越多越好,过少或过多都会导致程序运行变慢。建议您根据自己服务器的实际规格进行配置。
在服务器上只运行 Sambert 语音合成服务的情况下,进行测试后得到了如下推荐配置供您参考:
| 常见机器配置(阿里云) | 单机最大并发数 | 对象池大小 | 连接池大小 |
|---|---|---|---|
| 4核8GiB | 600 | 1200 | 2000 |
在高并发调用时,同一个对象会复用同一个 WebSocket 连接,因此 WebSocket 连接只会在服务启动时创建。需要注意的是,同时创建过多的 WebSocket 连接会导致阻塞,因此在实际启动服务时应逐步提高单机并发数。
可配置参数
连接池
DashScope Java SDK 使用了 OkHttp3 提供的连接池来复用 WebSocket 连接,从而减少频繁创建 WebSocket 连接的耗时和资源开销。
连接池是 DashScope SDK 默认开启的优化项,您需要根据使用场景配置连接池的大小。
请在运行 Java 服务前,通过环境变量的方式提前按需配置好连接池的相关参数。连接池配置参数如下:
| 参数 | 说明 |
|---|---|
DASHSCOPE_CONNECTION_POOL_SIZE | 配置连接池大小。默认值为 32。推荐配置为您的峰值并发数的 2 倍以上。 |
DASHSCOPE_MAXIMUM_ASYNC_REQUESTS | 配置最大异步请求数。默认值为 32。推荐配置为和连接池大小一致。更多信息参见 OkHttp3 Dispatcher 参考文档。 |
DASHSCOPE_MAXIMUM_ASYNC_REQUESTS_PER_HOST | 配置单 host 最大异步请求数。默认值为 32。推荐配置为和连接池大小一致。更多信息参见 OkHttp3 Dispatcher 参考文档。 |
对象池
推荐使用对象池的方式来复用 SpeechSynthesizer 对象,这样可以进一步降低反复创建和销毁对象带来的内存和时间开销。
请在运行 Java 服务前,通过环境变量或代码的方式提前按需配置好对象池的大小。对象池配置参数如下:
| 参数 | 说明 |
|---|---|
SAMBERT_OBJECTPOOL_SIZE | 对象池大小。推荐配置为您的峰值并发数的 1.5~2 倍。对象池大小需要小于或等于连接池大小,否则会出现对象等待连接的情况,导致调用阻塞。 |
示例代码
以下为使用资源池的示例代码。其中,对象池为全局单例对象。
- 每个主账号默认每秒可提交 3 个 Sambert 语音合成任务。如需开通更高 QPS,请联系我们。
- 示例代码中,不同的线程通过等待随机时间来避免同时创建过多的 WebSocket 连接。
您需要在项目中引入 DashScope 和 org.apache.commons.pool2 相关的包,DashScope 要求版本号 >= 2.16.9。
您需要在项目中引入 DashScope 和 org.apache.commons.pool2 相关的包,DashScope 要求版本号 >= 2.16.9。
以 Maven 和 Gradle 为例,配置如下:
- Maven
- Gradle
- 打开您的 Maven 项目的
pom.xml文件。 - 在
<dependencies>标签内添加以下依赖信息。
- 保存
pom.xml文件。 - 使用 Maven 命令(如
mvn clean install或mvn compile)来更新项目依赖。
异常处理
- 在服务出现 TaskFailed 报错时,不需要额外处理。
- 如果在语音合成中途,客户端出现错误(如 SDK 内部异常或业务逻辑异常)导致语音合成任务未完成,则需要您主动关闭连接。
常见异常
异常 1、业务流量平稳,但是服务器 TCP 连接数持续上升
异常 1、业务流量平稳,但是服务器 TCP 连接数持续上升
出错原因:类型一:每一个 SDK 对象创建时都会申请一个连接。如果没有使用对象池,每一次任务结束后对象都被析构。此时这一个连接将进入无引用状态,需要等待 61s 后服务端报错连接超时才会真正断开,这会导致这个连接在 61 秒内不可复用。在高并发场景下,新的任务在发现没有可复用连接时会创建新连接,会造成如下后果:
- 连接数持续上升。
- 由于连接数过多,服务器资源不足,服务器卡顿。
- 连接池被打满、新任务由于启动时需要等待可用连接而阻塞。
异常 2、任务耗时比正常调用多 60 秒
异常 2、任务耗时比正常调用多 60 秒
同"异常 1",连接池已经达到最大连接限制,新的任务需要等待无引用状态的连接 61 秒触发超时后才可以获得连接。
异常 3、服务启动时任务慢,之后慢慢恢复正常
异常 3、服务启动时任务慢,之后慢慢恢复正常
出错原因:在高并发调用时,同一个对象会复用同一个 WebSocket 连接,因此 WebSocket 连接只会在服务启动时创建。需要注意的是,任务启动阶段如果立刻开始较高并发调用,同时创建过多的 WebSocket 连接会导致阻塞。解决方法:启动服务后逐步提升并发量,或增加预热任务。
异常 4、服务端报错 Invalid action('run-task')! Please follow the protocol!
异常 4、服务端报错 Invalid action('run-task')! Please follow the protocol!
出错原因:这是由于出现了客户端报错后,服务端不知道客户端出错,连接处于任务中状态。此时连接和对象被复用并开启下一个任务,导致流程错误,下一个任务失败。解决方法:在抛出异常后主动关闭 WebSocket 连接后归还对象池。
异常 5、业务流量平稳,调用量出现异常尖刺
异常 5、业务流量平稳,调用量出现异常尖刺
出错原因:同时创建过多 WebSocket 连接导致阻塞,但业务流量持续打进来,导致任务短时间积压,并且在阻塞后所有积压任务立刻调用。这会造成调用量尖刺,并且有可能造成瞬时超过账号的并发数限制导致部分任务失败、服务器卡顿等。这种瞬间创建过多 WebSocket 的情况多发生于:
- 服务启动阶段
- 网络出现异常,大量 WebSocket 连接同时中断重连
- 某一时刻出现大量服务端报错,导致大量 WebSocket 重连。常见报错如并发数超过账号限制("Requests rate limit exceeded, please try again later.")。
- 检查网络情况。
- 排查尖刺前是否出现大量其他服务端报错。
- 提高账号并发限制。
- 调小对象池和连接池大小,通过对象池上限限制最大并发数。
- 提升服务器配置或扩充机器数。
异常 6、随着并发数提升,所有任务都变慢
异常 6、随着并发数提升,所有任务都变慢
解决方法:
- 检查是否已经达到网络带宽上限。
- 检查实际并发数是否已经过高。

