使用 ip/iptables 命令模拟 Docker bridge 网络

前文介绍,Linux Network namespace 用于给进程创建一个新的网络栈,路由、防火墙规则、网络设备。man ip-netns

A network namespace is logically another copy of the network stack, with its own routes, firewall rules, and network devices.

作为对 Network namespace 的实践,本文使用 ip/iptables 等命令模拟下 Docker bridge 网络,并会接触到 Network namespace,veth pair,Linux bridge,NAT 等概念。

实验

使用 ip命令操作 Network namespace

ip netns 子命令用于操作 Network namespace。使用 add 子命令,创建一个 Network namespace。

# ip netns add netns1

查看 netns1 的网络设备(network device)。使用 exec 子命令,后接 netns1 和要执行的命令。默认有一个 DOWN 状态的 lo 设备。

瘦终端指北 —— ICMP tunnel

因为公司有开发泄露源码在 Github,对公司声誉造成一定影响,公司层面推广起瘦终端,所有开发一起背锅 :( 。在瘦终端里,网络严格管控,vscode 下载插件都难,需要申请 IP 白名单。开发只允许在瘦终端里接触 git 仓库,只能向瘦终端拷贝文件,反之不能。这样就能防住代码泄露么?

搞笑的办法,瘦终端生成二维码,主机扫描,数据传输问题搞定。

从网络角度,怎么解决呢。我们来严肃看待这个技术问题。

ICMP

实践发现,瘦终端里不能访问百度,但是能 ping 通。从 TCP/IP 的角度,瘦终端在网络上只是 TCP 传输层被流量管控了,IP 层还是畅通无阻的。

下图为 TCP/IP 的层次结构,TCP 包封装于 IP 包。

../../images/Packet-encapsulation-TCP-IP-architecture-encapsulates-the-data-from-the-upper-layer-by.png

https://www.researchgate.net/figure/Packet-encapsulation-TCP-IP-architecture-encapsulates-the-data-from-the-upper-layer-by_fig4_49288737

目前网站的基石是 HTTP/TCP 协议,代理也普遍是基于 HTTP/TCP 的,shadowsocks 翻墙的思路不通。

所以 ICMP 协议是否能作为代理协议呢。从封包的角度,ICMP 与 TCP 一样,也是封在 IP 包中的。

Linux Namespace

Linux Namespace

namespace 在编程语言中是一种常见的概念,C++/Clojure 中就使用 namespace 关键字来模块化组织代码。模块与模块之间互不污染,模块A有个 helloworld 的方法,模块B也可以有一个 helloworld 的方法。Java/Go 中的 package 也是同样的意义。

Linux namespaces 是 Linux 内核用于隔离内核资源的手段,进程使用隔离的内核资源保证了与其他进程之间的独立。也是 Docker 容器的底层技术(Docker 主要开发语言是 Go,container 的创建使用 C)。

Namespaces are a feature of the Linux kernel that partitions kernel resources such that one set of processes sees one set of resources while another set of processes sees a different set of resources. The feature works by having the same namespace for a set of resources and processes, but those namespaces refer to distinct resources. Resources may exist in multiple spaces. Examples of such resources are process IDs, hostnames, user IDs, file names, and some names associated with network access, and interprocess communication.

记录一个 Impala JDBC 驱动问题

现象

洪敏在用 Metabase 写报表过程中,使用 Metabase 的日期变量,发现的诡异问题。两条语句仅有部分差异,返回的结果却差了一天。

../../images/image-20200807173209949.png

期望结果。

../../images/image-20200807173143617.png

与期望结果差了一天。

在 CDH 中查看 impala 服务器接收到的请求。

得到期望结果的SQL:

dt 是字符串,内容是日期,参数是TIMESTAMP,SQL引擎会自动转为两个 TIMESTAMP比较。

SELECT `a`.`dt`, (`a`.`x` - `b`.`x`) as `净增人数` FROM (SELECT `f_ods_wx_subscribe_di`.`dt`, COUNT(DISTINCT `f_ods_wx_subscribe_di`.`userinfo_openid`) as `x` FROM `product`.`f_ods_wx_subscribe_di` WHERE ((`f_ods_wx_subscribe_di`.`dt` < CAST( '2020-08-05 00:00:00.0' AS TIMESTAMP)) AND ((`f_ods_wx_subscribe_di`.`mid` = 'jt20191017175015910985') AND (`f_ods_wx_subscribe_di`.`dt` >= CAST( '2020-08-01 00:00:00.0' AS TIMESTAMP)))) GROUP BY `f_ods_wx_subscribe_di`.`dt`) AS a LEFT JOIN (SELECT `f_ods_wx_unsubscribe_di`.`dt`, COUNT(DISTINCT `f_ods_wx_unsubscribe_di`.`userinfo_openid`) as `x` FROM `product`.`f_ods_wx_unsubscribe_di` WHERE ((`f_ods_wx_unsubscribe_di`.`dt` < CAST( '2020-08-05 00:00:00.0' AS TIMESTAMP)) AND ((`f_ods_wx_unsubscribe_di`.`mid` = 'jt20191017175015910985') AND (`f_ods_wx_unsubscribe_di`.`dt` >= CAST( '2020-08-01 00:00:00.0' AS TIMESTAMP)))) GROUP BY `f_ods_wx_unsubscribe_di`.`dt`) AS b ON (`a`.`dt` = `b`.`dt`)

得到错误结果的SQL:

dt 本身是字符串,参数也是字符串。变成两个字符串比较,结果确实差一天。只是在select里使用了一个函数,就造成SQL巨大差异,很神奇。

 select a.dt ,(a.x - nvl(b.x,0)) as `净增人数` from ( SELECT dt, count(distinct userinfo_openid) as x FROM f_ods_wx_subscribe_di WHERE mid = 'jt20191017175015910985' AND dt >= '2020-08-01 00:00:00.0' and dt < '2020-08-05 00:00:00.0' group by dt ) a left join ( SELECT dt, count(distinct userinfo_openid) as x FROM f_ods_wx_unsubscribe_di WHERE mid = 'jt20191017175015910985' AND dt >= '2020-08-01 00:00:00.0' and dt < '2020-08-05 00:00:00.0' group by dt ) b on a.dt = b.dt

metabase,metabase impala driver,impala JDBC driver都会有问题。

【阅读】How Ray Uses gRPC (and Arrow) to Outperform gRPC

原文:How Ray Uses gRPC (and Arrow) to Outperform gRPC

对理解 Ray 的底层逻辑有帮助。文中描述的Ray版本为0.8。

Overview of Ray

Ray 的计算任务分为两类,无状态计算任务 Task,有状态计算任务 Actor。

  • Tasks (remote functions): these let you run a function remotely in a cluster. Tasks are for stateless computation.
  • Actors (remote classes): these are instances of Python classes running remotely in worker processes in a cluster. Actors are for stateful computation, where evolving state needs to be managed.

原文讲的是Ray核心逻辑,如何使用gRPC和Arrow的。

【阅读】Machine Learning Serving Broken

原文 Machine Learning Serving is BrokenDistributed Computing with Ray 专栏文章,聊了机器学习模型的 Serving 问题,记录一二。

设立好机器学习目标后,从模型角度,机器学习整体可分这么2个阶段:

  1. 模型的创建。模型训练 Training。包括训练数据准备,选择最好的模型(超参数调优)。
  2. 模型的使用。模型推理 Inference。也包括输入数据的准备。

模型被使用,才是机器学习落地的开始。

../../images/1*P_eJtjAZjntemqvLreZ8EA.jpeg

Wrap Your Model in Flask

机器学习模型一般使用 Python 开发,所以使用 Flask 是很自然就能想到的方案。

从 coding 角度,与传统的Web应用开发区别不大。把模型、数据库当做黑盒,开发只关心输入输出。

../../images/1*boWvKC0jg5hrVv53icMwIg.png

使用 Flask 进行 Serving,给了模型的开发者很大的便利,同样的 Python 技术栈,Flask 学习成本又低,从模型开发到模型API化可以一人搞定。不同的机器学习模型的格式差异(ScikitLearn与TensorFlow的模型格式就迥异)统一使用HTTP协议抹平。这是优点。

表面上是美好的。但是,机器学习 Serving 需要大内存加载模型,并且执行计算密集型任务。响应时间秒级,QPS 100+是常见的。下图比较的是单机与传统Web Serving的不同。

../../images/1*TOFL3owzto7bD0o5K1AopQ.png