性能测试应该怎么做?
偶然间看到了阿里中间件Dubbo的性能测试报告,我觉得这份性能测试报告让人觉得做这性能测试的人根本不懂性能测试,我觉得这份报告会把大众带沟里去,所以,想写下这篇文章,做一点科普。
首先,这份测试报告里的主要问题如下:
1)用的全是平均值。老实说,平均值是非常不靠谱的。
2)响应时间没有和吞吐量TPS/QPS挂钩。而只是测试了低速率的情况,这是完全错误的。
3)响应时间和吞吐量没有和成功率挂钩。
偶然间看到了阿里中间件Dubbo的性能测试报告,我觉得这份性能测试报告让人觉得做这性能测试的人根本不懂性能测试,我觉得这份报告会把大众带沟里去,所以,想写下这篇文章,做一点科普。
首先,这份测试报告里的主要问题如下:
1)用的全是平均值。老实说,平均值是非常不靠谱的。
2)响应时间没有和吞吐量TPS/QPS挂钩。而只是测试了低速率的情况,这是完全错误的。
3)响应时间和吞吐量没有和成功率挂钩。
昨天,我看到一个新闻——雅虎取消了QA团队,工程师必须自己负责代码质量,并使用持续集成代替QA。 同时,也听到网友说,“听微软做数据库运维的工程师介绍,他们也是把运维工程师和测试工程师取消了,由开发全部完成。每个人都是全栈工程师”。于是,我顺势引用了几年前写过一篇文章《我们需要专职的QA吗?》,并且又鼓吹了一下全栈。当然,一如既往的得到了一些的争议和嘲弄;-)。
有人认为取消QA基本上是公司没钱的象征,这个观点根本不值一驳,属于井底之蛙。有人认为,社会分工是大前提,并批评我说怎么不说把所有的事全干的,把我推向了另外一个极端。另外,你千万不要以为有了分工,QA的工作就保得住了。
就像《乔布斯传》中乔布斯质疑财务制度的时候说的,有时候,很多人都不问为什么,觉得存在的东西都是理所应当的东西。让我们失去了独立思考的机会。分工也是一样。
所以,为了说完整分工这个逻辑。请大家耐住性子,让我就先来谈谈“分工的优缺点”吧。
在上一篇介绍AUFS的文章中,大家可以看到,Docker的分层镜像是怎么通过UnionFS这种文件系统做到的,但是,因为Docker首选的AUFS并不在Linux的内核主干里,所以,对于非Ubuntu的Linux分发包,比如CentOS,就无法使用AUFS作为Docker的文件系统了。于是作为第二优先级的DeviceMapper就被拿出来做分层镜像的一个实现。
DeviceMapper自Linux 2.6被引入成为了Linux最重要的一个技术。它在内核中支持逻辑卷管理的通用设备映射机制,它为实现用于存储资源管理的块设备驱动提供了一个高度模块化的内核架构,它包含三个重要的对象概念,Mapped Device、Mapping Table、Target device。
Mapped Device 是一个逻辑抽象,可以理解成为内核向外提供的逻辑设备,它通过Mapping Table描述的映射关系和 Target Device 建立映射。Target device 表示的是 Mapped Device 所映射的物理空间段,对 Mapped Device 所表示的逻辑设备来说,就是该逻辑设备映射到的一个物理设备。
Mapping Table里有 Mapped Device 逻辑的起始地址、范围、和表示在 Target Device 所在物理设备的地址偏移量以及Target 类型等信息(注:这些地址和偏移量都是以磁盘的扇区为单位的,即 512 个字节大小,所以,当你看到128的时候,其实表示的是128*512=64K)。
AUFS是一种Union File System,所谓UnionFS就是把不同物理位置的目录合并mount到同一个目录中。UnionFS的一个最主要的应用是,把一张CD/DVD和一个硬盘目录给联合 mount在一起,然后,你就可以对这个只读的CD/DVD上的文件进行修改(当然,修改的文件存于硬盘上的目录里)。
AUFS又叫Another UnionFS,后来叫Alternative UnionFS,后来可能觉得不够霸气,叫成Advance UnionFS。是个叫Junjiro Okajima(岡島順治郎)在2006年开发的,AUFS完全重写了早期的UnionFS 1.x,其主要目的是为了可靠性和性能,并且引入了一些新的功能,比如可写分支的负载均衡。AUFS在使用上全兼容UnionFS,而且比之前的UnionFS在稳定性和性能上都要好很多,后来的UnionFS 2.x开始抄AUFS中的功能。但是他居然没有进到Linux主干里,就是因为Linus不让,基本上是因为代码量比较多,而且写得烂(相对于只有3000行的union mount和10000行的UnionFS,以及其它平均下来只有6000行代码左右的VFS,AUFS居然有30000行代码),所以,岡島不断地改进代码质量,不断地提交,不断地被Linus拒掉,所以,到今天AUFS都还进不了Linux主干(今天你可以看到AUFS的代码其实还好了,比起OpenSSL好N倍,要么就是Linus对代码的质量要求非常高,要么就是Linus就是不喜欢AUFS)。
不过,好在有很多发行版都用了AUFS,比如:Ubuntu 10.04,Debian6.0, Gentoo Live CD支持AUFS,所以,也OK了。
好了,扯完这些闲话,我们还是看一个示例吧(环境:Ubuntu 14.04)
前面,我们介绍了Linux Namespace,但是Namespace解决的问题主要是环境隔离的问题,这只是虚拟化中最最基础的一步,我们还需要解决对计算机资源使用上的隔离。也就是说,虽然你通过Namespace把我Jail到一个特定的环境中去了,但是我在其中的进程使用用CPU、内存、磁盘等这些计算资源其实还是可以随心所欲的。所以,我们希望对进程进行资源利用上的限制或控制。这就是Linux CGroup出来了的原因。
Linux CGroup全称Linux Control Group, 是Linux内核的一个功能,用来限制,控制与分离一个进程组群的资源(如CPU、内存、磁盘输入输出等)。这个项目最早是由Google的工程师在2006年发起(主要是Paul Menage和Rohit Seth),最早的名称为进程容器(process containers)。在2007年时,因为在Linux内核中,容器(container)这个名词太过广泛,为避免混乱,被重命名为cgroup,并且被合并到2.6.24版的内核中去。然后,其它开始了他的发展。
Linux CGroupCgroup 可让您为系统中所运行任务(进程)的用户定义组群分配资源 — 比如 CPU 时间、系统内存、网络带宽或者这些资源的组合。您可以监控您配置的 cgroup,拒绝 cgroup 访问某些资源,甚至在运行的系统中动态配置您的 cgroup。
主要提供了如下功能:
时下最热的技术莫过于Docker了,很多人都觉得Docker是个新技术,其实不然,Docker除了其编程语言用go比较新外,其实它还真不是个新东西,也就是个新瓶装旧酒的东西,所谓的The New “Old Stuff”。Docker和Docker衍生的东西用到了很多很酷的技术,我会用几篇 文章来把这些技术给大家做个介绍,希望通过这些文章大家可以自己打造一个山寨版的docker。
当然,文章的风格一定会尊重时下的“流行”——我们再也没有整块整块的时间去看书去专研,而我们只有看微博微信那样的碎片时间(那怕我们有整块的时间,也被那些在手机上的APP碎片化了)。所以,这些文章的风格必然坚持“马桶风格”(希望简单到占用你拉一泡屎就时间,而且你还不用动脑子,并能学到些东西)
废话少说,我们开始。先从Linux Namespace开始。
Linux Namespace是Linux提供的一种内核级别环境隔离的方法。不知道你是否还记得很早以前的Unix有一个叫chroot的系统调用(通过修改根目录把用户jail到一个特定目录下),chroot提供了一种简单的隔离模式:chroot内部的文件系统无法访问外部的内容。Linux Namespace在此基础上,提供了对UTS、IPC、mount、PID、network、User等的隔离机制。
在 Docker基础技术:Linux Namespace(上篇)中我们了解了,UTD、IPC、PID、Mount 四个namespace,我们模仿Docker做了一个相当相当山寨的镜像。在这一篇中,主要想向大家介绍Linux的User和Network的Namespace。
好,下面我们就介绍一下还剩下的这两个Namespace。
User Namespace主要是用了CLONE_NEWUSER的参数。使用了这个参数后,内部看到的UID和GID已经与外部不同了,默认显示为65534。那是因为容器找不到其真正的UID所以,设置上了最大的UID(其设置定义在/proc/sys/kernel/overflowuid)。
要把容器中的uid和真实系统的uid给映射在一起,需要修改 /proc/<pid>/uid_map 和 /proc/<pid>/gid_map 这两个文件。这两个文件的格式为:
ID-inside-ns ID-outside-ns length
其中:
今天,在微博上看了一篇《微信和淘宝到底是谁封谁》的文章,我觉得文章中逻辑错乱,所以,我发了一篇关于这篇文章逻辑问题的长微博。后面,我被原博主冷嘲热讽了一番,说是什么鸡汤啊,什么我与某某之流的人在一起混淆视听啊,等等。并且也有一些网友找我讨论一下相关的钓鱼式攻击的技术问题。所以,我想写下这篇纯技术文章,因为我对那些商业利益上的东西不关心,所以,只谈技术,这样最简单。
首先说明一下,我个人不是一个安全专家,也不是一个移动开发专家,按道理来说,这篇文章不应该我来写,但是我就试一试,请原谅我的无知,也期待抛砖引玉了,希望安全的同学斧正。
关于钓鱼式攻击,其实是通过一种社会工程学的方式来愚弄用户的攻击式,攻击者通常会模仿一个用户信任的网站来偷取用户的机密信息,比如用户密码或是信用卡。一般来说,攻击者会通过邮件和实时通信工具完成,给被攻击者发送一个高仿的网站,然后让用户看不出来与正统网站的差别,然后收集用户的机密数据。
因为钓鱼式攻击并不新鲜,所以我这里只讲移动方面的。
在移动端,这个事情会更容易干,因为移动端有如下特点:
下面我们来分析下移动端的用户操作,我们重点关注用户控制权的切换过程(因为这是攻击点)
在知乎上,有个人问了这样的一个问题——为什么vfork的子进程里用return,整个程序会挂掉,而且exit()不会?并给出了如下的代码,下面的代码一运行就挂掉了,但如果把子进程的return改成exit(0)就没事。
我受邀后本来不想回答这个问题的,因为这个问题明显就是RTFM的事,后来,发现这个问题放在那里好长时间,而挂在下面的几个答案又跑偏得比较严重,我觉得可能有些朋友看到那样的答案会被误导,所以就上去回答了一下这个问题。
下面我把问题和我的回答发布在这里,也供更多的人查看。
#include <stdio.h> #include <stdlib.h> #include <unistd.h> int main(void) { int var; var = 88; if ((pid = vfork()) < 0) { printf("vfork error"); exit(-1); } else if (pid == 0) { /* 子进程 */ var++; return 0; } printf("pid=%d, glob=%d, var=%d\n", getpid(), glob, var); return 0; }
Leetcode这个网站上的题都是一些经典的公司用来面试应聘者的面试题,很多人通过刷这些题来应聘一些喜欢面试算法的公司,比如:Google、微软、Facebook、Amazon之类的这些公司,基本上是应试教育的功利主义。
我做这些题目的不是为了要去应聘这些公司,而是为了锻炼一下自己的算法和编程能力。因为我开始工作的时候基本没有这样的训练算法和编程的网站,除了大学里的“算法和数据结构”里的好些最基础最基础的知识,基本上没有什么训练。所以,当我看到有人在做这些题的时候,我也蠢蠢欲动地想去刷一下。
于是,我花了3-4个月的业余时间,我把Leetcode的154道题全部做完了。(这也是最近我没有太多的时间来写博客的原因,你可以看到我之前做的那个活动中有几个算法题来自于Leetcode)有人说我时间太多了,这里声明一下,我基本上都是利用了晚上10点以后的时间来做这些题的。
LeetCode的题大致分成两类:
1)基础算法的知识。这些题里面有大量的算法题,解这些题都是有套路的,不是用递归(深度优先DFS,广度优先BFS),就是要用动态规划(Dynamic Programming),或是拆半查找(Binary Search),或是回溯(Back tracing),或是分治法(Divide and Conquer),还有大量的对树,数组、链表、字符串和hash表的操作。通过做这些题能让你对这些最基础的算法的思路有非常扎实的了解和训练。对我而言,Dynamic Programming 是我的短板,尤其是一些比较复杂的问题,在推导递推公式上总是有思维的缺陷(数学是我的硬伤),通过做了这些题后,我能感到我在DP的思路上有了很大的收获。
2)编程题。比如:atoi,strstr,add two num,括号匹配,字符串乘法,通配符匹配,文件路径简化,Text Justification,反转单词等等,这些题的Edge Case, Corner Case有很多。这些题需要你想清楚了再干,只要你稍有疏忽,就会有几个case让你痛不欲生,而且一不小心就会让你的代码会写得又臭又长,无法阅读。通过做这些题,可以非常好的训练你对各种情况的考虑,以及你对程序代码组织的掌控(其实就是其中的状态变量)。还记得我在《函数式编程》中说的,程序中的状态是你程序变得复杂难维护的直接原因。
我觉得每个程序员都应该花时间和精力做这些题,因为你会从这些题中得到很大的收益。做完这些题后你一定会明白下面几个道理: