FunASR C++部署实战:Websocket服务器高性能实现
引言:语音交互时代的服务端挑战
在实时语音交互场景中,Websocket协议因其全双工通信特性成为音频流传输的首选方案。FunASR作为阿里巴巴达摩院开源的端到端语音识别工具包,提供了高性能的语音识别能力。本文将深入解析如何基于FunASR构建C++ Websocket服务器,通过线程池优化、异步IO设计和模型推理加速,实现日均百万级语音请求的处理能力。
核心痛点与解决方案
| 痛点 | 解决方案 | 性能收益 |
|---|---|---|
| 高并发连接处理 | IO线程池与业务线程池分离 | 支持10k+并发连接 |
| 语音流实时解码 | 异步任务队列+批处理推理 | 降低90%上下文切换开销 |
| 模型加载耗时 | 预加载+内存共享 | 启动时间减少70% |
| 动态热词更新 | FST有限状态机集成 | 热词生效延迟<100ms |
技术架构:高性能服务器的设计范式
整体架构
线程模型设计
FunASR Websocket服务器采用三级线程架构:
- IO线程池:处理TCP连接和WebSocket协议解析,默认2线程
- 解码线程池:执行语音特征提取和模型推理,可配置8-16线程
- 模型线程池:内部OP并行计算,通过
--model-thread-num控制
关键代码位于websocket-server.cpp的on_message回调:
asio::post(io_decoder_,
std::bind(&WebSocketServer::do_decoder, this,
std::move(*(sample_data_p.get())),
std::move(hdl),
std::ref(msg_data->msg),
std::ref(*thread_lock_p),
std::move(hotwords_embedding_),
msg_data->msg["wav_name"],
msg_data->msg["itn"],
msg_data->msg["audio_fs"],
msg_data->msg["wav_format"],
std::ref(msg_data->decoder_handle)));
编译部署:从源码到服务
环境准备
| 依赖项 | 版本要求 | 作用 |
|---|---|---|
| GCC | 7.5+ | C++14特性支持 |
| CMake | 3.16+ | 项目构建系统 |
| ONNX Runtime | 1.14.0+ | 模型推理引擎 |
| FFmpeg | 5.0+ | 音频格式处理 |
| WebSocketpp | 0.8.2 | WebSocket协议栈 |
| Asio | 1.24.0 | 异步IO库 |
编译步骤(Linux)
# 1. 克隆代码库
git clone https://gitcode.com/GitHub_Trending/fun/FunASR.git
cd FunASR/runtime/websocket
# 2. 安装系统依赖
sudo apt-get install libopenblas-dev libssl-dev
# 3. 下载依赖库
bash third_party/download_onnxruntime.sh
bash third_party/download_ffmpeg.sh
# 4. 编译项目
mkdir build && cd build
cmake -DCMAKE_BUILD_TYPE=release .. \
-DONNXRUNTIME_DIR=../third_party/onnxruntime \
-DFFMPEG_DIR=../third_party/ffmpeg
make -j 8
Windows编译要点
Windows环境需额外配置OpenSSL和Visual Studio:
# 下载依赖
wget https://isv-data.oss-cn-hangzhou.aliyuncs.com/ics/MaaS/ASR/dep_libs/openssl-1.1.1w.zip
# 编译命令
cmake ../ -D OPENSSL_ROOT_DIR=d:/openssl-1.1.1w \
-D FFMPEG_DIR=d:/ffmpeg-master-latest-win64-gpl-shared \
-D ONNXRUNTIME_DIR=d:/onnxruntime-win-x64-1.16.1
核心代码解析
连接管理机制
服务器采用std::map存储活跃连接,结合智能指针和互斥锁实现线程安全:
void WebSocketServer::on_open(websocketpp::connection_hdl hdl) {
scoped_lock guard(m_lock);
std::shared_ptr<FUNASR_MESSAGE> data_msg = std::make_shared<FUNASR_MESSAGE>();
data_msg->samples = std::make_shared<std::vector<char>>();
data_msg->thread_lock = std::make_shared<websocketpp::lib::mutex>();
data_map.emplace(hdl, data_msg);
LOG(INFO) << "active connections: " << data_map.size();
}
异步解码流程
do_decoder函数实现音频数据的异步处理:
- 从缓冲区获取音频数据
- 调用FunASR离线推理API
- 封装JSON结果并返回客户端
void WebSocketServer::do_decoder(const std::vector<char>& buffer,
websocketpp::connection_hdl& hdl,
nlohmann::json& msg,
websocketpp::lib::mutex& thread_lock,
std::vector<std::vector<float>> &hotwords_embedding,
std::string wav_name,
bool itn,
int audio_fs,
std::string wav_format,
FUNASR_DEC_HANDLE& decoder_handle) {
// 音频数据处理与ASR推理
FUNASR_RESULT Result = FunOfflineInferBuffer(
asr_handle, buffer.data(), buffer.size(), RASR_NONE, nullptr,
hotwords_embedding, audio_fs, wav_format, itn, decoder_handle);
// 结果封装与发送
nlohmann::json jsonresult;
jsonresult["text"] = FunASRGetResult(Result, 0);
jsonresult["mode"] = "offline";
jsonresult["timestamp"] = FunASRGetStamp(Result);
// ...发送逻辑
}
热词优化实现
通过FST有限状态机实现热词加权:
// 热词加载
std::unordered_map<std::string, int> merged_hws_map;
FunWfstDecoderLoadHwsRes(msg_data->decoder_handle, fst_inc_wts_, merged_hws_map);
// 热词文件格式示例 (hotwords.txt)
阿里巴巴 20
通义实验室 30
性能优化实践
线程池参数调优
| 参数 | 建议值 | 说明 |
|---|---|---|
| --io-thread-num | 2-4 | 网络IO线程数,不宜过多 |
| --decoder-thread-num | CPU核心数*1.5 | 解码线程池大小 |
| --model-thread-num | 1-2 | 模型内部并行线程 |
| --batch-size | 4-8 | GPU推理批处理大小 |
内存优化策略
- 模型共享:多实例共享模型权重,降低内存占用
- 缓冲区复用:音频缓冲区池化,减少动态内存分配
- 结果串池:识别结果字符串复用,降低GC压力
网络优化
- TCP_NODELAY:禁用Nagle算法,降低延迟
- SO_RCVBUF/SO_SNDBUF:调整TCP缓冲区大小至64KB-128KB
- 连接心跳:定期清理无效连接,释放资源
部署与监控
启动命令示例
./build/bin/funasr-wss-server \
--download-model-dir ./models \
--model-dir damo/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-pytorch \
--vad-dir damo/speech_fsmn_vad_zh-cn-16k-common-pytorch \
--punc-dir damo/punc_ct-transformer_zh-cn-common-vocab272727-pytorch \
--port 10095 \
--io-thread-num 4 \
--decoder-thread-num 12 \
--hotword ./hotwords.txt
关键监控指标
| 指标 | 阈值 | 优化方向 |
|---|---|---|
| 连接数 | <10k | 水平扩展或负载均衡 |
| 解码延迟 | <300ms | 调整批处理大小或模型量化 |
| 内存占用 | <2GB | 模型裁剪或蒸馏 |
| CPU使用率 | <80% | 线程数调整或GPU加速 |
常见问题排查
编译错误
- 依赖缺失:
CMake Error at CMakeLists.txt:102 (find_package):
Could not find OpenSSL.
解决:安装libssl-dev:sudo apt-get install libssl-dev
- onnxruntime链接错误:
undefined reference to `Ort::Env::Env(OrtLoggingLevel, char const*)'
解决:检查ONNXRUNTIME_DIR路径是否正确
运行时问题
-
模型下载失败:
- 检查网络连接
- 手动下载模型并指定
--model-dir
-
高延迟:
- 降低
--global-beam(默认3.0) - 增加
--decoder-thread-num - 启用模型量化(
--quantize true)
- 降低
总结与展望
本文详细介绍了FunASR WebSocket服务器的C++实现方案,从架构设计、编译部署到性能优化,完整覆盖了高性能语音服务的关键技术点。通过IO与业务线程分离、异步任务处理和模型优化,该方案可满足高并发、低延迟的语音识别需求。
未来优化方向:
- GPU加速:通过
--use-gpu true启用GPU推理 - 动态批处理:根据请求量自适应调整批大小
- K8s部署:容器化部署与自动扩缩容
项目地址:https://gitcode.com/GitHub_Trending/fun/FunASR
欢迎点赞、收藏、关注,获取更多语音识别部署实战技巧!
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



