分类 OpenStack 下的文章

默认 Nova 调度有 10+ filter,但大集群下默认配置往往不够。本文是我的调优实战记录。

调度流程

  1. 拉所有 hypervisor 列表
  2. 过 filter 链,每个 filter 排除一批
  3. 剩下的过 weigher,按权重排序
  4. 取 top 1(或前 N,从中随机选)

性能瓶颈:filter 链越长越慢。1000 节点集群默认配置,调度一次要 5+ 秒。

减 filter

不需要的 filter 直接删,比如:

[filter_scheduler]
enabled_filters = AvailabilityZoneFilter,ComputeFilter,ComputeCapabilitiesFilter,ImagePropertiesFilter,ServerGroupAntiAffinityFilter,ServerGroupAffinityFilter

我删掉的:
- RetryFilter:默认重试机制,集群正常时无用
- CoreFilter / RamFilter / DiskFilter:已被 PlacementFilter 取代(Ocata 之后)
- SameHostFilter / DifferentHostFilter:很少用到
- PciPassthroughFilter:没 GPU/PCI 场景删掉

Placement 是关键

Pike 之后 Nova 引入 Placement API,资源跟踪从 Nova-scheduler 移到 Placement service。优先用 Placement 而不是 filter 做资源筛选

[scheduler]
query_placement_for_image_type_support = True
limit_tenants_to_placement_aggregate = True

Placement 查询是 SQL JOIN,10000 节点也是毫秒级,filter 是 Python 循环。

Weigher 调优

[filter_scheduler]
weight_classes = nova.scheduler.weights.all_weighers
ram_weight_multiplier = 1.0
disk_weight_multiplier = 0.5
io_ops_weight_multiplier = -2.0
build_failure_weight_multiplier = -1000000.0

实战意义:
- ram_weight_multiplier > 0:偏好 RAM 多的节点(spread 模式)
- < 0:偏好 RAM 少的节点(pack 模式,节省机器)
- build_failure_weight_multiplier 负超大:最近构建失败的节点强制避开

大集群必加:host subset size

[filter_scheduler]
host_subset_size = 5

调度时不取 top 1,而是从前 5 个里随机选。避免羊群效应——同时多个 VM 调度都选同一个最空节点,结果撞车。

监控

# scheduler 调度时间
grep "Scheduling decision" /var/log/nova/nova-scheduler.log | awk '{print $NF}'

# 失败率
grep NoValidHost /var/log/nova/nova-scheduler.log | wc -l

教训:1000 节点以上集群 nova-scheduler 跑得慢,第一步是看 Placement 有没有用上,filter 越少越好。

Keystone 是 OpenStack 的认证中心,挂了整个云就废了。本文是我在生产部署的 3 节点 HA 方案。

架构

        VIP (HAProxy keepalived)
         |
   +-----+-----+
   |     |     |
 Key1  Key2  Key3   (Apache + mod_wsgi)
   |     |     |
   +-----+-----+
         |
      Galera Cluster (MariaDB 3 节点)

要点:

  • Keystone 服务无状态,水平扩容
  • 数据库用 Galera 多主同步
  • 前面挂 HAProxy + VIP,单点故障不影响

关键配置 keystone.conf

[database]
connection = mysql+pymysql://keystone:password@<VIP>:3306/keystone
max_pool_size = 50
max_overflow = 100

[token]
provider = fernet
expiration = 3600

用 fernet token,不要用旧的 uuid token:

  • fernet 不存数据库,纯加密 token
  • 性能好 10 倍以上
  • token rotation 自动化

Fernet key 同步

3 个节点的 fernet key 必须一致:

# 主节点生成
keystone-manage fernet_setup --keystone-user keystone --keystone-group keystone

# rsync 到其他节点
rsync -av /etc/keystone/fernet-keys/ node2:/etc/keystone/fernet-keys/
rsync -av /etc/keystone/fernet-keys/ node3:/etc/keystone/fernet-keys/

# 定期 rotate(crontab,每 24h)
keystone-manage fernet_rotate --keystone-user keystone --keystone-group keystone

rotate 后必须同步到所有节点,否则部分节点 token 验证失败。

HAProxy 配置

listen keystone_api
    bind <VIP>:5000
    balance source           # 同一客户端固定到同一后端,防 session 漂
    option httpchk GET /v3
    server key1 <node1>:5000 check inter 2000 rise 2 fall 3
    server key2 <node2>:5000 check inter 2000 rise 2 fall 3
    server key3 <node3>:5000 check inter 2000 rise 2 fall 3

balance source 比 roundrobin 更稳,但流量分布略不均。

监控要看的指标

  • Keystone API 响应时间(>500ms 报警)
  • Token 创建 QPS
  • Galera 集群同步延迟(wsrep_local_recv_queue)
  • Fernet key 文件 mtime 一致性

一个真实事故

某次我们的 HAProxy 健康检查写成 option httpchk GET / ——返回 300 重定向。HAProxy 把所有节点判 down,Keystone 全部摘除,整个云挂 20 分钟。

教训:健康检查 URL 一定要返回 2xx,别用根路径。