整个工程量其实不大,截止到现在 dpvs 代码量只有不到 2w 行,相当轻量级了,和当年 redis 开源时体量相当。
整体架构
先看架构图,对外交互层 control plane 比较像 lvs,不会陌生。Load Balancer 模块根据 lvs 翻译而来,支持大家常用的几种转发模式。和 lvs 差别最大的地方就是,dpvs 自己实现了轻量级的 tcp 协义栈,并且在用户层模拟了网卡,就是最下面的 Net Devices 层。为什么要自己实现设备层呢?
了解配置文件
先熟悉配置文件对了解整体框架很有帮助,查看源码库自带的配置文件 dpvs.conf.sample,包含几个模块:
global_defs 全局配置模块:日志级别,路径等等
global_defs {
log_level WARNING
! log_file /var/log/dpvs.log
}
netif_defs 网卡设备模块:
netif_defs {
pktpool_size 2097151
pktpool_cache 256
device dpdk0 {
rx {
queue_number 8
descriptor_number 1024
rss tcp
}
tx {
queue_number 8
descriptor_number 1024
}
! promisc_mode
kni_name dpdk0.kni
}
}
pktpool 是内存池相关的,代码里再细说。device 就是定义的网卡设备,由于 dpdk 程序会将网卡劫持,所以流量不会经过内核,如果其它程序,比如 ssh 想使用网卡,就需要额外配置 kni kernel nic interface 模块,dpdk 不感兴趣的流量会透传到内核。tx, rx 是网卡硬件队列个数配置,现代网卡标配。
worker_defs 工作核心
worker_defs {
worker cpu0 {
type master
cpu_id 0
}
worker cpu1 {
type slave
cpu_id 1
port dpdk0 {
rx_queue_ids 0
tx_queue_ids 0
! isol_rx_cpu_ids 9
! isol_rxq_ring_sz 1048576
}
port dpdk1 {
rx_queue_ids 0
tx_queue_ids 0
! isol_rx_cpu_ids 9
! isol_rxq_ring_sz 1048576
}
}
}
dpdk 程序将 cpu 称为 lcore,即逻辑核。分为 master, slave 两种类型,一般 master 做管理相关的,slave cpu 是真正处理业务的核,每个 lcore 可以负责多个网卡的多个队列,dpdk 中将网卡叫做 port. rx_queue_ids 和 tx_queue_ids 分别是接收和发送队列号。其中 isol_rx_cpu_ids 表示当前 lcore 专职负责接收数据,isol_rxq_ring_sz 专职接收数据的 ring buffer 大小。
timer_defs 定时器相关
timer_defs {
# cpu job loops to schedule dpdk timer management
schedule_interval 500
}
neight_defs 邻居子系统
neigh_defs {
unres_queue_length 128
timeout 60
}
由于自己实现 tcp 协义,那邻居子系统和路由系统肯定也要实现,只不过比较精简专用
ipv4_defs
ipv4_defs {
ipv4_forward off ! set this to on, dpvs will forward packets that NOT hit rules directly
default_ttl 64
fragment {
bucket_number 4096
bucket_entries 16
max_entries 4096
ttl 1
}
}
以后一定会有 ipv6_defs
ctrl_defs 控制配置
ctrl_defs {
lcore_msg {
ring_size 4096
multicast_queue_length 256
sync_msg_timeout_us 2000
}
ipc_msg {
unix_domain /var/run/dpvs_ctrl
}
}
交互命令通过 unix socket
ipvs_defs 核心配置
ipvs_defs {
conn {
conn_pool_size 2097152
conn_pool_cache 256
conn_init_timeout 3
}
udp {
defence_udp_drop
timeout {
normal 300
last 3
}
}
tcp {
defence_tcp_drop
timeout {
no