Tsung笔记之分布式增强跳出SSH羁绊篇
前言
Erlang天生支持分布式环境,Tsung框架的分布式压测受益于此,简单轻松操控子节点生死存亡、派发任务等不费吹灰之力。
Tsung启动分布式压测时,主节点tsung_controller默认情况下需要通过SSH通道连接到远程机器上启动从节点,那么问题便来了,一般互联网公司基于跳板/堡垒机/网关授权方式访问机房服务器,那么SSH机制失效,并且被明令禁止。SSH不通,Tsung主机启动不了从机,分布式更无从谈起。
那么如何解决这个问题呢,让tsung在复杂的机房网络环境设定下更加如鱼得水,将是本文所讨论的内容。
RSH:Remote Shell
RSH,remote shell缩写,维基百科上英文解释:https://en.wikipedia.org/wiki/Remote_Shell。作为一个终端工具,Linux界鸟哥曾经写过 RSH客户端和服务器端搭建教程。
在CentOS下安装也简单:
yum install rsh
Erlang借助于rsh命令行工具通过SSH通道连接到从节点启动Tsung应用,下面可以看到rsh工具本身失去了原本的含义,类似于exec
命令功效。
比如Erlang主节点(假设这个服务器名称为node_master
,并且已经在/etc/hosts文件建立了IP地址映射)在启动时指定rsh的可选方式为SSH:
erl -rsh ssh -sname foo -setcookie mycookie
启动之后,要启动远程主机节点名称为node_slave
的子节点:
slave:start(node_slave, bar, "-setcookie mycookie").
上面Erlang启动从节点函数,最终被翻译为可执行的shell命令:
ssh node_slave erl -detached -noinput -master foo@node_master -sname bar@node_slave -s slave slave_start foo@node_master slave_waiter_0 -setcookie mycookie
erl
命令Erlang的启动命令,要求主机node_slave
自身也要安装了Erlang的运行时环境才行。
从节点的启动命令最终依赖于SSH连接并远程执行,其通用一般格式为:
ssh HOSTNAME/IP Command
这就是基于Erlang构建的Tsung操控从节点启动的最终实现机制。
其它语言中,Master启动Slave也是如此机制
SSH为通用方案,但不是最好的方案
业界选用SSH机制连接远程Unix/Linux服务器主机,分布式环境下要能够自由免除密码方式启动远程主机上(这里指的是内部Lan环境)应用,一般需要设置公钥,需要传递公钥,需要保存到各自机器上,还有经常遇到权限问题,很是麻烦,这是其一。若要取消某台服务器登陆授权,则需要被动修改公钥,也是不够灵活。
另外一般互联网公司处于安全考虑都会禁止公司内部人员直接通过SSH方式登录到远程主机进行操作,这样导致SSH通道失效,Tsung主机通过SSH连接到从机并执行命令,也就不可能了。
其实,在基于分布式压测环境下,快速租赁、快速借用/归还的模型就很适合。一般公司很少会存在专门用于压测的大量空闲机器,但是线上会运行着当前负载不高的服务器,可以拿来用作压测客户端使用,用完就归还。因为压测不会是长时间运行的服务,其为短时间行为。这种模式下就不适合复杂的SSH公钥满天飞,后期忘记删除的情况,在压测端超多的情况下,无疑也将造成运维成本激增,安全性降低等问题。
SSH替换方案:一种快速租赁模式远程终端方案
现在需要寻找一种新的代替方案,一种适应快速租赁的远程终端实现机制。
替换方案要求点
- 类似于SSH Server,监听某个端口,能够执行传递过来的命令
- 能够根据IP地址授权,这样只有Tsung Master才能够访问从节点,从节点之间无法直接对连
- 需要接受一些操控指令,可以判断是否存活
- 一到两个脚本/程序搞定,尽量避免安装,开箱即用
- 总之配置、操作一定要简单,实际运维成本一定要低
没找到很轻量的实现,可以设计并实现这样一种方案。
服务器端守护进程
轻量级服务端守护进程 = 一个监控端口的进程(rsh_daemon.sh
) + 执行命令过滤功能(rsh_filter)
rsh_daemon.sh
负责守护进程的管理:
- 基于CentOS 6/7默认安装的
ncat
程序 - 主要用于管理19999端口监听
- start/stop/restart 负责监控进程启动、关闭
- status 查看进程状态
- kill 提供手动方式关闭并删除掉自身
rsh_filter
用于检测远程传入命令并进行处理- 接收ping指令,返回pong
- 执行Erlang从节点命令,并返回 done 字符串
- 对不合法命令,直接关闭
rsh_daemon.sh
代码很简单:
#!/bin/bash
# the script using for start/stop remote shell daemon server to replace the ssh server
PORT=19999
FILTER=~/tmp/_tmp_rsh_filter.sh
# the tsung master's hostname or ip
tsung_controller=tsung_controller
SPECIAL_PATH=""
PROG=`basename $0`prepare() {cat << EOF > $FILTER
#!/bin/bash
ERL_PREFIX="erl"while true
doread CMDcase \$CMD inping)echo "pong"exit 0;;*)if [[ \$CMD == *"\${ERL_PREFIX}"* ]]; thenexec $SPECIAL_PATH\${CMD}fiexit 0;;esac
done
EOFchmod a+x $FILTER
}start() {NUM=$(ps -ef|grep ncat | grep ${PORT} | grep -v grep | wc -l)if [ $NUM -gt 0 ];thenecho "$PROG already running ..."exit 1fiif [ -x "$(command -v ncat)" ]; thenecho "$PROG starting now ..."ncat -4 -k -l $PORT -e $FILTER --allow $tsung_controller &elseecho "no exists ncat command, please install it ..."fi
}stop() {NUM=$(ps -ef|grep ncat | grep rsh | grep -v grep | wc -l)if [ $NUM -eq 0 ]; thenecho "$PROG had already stoped ..."elseecho "$PROG is stopping now ..."ps -ef|grep ncat | grep rsh | grep -v grep | awk '{print $2}' | xargs killfi
}status() {NUM=$(ps -ef|grep ncat | grep rsh | grep -v grep | wc -l)if [ $NUM -eq 0 ]; thenecho "$PROG had already stoped ..."elseecho "$PROG is running ..."fi
}usage() {echo "Usage: $PROG <options> start|stop|status|restart"echo "Options:"echo " -a <hostname/ip> allow only given hosts to connect to the server (default is tsung_controller)"echo " -p <port> use the special port for listen (default is 19999)"echo " -s <the_erl_path> use the special erlang's erts bin path for running erlang (default is blank)"echo " -h display this help and exit"exit
}while getopts "a:p:s:h" Option
docase $Option ina) tsung_controller=$OPTARG;;p) PORT=$OPTARG;;s) TMP_ERL=$OPTARGif [ "$OPTARG" != "" ]; thenif [[ "$OPTARG" == *"/" ]]; thenSPECIAL_PATH=$OPTARGelseSPECIAL_PATH=$OPTARG"/"fifi;;h) usage;;*) usage;;esac
done
shift $(($OPTIND - 1))case $1 instart)preparestart;;stop)stop;;status)status;;restart)stopstart;;*)usage;;
esac
总结一下:
- 基于
ncat
监听19999端口提供bind shell机制,但限制有限IP可访问 - 动态生成命令过滤脚本
rsh_filter.sh
,执行Erlang从节点命令
请参考:https://github.com/weibomobile/tsung_rsh/blob/master/rsh_daemon.sh
客户端连接方案
服务器端已经提供了端口接入并准备好了接收指令,客户端(rsh_client.sh
)可以进行连接和交互了:
- 类似SSH客户端接收方式:
rsh_client.sh Host/IP Command
- 完全基于
nc
命令,连接远程主机 - 连接成功,发送命令
- 得到相应,流程完成
一样非常少的代码呈现。
#!/bin/sh
PORT=19999if [ $# -lt 2 ]; thenecho "Invalid number of parameters"exit 1
fiREMOTEHOST="$1"
COMMAND="$2"if [ "${COMMAND}" != "erl" ]; thenecho "Invalid command ${COMMAND}"exit 1
fishift 2echo "${COMMAND} $*" | /usr/bin/nc ${REMOTEHOST} ${PORT}
Erlang主节点如何启动
有了SSH替换方案,那主节点就可以这样启动了:
erl -rsh ~/.tsung/rsh_client.sh -sname foo -setcookie mycookie
比如当Tsung需要连接到另外一台服务器上启动从节点时,它最终会翻译成下面命令:
/bin/sh /root/.tsung/rsh_client.sh node_slave erl -detached -noinput -master foo@node_master -sname bar@node_slave -s slave slave_start foo@node_master slave_waiter_0 -setcookie mycookie
客户端脚本rsh_client.sh
则最终需要执行连接到服务器、并发送命的命令:
echo "erl -detached -noinput -master foo@node_master -sname bar@node_slave -s slave slave_start foo@node_master slave_waiter_0 -setcookie mycookie" | /usr/bin/nc node_slave 19999
这样就实现了和SSH一样的功能了,很简单吧。
Tsung如何切换切换?
为tsung启动添加-r
参数指定即可:
tsung -r ~/.tsung/rsh_client.sh -f tsung.xml start
进阶:可指定运行命令路径
rsh_client.sh
脚本最后一行修改一下,指定目标服务器erl运行命令:
#!/bin/sh
PORT=19999if [ $# -lt 2 ]; thenecho "Invalid number of parameters"exit 1
fiREMOTEHOST="$1"
COMMAND="$2"if [ "${COMMAND}" != "erl" ]; thenecho "Invalid command ${COMMAND}"exit 1
fishift 2
exec echo "/root/.tsung/otp_18/bin/erl $*" | /usr/bin/nc ${REMOTEHOST} 19999
上面脚本所依赖的上下文环境可以是这样的,机房服务器操作系统和版本一致,我们把Erlang 18.1整个运行时环境在一台机器上已经安装的目录(比如目录名为otp_18),拷贝到远程主机/root/.tsung/
目录,相比于安装而言,可以让Tsung运行依赖的Eralng环境完全可以移植化(Portable),一次安装,多次复制。
代码托管地址
本文所谈及代码,都已经托管在github:
https://github.com/weibomobile/tsung_rsh
后续代码更新、BUG修复等,请直接参考该仓库。
小结
简单一套新的替换SSH通道无密钥登陆远程主机C/S模型,虽然完整性上无法与SSH相比,但胜在简单够用,完全满足了当前业务需要,并且其运维成本低,无疑让Tsung在复杂服务器内网环境下适应性又朝前多走了半里路。
下一篇将介绍为Tsung增加IP直连特性支持,使其分布式网络环境下适应性更广泛一些。
转自:http://www.blogjava.net/yongboy/archive/2016/07/27/431340.html
Tsung笔记之分布式增强跳出SSH羁绊篇相关推荐
- Hadoop学习笔记—13.分布式集群中节点的动态添加与下架
Hadoop学习笔记-13.分布式集群中节点的动态添加与下架 开篇:在本笔记系列的第一篇中,我们介绍了如何搭建伪分布与分布模式的Hadoop集群.现在,我们来了解一下在一个Hadoop分布式集群中,如 ...
- Git笔记(19) 生成SSH公钥
Git笔记(19) 生成SSH公钥 1. SSH公钥认证 2. 密钥 3. 公钥 1. SSH公钥认证 许多 Git 服务器都使用 SSH 公钥进行认证 如果某系统用户尚未拥有密钥,必须事先为其生成一 ...
- 【笔记】分布式系统核心问题概述(二)
[笔记]分布式系统核心问题概述(一) 文章目录 六.Paxos算法与Raft算法 1.Paxos算法 2.Raft算法 七.拜占庭问题与算法 八.可靠性指标 1.几个9的指标 2.两个核心时间 3.提 ...
- Python3《机器学习实战》学习笔记(八):支持向量机原理篇之手撕线性SVM
原 Python3<机器学习实战>学习笔记(八):支持向量机原理篇之手撕线性SVM 置顶 2017年09月23日 17:50:18 阅读数:12644 转载请注明作者和出处: https: ...
- [转]分布式事务科普(初识篇)
分布式事务科普(初识篇) 微信=>朱小厮的博客 <分布式事务科普>是我在YQ期间整理的一篇科普型文章,内容共计两万五千字左右,应该算是涵盖了这个领域的大多数知识点.篇幅较长,遂分为上 ...
- [源码解析] PyTorch分布式优化器(1)----基石篇
[源码解析] PyTorch分布式优化器(1)----基石篇 文章目录 [源码解析] PyTorch分布式优化器(1)----基石篇 0x00 摘要 0x01 从问题出发 1.1 示例 1.2 问题点 ...
- Mini 容器学习笔记4——组件的生命周期(应用篇)
Mini容器支持6中生命周期类型: 1. Singleton :单利类型(缺省组件都是单利类型的生命周期,由容器进行托管的) [Test]public void SingletonLifestyleT ...
- PostCSS自学笔记(二)【番外篇二】
图解PostCSS的插件执行顺序 文章其实是一系列的早就写完了. 才发现忘了发在SegmentFault上面, 最早发布于https://gitee.com/janking/Inf... 这次我继续研 ...
- FPGA笔记之verilog语言(基础语法篇)
文章目录 FPGA笔记之verilog语言(基础语法篇) 1. verilog 的基础结构 1.1 verilog设计的基本单元--module 1.2 module的使用 1.3 I/O的说明 1. ...
最新文章
- 离线安装k8s 1.9.0
- 演化计算简单实例(附代码)
- 2021前端高频面试题整理,附答案
- 转帖-Linux学习(Find命令使用实例)
- charles抓取手机APP,配置正确却抓不到数据
- BZOJ 1270: [BeijingWc2008]雷涛的小猫( dp )
- 无法对视图创建索引,因为该视图未绑定到架构
- Jmeter系列之no-gui模式
- idea代码格式化详细总结(快捷键、格式化规则、格式化模板)
- html+CSS+JS实现小米官网(附全部代码)
- vray渲染出图尺寸_3d最终渲染参数设置、vr相片级成品参数值
- JS自定义鼠标右键菜单
- 谷歌地图,计算两个坐标点之间的距离
- 使用Uber-go Zap日志库
- MATLAB混度系统仿真其二:蔡氏电路系统和三阶RC梯形移相振荡器仿真
- web前端培训班有哪些
- ubuntu18.04安装显卡驱动,Anaconda,CUDA,pytorch全套流程
- 集成seata到springboot,cloud项目,找不到事务分组
- 小布老师讲座笔记(五)
- 剖析 Android ART Runtime (2) – dex2oat