Jepsen是一款用来验证分布式系统安全性的工具。
安装
Jepsen是使用Clojure编写,Clojure基于JVM上的一款Lisp方言,本文假设对Lisp和函数式编程是有基础知识。特别地,我们关注以下几点语法
函数
函数使用defn
定义,使用一个中括号接受参数。在参数列表中可以使用[& args]
,表示&
之后的args
是一个可变参数列表。函数可以拥有多个重载,如下面代码所示1
2
3
4
5(defn hello3
([] "Hello World")
([name] (str "Hello " name)))
(hello3 "Jake") ; => "Hello Jake"
(hello3) ; => "Hello World"函数调用
使用/
调用静态函数,例如c/cd
调用类c
里面的cd
方法。
使用.
调用成员函数,例如. (Date.) getTime
调用了一个Date
类型的对象Date.
的成员方法getTime
映射数据结构
我们使用如下所示的方式定义一个Map1
2
3
4(def popsicle-map
(hash-map :red :cherry, :green :apple, :purple :grape))
(def popsicle-map
{:red :cherry, :green :apple, :purple :grape}) ; same as previous然后使用这样的方式访问其中的元素
1
2
3(get popsicle-map :green)
(popsicle-map :green)
(:green popsicle-map)doto
类似vb里面的With
Leiningen是Clojure项目的自动化配置工具,可以通过其官网的自安装脚本使用。
在Docker上配置Jepsen
Jepsen官方推荐的Jepsen使用方式是借助于Docker或者虚拟机。特别地,试图用同一个IP上的多个端口来处理是很麻烦的。因此使用Docker是单机上运行Jespen的做法。
以etcd测试为例,Jespen喜欢从官网上下载项目的release并安装,这对于国内用户是相当不友好的。对此,我们可以进入Jespen项目中的docker/control文件夹,将我们需要的binary放进去。这样在up.sh中,Jepsen会统一将control目录中的文件进行打包拷贝到容器中。接着我们修改Dockerfile,用来将我们传入容器中的release安装到指定位置。以etcd为例,我们编写如下所示的代码
1 | # /docker/control/Dockerfile |
并且注释掉etcd/src/jepsen/etcd.clj里面的从googleapis下载etcd的命令。
接着我们清除旧的容器,并启动新的
1 | docker stop $(docker ps -aq) |
常见错误
ssh配置问题
我在使用百度的jepsen时出现这个错误。通常原因是没有配置好ssh
1 | lein test :only jepsen.atomic-test/create-partition |
docker配置问题
下面这个错误的第一个原因是jepsen-control上没有sudo
1 | ERROR [2019-02-21 14:04:00,576] main - jepsen.cli Oh jeez, I'm sorry, Jepsen broke. Here's why: |
第二个原因是jepsen-n1等节点上没有etcd,我们需要改以下的细节
在up.sh中加上
1
2
3
4
5
6INFO "Copying .. to node/jepsen"
(
rm -rf ./node/jepsen
mkdir ./node/jepsen
(cd ..; tar --exclude=./docker --exclude=./.git -cf - .) | tar Cxf ./node/jepsen -
)参照control/Dockerfile修改node/Dockerfile
将etcd也复制到node文件夹里面
修改etcd.clj里面的代码,注释掉下载etcd和删除etcd文件夹的语句。
etcd问题
在control节点中运行lein run test --concurrency 10
时出现这个问题
1 | INFO [2019-02-22 07:37:52,339] jepsen worker 5 - jepsen.util 35 :invoke :write [0 1] |
查看n1节点的etcd日志发现以下错误
1 | 2019-02-22 07:37:45 Jepsen starting etcd :--name n1 :--listen-peer-urls http://n1:2380 :--listen-client-urls http://n1:2379 :--advertise-client-urls http://n1:2379 :--initial-cluster-state :new :--initial-advertise-peer-urls http://n1:2380 :--initial-cluster n1=http://n1:2380,n2=http://n2:2380,n3=http://n3:2380,n4=http://n4:2380,n5=http://n5:2380 :--log-output :stdout |
这是因为我们在url里面使用了n1、n2这样的名字。修改etcd.clj里面的代码,将所有的name
改成jepsen.control.net/ip
即可解决问题。特别地,这个问题在jepsen的一个PR中出现过