背景

Jmeter连接数据库的方式,网上有很多,包括使用配置元件等等,这里就不说了。

如果你的mysql部署在远程服务器,而且还需要SSH登录连接时,那么使用Jmeter如何连接呢?

相信我,网上资料很少,这里是使用beanshall方式。

准备

首先你得下载两个jar包,一个是mysql的,一个是java的搭建ssh代理的包

mysql包下载:官网(我使用的是mysql8,所以下载的是8.0.25)

hbase远程登录 hbase shell 远程连接_hbase远程登录

 java的ssh代理包下载:官网(我下载的是jsch-0.1.55.jar)

hbase远程登录 hbase shell 远程连接_mysql_02

然后把包放在apache-jmeter-5.4.3\lib\ext目录下,再次重启jmeter即可(如果测试计划添底部引入jar包目录,可以不用重启jmeter)。

这时你应该还知道

  1. mysql的远程地址、端口号、数据库登录用户名及用户密码
  2. SSH服务器的远程地址、SSH端口号、服务器登录用户名及用户密码

接着

  1. 打开jmeter
  2. 添加一个jsr223取样器,选择beanshall
  3. 然后开始可以写代码调试了

hbase远程登录 hbase shell 远程连接_mysql_03

我的完整代码如下,startSSH是开启SSH代理,testSSH是测试执行,可以把要执行的sql放这里面:

import java.sql.Connection;
import java.sql.DriverManager;
import java.net.DatagramSocket;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.Date;
import java.text.SimpleDateFormat;

import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;

static int localPort = 3306;// 本地端口
static String remoteHost = "xxx";// 远程MySQL服务器
static int remotePort = 3306;// 远程MySQL服务端口

public static void startSSH() throws JSchException {
   // SSH连接用户名
	String sshUser = "xxx";
   // SSH连接密码
	String sshPassword = "xxx";
   // SSH服务器地址
	String sshHost = "xxx";
   // SSH服务器访问端口
	int sshPort = 22;
	JSch jsch = new JSch();
	Session session = jsch.getSession(sshUser, sshHost, sshPort);
	session.setPassword(sshPassword);
	// 设置第一次登录的时候提示,可选值:(ask | yes | no)
	session.setConfig("StrictHostKeyChecking", "no");
	session.connect();
	// 打印SSH服务器版本信息
	System.out.println(session.getServerVersion());
	try{
		DatagramSocket ds=new DatagramSocket(3306);
	// 设置SSH本地端口转发,本地转发到远程
		int assinged_port = session.setPortForwardingL(localPort, remoteHost, remotePort);
	// 设置SSH远程端口转发,远程转发到本地
	// session.setPortForwardingR(remotePort, remoteHost, localPort);
		log.info("localhost:" + assinged_port + " -> " + remoteHost + ":" + remotePort);
		testSSH();

		}catch (SocketException e){
			System.out.println("busy port:"+i);
			}
		finally {
	// 删除本地端口的转发
		session.delPortForwardingL(localPort);
	// 断开SSH链接
		session.disconnect();
			}

//   System.out.println("localhost:" + assinged_port + " -> " + remoteHost + ":" + remotePort);
}

public static void testSSH() throws Exception {
   Connection conn = null;
   Statement st = null;
   ResultSet rs = null;
   try {
       Class.forName("com.mysql.cj.jdbc.Driver"); // mysql8是这个,8以下用???
       // 设置SSH本地端口转发后,访问本地ip+port就可以访问到远程的ip+port
       conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/dbname?useSSL=false&serverTimezone=GMT", "用户名", "用户密码");
       st = conn.createStatement();
       String userId = vars.get("userId");
       String superior = vars.get("userName");
       SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
       Date date = new Date(System.currentTimeMillis());
       String time = formatter.format(date);
       String value = "('" + userName + "','" + userId + "'," + "1,'" + time +"')";
       log.info("----" + value);
//	  String value = "('111','111',1,'2022-07-26 17:32:32')";
// 定义sql
       String sql = "INSERT INTO t_user (userName,userId,status,time) VALUES " + value;
//       String sql2 = "SELECT * FROM t_invitation_relationship LIMIT 1;";
//       rs = st.executeQuery(sql2);  // select语句用
	  st.execute(sql);  // insert语句用
//       log.info("-------re:" + rs);
//       while (rs.next())
//           System.out.println(rs.getString(1));
//           
   } catch (Exception e) {
       throw e;
   } finally {
//       if (rs!=null) {rs.close();rs=null;}
       if (st!=null) {st.close();st=null;}
       if (conn!=null) {conn.close();conn=null;}
   }
}
startSSH();

最后

开始验证,运行jmeter,就可以看到已经连接成功了,如果有数据库报错,检查一下sql语句。

hbase远程登录 hbase shell 远程连接_hbase远程登录_04

 

hbase远程登录 hbase shell 远程连接_hbase远程登录_05

后记

我是在windows下运行的,当我尝试循环执行2次时,出现如下报错,报错提示为3306端口未注册。

hbase远程登录 hbase shell 远程连接_hbase远程登录_06

而单次执行不会报错。。。

hbase远程登录 hbase shell 远程连接_sql_07

 明明session连接已经关闭释放了,为什么会出现上述情况?查看端口情况,发现下图,期间执行了多次脚本。

 

hbase远程登录 hbase shell 远程连接_hbase远程登录_08

原来每次 jmeter执行测试计划时会申请一个端口(如第二列的56751)去跟本地3306建立一个连接,虽然session连接释放只是关闭了tcp连接(对应图中的TIME_WAIT状态),未释放端口,所以第二次循环用同样的端口(56751)就绑定不了3306端口,就会报错。

而再次执行测试计划,会重新申请一个端口(如第二列的56735),这时就能绑定3306端口了,就不会报错。

那本地端口绑定的连接就不会关闭了吗?也不是:

  1. TIME_WAIT状态是TCP连接的一个状态,大概3分钟系统会自动清除连接
  2. 重启jmeter也会自动关闭连接

所以,只能把ssh代理脚本设置为循环期间仅一次执行或放入setUp线程组中,才能实现业务的循环操作。如果你有更优雅关闭端口绑定的办法,欢迎留言。