面试官喜欢问的项目——DPVS

面试的时候问的很多问题是关于计算机网络的,而网络中的负载均衡问题又是重中之中,笔者曾经面试大厂的时候就被面试官虐的体无完肤,所以提前掌握了负载均衡问题,并且在此基础上掌握DPVS项目就能跟面试官拼一拼 : )
DPVS是爱奇艺开源的用户态高性能负载均衡项目,将传统的内核 LVS基于 DPDK改造而成。

CDN中的技术

CDN本质上是分布式缓存服务器,其中很重要的就是负载均衡。说起负载均衡,准备过后端面试的同学肯定背的滚瓜烂熟了:四层负载均衡LVS,七层负载均衡nginx。没记住的没关系,赶紧记笔记。LVS一个阿里的传奇人物写的,被纳入了linux源码。

why CDN

为什么提CDN呢?原因就是CDN将负载均衡用到了极致。简单介绍一下吧。首先我们用浏览器输入一个网址,浏览器会拿着这个网址的域名向DNS服务器做DNS解析,DNS解析的结果不一定是个IP地址,也可以是CNAME即另一个域名,然后浏览器继续DNS解析,直到得到A记录即IP地址。CDN厂商就能在此做文章了。举个栗子,小白访问了http://www.baidu.com,浏览器第一次DNS得到的是http://www.baidu.com.cdn.com,这个是百度公司在他的域名服务器上配置的,百度买了http://cdn.com公司的服务,浏览器第二次请求http://www.baidu.com.cdn.com,这个域名解析服务交给了CDN厂商http://cdn.com公司的服务器,这个服务器根据小白的源IP地址,确定了小白的地理位置在北京市海淀区,用的是电信宽带,根据算法取一个离小白最近的机房的IP返回给了浏览器作为http://www.baidu.com的最终目的IP,浏览器用这个IP发送http请求,发到了CDN厂商的服务器上,服务器不是一台设备,是一个大机房,公用一个IP,到底那个机器提供服务就取决于负载均衡算法。负载均衡主要有两层,首先是传输层的负载均衡,用了LVS;其次是应用层的负载均衡,用了nginx。决定出给小白服务的机器,请求也就到了那个机器上,这个机器可以理解成一个缓存硬盘,发现有http://www.baidu.com,就直接回给小白,不让就代替小白向百度请求http://www.baidu.com,保存下来,并且返回给小白。这就是CDN的大致流程。

LVS——CDN的宝剑

LVS的中文译文是Linux虚拟服务器,是中国前阿里程序员写的,内核代码里能找到,可见他的牛逼之处。同iptables一样,是基于内核的netfilter框架实现的,不得不佩服内核结构化设计如此巧妙。篇幅有限,但是非常重要,请读者自行使用搜索引擎学习。

基于DPDK的用户态LVS——DPVS

DPVS的优势

为了达到高性能,使用了多种不同技术

  • 绕过内核(在用户空间实现)
  • 每个cpu的关键数据无共享(无锁)
  • RX控制和CPU亲合性绑定(避免上下文切换)
  • 批处理TX / RX
  • 零拷贝技术(避免数据包拷贝和系统调用)
  • 轮询替换中断
  • 高性能ICP的无锁信息
  • 其他技术由DPDK加强

今天不想写了,先写点安全相关的

强大的DDoS高防功能——synproxy

  • 功能初始化 dp_vs_synproxy_init()
int dp_vs_synproxy_init(void)
{
     //初始化随机数g_net_secret
     //初始化一个每分钟增1的随机数g_minute_count
     //申请ack_mbufpool
}
  • 收到客户端的syn包处理 dp_vs_synproxy_syn_rcv()
int dp_vs_synproxy_syn_rcv(int af, struct rte_mbuf *mbuf,
        const struct dp_vs_iphdr *iph, int *verdict)
{
     /* 查询是否有服务
     1. 没有服务接收包
     2. 有服务没有realserver丢弃包
     3. 源ip在服务的黑名单丢弃包

     /* 核心函数
     1. 设置tcp options  syn_proxy_parse_set_opts()
     2. 生成cookie  syn_proxy_cookie_v4_init_sequence()
     3. 设置seq和ack
     4. 交换ip和port
     5. 计算校验和
     syn_proxy_reuse_mbuf();

     /* 交换 mac */
     /* 发包 */
     netif_xmit()
}
  • 收到客户端的ack包处理 dp_vs_synproxy_ack_rcv()
int dp_vs_synproxy_ack_rcv(int af, struct rte_mbuf *mbuf,
        struct tcphdr *th, struct dp_vs_proto *pp,
        struct dp_vs_conn **cpp,
        const struct dp_vs_iphdr *iph, int *verdict)
{
     /* 查询是否有服务
     1. 没有服务接收包
     2. 检查是否带数据
     3. 校验cookie
     
     /* 查询负载出的realserver
     dp_vs_schedule()
}
  • 收到realserver的synack包处理dp_vs_synproxy_synack_rcv()

学习地址:Dpdk/网络协议栈/vpp/OvS/DDos/NFV/虚拟化/高性能专家(免费订阅,永久学习)

【文章福利】需要更多DPDK/SPDK学习资料加群793599096(资料包括C/C++,Linux,golang技术,内核,Nginx,ZeroMQ,MySQL,Redis,fastdfs,MongoDB,ZK,CDN,P2P,K8S,Docker,TCP/IP,协程,DPDK,大厂面试题 等)可以自行添加学习交流群点击这里噢~

发现采用DR模式会死锁在dp_vs_synproxy_synack_rcv(),因为单向代理收不到realserver的synack包。后来询问开源项目组成员,得到的回复是syncookie只能用在fullnat模式中。感觉这里可以改进!

现在来从头写吧

main.c 是世界的本源

  • parse_app_args() dpvs自定义的参数解析函数在dpdk eal解析参数之前先解析dpvs的自定义参数
  • dpvs_running() 从/var/run/标准守护进程文件中找到dpvs的pid,检查是否有dpvs正在运行
  • dpvs_state_set(DPVS_STATE_INIT) 设置DPVS状态
  • 获取时间戳,初始化随机树种子
  • set_allthreadaffinity() 设置主线程跑到所有核上,这个操作是啥神奇操作?主线程在rte_eal_init()会绑到一个核上
  • rte_eal_init() DPDK的初始化函数,所有DPDK程序都有这个,懂的都懂
  • rte_timer_subsystem_init() 初始化dpdk计时器子系统
  • rte_pdump_init() 初始化dpdk抓包
  • dpvs_scheduler_init() 初始化dpvs工作队列
  • global_data_init() 初始化dpvs几个全局变量
  • cfgfile_init() 初始化信号处理函数和从文件中初始化一些字段
  • netif_virtual_devices_add() 创建bonding网口
  • dpvs_timer_init() 初始化时间轮 dpvs学习笔记: 6 定时器实现及连接老化超时

转自;https://zhuanlan.zhihu.com/p/336907882

猜你喜欢

转载自blog.csdn.net/lingshengxiyou/article/details/130175366