开源方案搭建外呼系统:从FreeSWITCH到FreePBX的完整实践

一、系统架构设计:模块化与可扩展性

外呼系统的核心需求包括号码管理、拨号策略、通话录音、IVR交互及数据统计,需基于开源组件构建分层架构。推荐采用FreeSWITCH作为核心音视频引擎,负责信令处理与媒体流转发;FreePBX作为管理界面,提供呼叫路由、用户权限及报表可视化功能;数据库层存储客户数据、通话记录及系统配置;API网关对接CRM或业务系统,实现自动化外呼。

架构设计需遵循高可用原则:

  1. FreeSWITCH集群:通过ESL(Event Socket Library)实现多节点负载均衡,避免单点故障。
  2. 数据库分片:对通话记录表按时间或客户ID分片,提升查询效率。
  3. 缓存层:使用Redis存储实时呼叫状态,减少数据库压力。

示例配置片段(FreeSWITCH的autoload_configs/modules.conf.xml):

  1. <modules>
  2. <load module="mod_sofia"/>
  3. <load module="mod_db"/>
  4. <load module="mod_event_socket"/>
  5. </modules>

二、FreeSWITCH核心功能实现

1. 拨号计划与路由策略

FreeSWITCH的拨号计划(Dialplan)定义呼叫流程,支持正则匹配与条件分支。例如,实现“先直拨,后转IVR”的逻辑:

  1. <extension name="Outbound_Call">
  2. <condition field="destination_number" expression="^(\d+)$">
  3. <action application="bridge" data="user/$1@default"/>
  4. <action application="answer" data=""/>
  5. <action application="playback" data="/path/to/ivr.wav"/>
  6. </condition>
  7. </extension>

2. 媒体处理与录音

通过mod_dptools实现通话录音,需在拨号计划中添加:

  1. <action application="record_session" data="/var/recordings/${strftime(%Y%m%d)}/${uuid}.wav"/>

录音文件按日期与会话ID命名,便于后续检索。

3. 性能优化关键点

  • 线程池配置:调整sip_profile.xml中的threads-per-channel参数,平衡并发与资源消耗。
  • RTP端口范围:限制<param name="rtp-start-port" value="16384"/><param name="rtp-end-port" value="32768"/>,避免端口耗尽。
  • 日志分级:设置<loglevel>WARNING</loglevel>减少I/O开销。

三、FreePBX集成与功能扩展

1. 安装与基础配置

通过包管理器安装FreePBX(以CentOS为例):

  1. yum install -y httpd mariadb-server php php-mysqlnd
  2. systemctl enable --now httpd mariadb

访问Web界面后,需完成以下步骤:

  1. 创建管理员账号并设置安全策略。
  2. 配置SIP中继,填写FreeSWITCH的IP与端口。
  3. 导入客户号码库,支持CSV批量上传。

2. 高级功能实现

  • 预测式外呼:通过FreePBX的Outbound Routes设置并发上限,结合FreeSWITCH的API动态调整拨号速率。
  • 黑名单过滤:在MySQL中创建blacklist表,通过FreeSWITCH的Lua脚本实时拦截:
    1. local dbh = freeswitch.DBH("mysql", "dbname", "user", "pass")
    2. dbh:query("SELECT COUNT(*) FROM blacklist WHERE number = '" .. argv[1] .. "'",
    3. function(row)
    4. if row[1] > 0 then freeswitch.consoleLog("ERR", "Blacklisted number\n") end
    5. end
    6. )

四、系统对接与API开发

1. RESTful API设计

推荐使用Flask构建API网关,提供以下接口:

  • POST /api/call:触发外呼,参数包括主叫号码、被叫号码、IVR脚本ID。
  • GET /api/records:查询通话记录,支持分页与条件过滤。

示例代码(Python Flask):

  1. from flask import Flask, request
  2. import requests
  3. app = Flask(__name__)
  4. @app.route('/api/call', methods=['POST'])
  5. def trigger_call():
  6. data = request.json
  7. esl_cmd = f"api originate {{origination_caller_id_number={data['caller']}}} " \
  8. f"sofia/gateway/default/{data['callee']} &park()"
  9. # 调用FreeSWITCH的ESL接口
  10. return {"status": "queued"}

2. CRM系统集成

通过WebSocket实时推送通话事件至CRM,示例(Node.js客户端):

  1. const WebSocket = require('ws');
  2. const ws = new WebSocket('ws://freeswitch_ip:8021/api');
  3. ws.on('open', () => {
  4. ws.send('event plain CHANNEL_CREATE');
  5. });
  6. ws.on('message', (data) => {
  7. const event = JSON.parse(data);
  8. if (event['Event-Name'] === 'CHANNEL_CREATE') {
  9. // 解析主被叫号码并推送至CRM
  10. }
  11. });

五、部署与运维最佳实践

1. 容器化部署

使用Docker Compose简化环境配置,示例docker-compose.yml

  1. version: '3'
  2. services:
  3. freeswitch:
  4. image: freeswitch/freeswitch
  5. volumes:
  6. - ./conf:/etc/freeswitch
  7. ports:
  8. - "5060:5060/udp"
  9. - "8021:8021/tcp"
  10. freepbx:
  11. image: freepbx/freepbx
  12. depends_on:
  13. - mariadb

2. 监控与告警

  • Prometheus + Grafana:采集FreeSWITCH的freeswitch_stats指标,监控并发数、丢包率。
  • ELK日志分析:集中存储通话日志,通过Kibana搜索异常事件。

3. 灾备方案

  • 冷备节点:定期备份FreeSWITCH的配置文件与数据库,故障时快速切换。
  • 多地域部署:在云服务商的不同可用区部署实例,通过DNS智能解析实现流量调度。

六、常见问题与解决方案

  1. NAT穿透失败:检查sip_profile.xml中的ext-rtp-ipext-sip-ip是否为公网IP。
  2. 并发不足:调整<param name="max-sessions" value="1000"/>并优化线程模型。
  3. 录音文件丢失:确保存储路径有足够空间,并配置NFS共享存储。

通过上述方案,开发者可基于开源组件快速构建功能完善的外呼系统,兼顾灵活性与成本控制。实际部署时需根据业务规模调整架构细节,并持续监控性能指标。