假设还是沉湎于之前的战果以及强加的感叹,不要冥想,将其升华。

1.C还是脚本

以前,我用bash组织了复杂的iptables,ip rule等逻辑来配合OpenVPN,将其应用于差点儿全部能够想象得到的复杂网络场景中,实现网间VPN隧道。后来我发现玩大了,要不是当时留下一份文档,我自己差点儿已经无法通过这些关系错综复杂的bash脚本还原当时的思路,一切太复杂了。
       我想重构它们,同一时候将其改造成“能经得起继续复杂化”的系统,因此我不得不想办法将这些关系理顺。是的,bash太复杂了,那么改用什么好呢?用Python?或者PHP?再或者Java?或者直接用C?总之,不再用bash了。
       脚本的长处在于,你能够随时实验新想法,所见即所得,不用携带不论什么装备,仅仅要有个终端就能做事。缺点在于,正是由于上述那些随时编写随时执行的任意性,bash写出的东西非常easy发散开来以后便无法收敛,Python声称自己支持OO,支持复杂数据结构组织与easy,看上去会比bash好些,可是那依赖程序猿拥有良好的设计与编码能力,让一个菜鸟比方我写Python,你能想象他能写得多么恶心吗?能用C写出好软件的不算高手,用脚本写出好软件的才叫猛士。新手写bash脚本,一般都会搞得关系错综复杂,毕竟bash脚本中并没有什么好用的容器能够容纳数据结构,所以,bash天生就是发散了。
       C的缺点正是脚本的长处,那就是你不得不随身携带一些重量级装备,比方gcc,gnu make,gdb,strace...而这些一般在运维环境中是没有的,所以你要拥有一台时刻能够派上用场的开发用虚拟机,并且随身携带,假设没有,那就非常悲慘了。上周的某天,我就中午从公司回家去调试C程序,仅仅由于我的笔记本没有带到公司。在云上架一台开发机是好主意,可是那须要你有財力支持以及你时刻都要能够接入互联网。C的长处在于它是内敛的,对于刚開始学习的人而言,一般都会将全部逻辑写到一个文件里,也不善于调用外部的库函数或者脚本,假设说bash引诱你利用其他小命令组织大程序的话,那么C就是阻止这一切的发生,仅仅有高手才倾向于写小的C程序,然后通过动态库或者脚本将其组织起来,对于新手而言,一般都是倾向于写完备的大程序,即全部的逻辑集中在一起。
       我写了蜘蛛网般的bash代码,说明我是一个新手,为了将逻辑略微集中一下,作为新手,写出来的C应该是超级内敛的,非常可能全部的用户态逻辑都在一个so中,全部的内核逻辑都在一个ko中...然而,这是大忌讳,怎么办?简单,那就是最大限度利用系统本身提供的功能而不是自己用bash组织逻辑。

2.一台机器当多台用

试想,在一台机器上启用一个OpenVPN服务端是一件多么简单的事!
可是,为何这样不行,为何我非要费劲地折腾什么多实例多进程,由于OpenVPN本身不支持这些。上一篇系列文章中,我已经在OpenVPN内部使其支持了多线程,可是假设我没有改动OpenVPN代码的能力呢?假设换另外一个人来做这件事呢。我决定又一次给出一个方案。
       既然一台机器启动一个OpenVPN服务端进程超级简单,那么假设有N台机器的话,每台机器上启1个OpenVPN服务端也就是个体力活。在实际上没有N台机器的前提下,换个思路,怎样将一台机器当N台机器使用。
       Linux的netns完美攻克了这个问题:
ip netns add vpn1
ip netns add vpn2

这样就加入�了两个命名空间。接下来就是要为这两个命名空间加入�网卡,假设我的机器上仅仅有一块网卡,给了vpn1,它就被vpn1独占了,外面以及vpn2就都看不到了,显然不行,我又不可能在机器上插物理网卡,此时veth虚拟网卡帮了忙。
ip link add veth0_vpn1 type veth peer name veth_vpn1
ip link add veth0_vpn2 type veth peer name veth_vpn2
随后将veth0_vpn1给了vpn1,将veth0_vpn2给了vpn2
ip link set veth0_vpn1 netns vpn1
ip link set veth0_vpn2 netns vpn2
然后将veth_vpn1,veth_vpn2,eth0桥接在一起:
brctl addbr br0
brctl addif br0 eth0 veth_vpn1 veth_vpn2
好了,接下来就是在这两个命名空间执行OpenVPN了:
ip netns exec vpn1 ifconfig veth0_vpn1 192.168.1.1/24
ip netns exec vpn2 ifconfig veth0_vpn2 192.168.1.1/24
ip netns exec vpn1 openvpn --config /home/zy/vpn/server.conf
ip netns exec vpn2 openvpn --config /home/zy/vpn/server.conf
两个openvpn进程读取同样的配置文件,可是此时它们的网络已经是隔离的了。能够看出,两个命名空间的veth网卡地址全然一样,其实,对于网络配置而言,vpn1和vpn2是全然同样的。由于此时两个命名空间的veth的peer已经和eth0桥接在一起了,接下来的问题是怎样将数据包分发到两个命名空间,此时iptables的CLUSTER target来帮忙了。给出结论之前,眼下的系统原理图例如以下:

3.构建分布式Cluster

如今的问题就是怎样把数据包分发到这两个(实际环境是多个,视CPU数量而定)命名空间。难道要在Bridge这个层次再搞一个相似LVS之类的东西吗?思路是对的,可是我不会那么做,由于那样做还不如不搞命名空间直接在LVS上跑多个服务呢。其实,之所以搞命名空间,就是由于iptables提供了一种分布式的集群负载均衡算法模型,将集中式的决定“由哪个节点处理数据包”这个问题转化为分布式的“这个数据包是否由我来处理”。也就是说,计算分布化了,不再处于一个点上,详细的思想能够參见我的还有一篇文章以及早期全广播以太网的寻址思想。
       如今的问题就是怎样实现将数据包广播到全部的这些命名空间中,对于上图为例,不论什么广播到veth_vpn1和veth_vpn2这两个桥接端口中。iptables的CLUSTER target支持将veth0_vpn1和veth0_vpn2这两个网卡的MAC设置成同一个“组播MAC地址”,而我的工作就是在数据包从eth0进入后,将其目标MAC地址转换为那个组播地址,接下来在网桥forward数据的时候,看到目标是组播,便从veth_vpn1和veth_vpn2两个口都发出去了。这个难道不能通过ebtables的dnat来做吗?
       要问怎样来设置iptables的CLUSTER,也非常easy,两个命名空间除了local-node不一样之外,其余的都一样(这俩命名空间实际上相当于两台机器):
iptables -A INPUT -p udp --dport 1194 -j CLUSTERIP --new --hashmode sourceip --clustermac 01:00:5e:00:00:20 --total-nodes 2 --local-node 1
iptables -A INPUT -p udp --dport 1194 -j CLUSTERIP --new --hashmode sourceip --clustermac 01:00:5e:00:00:20 --total-nodes 2 --local-node 2
CLUSTER target是怎么将hash值映射到node-num的不重要,重要的是它确实能够将来自一个流的hash值映射到1~total-nodes中的一个,并且仅映射到那一个,这样的固定的映射方式保证了一个数据流始终被同一个命名空间处理。如今的图演示样例如以下:

4.知识的广度与深度

懂多少知识不重要,重要的是这些知识能用来干什么。其实,我觉得两类人是不同的,拥有构建能力的人不须要拥有多少知识的细节,属于比較有广度的人,而专攻一点的人往往对细节理解非常深入,属于有深度的人,对于系统project的构建阶段,我个人觉得广度比深度要来得重要,但同一时候绝不能忽略深度,相反,须要一种升华,即你须要拥有极强的洞察力,不须要深入细节的前提下迅速捕捉到关键点,做到这一点,没有对知识的深度理解与积累是非常难做到的。可是对于系统的调试,排错和优化阶段,知识深度的重要性就要大于知识的广度的重要性了。
       知识的广度能够是来自别处的,比方教科书,互联网论坛,博客等,可是知识的深度很多其他的是自己挖掘出来或者悟出来的,对于后者而言,那就是能力了。一个简单的样例,那就是TCP服务器端大量的TIME_WAIT状态套接字对系统的影响,人们提出了非常多的解决方案,比方设置recycle,reuse等,并且都是千篇一律的,是的,这样是能解决这个问题,可是有谁去挖掘过TIME_WAIT究竟带来了什么问题吗?并且是大量的TW套接字,其数量超过ESTABLISH套接字几个数量级的情况。人们普遍的回答是占用系统资源,耗尽socket资源,可是在如今服务器拼硬件的时代,动不动就几百个G的内存的情况下,这都不是什么问题。有人把思路从空间开销转向时间开销吗?有是有,但非常少。为什么呢?可能是由于他们总觉得升级内存比升级CPU划算吧,可其实,差点儿每一个人都知道数据结构的组织不仅仅影响内存占用,还影响操纵效率。仅仅须要略微想一下TCP socket的实现就会明确下面的事实:一个数据包相应到一个socket,须要一个查表的过程,对于TCP而言,首先要检查该数据包是否已经相应到了一个socket,假设没有查到再去查是否有listen socket与之相应(否则怎么办呢?)。也就是说,listen socket的查找是最后才做的。对于一个新建的连接而言,首先它不可能在ESTABLISH状态的socket链表中找到,假设ESTABLISH socket不多的话,这个开销能够忽略,即便非常多,也是必须要例行公事,因此这个查找是必定的开销,可是接下来还要看它是否和一个TIME_WAIT状态的socket相应,此时假设存在大量的TW套接字,那么这样的开销就是额外的开销,是能够避免的,可是有一个前提,那就是必须避开TW带来的问题(在取消一个机制之前,必须明确该机制的全部方方面面)。因此,大量的TW套接字除了消耗空间外,还会减少新建连接的效率,大量的时间会消耗在查表上,对于已经建立的连接的传输数据效率则影响不大,由于在查询TW状态套接字之前,它已经查到了一个ESTABLISH套接字了。假设你本身就懂Linux的TCP层的实现,那么以上的问题非常easy分析,可是假设你从没看过源代码的实现,就须要自己思考了。诚然,熟悉接口而不关注细节能够提高编码的效率,可是这并非箴言,由于熟悉实现细节更能提高出了问题后的排错效率。所以,知识的深度和广度都是必不可少的,关键是你处在哪个阶段。
       假设过度在意学到的东西,那么就会比較僵化,假设过度在意挖掘或者感悟出来的东西,就会easy钻入牛角尖且变得自负。怎样权衡知识的利用方式,十分重要。

OpenVPN多处理之-netns容器与iptables CLUSTER的更多相关文章

  1. 解决Docker容器 iptables问题---docker: Error response from daemon: driver failed programming external connectivity on endpoint quizzical_thompson

    一.问题现象 最近在研究Docker容器日志管理时,启动容器出现iptables相关报错,具体问题如下 运行容器 [root@node-11 ~]# docker run -d -p 24224:24 ...

  2. docker+openvswitch实现主机与容器的网络通信

    主要用到openvswitch和netns网络名称空间的相关知识还有ip命令的使用. 实验环境的结构图如下: 思路如下: 安装openvswitch ovs创建br0,br1,并启动两个不加载网络的d ...

  3. Docker容器的原理与实践 (下)

    欢迎访问网易云社区,了解更多网易技术产品运营经验. Docker原理分析 Docker架构 镜像原理 镜像是一个只读的容器模板,含有启动docker容器所需的文件系统结构及内容Docker以镜像和在镜 ...

  4. Iptables工作原理使用详解

    Iptables防火墙简介 Iptables名词和术语 Iptables工作流程 基本语法 Filter 参数说明 NAT表: Icmp协议 TCP FLAG 标记 什么是状态检测 iptables的 ...

  5. Centos7.2下OpenVPN 环境完整部署记录

    关于OpenVPN的有关介绍及为何使用OpenVPN在此就不做赘述了,下面直接记录Centos7.2系统下部署OpenVPN环境的操作过程: 1) 先将本机的yum换成阿里云的yum源 [root@t ...

  6. 理解kubernetes环境的iptables

    node节点的iptables是由kube-proxy生成的,具体实现可以参见kube-proxy的代码 kube-proxy只修改了filter和nat表,它对iptables的链进行了扩充,自定义 ...

  7. 通过OpenVPN来穿越上网(未实践)

    说明: 1.其实OpenVPN可以通过其实现穿越来上网,即全部请求都经过OpenVPN来处理.其原理是iptables转发.如果全程走iptables也是可以的,网上的教程基本都是基于iptables ...

  8. 【 Linux 网络虚拟化 】Netns

    netns 可以创建一个完全隔离的新网络环境,这个环境包括一个独立的网卡空间,路由表,ARP表,ip地址表,iptables等.总之,与网络有关的组件都是独立的. 创建网络空间: # ip netns ...

  9. openstack通过Network Namespace和iptables实现租户私有网络互訪和L3路由功能

    安装架构介绍 本文旨在通过自己搭建类似neutron (openvswitch + gre) 实现SDN 的环境,学习了解其工作原理,模拟核心原理.比方:同一租户自己定义网络 instance 互通, ...

随机推荐

  1. 函数可以作为Javascript对象(哈希表)的键吗

    一般Javascript书在讲解对象时,都指出Javascript中的对象可以作为哈希表,存储键值数据.通常情况下,键为字符串,如果键是数字的话,实际上在内部也会转换为字符串. 比如 var o = ...

  2. Acitivity创建与配置

    •Activity的创建和配置 –Activity提供了和用户交互的可视化界面.创建一个Activity一般是继承Activity(当然也可以继承ListActivity.MapActivity等), ...

  3. 华为HCNA教程(笔记)

    第一章 VRP操作基础 1VRP基础 MiniUsb串口连接交换机的方法 2eNSP入门 3命令行基础(1) eNSP中路由开启后(记住port)---第三方软件连接该路由方法:telnet 127. ...

  4. linux定时调度器每秒运行一次

    linux操作系统最小粒度的定时调度器仅仅能调到分钟的级别,工作中有时需在到秒的调度,所以须要自己编写脚本来实现 #!/bin/bash while [ true ]; do /bin/sleep 1 ...

  5. libevent: linux安装libevent

    http://libevent.org/上下载最新的libevent, 如 libevent-2.0.22-stable.tar.gz. 然后解压,按照README里面的步骤安装.

  6. Gradle的简介与安装

    Gradle介绍 Gradle是一个基于JVM的构建工具,它提供了: 像Ant一样,通用灵活的构建工具 可以切换的,基于约定的构建框架 强大的多工程构建支持 基于Apache Ivy的强大的依赖管理 ...

  7. 趋势科技4月移动client病毒报告

    2014年4月移动client安全威胁概况 截至2014年4月30日,中国区移动client病毒码1.669.60,大小9,792,484字节,能够检測病毒约221万个.移动client病毒约12万个 ...

  8. fcntl()

      fcntl() F_GETFL---------------------------------------------        将文件状态标志作为函数值返回. 文件状态标志:        ...

  9. Python MySQLdb Mac安装遇到的问题

    Mac 下使用Python 连接Mysql 数据库,使用到模块MySQLdb,各种问题都出现,搜集整理下,最后发现最关键的还是Mac 下的Python 版本问题 前置条件: 1. 已经安装mysql ...

  10. 在Windows下搭建C++11 编译环境(附下载,包括mingw-build,TDM-GCC, nuwen MinGW Distro)

    由于现实的一些原因,并不是所有人都能很方便的享受到C++11 特性.特别是C++ Primer 第五版 和 The C++ Programming Language 第四版等全面C++ 11 铺开以后 ...