使用smack对tigase进行压力测试

1:关于smack与tigase的用法跟作用请大家自己去网上查看相关资料,这里就不做描述了。

PS:这篇文章主要是说明在客户端jvm创建的最大线程数的大小。

之前公司要求做一个客户端用于测试刚刚部署的tigase的性能,所以项目经理就安排了一个事情就是自己动手在客户端写一个基于smack长连接的压力测试工具。

初期的要求是这样的:

1、并发注册10000个用户

2、用户之间相互收发消息

3、可以调整并发数量

用smack 做客户端连接

由于之前对多线程这块懂的不是很深,在这个过程中碰了走了很多弯路(总以为是代码的问题,实际上不是),我的机子的配置是:32位,xp,4G内存。自己写了个程序无论怎么跑在线数都不能突破2000,离要求还差一大截呢!自己反反复复检查程序,没啥不对啊!后来使用jconsole工具观察发现线程数6k一直是最高峰,难怪用户量上不去,要知道要保证10000个用户同时在线至少客户端要启动10000个线程吧!问题总算找到了,于是百度了一下,发现了一个jvm启动线程数的公式:

(MaxProcessMemory - JVMMemory - ReservedOsMemory) / (ThreadStackSize) = Number of threads
MaxProcessMemory 指的是一个进程的最大内存
JVMMemory         JVM内存
ReservedOsMemory  保留的操作系统内存
ThreadStackSize      线程栈的大小

原来:在java语言里, 当你创建一个线程的时候,虚拟机会在JVM内存创建一个Thread对象同时创建一个操作系统线程,而这个系统线程的内存用的不是JVMMemory,而是系统中剩下的内存(MaxProcessMemory - JVMMemory - ReservedOsMemory)

OK问题找到了有了解决问题的思路:根据自己的测试发现当给jvm设置的内存数为512m时创建的线程数是最多的,如下:

2*1024*1024-1024*64-512*1024)/128=11776

又通过观察发现要保持一个长连接本地至少了启动四个线程于是支持的在线用户数为:11776/4

OK:测试结果想如下:

看图说话,哈哈 问题解决:

代码如下:

public class SmackConf {

public static String server="XXXX";

public static int port=5222;

private SmackConf(){};

//初始化配置

private static class ConnectionConfig{

private static  ConnectionConfiguration config;

static{

config = new ConnectionConfiguration(server, 5222, "XXX");

config.setSASLAuthenticationEnabled(false);

config.setSecurityMode(ConnectionConfiguration.SecurityMode.disabled);

//config.setSendPresence(false);

System.out.println("加载配置文件类完毕");

}

}

public  static ConnectionConfiguration getConnectionConfiguration(){

return ConnectionConfig.config;

}

}

public class SmackUtils {

private static Logger log = Logger.getLogger(SmackUtils.class);

private static int sleepTime = 1000;

public static void chart(User user) {

Connection connection = MapsUtils.getConnection(user.getUsername());

try {

if(connection==null||!connection.isConnected()){

initConnection(user);

}

if (!connection.isAuthenticated()) {

initLogin(user);

}

synchronized (connection) {

PacketFilter filter = new MessageTypeFilter(Message.Type.chat);

connection.addPacketListener(new PacketListener() {

@Override

public void processPacket(Packet packet) {

Message message = (Message) packet;

if (message.getBody() != null) {

String fromName = (String) message

.getProperty("fromId");

System.out.println("Got text [" + message.getBody()

+ "] from [" + fromName + "]");

}

}

}, filter);

}

} catch (Exception e) {

System.out.println("chart===="+e.getMessage());

log.info("chart===="+e.getMessage());

}

}

/*

* 获得连接

*/

private static void getConnection(User user, int i) throws Exception {

Connection connection = null;

try {

log.info("第" + i + "次开始申请连接,用户:" + user.getUsername());

connection = MapsUtils.getConnection(user.getUsername());

if (connection == null) {

connection = new XMPPConnection(SmackConf.getConnectionConfiguration());

MapsUtils.put(user.getUsername(), connection);

}

if(connection.isConnected()){

connection.disconnect();

}

connection.connect();

user.setConnectionFa(true);

log.info("第" + i + "次申请连接,用户:" + user.getUsername() + "成功");

} catch (Exception e) {

log.info("第" + i + "次申请连接,用户:" + user.getUsername() + "失败");

System.out.println("获得连接的err:"+e.getMessage());

log.info("获得连接的err:"+e.getMessage());

throw e;

}

}

public static void getConnection(User user) {

/** 建立连接 */

try {

getConnection(user, 0);

} catch (Exception e) {

while (user.getiConnent() < MapsUtils.count

&& !user.isConnectionFa()) {

try {

Thread.sleep(sleepTime);

} catch (InterruptedException e1) {

}

user.setiConnent(user.getiConnent() + 1);

try {

getConnection(user, user.getiConnent());

} catch (Exception e1) {

e1.printStackTrace();

}

}

}

}

private static void initConnection(User user) throws Exception {

try {

log.info("开始初始化创建连接:" + user.getUsername());

user.setConnectionFa(false);

user.setiConnent(0);

getConnection(user);

} catch (Exception e) {

throw e;

}

}

/**

* 注册新用户

*

* @param i

* @throws Exception

*/

private static void createAccount(User user, int i) throws Exception {

Connection connection = MapsUtils.getConnection(user.getUsername());

try {

if (connection == null || !connection.isConnected()) {

initConnection(user);

}

synchronized (connection) {

AccountManager am = null;

log.info("第" + i + "次开始注册用户:" + user.getUsername());

am = connection.getAccountManager();

am.createAccount(user.getUsername(), user.getPassword());

user.setCreateFa(true);

log.info("第" + i + "次开始注册用户:" + user.getUsername() + "成功");

}

} catch (Exception e) {

log.info("第" + i + "次开始注册用户:" + user.getUsername() + "失败");

String message=e.getMessage();

log.info("注册用户的err:"+e.getMessage());

reInit(message, user);

throw e;

}

}

public static void createAccount(User user) {

try {

createAccount(user, 0);

} catch (Exception e) {

while (user.getiCreate() < MapsUtils.count && !user.isCreateFa()) {

try {

Thread.sleep(sleepTime);

} catch (InterruptedException e2) {

}

user.setiCreate(user.getiCreate() + 1);

try {

createAccount(user, user.getiCreate());

} catch (Exception e1) {

e1.printStackTrace();

}

}

}

}

// 登陆

public static void login(User user) {

try {

login(user, 0);

} catch (Exception e) {

while (user.getiLogin() < MapsUtils.count && !user.isLoginFa()) {

try {

Thread.sleep(sleepTime);

} catch (InterruptedException e1) {

}

user.setiLogin(user.getiLogin() + 1);

try {

login(user, user.getiLogin());

} catch (Exception e2) {

e2.printStackTrace();

}

}

}

}

private static void initSignUser(User user) throws Exception {

try {

log.info("开始初始化注册:" + user.getUsername());

user.setiCreate(0);

user.setCreateFa(false);

createAccount(user);

} catch (Exception e) {

throw e;

}

}

// 登陆

private static void login(User user, int i) throws Exception {

Connection connection = MapsUtils.getConnection(user.getUsername());

try {

if(connection==null){

initConnection(user);

}

if(!connection.isConnected()){

initConnection(user);

}

if (!user.isCreateFa()) {

initSignUser(user);

}

if(connection.isAuthenticated()){

return;

}

synchronized (connection) {

log.info("第" + i + "次开始登陆,用户:" + user.getUsername());

connection.login(user.getUsername(), user.getPassword());

user.setLoginFa(true);

/** 设置状态 */

Presence presence = new Presence(Presence.Type.available);

presence.setStatus("Q我吧");

connection.sendPacket(presence);

log.info("第" + i + "次开始登陆,用户:" + user.getUsername() + "成功");

}

} catch (Exception e) {

log.info("第" + i + "次开始登陆,用户:" + user.getUsername() + "失败");

String message = e.getMessage();

log.error("登陆异常信息:" + message);

System.out.println("用户登陆的err:"+e.getMessage());

log.info("用户登陆的err:"+e.getMessage());

reInit(message, user);

throw e;

}

}

private static void initLogin(User user) throws Exception {

try {

log.info("开始初始化登陆:" + user.getUsername());

user.setiLogin(0);

user.setLoginFa(false);

login(user);

} catch (Exception e) {

throw e;

}

}

public static void sendMessage(String from, String to, String message) {

/** 获取当前登陆用户的聊天管理器 */

int messageIndex = 0;

try {

sendMessage(from, to, message, messageIndex);

} catch (Exception e) {

e.printStackTrace();

while (messageIndex < MapsUtils.count) {

System.err.println("消息发送次数:" + messageIndex + "消息来源:" + from

+ "\t消息目的地:" + to + "\t消息内容:" + message);

try {

Thread.sleep(sleepTime);

} catch (InterruptedException e1) {

// TODO Auto-generated catch block

e1.printStackTrace();

}

messageIndex++;

try {

sendMessage(from, to, message, messageIndex);

} catch (Exception e1) {

// TODO Auto-generated catch block

e1.printStackTrace();

}

}

}

}

private static void sendMessage(String from, String to, String message,

int count) throws Exception {

/** 获取当前登陆用户的聊天管理器 */

Connection connection = MapsUtils.getConnection(from);

try {

if (!connection.isAuthenticated()) {

log.info(from + "==没有登陆");

return;

}

synchronized (connection) {

/** 发送消息 */

ChatManager chatManager = connection.getChatManager();

Chat chat = chatManager.createChat(to + "@tt.com", null);

chat.sendMessage("消息来源:" + from + "\t消息目的地:" + to + "\t消息内容:"

+ message);

System.err.println("消息来源:" + from + "\t消息目的地:" + to + "\t消息内容:"

+ message);

}

} catch (Exception e) {

throw e;

}

}

private static void reInit(String message,User user) throws Exception{

if(message==null){

throw new IllegalArgumentException("message参数不能为空");

}

try {

if(message.indexOf("Not connected")>-1){

//没有连接

initConnection(user);

}else if(message.indexOf("not-authorized(401)")>-1){

//没有注册

initSignUser(user);

}else if(message.indexOf("conflict(409)")>-1){

//重复注册

user.setCreateFa(true);

}else if(message.indexOf("No response")>-1){

//没有返回

initConnection(user);

}

} catch (Exception e) {

throw e;

}

}

}

private ExecutorService executorService=null;

public ThreadSysUilt(ExecutorService executorService) {

super();

this.executorService = executorService;

}

/**

* 执行线程任务

* @param rs

* @param fa true(代表全部线程任务需要执行完才能返回),false(与true相反)

* @return

*/

public void execute(List<Runnable> rs){

for(Runnable r:rs){

executorService.execute(r);

}

executorService.shutdown();

}

/**

* 线程执行任务

* @param cs

* @return

*/

public <V> List<Future<V>> submit(List<Callable<V>> cs){

List<Future<V>> fLists=null;

try {

fLists = executorService.invokeAll(cs);

} catch (InterruptedException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

executorService.shutdown();

return fLists;

}

public class ConnThreadMore implements Callable<MoreUser> {

private Logger log = Logger.getLogger(ConnThreadSpe.class.getName());

private MoreUser moreUser = null;

public ConnThreadMore(MoreUser moreUser) {

super();

this.moreUser = moreUser;

}

@Override

public MoreUser call()  {

// TODO Auto-generated method stub

List<User> users=moreUser.getUsers();

for(User user:users){

log.info("开始新建线程:"+Thread.currentThread().getName()+"==执行:"+user.getUsername()+"==创建连接");

try {

SmackUtils.getConnection(user);

Thread.sleep(1000);

} catch (Exception e) {

log.error("申请连接异常", e);

}

try {

SmackUtils.createAccount(user);

Thread.sleep(1000);

} catch (Exception e) {

log.error("申请连接异常", e);

}

}

return moreUser;

}

}

public class LoginThreadMore implements Runnable {

private Logger log = Logger.getLogger(LoginThreadSpe.class.getName());

private MoreUser moreUser = null;

public LoginThreadMore(MoreUser moreUser) {

super();

this.moreUser = moreUser;

}

@Override

public void run() {

// TODO Auto-generated method stub

List<User> users=moreUser.getUsers();

for(User user:users){

log.info("开始新建线程:"+Thread.currentThread().getName()+"==执行:"+user.getUsername()+"==注册并登录");

try {

SmackUtils.login(user);//登录

Thread.sleep(100);

} catch (InterruptedException e) {

log.info("登陆异常", e);

e.printStackTrace();

}

try {

SmackUtils.chart(user);//启动消息

Thread.sleep(100);

} catch (InterruptedException e) {

log.info("启动消息", e);

e.printStackTrace();

}

}

}

}

总结:这个实现上是比较简单的,关键的问题是培养自己解决问题的能力,有不对之处希望大家多多指正。

使用smack对tigase进行压力测试,布布扣,bubuko.com

时间: 2024-08-09 06:35:34

使用smack对tigase进行压力测试的相关文章

如何做云端压力测试和业务容量的测试与规划

云智慧产品总监 陆兴海 高速增长的互联网业务要求产品开发.迭代和交付周期越来越短,而IT基础设施的广泛云化和第三方API接口的大量使用,使传统的基于内部环境搭建的压力测试方法和测试工具越来越难以满足应用功能可用和容量规划预估的需求. 企业该如何为频繁的市场活动和产品快速迭代进行有效而准确的压力测试呢?希望通过云端压力测试专家,云智慧压测宝产品总监陆兴海分享的两个客户案例,为企业的云端压力测试和业务容量规划带来一些有价值的参考. 压测宝云压测客户案例1:压测宝如何做业务容量的测试与规划? 云智慧有

网站压力测试工具 Webbench

webbench最多可以模拟3万个并发连接去测试网站的负载能力 Webbench是有名的网站压力测试工具,它是由 Lionbridge公司(http://www.lionbridge.com)开发. Webbech 能测试处在相同硬件上,不同服务的性能以及不同硬件上同一个服务的运行状况.webBech的标准测试可以向我们展示服务器的两项内容:每秒钟相应请求数 和每秒钟传输数据量.webbench不但能具有便准静态页面的测试能力,还能对动态页面(ASP,PHP,JAVA,CGI)进行测试的能力.还

压力测试工具tsung用法简介

tsung是用erlang开发的一款简单易用的压力测试工具,可以生成成千上万的用户模拟对服务器进行访问.目前对tsung的理解也仅限于会简单的应用,其内部结构没有深入研究过. 1.安装 tsung是用erlang编写的,所以首先安装erlang的运行环境.然后就是按照tsung的官网下载编译tsung.需要注意的是,生成测试报告需要gnuplot和perl的支持,其中perl需要安装Template扩展.具体安装过程请看相关手册或者google之. 2.配置文件 默认情况下,tsung会加载配置

开发人员学Linux(4):使用JMeter对网站和数据库进行压力测试

前言表面看来,JMeter与本系列课程似乎关系不大,但实际上在后面的很多场景中起着重要作用:如何获知修改了某些代码或者设置之后系统性能是提升了还是下降了呢?商业的压力测试工具LoadRunner确实很高大上,但是据说费用也不便宜且体积也不小,而目前最高版本的开源免费压力测试工具JMeter3.2压缩包体积才不到53M,而且对于开发人员而非专业测试人员来说,JMeter提供的测试功能已经够强大了.要完整地介绍JMeter,即使把JMeter自带的文档翻译成中文就是一本厚厚的书了.但是在本篇只讲述如

mysqlslap 压力测试使用总结

今天从运维同事那听说了mysql压力测试工具mysqlslap.经了解其实mysql自带就有一个叫mysqlslap的压力测试工具,还是模拟的不错的.下面举例说说.mysqlslap是从5.1.4版开始的一个MySQL官方提供的压力测试工具.通过模拟多个并发客户端访问MySQL来执行压力测试,同时详细的提供了"高负荷攻击MySQL"的数据性能报告.并且能很好的对比多个存储引擎在相同环境下的并发压力性能差别.通过mysqlslap –help可以获得可用的选项,这里列一些主要的参数,更详

apache ab压力测试报错apr_socket_recv

apache ab压力测试报错(apr_socket_recv: Connection reset by peer (104)) apache 自带的ab工具测试,当并发量达到1000多的时候报错如下: [[email protected] ~]# ab -n 100000 -c 1000 http://192.168.2.170/index.htmlThis is ApacheBench, Version 2.3 <$Revision: 655654 $>Copyright 1996 Ada

sysbench对数据库进行压力测试

sysbench是一款压力测试工具,可以测试系统的硬件性能,也可以用来对数据库进行基准测试. 安装方式:https://github.com/akopytov/sysbench/blob/master/README.md#general-command-line-options 此处安装的是sysbench 1.0.6版本,和网上大部分的0.4,0.5版本的命令不太一样. sysbench支持三种测试方案: 1.使用自带的测试模块,如对cpu,I/O,memory等的测试. 2.使用自带的lua

tcpcopy,模拟在线MySQL压力测试的好帮手

主要信息来自:http://code.google.com/p/tcpcopy/ tcpcopy是一个基于底层的应用请求复制(所有基于tcp的packets)开源项目,可用于替代ab做在线模拟压力测试,可转发各种在线请求到测试服务器上,进行较为详尽的近乎实际的测试,从而避免了新业务.系统上线带来的潜在问题. tcpcopy的四大功能: 1)分布式压力测试,将多个前段请求集中到某个后端进行压力测试2)上线前测试,检验新系统可靠性,提前发现潜在问题3)对比测试,同样请求,针对不同或不同版本程序,可以

Jmeter教程 简单的压力测试

转载:http://www.cnblogs.com/TankXiao/p/4059378.html?utm_source=tuicool Jmeter是一个非常好用的压力测试工具.  Jmeter用来做轻量级的压力测试,非常合适,只需要十几分钟,就能把压力测试需要的脚本写好. 什么是压力测试 顾名思义:压力测试,就是  被测试的系统,在一定的访问压力下,看程序运行是否稳定/服务器运行是否稳定(资源占用情况) 比如: 2000个用户同时到一个购物网站购物,这些用户打开页面的速度是否会变慢,或者网站