`

监控客户端设计-记录-输出部分

阅读更多

现在正在做一个监控的工作,看似简单,但如果多想想还是有很多技巧和问题可以探讨的

 

需求场景:

 

  1. 客户端应该是一个静态类
  2. 客户端调用该类的记录信息API频度可能很大
  3. 该类记录信息的API应该是异步的,保证主体性能
  4. 能够提供多种记录的方式
  5. 能够记录多种数据方式
需求其实可以分为两部分:
  1. 对于需要记录的信息最终可能有多种形式来表达
  2. 使用什么方式(媒体)来表达,比如log,socket,或者消息系统

 

所以设计的时候,在最开始用Recorder和Out两个接口来表达。

 

其中Recorder中定义以下方法

 

/**
 * 信息记录者借口
 * @author dongxuan.lb
 *
 */
public interface Recorder {
	/**
	 * 记录信息
	 * @param keys
	 */
	void record(String... keys);
	
	/**
	 * 该Recorder的名称
	 * @return
	 */
	String getName();
	
	void setName(String name);
	
	/**
	 * 将记录输出
	 * 同时清理内部数据
	 * 内部使用Out接口
	 */
	void free();
}

 

 Out接口很简单:

 

/**
 * 记录输出接口
 * @author dongxuan.lb
 *
 */
public interface Out {
	void output(String info);
}

 

 复杂的输出由具体的子类来完成。

 

到这里,这两个接口是完全解耦的,彼此没有什么关系。

 

========================================================================

到这里,可以开始设计具体的Recorder类了。(不同的业务需求可以自己实现Recorder)

 

这里需要具体化的需求:

 

 写道
主体会接收到一个字符窜数组,不定长度

该API能够在一定时期后输出出现过的key以及该key的次数

比如A.record("a","a","b")

可能的结果是

a=2|b=1

当然这里record中的字符串长度不会非常大,通常小于100个,但是调用该api的频度非常大,可能在1000至10000

 

 监控方面的设计,在使用API记录是不能同步阻塞住 主体业务,所以使用线程方式进行异步。

 

 

在这里使用了ThreadPoolExecutor作为作为线程池。

 

 

protected ThreadPoolExecutor recorderPool = new ThreadPoolExecutor(
			coreSize, coreSize * 2, 30, TimeUnit.SECONDS, 
			new ArrayBlockingQueue<Runnable>(60), 
			new RecorderThreadFactory("recorderPool"), 
			new ThreadPoolExecutor.CallerRunsPolicy());

 这里需要注意的是coreSize和maxPoolSize的设置,当然这里也是可以调优的地方。

 

当然使用ThreadPoolExecutor最主要的是RejectedExecutionHandler的具体实现可以高度自由化

 

当核心处理不过来的时候可以选择自己实现的RejectedExecutionHandler,以满足业务需求

 

AbstractKeyCountRecorder中代码

 

private Integer coreSize = Runtime.getRuntime().availableProcessors();
	/*
	 * 记录者线程池
	 */
	protected ThreadPoolExecutor recorderPool = new ThreadPoolExecutor(
			coreSize, coreSize * 2, 30, TimeUnit.SECONDS, 
			new ArrayBlockingQueue<Runnable>(60), 
			new RecorderThreadFactory("recorderPool"), 
			new ThreadPoolExecutor.CallerRunsPolicy());
	
	protected abstract Runnable getWorker(String... key);
	
	@Override
	public void record(String... keys) {
		recorderPool.execute(getWorker(keys));
	}
 

 

========================================================================

回到具体需求上来。

 

首先为了记录key的次数,需要一个map来作为记录存数,其中map的K中存储key的名称,map的V中存储key的出现次数。

 

但这里有两个问题:

 

  1. 使用hashMap线程不安全,get和put方法均有可能出现并发问题,导致记录错误
  2. map中的V存在自加操作,在操作也会有线程问题
事实证明,
map的同步影响的是性能问题,而V得类型选择则非常影响最终结果的正确与否(当然背后还是同步问题)

========================================================================
map的同步选择:
  1. 选择hashtable
  2. 使用Collections.synchronizedMap()方式
  3. 使用ConcurrentHashMap
  4. 自己手动维护同步
在这里,不想过多介绍这个问题,不过比较奇怪的是,我测试下来,Collections.synchronizedMap()方式比较耗性能
这里有篇文章和我的测试大致一样:http://blog.csdn.net/java2000_net/archive/2008/11/25/3373181.aspx

最终为了方便,直接选择ConcurrentHashMap

========================================================================
这里需要重点指出的是,map中V的选型,通常就使用Integer就可以了,但是在这里,虽然map的put,get方法已经同步,但是当多个线程去取同一个V的值时可能看到的是一样的,这样当自加后在put进去,就丢掉了几次记录。

所以如果使用Integer作为计数器类,结果必然小了很多。

那么自然想到的便是AtomInteger类了。内部使用的机制比较复杂,在《java Thread》那本书上有提到过。

 写道
private Map<String, AtomicInteger> hitMap = new ConcurrentHashMap<String, AtomicInteger>(1000);
 ========================================================================
之前说过,Recorder和Out很好的解耦了,到了具体的Recorder中,由传入的out负责具体的输出部分

外部注入out实体
public LevelKeyCountRecorder(Out out) {
		this();
		this.out = out;
	}
 当需要输出时调用Out的output方法
@Override
	public void free() {
		if(!hitMap.isEmpty()) {
			StringBuilder value = new StringBuilder();
			for (final Entry<String, AtomicInteger> entry : hitMap.entrySet()) {
				value.append(
						entry.getKey()
						+ "=" 
						+ entry.getValue() 
						+ "|");
			}
			out.output(value.toString());
			hitMap.clear();
		}
	}
 =======================================================================
最后 ,使用日志输出结果
Logger logger = Logger.getLogger(LevelKeyCountRecorder.class);
		Out logOut = new LogOut(logger);
		Recorder levelRecorder = new LevelKeyCountRecorder(logOut)
 
  • 大小: 29.6 KB
分享到:
评论
1 楼 kkqqcom 2011-01-16  
我也在做类似的事情。
整理整理,一起交流。

我的场景要求高稳定性和吞吐量,并发不大。

相关推荐

    史上最强网络监控软件--Active Wall 附专业版1000用户License!

    它能有效监视、控制和记录内部电脑在互联网上的活动,实时记录局域网内计算机所有收发的邮件、浏览的网页以及FTP上传下载的文件,监视和管理网内用户的聊天行为,控制网内用户访问指定网络资源或网络协议。...

    Visual Basic.NET自动化系统监控--RS-232串行通信.(清华出版.范逸之.廖锦棋)

    书名:《Visual Basic.NET自动化系统监控--RS-232串行通信》(清华大学出版社.范逸之.廖锦棋)。PDF格式扫描版,全书共分为9章,共475页。 介绍 Visual Basic .NET为广大Visual Basic用户打开了通往程序设计殿堂的...

    QX2006监控软件含客户端

    3 监控系统不能拷到桌面运行,建议放在C盘根目录下运行(例如C:\nv700x_5.0) 4 必须把颜色设为真彩色32位,否则回放会出现底片等不正常的效果 5 如果板卡上印着ver4.1,请安装新板驱动程序   说明书含常见问题...

    欣荣泉安防视频监控软件-单机版

    1.单机版:属于单机管理软件,集服务器和客户端于一体,可以满足区域内实施视频监控的需求(普通的社区/校园/楼宇/商场/交通均可适用),您目前下载的即为单机版免费软件。 2.分发版:功能更加完备,可以满足视频分发...

    一个oracle客户端(oracle sql handler)

    支持批量SQL语句的运行:用监控器监控每条语句的运行,在运行过程中可以中断/暂停/继续正在运行的语句,甚至可以更正出错误的语句 o 方便高效的块操作,以满足特殊需求: (1)“Format SQL” 按钮能将语句块中...

    php运行状态报告工具php-timer.zip

    最近写了一个异步mysql客户端的封装,想与传统的串行方式做下性能对比。包括运行时间、内存使用情况等信息。在github和packagist上搜索并没有找到自己想要的,xhprof又太大了,结果也太复杂,不符合现在的需要。所以...

    travis.rb:Travis CI客户端(CLI和Ruby库)

    -输出客户端版本 -显示帐户及其订阅状态 -交互式外壳; 需要pry -显示或更改API端点 -根据API进行身份验证并存储令牌 实时监控发生的情况 进行(已验证的)API调用并打印出结果 -生成对提交问题有用的报告 列...

    厂区监控系统的设计方案.doc

    厂区监控系统的设计方案 1. 系统概述 安全防范项目是企业管理的一个重要组成部分,也是体现安全保卫功能先进性的重要 环节。为了充分体现现代大型企业的时代特色,我们采用了国内最先进的基于数字安防 产品,为贵...

    高性能MySQL协议抓包工具 - MySQL Sniffer 源码

    它能够实时捕捉到MySQL服务器端或客户端的请求,并以友好的格式输出抓取内容。输出信息详尽,包括但不限于访问时间、用户、来源IP、数据库、命令执行耗时、返回的行数以及具体的执行语句等。此外,该工具支持批量...

    7130监控驱动软件

    客户端录像:将网络传送的压缩数据以文件形式保存到客户端的主机上; 云台控制:对网络硬盘录像机各监控通道所连接的云台及镜头进行控制; 开关控制:对网络硬盘录像机所连接的报警盒进行输出控制; 远程配置:通过...

    iSee视频监控 v5.2

    在使用本监控卡之前,请详细阅读本说明书所涉及的相关事项,熟悉 硬件、软件各部分的功能后,方能使用,以确保该系统为您发挥最佳功能。 否则一切后果自负。 本说明书将向您详细阐述全实时“视频监控系统”的安装、...

    vc++ 开发实例源码包

    实现了 清楚internet临时文件、Cookie的清除、游览器地址栏历史地址的清除、清楚表单自动完成历史记录、清楚自动密码历史记录、清除收藏夹中的内容、清除RAS自动拨号历史记录、清除系统临时文件夹、清空回收站、清除...

    C#开发典型模块大全(光盘)第一部分

    2.3.5 客户端消息发送模块设计 2.3.6 服务器端控制台模块设计 第3章 SQL数据表提取器模块 3.1 概述 3.2 关键技术 3.2.1 如何备份数据库 3.2.2 如何还原数据库 3.2.3 如何附加数据库 3.2.4 如何分离数据库 3.2.5 ...

    C#开发典型模块大全(光盘)第二部分

    2.3.5 客户端消息发送模块设计 2.3.6 服务器端控制台模块设计 第3章 SQL数据表提取器模块 3.1 概述 3.2 关键技术 3.2.1 如何备份数据库 3.2.2 如何还原数据库 3.2.3 如何附加数据库 3.2.4 如何分离数据库 3.2.5 ...

    IIS专家信息监控系统 v1.2

    拥有以下功能:1、关键词拦截2、关键词替换3、关键词记录4、SQL注入保护5、文件保护6、日志分析【关键词拦截】可以任意设置100个关键词,当网页中出现这些词时,系统会拦截当前网页,不让其输出到客户端。...

    门禁系统设计方案(3).doc

    由于本方案设计的门禁系统是整个智能一卡通系统的组成部分,因此,通过系统扩展 ,很容易实现考勤、电梯控制、停车场管理、POS消费、食堂餐饮消费、保安巡更管理等 功能。一张智能卡可通用于所有子系统,所有子系统...

    java应用软件程序设计

    ReadTestquestion 7.5. 课程设计作业 第8章 日历记事本 8.1. 设计内容 8.2. 设计要求 8.3. 总体设计 8.4. 具体设计 8.4.1. 运行效果与程序发布 8.4.2. 主类CalendarPad 8.4.3. 记事本...

    C#开发典型模块大全

    2.3.5 客户端消息发送模块设计 48 2.3.6 服务器端控制台模块设计 52 第3章 SQL数据表提取器模块 3.1 概述 56 3.2 关键技术 56 3.2.1 如何备份数据库 56 3.2.2 如何还原数据库 57 3.2.3 如何附加...

    C#开发典型模块大全(光盘)

    2.3.5 客户端消息发送模块设计 2.3.6 服务器端控制台模块设计 第3章 SQL数据表提取器模块 3.1 概述 3.2 关键技术 3.2.1 如何备份数据库 3.2.2 如何还原数据库 3.2.3 如何附加数据库 3.2.4 如何分离数据库 3.2.5 ...

    Oracle开发工具 - Oracle SQL Handler(功能强大,超方便好用, 免装客户端, Windows / Linux)

    Oracle SQL Handler,是专为 Oracle 数据库开发人员及操作人员精心打造的一款 Oracle 客户端工具: 超智能的SQL编辑器;超方便的表格操作(可以通过修改表格的单元格数据去更新数据 库表);多种格式的数据导出包括...

Global site tag (gtag.js) - Google Analytics