Yeti-Switch 配置参数详解

Yeti-Switch 三层配置全解:SEMS + yeti module 流量平面 sems.conf(general/signaling/media/modules/yeti/jsonrpc/redis)、yeti-web Rails 管理平面(database.yml/yeti_web.yml/secrets.yml)、PostgreSQL 18 双库与 Redis 生产模板(PoC/中型/集群三档)。

Yeti-SwitchYeti-SwitchSIP 协议VoIP 语音SBC电信软交换REST2026/10/27

Yeti-Switch 配置参数详解

目标:完整覆盖 Yeti-Switch v1.14 的三层配置体系——SEMS + yeti module 流量平面(/etc/sems/sems.conf)、yeti-web Rails 管理平面(/opt/yeti-web/config/*.yml)、PostgreSQL 双库与 Redis 基础设施配置。所有参数来自官方 1.14 安装指南与 SEMS 配置参考,按功能域分组,含类型/默认值/说明/生产推荐。检索日期 2026-10-27。

一、环境信息

  • Yeti-Switch 版本:1.14.x(1.15.x 参数基本兼容,新增 OAuth/OIDC 配置项见 changelog)
  • 依赖:SEMS(yeti 维护分支)、PostgreSQL 18 + 扩展、Redis 7.x、yeti-web (Rails 7.2)
  • 配置文件位置(裸机):
    • SEMS:/etc/sems/sems.conf
    • yeti-web 数据库:/opt/yeti-web/config/database.yml
    • yeti-web 安全密钥:/opt/yeti-web/config/secrets.yml
    • yeti-web 业务参数:/opt/yeti-web/config/yeti_web.yml
    • Redis:/etc/redis/redis.conf
    • PostgreSQL:/etc/postgresql/18/main/postgresql.conf + pg_hba.conf
    • systemd:/lib/systemd/system/sems.service + /lib/systemd/system/yeti-*.service

二、前置条件

2.1 参数查看方式

平面查看方式
SEMS直接 cat 配置文件;运行态参数 yeti-cli 查看(yeti-cli sems.show.*)
yeti-web配置文件;Rails Console 动态查看(rails runner 'puts YetiConfig.to_h')
PostgreSQLSHOW ALL;
Redisredis-cli CONFIG GET *

2.2 参数修改生效范围

组件配置修改生效方式
SEMS(流量平面)/etc/sems/sems.conf 多数systemctl restart sems
SEMS yeti 实体缓存网关/路由/账号Web UI 保存后 yeti 模块 JSONRPC 热重载(5s 内)
yeti-webdatabase.yml / secrets.yml / yeti_web.ymlsystemctl restart yeti-web
Redis/etc/redis/redis.confsystemctl restart redis-server
PostgreSQLpostgresql.confsystemctl restart postgresql@18-main
pgqd/etc/pgqd.iniservice pgqd restart

💡 技术拓展:Yeti-Switch 的「流量平面热重载」——SEMS yeti 模块把网关、路由、账号、费率、认证凭据等实体缓存在内存。yet-web 的保存动作会通过 PostgreSQL LIST/NOTIFY 或 JSONRPC 触发 SEMS 重拉对应表。这是 Yeti 相对 FreeSWITCH dialplan 的核心优势之一:路由/计费规则改完秒级生效,无需重启流量进程。

三、参数总览

三层配置结构:

Yeti-Switch 配置
├── SEMS + yeti module(/etc/sems/sems.conf)—— 流量平面
│   ├── general {} —— 进程级参数
│   ├── signaling-interfaces {} —— SIP 信令监听
│   ├── media-interfaces {} —— RTP 媒体监听
│   └── modules {} —— 各功能模块(yeti/jsonrpc/redis/postgresql/...)
├── yeti-web(/opt/yeti-web/config/*.yml)—— 管理平面
│   ├── database.yml —— PostgreSQL 双库连接
│   ├── secrets.yml —— Rails secret_key_base
│   ├── yeti_web.yml —— 业务参数(OAuth、CDR、PDF、S3 等)
│   └── nginx.conf —— Nginx 反代 yeti-web.dist.nginx
├── Redis(/etc/redis/redis.conf)
├── PostgreSQL 18(routing + cdr 双库独立配置)
└── pgqd(CDR ticker)

四、SEMS + yeti module 核心参数详解

4.1 general {} —— 进程级

参数类型默认说明生产推荐
stderrboolyes输出到 stderrno(改 syslog)
syslog_loglevelint2syslog 日志级别(0=fatal…5=debug)2 或 3(线上不低于 2,排障临时升 5)
syslog_facilityenumLOCAL0syslog facilityLOCAL0 或 LOG_DAEMON
node_idint—本 SEMS Node ID(yet-web System→Nodes 创建后填写)必填,集群每节点唯一
media_processor_threadsint2媒体转码线程数= CPU 核数(8 vCPU 配 8)
rtp_receiver_threadsint1RTP 接收线程= CPU 核数
session_processor_threadsint10会话处理线程(决定并发上限)= 20–50(视并发,电信级 ≥ 40)
sip_udp_server_threadsint1SIP UDP 监听线程2
sip_tcp_server_threadsint1SIP TCP 监听线程2
dead_rtp_timeint (sec)30RTP 静默超时自动断呼30(短一点防僵尸)
default_bl_ttlint (sec)0黑名单/容量计数器默认 TTL0(永久,靠 yeti-web 管理)
symmetric_rtp_modeenumpacketsNAT 穿透 symmetric RTP 模式:packets/auto/offpackets(最保守)
symmetric_rtp_packetsint10symmetric RTP 判定包数20(更保守)

生产模板片段:

general {
  stderr = no
  syslog_loglevel = 2
  syslog_facility = LOCAL0
  node_id = 1
  media_processor_threads = 8
  rtp_receiver_threads = 8
  session_processor_threads = 40
  sip_udp_server_threads = 2
  sip_tcp_server_threads = 2
  dead_rtp_time = 30
  symmetric_rtp_mode = packets
  symmetric_rtp_packets = 20
}

4.2 signaling-interfaces {} —— SIP 信令

signaling-interfaces {
  interface <NAME> {
    default-media-interface = <MEDIA_IFACE_NAME>
    ip4 {
      sip-udp {
        address = <0.0.0.0 或 具体 IP>
        port = 5060
        use-raw-sockets = off   # on = 高性能原始套接字(可能需 CAP_NET_RAW)
      }
      sip-tcp {
        address = <IP> port = 5060
        connect-timeout = 2000
        static-client-port = on   # 固定 TCP 源端口
        idle-timeout = 900000     # 15 分钟
      }
    }
    # IPv6 类似:ip6 { sip-udp {...} sip-tcp {...} }
  }
}

生产关键:

  • address 填具体公网 IP(NAT 场景),0.0.0.0 是通配但对端看到的 Via 会是 0.0.0.0;
  • use-raw-sockets = on 在万级 CPS 场景下降低 UDP recvfrom 开销,需 SEMS 进程 CAP_NET_RAW 或 root;
  • TLS 端口(5061)在 Sip-TLS 节单独配置证书路径。

4.3 media-interfaces {} —— RTP 媒体

media-interfaces {
  interface <NAME> {
    ip4 {
      rtp {
        address = <MEDIA_IP>
        low-port = 16384
        high-port = 32769
        dscp = 46                  # EF Expedited Forwarding
        use-raw-sockets = off
      }
    }
  }
}

生产关键:

  • RTP 端口范围 low-port ~ high-port 决定可并发通话数:(high - low) / 2 ≈ 单节点并发上限;16384–32769 约 8000 并发;
  • dscp = 46 给媒体流 EF 优先级,交换机/QoS 配置对应队列;
  • 端口范围不可与宿主机其他媒体服务重叠(FreeSWITCH 默认 16384–32768,正好同范围!)。

4.4 modules.module "yeti" {} —— 核心 yeti 模块

这是 Yeti-Switch 的心脏,子参数按功能域分组:

4.4.1 基础

参数类型默认说明生产推荐
pop_idint—PoP ID(yet-web 创建后填)必填
auth.realmstringyeti-switchSIP Digest 鉴权 realmyeti-switch 或自定义
msg_logger_dirpath/var/spool/sems/dumpPcap dump 目录/var/spool/sems/dump,定期清理
audio_recorder_dirpath/var/spool/sems/records录音目录(若启用)独立盘挂载
audio_recorder_compressboolfalse录音自动 gziptrue(节省空间)
db_refresh_intervalint (sec)5DB 实体刷新周期5(最小)
ip_auth_reject_if_no_matchedbooltrueIP 鉴权不匹配时静默拒绝true(防扫描)

4.4.2 routing {} —— 路由查表

routing {
  schema = switch22                 # PostgreSQL schema
  function = route_release          # 存储过程名
  init = init                       # 初始化存储过程
  pass_input_interface_name = true  # 把输入接口名传给路由脚本
  new_codec_groups = true           # 新版 codec group 逻辑

  headers {
    header(x-yeti-auth)
    header(diversion, json, uri_json_array)
    header(x-orig-ip, inet)
    header(x-orig-port, integer)
    header(x-orig-proto, smallint)
    # ... 其他透传 header
  }

  master_pool { host = ... port = 5432 name = yeti user = ... pass = ... size = 4 }
  failover_to_slave = false
  slave_pool  { host = ... port = 5432 name = yeti user = ... pass = ... size = 4 }
}

生产关键:

  • schema / function / init 是 yeti DB schema 内部约定,不要改;
  • master_pool.size = PostgreSQL 连接数,建议 ≥ session_processor_threads / 2;
  • 有只读副本时设 failover_to_slave = true 并填 slave_pool;
  • headers 定义哪些 SIP header 透传给路由存储过程,影响 LCR 策略判断。

4.4.3 cdr {} —— 计费

cdr {
  pool_size = 2
  auth_pool_size = 2
  schema = switch
  function = writecdr
  master { host = ... port = 5432 name = cdr user = ... pass = ... }
  failover_to_slave = false
  slave  { host = ... port = 5432 name = cdr user = ... pass = ... }
  batch_size = 1            # 实时计费通常 1(每次通话立即写)
  batch_timeout = 5000      # ms,batch_size 未到上限时的等待上限
  auth_batch_size = 1       # 鉴权查询 batch
  auth_batch_timeout = 20000
}

4.4.4 resources {} —— Redis 容量/计数器

resources {
  reject_on_error = false
  write { hosts = { 127.0.0.1:6379 } timeout = 500 }
  read  { hosts = { 127.0.0.1:6379 } timeout = 1000 }
}

生产关键:

  • reject_on_error = false(默认):Redis 不可用时降级放行,不阻断通话。电信级建议 true + 多 Redis 哨兵;
  • 集群部署时 hosts 填所有 Redis 节点,SEMS 做 round-robin。

4.5 modules.module "jsonrpc" {} —— JSONRPC(yet-web / yeti-cli 调用)

module "jsonrpc" {
  listen { address = 127.0.0.1 port = 7080 }
  server_threads = 1
  map(yeti.request.registrations.reload, yeti.request.db_states.reload)
  # ... 约 10 条 reload 映射
}

⚠️ 安全红线:JSONRPC 端口 7080 必须仅 127.0.0.1 监听,ufw 禁外网。yet-web 与 yeti-cli 是唯一合法调用方,恶意访问可 shutdown SEMS 节点。

4.6 modules.module "redis" {} —— Redis 客户端

module "redis" {
  max_batch_size = 10
  batch_timeout = 100
  max_queue_size = 1000
}

4.7 modules.module "registrar" {} —— SIP Registrar(动态网关 IP)

module "registrar" {
  redis {
    write { hosts = { 127.0.0.1:6379 } }
    read  { hosts = { 127.0.0.1:6379 } }
  }
  headers = { x-orig-ip, x-orig-port, x-orig-proto }
}

五、yeti-web Rails 配置参数详解

5.1 config/database.yml —— PostgreSQL 双库

production:
  primary:
    adapter: postgresql
    encoding: unicode
    database: yeti
    username: yeti
    password: ${DB_PRIMARY_PASS}
    host: 127.0.0.1
    port: 5432
    schema_search_path: 'gui, public, switch, billing, class4, runtime_stats, sys, logs, data_import'
    min_messages: notice
    pool: 10                  # Rails 连接池,SEMS pool_size 另算
    # prepared_statements: false   # 高并发下可关
  cdr:
    adapter: postgresql
    encoding: unicode
    database: cdr
    username: cdr
    password: ${DB_CDR_PASS}
    host: 127.0.0.1
    port: 5432
    schema_search_path: 'cdr, reports, billing'
    min_messages: notice
    pool: 10
    migrations_paths: db/cdr_migrate
参数生产推荐
poolyeti-web Rails 连接池,与 SEMS master_pool.size 独立,Rails 通常 5–10 足够
schema_search_path必须与 yeti DB schema 匹配,不要删改任何项
host跨机部署时填数据库 IP

5.2 config/secrets.yml

production:
  secret_key_base: <128 位随机字符串>   # pwgen -s 128 1 生成

必须修改,泄露后可伪造 Rails session。

5.3 config/yeti_web.yml —— 业务参数

这是 yeti-web 的核心业务配置文件,从 yeti_web.yml.distr 复制后修改。按 1.14 文档与 1.15 changelog 归类:

# 数据库自动维护
maintenance:
  auto_vacuum: true
  autovacuum_max_workers: 3
  autovacuum_naptime: 1min

# CDR 分区
cdr:
  retention_days: 90          # CDR 自动保留天数
  partition_interval: 1month  # CDR 按月分区

# 邮件(Invoice / Email Log)
smtp_connection:
  host: smtp.example.com
  port: 587
  username: invoice@example.com
  password: ${SMTP_PASS}
  enable_starttls_auto: true

# OAuth/OIDC(1.15 新增)
oauth:
  oidc:
    enabled: false

# PDF 生成(1.15 新增 yeti-pdf 外部服务)
pdf:
  service_url: http://yeti-pdf.local:5000

# S3 存储(1.15 新增:CDR / Invoice 归档)
storage:
  s3:
    enabled: false
    endpoint: s3.example.com
    bucket: yeti-archive
    access_key_id: ${S3_KEY}
    secret_access_key: ${S3_SECRET}

# API 日志
api_log:
  enabled: true
  retention_days: 30

5.4 Nginx(yet-web 反代)

# 来自 /opt/yeti-web/config/yeti-web.dist.nginx,需根据生产调整
server {
  listen 80 default_server;
  # Admin API 默认屏蔽,生产改 allow
  location /api/rest/admin/ {
    allow <管理网段>;
    deny all;
    proxy_pass http://unix:/run/yeti/yeti-unicorn.sock;
  }
  location /api/rest/customer/ {
    proxy_pass http://unix:/run/yeti/yeti-unicorn.sock;
  }
  location / {
    proxy_pass http://unix:/run/yeti/yeti-unicorn.sock;
  }
}

六、Redis 配置

只改一行,其余保持 Ubuntu/Debian 官方默认:

sed -i 's/^notify-keyspace-events.*/notify-keyspace-events "Egx"/' /etc/redis/redis.conf
systemctl restart redis-server

# 验证
redis-cli CONFIG GET notify-keyspace-events
# "notify-keyspace-events" "Egx"
Redis 关键参数生产推荐
notify-keyspace-events"Egx"(Expired / Generic / String)—— Yeti Registrar incoming registrations 必需
maxmemory4GB 起(视集群规模,存储 capacity / registrations)
bind127.0.0.1 或具体内网 IP
protected-modeyes

七、PostgreSQL 18 配置

7.1 routing-db 与 cdr-db 建议参数

两个数据库实例配置相同(routing 库低写入高并发,cdr 库高写入批量):

# postgresql.conf 生产关键项
max_connections = 500                 # 足够 yeti-web(10) + SEMS(8) + pgqd(2) + 运维
shared_buffers = 4GB                  # 25% 物理内存(PostgreSQL 经典建议)
effective_cache_size = 12GB           # 剩余内存估计
work_mem = 32MB                       # 排序/哈希中间态
maintenance_work_mem = 2GB            # VACUUM / CREATE INDEX
synchronous_commit = on               # 电信级计费不建议 off
wal_level = replica
max_wal_senders = 10
wal_buffers = 64MB                    # 高写入 cdr 库建议加大
checkpoint_completion_target = 0.9
max_wal_size = 8GB
min_wal_size = 2GB

# cdr 库额外:高写入优化
wal_buffers = 256MB
synchronous_commit = on               # 计费不建议关
# 路由库可改为 off 降低小事务延迟(有丢失风险)

7.2 pg_hba.conf 关键规则

# routing 库(SEMS + yeti-web 本机访问)
host    yeti      yeti-web      127.0.0.1/32    scram-sha-256
host    yeti      yeti          127.0.0.1/32    scram-sha-256
# cdr 库(SEMS + yeti-web 本机访问)
host    cdr       cdr           127.0.0.1/32    scram-sha-256
# 跨机部署时加对应网段

7.3 pgqd

# /etc/pgqd.ini
[pgqd]
base_connstr = host=127.0.0.1 port=5432 dbname=cdr user=cdr password=q1w2e3r4
initial_database = cdr
database_list = cdr
pidfile = /var/run/postgresql/pgqd.pid

八、生产配置模板

以下三档模板基于 8 vCPU / 16GB RAM / NVMe SSD / 单节点 的规格,供选型参考。

8.1 模板 A:PoC / 小型测试

规格:4 vCPU / 8GB RAM / 20GB SSD / 100 并发以内

# sems.conf 关键段
general { session_processor_threads = 20 media_processor_threads = 4 rtp_receiver_threads = 4 }
media-interfaces { rtp low-port = 16384 high-port = 24576 }   # ≈4000 并发
modules.module "yeti" {
  master_pool { size = 4 } cdr { batch_size = 1 } resources { write.timeout = 500 }
}
# database.yml pool = 5 / Redis 4GB / shared_buffers = 1GB

8.2 模板 B:中型生产(批发运营商 / 5000 并发)

规格:16 vCPU / 32GB RAM / 500GB NVMe / routing + cdr 分机

# sems.conf
general { session_processor_threads = 60 media_processor_threads = 16 rtp_receiver_threads = 16 }
media-interfaces { rtp low-port = 16384 high-port = 32768 }   # ≈8000 并发
modules.module "yeti" {
  master_pool { size = 16 } cdr { pool_size = 4 batch_size = 1 batch_timeout = 3000 }
  resources { reject_on_error = true }
}
# yeti-web database.yml pool = 10
# Redis maxmemory = 8GB
# PostgreSQL routing: shared_buffers = 8GB / cdr: shared_buffers = 4GB + wal_buffers = 256MB
# pgqd 与 cdr 同机

8.3 模板 C:集群 / Geo 多节点

规格:3+ Switch Node(每个 16 vCPU / 32GB)+ 独立 routing-db + 独立 cdr-db + Redis 哨兵

# 每个 SEMS 节点相同,node_id / pop_id 不同
# SEMS 节点 media_interfaces.address = 节点具体 IP(非 0.0.0.0)
# routing 库 PostgreSQL streaming replication + failovermanager
# cdr 库独立机,pgqd 常驻
# Redis 哨兵 3 节点,SEMS modules.module "redis" hosts 写 3 个地址
# yeti-web 双机 active-passive(keepalived)

九、常见问题

Q1:session_processor_threads 设多少合适?
电信级生产设 40+,session_processor_threads < 并发数 会导致排队丢包。单节点并发上限 ≈ session_processor_threads × 50(经验系数)。

Q2:db_refresh_interval 能调大吗?
可以。10–60 秒可降低 DB 压力,代价是 Web UI 配置变更到 SEMS 生效的延迟。热重载(JSONRPC 主动通知)不受此参数影响。

Q3:routing.master_pool 报 too many connections?
pool.size 设太大(超过 PostgreSQL max_connections)。SEMS 连接数 = session_processor_threads / 2 + db_refresh_interval 相关轮询连接。PostgreSQL 18 默认 max_connections = 100,电信级调 ≥ 500。

Q4:Redis 挂了会影响通话吗?
默认 resources.reject_on_error = false——降级放行,通话继续但容量控制失效(可能超卖)。生产建议 true + Redis 哨兵。

Q5:synchronous_commit = off 在 cdr 库安全吗?
有丢失通话 CDR 的风险(掉电时 WAL 缓冲区未落盘)。电信计费强烈建议 on。可在 routing 库关(丢几秒路由缓存影响小)。

Q6:SEMS node_id 和 yet-web 的 Node 数据库 id 要一致?
不一致!SEMS node_id 是本进程编号(集群内唯一),yet-web Node 数据库 id 是自增主键。yet-web System → Nodes 里填的 Rpc endpoint(127.0.0.1:7080)才是 yet-web 发现本 SEMS 的方式。

十、参考链接