安装loadrunner_linux代理端

[TOC]

安装loadrunner_linux代理端

1. loadrunner_linux版下载

下载特别难找,此处是我的百度网盘地址,如果有问题,请联系我:

链接:https://pan.baidu.com/s/1mhDT9AbId5JPQ5lj4WXJug 密码:qfmb

其中 context.zip 为linux版以及c语言写的远程调用lib。

iso镜像为原始的版本,如果不是linux环境使用,其他情况请使用context.zip包。

2.安装

1. 如果可以联网,有yum,可使用yum进行安装

使用root用户,执行如下命令:

  • centos 7执行如下命令
yum install compat-libstdc++-33-3.2.3-72.el7.i686 -y 
yum install glibc-devel.i686 -y 
yum install make -y 
yum install gcc -y
yum clean all
  • centos6执行如下命令
yum install compat-libstdc++-33.i686 -y 
yum install glibc-devel.i686 -y 
yum install make -y 
yum install gcc -y
  • 如果可以联网,但yum源无效,可以进行如下配置:

检查系统版本:

cat /etc/redhat-release

[root@d0d286f085a2 POC001]# cat /etc/redhat-release
CentOS Linux release 7.4.1708 (Core)
[root@d0d286f085a2 POC001]#

根据不同的版本,把CentOS后面的数字改成对应的数字。(vi CentOS6-Base-163.repo)

# CentOS-Base.repo
#
# The mirror system uses the connecting IP address of the client and the
# update status of each mirror to pick mirrors that are updated to and
# geographically close to the client.  You should use this for CentOS updates
# unless you are manually picking other mirrors.
#
# If the mirrorlist= does not work for you, as a fall back you can try the
# remarked out baseurl= line instead.
#
#

[base]
name=CentOS-6 - Base - 163.com
baseurl=http://mirrors.163.com/centos/6/os/$basearch/
#mirrorlist=http://mirrorlist.centos.org/?release=6&arch=$basearch&repo=os
gpgcheck=1
gpgkey=http://mirror.centos.org/centos/RPM-GPG-KEY-CentOS-6

#released updates
[updates]
name=CentOS-6 - Updates - 163.com
baseurl=http://mirrors.163.com/centos/6/updates/$basearch/
#mirrorlist=http://mirrorlist.centos.org/?release=6&arch=$basearch&repo=updates
gpgcheck=1
gpgkey=http://mirror.centos.org/centos/RPM-GPG-KEY-CentOS-6

#additional packages that may be useful
[extras]
name=CentOS-6 - Extras - 163.com
baseurl=http://mirrors.163.com/centos/6/extras/$basearch/
#mirrorlist=http://mirrorlist.centos.org/?release=6&arch=$basearch&repo=extras
gpgcheck=1
gpgkey=http://mirror.centos.org/centos/RPM-GPG-KEY-CentOS-6

#additional packages that extend functionality of existing packages
[centosplus]
name=CentOS-6 - Plus - 163.com
baseurl=http://mirrors.163.com/centos/6/centosplus/$basearch/
#mirrorlist=http://mirrorlist.centos.org/?release=6&arch=$basearch&repo=centosplus
gpgcheck=1
enabled=0
gpgkey=http://mirror.centos.org/centos/RPM-GPG-KEY-CentOS-6

#contrib - packages by Centos Users
[contrib]
name=CentOS-6 - Contrib - 163.com
baseurl=http://mirrors.163.com/centos/6/contrib/$basearch/
#mirrorlist=http://mirrorlist.centos.org/?release=6&arch=$basearch&repo=contrib
gpgcheck=1
enabled=0
gpgkey=http://mirror.centos.org/centos/RPM-GPG-KEY-CentOS-6

然后执行

yum makecache

2. 如果没有网,只能内网,则使用安装包中的rpm进行安装

首选将安装包[context.zip]中的文件上传到服务器上的/tmp/下,解压,

  • 查看当前linux系统版本,如果是centos7,则执行如下命令

进入context/yum_rpm/c7目录,执行sh ./1.sh

# >> cat 1.sh
# glibc.i686
rpm -ivh libgcc-4.8.5-28.el7_5.1.x86_64.rpm --replacefiles
rpm -ivh glibc-common-2.17-222.el7.x86_64.rpm glibc-2.17-222.el7.x86_64.rpm --replacefiles
rpm -ivh nspr-4.19.0-1.el7_5.x86_64.rpm --replacefiles
rpm -ivh nss-util-3.36.0-1.el7_5.x86_64.rpm --replacefiles
rpm -ivh nss-softokn-freebl-3.36.0-5.el7_5.x86_64.rpm --replacefiles
rpm -ivh libgcc-4.8.5-28.el7_5.1.i686.rpm
rpm -ivh nss-softokn-freebl-3.36.0-5.el7_5.i686.rpm glibc-2.17-222.el7.i686.rpm
rpm -ivh compat-libstdc++-33-3.2.3-72.el7.i686.rpm
# glib-develop
rpm -ivh kernel-headers-3.10.0-862.9.1.el7.x86_64.rpm
rpm -ivh glibc-headers-2.17-222.el7.x86_64.rpm
rpm -ivh glibc-devel-2.17-222.el7.i686.rpm
# make
rpm -ivh make-3.82-23.el7.x86_64.rpm
# gcc
rpm -ivh mpfr-3.1.1-4.el7.x86_64.rpm
rpm -ivh libmpc-1.0.1-3.el7.x86_64.rpm
rpm -ivh cpp-4.8.5-28.el7_5.1.x86_64.rpm
rpm -ivh libgomp-4.8.5-28.el7_5.1.x86_64.rpm
rpm -ivh gcc-4.8.5-28.el7_5.1.x86_64.rpm

再少rpm的话,去阿里的镜像网站查看:https://opsx.alibaba.com/mirror,注意地址,直接mirror.aliyun是没有搜索的。

  • 查看当前linux系统版本,如果是centos6,则执行如下命令

进入context/yum_rpm/c6目录,执行sh ./1.sh

# glibc.i686
#rpm -ivh nss-util-3.36.0-1.el7_5.x86_64.rpm --replacefiles
rpm -ivh libgcc-4.4.7-23.el6.x86_64.rpm --replacefiles
rpm -ivh tzdata-2018e-3.el6.noarch.rpm --replacefiles
rpm -ivh glibc-common-2.12-1.212.el6.x86_64.rpm glibc-2.12-1.212.el6.x86_64.rpm --replacefiles
rpm -ivh ppl-0.10.2-11.el6.x86_64.rpm
rpm -ivh cloog-ppl-0.15.7-1.2.el6.x86_64.rpm
rpm -ivh libgcc-4.4.7-23.el6.i686.rpm
rpm -ivh glibc-2.12-1.212.el6.i686.rpm nss-softokn-freebl-3.14.3-23.3.el6_8.i686.rpm
rpm -ivh compat-libstdc++-33-3.2.3-69.el6.i686.rpm

# glib-develop
rpm -ivh kernel-headers-2.6.32-754.2.1.el6.x86_64.rpm --replacefiles
rpm -ivh glibc-headers-2.12-1.212.el6.x86_64.rpm --replacefiles
rpm -ivh glibc-devel-2.12-1.212.el6.i686.rpm --replacefiles
# make
#rpm -ivh make-3.82-23.el7.x86_64.rpm
# gcc
rpm -ivh mpfr-2.4.1-6.el6.x86_64.rpm
rpm -ivh cpp-4.4.7-23.el6.x86_64.rpm
rpm -ivh libgomp-4.4.7-23.el6.x86_64.rpm
rpm -ivh gcc-4.4.7-23.el6.x86_64.rpm

3.安装loadrunner客户端

  • 使用root用户,进入 context/Linux下,执行如下命令:
echo -e 'n\na\ni\nf\n'|bash ./installer.sh
  • 配置环境变量

如果有root用户或docker,则添加profile

echo -e '\n\nexport PRODUCT_DIR=/opt/HP/HP_LoadGenerator\n
export M_LROOT=$PRODUCT_DIR\n
export LD_LIBRARY_PATH=$M_LROOT/bin:$LD_LIBRARY_PATH\n
export PATH=$M_LROOT/bin:$PATH\n' >> /etc/profile
source /etc/profile

如果非root用户,可以再非root用户添加该环境变量

export PRODUCT_DIR=/opt/HP/HP_LoadGenerator
export M_LROOT=$PRODUCT_DIR
export LD_LIBRARY_PATH=$M_LROOT/bin:$LD_LIBRARY_PATH
export PATH=$M_LROOT/bin:$PATH

4. 启动代理端

source /etc/profile && cd /opt/HP/HP_LoadGenerator/bin/ && ./m_daemon_setup start

查看服务是否启动正常。查看54345端口。(错误日志放在/tmp下面)

ps -ef|grep m_agent_daemon
netstat -anp|grep 54345
  • loadrunner客户端配置代理服务

注意勾选`Don't use RSH配置。

image-20180727190837952

5. 附 Dockerfile

# base image
FROM centos

# MAINTAINER 作者信息
MAINTAINER suitianmou@tfrunning.com.cn

# 拷贝安装镜像
# 赋值context文件夹中的内容到tmp/,并不会复制context本身
COPY context/ /tmp/

## 安装gcc、make等软件包
RUN mkdir /opt/iso \
    && yum install compat-libstdc++-33-3.2.3-72.el7.i686 -y \
    && yum install glibc-devel.i686 -y \
    && yum install make -y \
    && yum clean all \
# centos无此头文件,编译可能会报错
    && touch /usr/include/stropts.h \
# 修改时区
    && ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \
# 安装LoadRunner,(next->agree->install->finish)
    && echo -e 'n\na\ni\nf\n'|bash /tmp/Linux/installer.sh \
# 安装tcplib
    && cp /tmp/tcplib/libtcploadcli.so  /lib/ \
# 清理安装文件夹
    && rm -rf /tmp/* \
# 修改, 使用ln -s
    && echo -e '\n\nexport PRODUCT_DIR=/opt/HP/HP_LoadGenerator\n\
        export M_LROOT=$PRODUCT_DIR\n\
        export LD_LIBRARY_PATH=$M_LROOT/bin\n\
        export PATH=$M_LROOT/bin:$PATH\n' >> /etc/profile\
    && source /etc/profile \
# 修改root密码
    && echo "pass"|passwd root --stdin \
    && echo -e '#!/bin/bash\nsource /etc/profile && cd /opt/HP/HP_LoadGenerator/bin/ && ./m_daemon_setup start && bash' > /docker_start.sh \
    && chmod 777 /docker_start.sh 
# 指定CMD
CMD ["/docker_start.sh"]

构建镜像命令:(需要context放在和Dockerfile同级目录下)

docker build -t loadrunner .

启动容器

docker stop loadrunner
docker rm loadrunner
docker run --name loadrunner -d -p 54345:54345 -it -v /Users/suitm/binsh/docker_lr/:/docker_file loadrunner

3.压测脚本使用

1. 配置远程代理服务器

Controller->Run->Load Generators中ADD一个新的代理,Name填写地址。平台要选择linux,临时文件目录很重要,后续脚本和日志都在这里面生成。

image-20180728144023995

2. 更新ktcplib的so到linux环境

更新包中context/ktcplib目录,编译会生成libtcploadcli.so/lib目录。里面包含了基本的tcp通讯,也可以不用这个库,在Aciton.c中写好通讯的程序。

3. 编写CVuser脚本

新建脚本,类型为cvuser类型, 主要是Action.c,下面是一个例子:

#include "lrun.h"

static int HttpHeaderReadln(int sockid, char *buf);

/* 混合消费: AGGREG01 */
#define SENDBUF "{\
    \"SYS_HEAD\":{\
        \"BRANCH_NO\":\"2204\",\
        \"CALL_DATE\":\"20180726\",\
        \"CALL_MSGID\":\"{V_USER}{CALL_MSGID}\",\
        \"CALL_SYSID\":\"LOADRUNNER\",\
        \"CALL_TIME\":\"1708\",\
        \"FROM_CHNL\":\"LOADRN\",\
        \"SERVICE_CODE\":\"AGGREG01\",\
        \"TELLER_NO\":\"0218\"\
    },\
    \"PAGE\":{\
        \"BEG_NUM\":\"0\",\
        \"PAGE_NUM\":\"0\"\
    },\
    \"BODY\":{\
        \"BUSI_TYPE\":\"001\",\
        \"PAYER_ACNO\":\"{CIF_PAYER}\",\
        \"PAYER_AMT\":\"1\",\
        \"PAYEE_ACNO\":\"622223199212121\",\
        \"PAYEE_AMT\":\"2\",\
        \"SCORE\":\"16\",\
        \"SCORE_ID\":\"001\"\
    }\
}"

//#define HTTP
#define DEBUG
#define CONN_IP "192.168.10.202"
#define CONN_PORT 9922

#define CONTENT_LENGTH "content-length"
#define CONTENT_LENGTH_STEP 2

Action()
{
    int ret = 0;
    int sock = 0;

    char head[200];
    char send_buf[2000];
    int send_len=0;

    char recv_head[200];
    char recv_buf[2000];
    int recv_len=0;

    char res[21];

    /* 组报文体 */
    memset(send_buf, 0x00, sizeof(send_buf));
    strcpy(send_buf, lr_eval_string(SENDBUF));
    lr_output_message("send_buf--[%s]", send_buf);

    /* 组HTTP报文头 */
#ifdef HTTP
    memset(head, 0x00, sizeof(head));
    sprintf(head+strlen(head), "POST /message/gateway.do HTTP/1.1\r\n");
    sprintf(head+strlen(head), "Content-Language:zh-CN\r\n");
    sprintf(head+strlen(head), "Content-Length:%ld\r\n", strlen(send_buf));
    sprintf(head+strlen(head), "Host:www.tfrunning.com.cn\r\n");
    sprintf(head+strlen(head), "Content-Type:text/xml;charset=utf-8\r\n");
    sprintf(head+strlen(head), "Connection:close\r\n");
    sprintf(head+strlen(head), "\r\n");
#endif
#ifndef HTTP
    sprintf( head, "%04ld", strlen(send_buf));
#endif

    ret = lr_load_dll("/lib/libtcploadcli.so");
    if (ret != 0)
    {
        lr_error_message("装载so[%d]", ret);
        return -1;
    }

    /* 连接地址 */
    sock = TcpCliOpen(CONN_IP, CONN_PORT);
    if (sock < 0)
    {
        lr_error_message("连接第三方错误[%d]", sock);
        return -1;
    }

    lr_start_transaction("POC压力测试");

    /* 发送报文 */
    ret = TcpSend(sock, head, strlen(head), 30);
    if (ret)
    {
        lr_end_transaction("POC压力测试", LR_FAIL);
        lr_error_message("发送报文失败[%d]", ret);
        return 0;
    }
    ret = TcpSend(sock, send_buf, strlen(send_buf), 30);
    if (ret)
    {
        lr_end_transaction("POC压力测试", LR_FAIL);
        lr_error_message("发送报文失败[%d]", ret);
        return 0;
    }

    /* 接收报文 */
#ifdef HTTP
    while(1)
    {
        memset(recv_head, 0x00, sizeof(recv_head));
        ret = HttpHeaderReadln(sock, recv_head);
        if( ret > 0)
        {
            lr_output_message("获取到报文头为[%s]", recv_head);
            if( strncmp( recv_head, CONTENT_LENGTH, strlen(CONTENT_LENGTH)) == 0 )
            {
                recv_len =  atol(recv_head+strlen(CONTENT_LENGTH)+ CONTENT_LENGTH_STEP);
                lr_output_message("获取到报文体长度为[%s][%d]", recv_head, recv_len);
            }
        }
        if( ret == 0)
        {
            lr_output_message("读取http头结束[%d]", ret);
            break;
        }
        if( ret < 0)
        {
            lr_end_transaction("POC压力测试", LR_FAIL);
            lr_error_message("接收返回包长错误[%d]", ret);
            return 0;
        }
    }
#endif
#ifndef HTTP
    ret = TcpRecv(sock, recv_head, 4, 30);
    if( ret != 0)
    {
            lr_end_transaction("POC压力测试", LR_FAIL);
            lr_error_message("接收返回包长错误[%d]", ret);
            return 0;
    }
    recv_len = atol(recv_head);
#endif
    ret = TcpRecv(sock, recv_buf, recv_len, 30);
    if (ret)
    {
        lr_end_transaction("POC压力测试", LR_FAIL);
        lr_error_message("接收返回报文错误[%d],[%d]", ret, recv_len);
        return 0;
    }

    TcpCliClose(sock);

    lr_output_message("返回报文[%s]", recv_buf);
    memset( res, 0x00, sizeof( res));
    if( strstr(recv_buf, "RET_CODE") != NULL)
        strncpy( res, strstr(recv_buf,"RET_CODE")+11, 10);
    if (0 == strncmp("0000", res, 4))
    {
        lr_end_transaction("POC压力测试", LR_PASS);
        lr_output_message("渠道交易成功!");
    }
    else
    {
        lr_end_transaction("POC压力测试", LR_FAIL);
        lr_error_message("渠道交易失败,响应码[%s]", res);
    }

#ifdef DEBUG
    /* 调试用,如果没有error,日志生成结束后会删除 */
    lr_error_message("保存运行日志在/tmp/abc/netdir/C/APP/下"); 
#endif
    return 0;
}

static int HttpHeaderReadln(int sockid, char *buf)
{
    int ret;
    int i = 0;
    char tmp[2];

    memset(tmp, 0x00, sizeof(tmp));

    while (1)
    {
        if (read(sockid, tmp, 1) <= 0)
            return -1;

        buf[i] = tmp[0];
        if (tmp[0] == '\n' && buf[i - 1] == '\r')
        {
            i--;
            buf[i] = '\0';
            break;
        }
        i++;
    }
    return i;
}

脚本写法有很多,有以下几点需要注意:

  • 加载动态库路径要写对

ret = lr_load_dll("/lib/libtcploadcli.so"); 此句话代表要加载的so路径,要和linux环境对应的上。

  • 用这种写法之后,不能在windows下调试脚本了,可以写完脚本,然后点击编译。可检查基本错误。

image-20180728144526287

  • 参数需要进行配置,才可以生效

lr_eval_string("{CALL_MSGID}"参数需要在脚本中进行配置,由于是流水号,这里配置的迭代增加。

image-20180728144811811

image-20180729103939998

  • lr_output_message会打印日志到linux目录下

具体路径应该是设置的路径/netdir/C/APP/LoadRunner/脚本地址。一个例子如下:

[root@d0d286f085a2 POC001]# pwd
/tmp/abc/brr_sOncLK/netdir/C/APP/LoadRunner/ICESKY/ZYPOC/POC001
[root@d0d286f085a2 POC001]# ls
Action.c    POC001.usr      mdrvKAUWmx.log  mdrvLS8KUU.log  mdrvTA46px.log  mdrvcUGUZd.log  mdrvqJ1cdg.log  vuser_end.c
POC001.prm  mdrv8778N0.log  mdrvKSfX7t.log  mdrvRF5UdJ.log  mdrvZg3UJK.log  mdrvdpVQLz.log  mdrvwo6XJK.log  vuser_init.c
[root@d0d286f085a2 POC001]#

下面脚本,还有执行生成的日志。 由于不能在windows下调试,所以只能批量执行,可以在调试的时候启动一个用户。

不停的查看该文件夹下日志。

如果没有错误日志,执行结束会清除日志,因此建议在调试的时候,在最后一行加上lr_error_message("调试调试");

常见问题

1. 脚本运行有多个事物

[TOC]

image-20180728105250737

这是loadrunner的bug,解决方法是,点击design->runtime-setting->把最后一项的两个点上,保存,再打开,再取消。

image-20180728105339275