Quantcast
Channel: IT社区推荐资讯 - ITIndex.net
Viewing all 15843 articles
Browse latest View live

Android开发在路上:少去踩坑,多走捷径

$
0
0

  最近一朋友提了几个Android问题让我帮忙写个小分享,我觉得对新人还是挺有帮助的,所以有了这个小分享。

   1. 目前, Android APP开发完成后,通常需要在哪些机型上进行测试?

   2. 目前, 开发Android APP时,需要考虑的分辨率有哪些?

  这两个问题可以合起来回答的。

   http://developer.android.com/about/dashboards/index.html

  源自Google Play的数据,每月都会进行update,可以及时了解Android版本比例趋势。

  屏幕密度数据

  OpenGL ES版本

  也可以参考一下国内一个第三方数据: http://www.umindex.com/#android_device

  目前三星和小米市场占有率是遥遥领先的,三星Note2、Note3、S3、S4、S5、小米123、红米必须测试,魅族也比较坑爹,加入测试名单吧。再选中小屏幕各一款(譬如华为C8650、Moto ME511)。

  Android 1.5、1.6、2.0、2.1和小屏幕的属于古董级别的机器,市场存量也很少,新出的机器都是4.0以上的了,所以必要时需要舍弃对古董的支持,因为适配成本很高,对于新开发的应用,这个适配不值得投入。

   3. 目前, 开发Android APP时,适应多个分辨率的技术方案有哪些?

  http://developer.android.com/guide/practices/screens_support.html

  Android的屏幕适配,可以在工程res目录下进行处理,无需写代码,Android自动找最适合的资源进行显示,相信大家都相当熟悉的了。

  目前我使用的是ADT22.6,新建一个Android工程,会自动在res目录下生成这个目录结构。这里有5个前缀drawable的文件夹,对应不同密度屏幕时所取的图片资源或者样式。

  做一个功能正常的App,开发者需要遵循一些开发守则,与此同时,设计师也需要有一套标准来设计Android UI,所有的Android UI设计指南都在这里了。

   http://developer.android.com/design/style/devices-displays.html

  9Path这个简单易用的工具,很实用,必须推荐。

  画个图标,都要出N种分辨率,每次机械操作实在有点弱爆,推荐一个牛X的工具:

  其中的功能可以自动切图输出各种屏幕密度的icon,可视化构建布局,自动生成布局文件。

   http://android-ui-utils.googlecode.com/hg/asset-studio/dist/index.html

  推荐这个,设计师应该会很喜欢,秒切图。

   http://www.cutandslice.me/

  实际开发中,考虑到包体积大小,不会在所有drawable中都放不同size的图片资源,而是只使用一套图片资源,编写不同的布局。个别特殊的图片资源就每个drawable文件夹中放相应的size,譬如程序图标,不按文件夹放可能会导致在Launcher显示失真。

  虽然不作任何改动也可以在Android Pad上跑,但由于Pad屏幕较大,操作体验不一样,建议重新设计。

   4. 开发Android APP时,配置文件应放在哪里(APP本地、远程WeB Server中)?应该如何考虑?  

  这个就要看需求了,如果只是本机使用,譬如保存软件设置,不需要联网操作的,那首选当然是保存在本地。

  如果业务需要和服务器交互,可以做成云配置方式。为了跨平台的兼容性,可以考虑使用Google的ProtoBuf,比XML更小更快更简单,后台和终端定义一套协议,自动生成C++、Java或者Python代码。

   https://developers.google.com/protocol-buffers/docs/overview?hl=zh-CN  

   5. Android APP测试方案通常考虑哪些因素?有测试方案的参考实例吗?  

   机型适配:屏幕大小,这个只能人工检验了(程序不知道你的UI长得好不好看)

  Android版本(某些API在低版本上没有的,会Crash,推荐Lint静态扫描)

   网络质量:联通、电信、移动、WiFi、弱网络等

   安全性:网络数据必定经过加密处理;本地不保存安全信息(帐号密码等),或者加密保存

  代码中敏感信息尽量使用byte数组而不是字符串代码混淆处理(Proguard)

  SD卡剩余空间很少,没SD卡,双SD卡,飞行模式,时间有误等。

   性能:CPU、内存占用(开发可以使用Linux的top命令或者DDMS里面的工具)

  网络流量消耗(有各种第三方流量监控软件)

   6. 开发Android APP时,为了提高工作效率,提高项目质量、通常需要抽象出一些lib出来,请列出经常用到的接口的名称和用途。  

  更多精彩可以上github搜搜,这就不班门弄斧了。

   7. Android APP开发中其它需要提醒的问题

  android4.4在UI线程无法进行网络操作不单只android API版本不一定导致运行异常,有些机型还使用Java 1.5进行编译,使用某些Java 1.6的函数会Crash的。

  注意OOM问题,目前android手机已经有3G内存了,但并非一个应用就能使用全部内存。了解一下堆内存,一个软件至少一个进程,一个进程跑一个虚拟机,进程使用的堆内存大小,每部手机不一定一样。

  Show Dialog的问题,永远要判断Activity是否还在。

  使用了高版本的API函数,在低版本机器上挂了。

  非UI线程不能操作UI。可能有各种权限被禁的问题。

  没有浏览器、没有软件安装器、没有Email等发生ActivityNotFoundexception。

  超快速连续点击按钮可能触发跑多个线程的问题。

  Android4.4短信权限设置,原生系统带有新接口,第三方系统可能裁剪掉了。

   8. 什么情况下发生OOM,如何避免?

  图片操作(图片缩放、bitmap生成等)、序列化反序列化数据等会消耗大量内存。合理使用数据结构(链表和数组),及时释放引用,使用弱引用等能降低OOM情况发生。

   9. 出现ANR怎么办?

  如果Android程序某个操作执行等待超过5s,会出现ANR(Application Not Responding)的对话框,对于执行耗时的操作,譬如网络操作,就不能在主线程上进行了(Android 4.4不让你这样做了),这些任务应该跑在主线程外,譬如新建一个线程处理,或者自己写一个网络引擎对所有网络请求进行管理。

   10. 如何跟踪研发质量?

  Coverity接入: https://scan.coverity.com/

  代码缺陷扫描,不扫不知道,一扫吓一跳。满分推荐!Fro Free!如果你写的是开源代码,还能直接接入GitHub,超方便。

  Crash是无法避免的,我们能做的是尽量把Crash的情况减少。发出去的版本,用户发生Crash了,我们需要把Crash数据收集起来。所以软件需要做一个Crash上报,汇总整理。统计每个版本的Crash率,并把Crash按优先级进行修复。

  当然,版本检查更新也少不了。

   11. 如果跟踪用户对产品的反馈?

  不管你写软件所用的技术有多么牛B,用户是不知道的,也不关心的。用户关心的是你的产品体验到底有多牛B。加上用户可以轻松反馈的反馈功能,你会发现有时用户的idea还不错的。

  做出来的产品好还是不好,需要有产品数据支撑,所以加插相关数据统计上报点,哪个功能热门,新增用户多少,活跃用户多少,一目了然。

   12. 安全检查

  为避免异常情况的跳转或者恶意攻击,Android组件在启动时都需要判断传入的参数是否为空。

  敏感信息需要进行权限限制或者加密处理。

  能不暴露的组件就不暴露,在AndroidManifest中为组件加上android:exported=”false”属性。

  需要暴露的组件通过自定义权限进行调用,添加自定义权限android:permission=”yourapp.permission.CALL”检测WebView漏洞http://security.tencent.com/index.php/opensource/detail/1

   13. 常用工具有哪些:

  Lint(清理资源、安全检查、layout优化等)

  一般在提测前清理一下冗余资源,查一下有没有用了一些高API Level才有的接口,查一下安全问题。

  Findbugs(检查java代码缺陷)

  在开发工程中就可以对单个文件进行检查,有问题可以及时处理。

  MAT(内存泄漏调试工具)http://www.eclipse.org/mat/

  遇到内存或者性能问题时,一般会结合几种工具来查问题,找解决方法。

  Method Profiling(统计方法耗时)

  Eclipse Class Decompiler(从此Eclipse不怕看不到jar包内的代码了) http://feeling.sourceforge.net/update

  Hierarchy Viewer(查看Activity堆栈、layout加载层次、像素眼)

  只能连接开发板手机或者模拟器,如果你的手机连不上,搜一下“Hierarchy Viewer 真机”,各种教程教你如何连上。

  Activity太多,有时出问题了,但又想不起这个页面叫什么名字,插上去,一目了然。

  很清晰看出Layout布局层次, 还能显示计算layout耗时,绘图耗时,UI性能优化好帮手。

  TinyPNG(压缩图片资源利器,山崩地裂推荐) https://tinypng.com/

  7z(压缩APK利器,上线前压一下就可以,简单实用,五星推荐)

  Apktool、Dex2jar 、jd-gui(反编译套装,你懂的)

  Mark Man(设计师何苦为难工程师)

  Beyond Compare(各种神对比,我喜欢对比代码)

   Tcpdump(Linux dump包工具)

  adb shell tcpdump -p -vv-s 0 -w /sdcard/capturenet.pcap  

  WireShark(查看网络dump包)

  遇到棘手问题时,还是需要他们帮忙解决的。

  CMD (很简单的脚本却能大大提高效率,大家多学多分享)

  一些经常操作的动作,使用手工操作又耗时又麻烦还可能出错,使用命令行去操作的话会极大提供效率。

  拖放安装应用,不用再弹出xx助手xx宝来的蜗牛速度安装了(速度快了,心情好了):

  adb install %1

  pause

  卸载应用:

  adb uninstall com.tencent.qqpim

  拉去SD卡目录文件

  adb pull /sdcard/test/log c:testlog

  获取联系人db

  adb pull /data/data/com.android.providers.contacts/databases/contacts2.db C:contact2.db

  tcpdump包

  adb shell tcpdump -p -vv -s 0 -w /sdcard/capturenet.pcap

  SDK裁剪打包

  裁目录:rd/s/q S:tencentsrcAGJ

  裁文件:del S:tencentsrccomtencenttestTestApplication.java


springbatch简介与helloworld

$
0
0

一、SpringBatch简介

Spring Batch是一个轻量级的批处理框架, 可以用于企业级海量数据处理, 它提供以下技术解决方案:

1. 定时批处理

2. 大规模并行处理

3. 企业消息驱动处理


二、SpringBatch结构

Spring Batch由应用层、核心层、基础架构层等组成:

1. 应用层: 包含所有的批处理作业,  使用spring框架管理程序员自定义的代码

2.核心层: 包含batch启动和控制所需要的核心类, 如: JobLauncher、Job、Setp等

3.基础架构层: 提供共通的读(ItemReader)、写(ItemWriter)和服务(RetryTemplate)

应用层和核心层简历在基础架构层之上, 下图展示了它们之间的关系:



三、SpringBatch流程

1. spring batch执行过程:

外部控制器调用JobLauncher启动一个Job, 每个batch都会包含一个Job, Job就像一个容器, 这个容器里装了若干个Setp, 

batch里面真正干活的就是这些Setp(ItemReader用来读取数据,ItemProcessor用来处理数据,ItemWriter用来写数据), 

Job调用Step实现对数据的操作, Setp处理完成后, 将处理结果一步步返回给上一层。

JobRepository是上述处理提供的一种持久化机制, 它为JobLauncher、Job、Setp实例童工CRUD操作。


2. Step执行过程:
从DB或文件中取出数据的时候, read操作每次只读取一条记录, 然后将这条数据传递给processor处理, batch框架将重复做这两步操作,

直到读取记录的数量达到配置文件中"commin-interval"设定值得时候就会调用一个write操作, 然后再重复以上操作, 直到处理完所有的

数据。当这个Setp工作完成以后可以调到其他Setp或结束处理。


四、HelloWorld实例

本实例没有像前面讲的那样配置ItemReader、ItemProcessor、ItemWriter,而是直接在Setp中调用Tasklet

由Tasklet完成"Hello World!"的输出。

1. 工程结构图:



2. applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
	xmlns:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="http://www.springframework.org/schema/beans  
	http://www.springframework.org/schema/beans/spring-beans-3.0.xsd  
	http://www.springframework.org/schema/context  
	http://www.springframework.org/schema/context/spring-context-2.5.xsd"
	default-autowire="byName"><bean id="jobLauncher" class="org.springframework.batch.core.launch.support.SimpleJobLauncher"><property name="jobRepository" ref="jobRepository" /></bean><bean id="jobRepository" class="org.springframework.batch.core.repository.support.MapJobRepositoryFactoryBean" /><bean id="transactionManager" class="org.springframework.batch.support.transaction.ResourcelessTransactionManager" /></beans>

applicationContext.xml主要用来配置一些spring信息, JobLaunch类用来启动Batch


3. springBatch.xml

<?xml version="1.0" encoding="UTF-8"?><bean:beans xmlns="http://www.springframework.org/schema/batch"
	xmlns:bean="http://www.springframework.org/schema/beans" 
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="http://www.springframework.org/schema/beans 
	http://www.springframework.org/schema/beans/spring-beans-3.0.xsd  
	http://www.springframework.org/schema/context 
	http://www.springframework.org/schema/context/spring-context-2.5.xsd
	http://www.springframework.org/schema/batch 
	http://www.springframework.org/schema/batch/spring-batch-2.1.xsd"><!-- 装载spring核心配置文件 --><bean:import resource="applicationContext.xml" /><job id="helloWorldJob"><step id="step_hello" next="step_world"><tasklet ref="hello" transaction-manager="transactionManager"></tasklet></step><step id="step_world"><tasklet ref="world" transaction-manager="transactionManager"></tasklet></step></job><bean:bean id="hello" class="com.zdp.springbatch.WriteTasklet"><bean:property name="message" value="Hello "></bean:property></bean:bean><bean:bean id="world" class="com.zdp.springbatch.WriteTasklet"><bean:property name="message" value=" World!"></bean:property></bean:bean></bean:beans>

springBatch.xml配置了一个ID为helloWorldJob的Job,这个Job有两个Setp:setp_hello和setp_world,

前者负责输出“Hello ”, 后者负责输出“World!”,当第一个Setp完成之后执行第二个Setp。


4. WriteTasklet:

public class WriteTasklet implements Tasklet {

    private String message;

    /**
     * @param message
     * the message to set
     */
    public void setMessage(String message) {
        this.message = message;
    }

    @Override
    public RepeatStatus execute(StepContribution stepContribution, ChunkContext chunkContext)throws Exception {
        System.out.println(message);
        return RepeatStatus.FINISHED;
    }

}
WriteTasklet中定义了一个message属性,通过springBatch.xml的hello和world bean为其注入值,execute方法由Tasklet接口继承而来,

是Tasklet实现业务逻辑的地方,此实例只是简单的输出message信息后直接返回。


5. JobLaunch

/**
 * Test client
 */
public class JobLaunch {

	public static void main(String[] args) {
		try {
			ApplicationContext context = new ClassPathXmlApplicationContext("springBatch.xml");

			JobLauncher jobLauncher = (JobLauncher) context.getBean("jobLauncher");
			Job job = (Job) context.getBean("helloWorldJob"); 

			// JobLauncher可以用来启动Job
			JobExecution result = jobLauncher.run(job, new JobParameters());
			
			// 处理结束,控制台打印处理结果 
			System.out.println(result.toString());
		} catch (Exception e) {
			throw new RuntimeException("error happens...", e);
		}
	}
}
通过spring配置取得JobLauncher和Job对象,然后由JobLauncher的run方法启动Job,JobParameters是标志Job的一些参数,

处理结束后控制台输出处理结果。
转自:http://www.cnblogs.com/gulvzhe

作者:zdp072 发表于2014-8-6 21:39:35 原文链接
阅读:35 评论:0 查看评论

毁掉你留给别人的第一印象的10种方式

$
0
0

英文原文: 10 Ways You Can Blow a First Impression

不知道你有没有听说过这样一句话:“留给别人好的第一印象的机会,你只有一次”?当然,你应该听说过,因为你过去并不是天真无知的。

要留给别人良好的第一印象所面临的困难是,通常情况下,当你认识新的人时,那个人是否对你或你的公司具有极大的价值,你可能根本不知道。没错,在一家餐厅或者棒球比赛中,朋友刚刚介绍给你的素不相识的人,可能在你目前正努力向其出售你的新产品的公司工作,甚至还可能是那家公司的老板。

但是,在你走进他们的办公室,并且发现你最近遇到过他之前,你是不会知道这些的。但愿你没有犯以下这 10 个错误中的一个,这 10 个错误会导致你留给别人的第一印象被毁掉。

1. 你戴着墨镜。这跟见面的时间是不是中午,你是否必须要面对着太阳没有什么关系。你的眼睛是了解你是一个怎样的人的第一门户。你的眼睛能够说明你的信心、真诚以及对与你见面的人的兴趣,所以帮自己一个忙吧,当你正在和新认识的人会面时,把你的墨镜摘掉——是的,即使他们仍然戴着墨镜。

2. 不知道你有没有听说过“着装上一定要能为对方留下良好印象”这句话?我生活在洛杉矶,所以我非常清楚地知道我刚从床上爬起来的样子,会被人认为是“赶时髦派”的作风,但是说实在的,你的着装究竟是不是会被看起来也是这种作风呢?你应该同时注意到另外一条谚语:“认知即现实”。也就是说,如果你看起来好像并不是那么在乎你自己,以至于甚至不能够稍微像样一点的话,那么你留给别人的第一印象可能就是,你真的不在乎你自己。

3. 握手软弱无力。是的,在有史以来每一篇关于“如何给人留下良好的第一印象”的文章或者书中,这个问题己经出现过很多次,但它是最重要的问题中之一,所以必须一次次被重申。通过握手,你可以了解一个人很多东西——柔如浮云的握手说明这个人软弱,稳定而有力的握手则代表了强大。这真的在别人认知里就这么简单。

4. 你看起来好像一点儿都不在乎。你不知道也不想去问他们是从事什么工作的,所以很显然,他们对你不重要,对不对?很遗憾你错了。如果你不知道他们是怎样的人,或者他们做了什么,你不在乎和他们的见面,他们也将会不在乎与你的见面。

5. 你似乎不能集中注意力。你是否曾经有过和这样的人谈话的经历:他们看起来好像是在看着你身后更远的地方,甚至看起来好像一直在盯着电视上的棒球比赛。那么很显然,你会觉得他们没有足够的的兴趣去了解你,以及也不在乎你是否注意到了这一点。所以,你必须专注在和你谈话的那个人身上,并且在那个时候,要像他们是你的生活中最重要的人一样对待他们。

6. 你带着自己的情绪包袱。一般来说,人们喜欢与别的快乐的人待在一起,但是你可能从早上起来开始就情绪不好,并且将不好的情绪表现了出来。你心情不好真的没有什么关系,但要知道你只有一次机会,所以要露出微笑,至少在相互沟通结束之前,然后你就可以回去宣泄了。

7. 你就是不能停止谈论自己。没有比和不停地谈论自己,或者把每一个故事都编成关于他们自己的故事的人待在一起更糟糕的事情了。很多人都知道,人们喜欢发出自己的声音,所以你需要更聪明一点,并且利用机会,以便让正在与你会面的人充分发表意见。相信我,他们会因为你做到了这一点而喜欢你的。

8. 攀龙附凤可以抬高自己的身份?真的是这样吗?没有人会在乎你整个夏天是不是都在与某某名人或者某某 CEO 一起在加勒比海上航行,因为这会让你看起来像是在过度伪装,而你可能真的就是在过度伪装。创造柔和的气氛,并且练习谦卑,这将会使你在短期和长期都得到更进一步的发展。

9. 你不会把你的手机放在一边。自从智能手机诞生以来,这是一个无疑越来越会成为人们关注的焦点的问题,但是这个问题真的需要一些关注。当你在与某些新认识的人——或者实际上与任何人——谈话的时候,如果你不能把你的手机放在一边,那么很明显,你对他们根本不感兴趣。这一点非常简单,任何人都可以认识得到。

10. 你不记得他们的名字。我知道这个问题有点难,但是这个问题绝对值得通过实践改进。你知道这是为什么吗?因为与谈论他们自己相比,只有一件事情人们更喜欢去做,而这件事情就是听到他们自己的名字。这可能是一个到目前为止最有价值的,获得良好的“第一印象”的工具了——你必须在合理的允许条件下,在整个谈话过程中以及在谈话结束时,尽可能经常的努力尝试去提到他们的名字,这样做绝对会让他们记住你。

本文链接

Java程序猿,手游引擎怎么选?(入门篇)

$
0
0

 

    手机等移动智能设备普及,让手机游戏呈现火山爆发之势,近两年来,手机游戏行业迅速崛起,催生了大量暴富神话。

 

据统计,《愤怒的小鸟》累计下载量突破10亿次,《水果忍者》和《神庙逃亡》累计下载量也分别超过3亿次和1.7亿次。在国内手游作品中,《大掌门》和《我叫MT》的月流水早超2000万元,而月流水过1000万的游戏有《百万亚瑟王》、《捕鱼达人》等。而在今年初爆发的《刀塔传奇》,一直稳居手游榜单第一位,在AppStore和安卓渠道表现强劲,双平台月流水更达到惊人的近2亿。

 



 

 

在这些爆发的手游背后,大多是年轻的创业团队,少则几人,多则十几人,然而却创造了大量财富。

 

大家不禁感叹,想要一夜暴富?想要快速变“壕”?开发手游吧!

 

 

 

           然而,做手游并不是一个毫无入门门槛的事情。做手游第一件事——选游戏引擎。无论是2D游戏还是3D游戏,游戏引擎都充当着游戏骨架的角色,没有游戏引擎就无法做出一款真正的游戏。

 

  出于节约成本、缩短周期和降低风险这三方面的考虑,很多游戏厂商倾向于使用第三方的现成引擎制作游戏,这样能将重心放在游戏的开发及设计上,不再受底层的技术及工具设计烦恼。游戏引擎是游戏开发的核心,所以选择好开发引擎至关重要。

 

 

 

目前比较流行的游戏引擎有Cocos2d-x, Unity, OGEngine.

 



 

 

Unity在国外占有大部分市场份额,  Unity是一个高效的IDE+代码库。它很好地封装了底层代码,提供许多简便的图形操作,还有商业级的高级功能。Unity采用C#开发,而且引擎核心版本是收费的。

 

  

 

  Cocos2d-x基于Cocos2d-iphone,拓展Cocos2d跨平台;采用C++开发,目前支持的平台有iOS,Android, Windows等。由于Cocos2d-iphone是以Objective-C为基础开发的,Cocos2d-x支持的语言是C++。所以采用Cocos2d-x开发游戏的开发者必须使用C++。

 

           Unity和Cocos2d-x都是不错的手游开发引擎,但是他们依然对开发者而言有一定技术门槛;尤其是对于Java开发者而言,采用C#、C++开发,意味着新的语言学习成本。

 

 

 

OGEngine主要使用Java语言开发,但是在大运算量耗时功能时,OGEngine试用了C/C++本地代码进行开发,比如物理引擎及音频处理。作为开发者,只需要关注Java就可以了,OGEngine已经将所有本地代码封装好了。OGEngine支持Android和iOS平台,支持使用Java直接开发iOS游戏。OGEngine是一个开源项目并且免费,这使得开发者在遇到问题时可以直接从源码、官网文档和开发者社区中找到答案,也能按照自己的需要对OGEngine进行修改和拓展。

 

 

为了方便开发者将自己开发的手游快速推向市场并获得收益,OGEngine还有系列组件和云服务,为开发者提供从开发、运营、到支付等一系列服务。目前已经有数万款手游基于OGEngine开发,并成功推向市场获得收益。

 

 

 

 



已有 0人发表留言,猛击->> 这里<<-参与讨论


ITeye推荐



常见分布式负载均衡工具介绍nginx lighttpd haproxy

$
0
0

       在架构系统的时候,通常会涉及到分布式,而处分布式里面最前端的是负载均衡器(当然还有cdn)。在网上搜寻一份,对目前常见的负载均衡器做一些介绍和常见组合,不涉及具体配置。

 

第一种是常见的硬件有比较昂贵的NetScaler、F5、Radware和Array等商用的负载均衡器,它的优点就是有专业的维护团队来对这些服务进行维护、缺点就是花销太大,所以对于规模较小的网络服务来说暂时还没有需要使用;

第二种是类似于LVS/HAProxy、Nginx的基于Linux的开源免费的负载均衡软件策略,这些都是通过软件级别来实现,所以费用非常低廉,所以我个也比较推荐大家采用第二种方案来实施自己网站的负载均衡需求。除了这些还有:Lighttpd、Apache-mod_proxy、Squid、Socks、TIS FWTK、Delegate。

 

LVS的特点是:

1.抗负载能力强、是工作在网络4层之上仅作分发之用,没有流量的产生,这个特点也决定了它在负载均衡软件里的性能最强的;
2.配置性比较低,这是一个缺点也是一个优点,因为没有可太多配置的东西,所以并不需要太多接触,大大减少了人为出错的几率;
3.工作稳定,自身有完整的双机热备方案,如LVS+Keepalived和LVS+Heartbeat,不过我们在项目实施中用得最多的还是LVS/DR+Keepalived;
4.无流量,保证了均衡器IO的性能不会收到大流量的影响;
5.应用范围比较广,可以对所有应用做负载均衡;
6.软件本身不支持正则处理,不能做动静分离,这个就比较遗憾了;其实现在许多网站在这方面都有较强的需求,这个是Nginx/HAProxy+Keepalived的优势所在。如果是网站应用比较庞大的话,实施LVS/DR+Keepalived起来就比较复杂了,特别后面有Windows Server应用的机器的话,如果实施及配置还有维护过程就比较复杂了,相对而言,Nginx/HAProxy+Keepalived就简单多了。

 

Nginx的特点是:

1.工作在网络的7层之上,可以针对http应用做一些分流的策略,比如针对域名、目录结构,它的正则规则比HAProxy更为强大和灵活,这也是许多朋友喜欢它的原因之一;
2.Nginx对网络的依赖非常小,理论上能ping通就就能进行负载功能,这个也是它的优势所在;
3.Nginx安装和配置比较简单,测试起来比较方便;
4.也可以承担高的负载压力且稳定,一般能支撑超过几万次的并发量;
5.Nginx可以通过端口检测到服务器内部的故障,比如根据服务器处理网页返回的状态码、超时等等,并且会把返回错误的请求重新提交到另一个节点,不过其中缺点就是不支持url来检测;
6.Nginx仅能支持http和Email,这样就在适用范围上面小很多,这个它的弱势;
7.Nginx不仅仅是一款优秀的负载均衡器/反向代理软件,它同时也是功能强大的Web应用服务器。LNMP现在也是非常流行的web架构,大有和以前最流行的LAMP架构分庭抗争之势,在高流量的环境中也有很好的效果。
8.Nginx现在作为Web反向加速缓存越来越成熟了,很多朋友都已在生产环境下投入生产了,而且反映效果不错,速度比传统的Squid服务器更快,有兴趣的朋友可以考虑用其作为反向代理加速器。

HAProxy的特点是:

1.HAProxy是支持虚拟主机的。
2.能够补充Nginx的一些缺点比如Session的保持,Cookie的引导等工作。
3.支持url检测后端的服务器出问题的检测会有很好的帮助。
4.它跟LVS一样,本身仅仅就只是一款负载均衡软件;单纯从效率上来讲HAProxy更会比Nginx有更出色的负载均衡速度,在并发处理上也是优于Nginx的。
5.HAProxy可以对Mysql读进行负载均衡,对后端的MySQL节点进行检测和负载均衡,不过在后端的MySQL slaves数量超过10台时性能不如LVS,所以我向大家推荐LVS+Keepalived。

6.HAProxy的算法现在也越来越多了,具体有如下8种:
① roundrobin,表示简单的轮询,这个不多说,这个是负载均衡基本都具备的;
② static-rr,表示根据权重,建议关注;
③ leastconn,表示最少连接者先处理,建议关注;
④ source,表示根据请求源IP,这个跟Nginx的IP_hash机制类似,我们用其作为解决session问题的一种方法,建议关注;
⑤ ri,表示根据请求的URI;
⑥ rl_param,表示根据请求的URl参数'balance url_param' requires an URL parameter name;
⑦ hdr(name),表示根据HTTP请求头来锁定每一次HTTP请求;
⑧ rdp-cookie(name),表示根据据cookie(name)来锁定并哈希每一次TCP请求。
 

 

Nginx和LVS作对比的结果

1、Nginx工作在网络的7层,所以它可以针对http应用本身来做分流策略,比如针对域名、目录结构等,相比之下LVS并不具备这样的功能,所 以 Nginx单凭这点可利用的场合就远多于LVS了;但Nginx有用的这些功能使其可调整度要高于LVS,所以经常要去触碰触碰,由LVS的第2条优点 看,触碰多了,人为出问题的几率也就会大。
2、Nginx对网络的依赖较小,理论上只要ping得通,网页访问正常,Nginx就能连得通,Nginx同时还能区分内外网,如果是同时拥有内外网的 节点,就相当于单机拥有了备份线路;LVS就比较依赖于网络环境,目前来看服务器在同一网段内并且LVS使用direct方式分流,效果较能得到保证。另 外注意,LVS需要向托管商至少申请多一个ip来做Visual IP,貌似是不能用本身的IP来做VIP的。要做好LVS管理员,确实得跟进学习很多有关网络通信方面的知识,就不再是一个HTTP那么简单了。站长教学网 eduyo.com
3、Nginx安装和配置比较简单,测试起来也很方便,因为它基本能把错误用日志打印出来。LVS的安装和配置、测试就要花比较长的时间了,因为同上所述,LVS对网络依赖比较大,很多时候不能配置成功都是因为网络问题而不是配置问题,出了问题要解决也相应的会麻烦得多。
4、Nginx也同样能承受很高负载且稳定,但负载度和稳定度差LVS还有几个等级:Nginx处理所有流量所以受限于机器IO和配置;本身的bug也还是难以避免的;Nginx没有现成的双机热备方案,所以跑在单机上还是风险较大,单机上的事情全都很难说。
5、Nginx可以检测到服务器内部的故障,比如根据服务器处理网页返回的状态码、超时等等,并且会把返回错误的请求重新提交到另一个节点。目前LVS中 ldirectd也能支持针对服务器内部的情况来监控,但LVS的原理使其不能重发请求。重发请求这点,譬如用户正在上传一个文件,而处理该上传的节点刚 好在上传过程中出现故障,Nginx会把上传切到另一台服务器重新处理,而LVS就直接断掉了,如果是上传一个很大的文件或者很重要的文件的话,用户可能 会因此而恼火。
6、Nginx对请求的异步处理可以帮助节点服务器减轻负载,假如使用apache直接对外服务,那么出现很多的窄带链接时apache服务器将会占用大 量内存而不能释放,使用多一个Nginx做apache代理的话,这些窄带链接会被Nginx挡住,apache上就不会堆积过多的请求,这样就减少了相 当多的内存占用。这点使用squid也有相同的作用,即使squid本身配置为不缓存,对apache还是有很大帮助的。LVS没有这些功能,也就无法能 比较。
7、Nginx能支持http和email(email的功能估计比较少人用),LVS所支持的应用在这点上会比Nginx更多。在使用上,一般最前端所 采取的策略应是LVS,也就是DNS的指向应为LVS均衡器,LVS的优点令它非常适合做这个任务。重要的ip地址,最好交由LVS托管,比如数据库的 ip、webservice服务器的ip等等,这些ip地址随着时间推移,使用面会越来越大,如果更换ip则故障会接踵而至。所以将这些重要ip交给 LVS托管是最为稳妥的,这样做的唯一缺点是需要的VIP数量会比较多。Nginx可作为LVS节点机器使用,一是可以利用Nginx的功能,二是可以利 用Nginx的性能。当然这一层面也可以直接使用squid,squid的功能方面就比Nginx弱不少了,性能上也有所逊色于Nginx。Nginx也 可作为中层代理使用,这一层面Nginx基本上无对手,唯一可以撼动Nginx的就只有lighttpd了,不过lighttpd目前还没有能做到 Nginx完全的功能,配置也不那么清晰易读。另外,中层代理的IP也是重要的,所以中层代理也拥有一个VIP和LVS是最完美的方案了。具体的应用还得 具体分析,如果是比较小的网站(日PV<1000万),用Nginx就完全可以了,如果机器也不少,可以用DNS轮询,LVS所耗费的机器还是比较 多的;大型网站或者重要的服务,机器不发愁的时候,要多多考虑利用LVS
 

 

反向代理从传输上分可以分为2种:

1:同步模式(apache-mod_proxy和squid)

2:异步模式(lighttpd 和 nginx)

 

在nginx的文档说明中,提到了异步传输模式并提到它可以减少后端连接数和压力,这是为何?

下面就来讲解下传统的代理(apache/squid)的同步传输和lighttpd,nginx的异步传输的差异。

 

 

同步传输:浏览器发起请求,而后请求会立刻被转到后台,于是在浏览器和后台之间就建立了一个通道。在请求发起直到请求完成,这条通道都是一直存在的。


异步传输:浏览器发起请求,请求不会立刻转到后台,而是将请求数据(header)先收到nginx上,然后nginx再把这个请求发到后端,后端处理完之后把数据返回到nginx上,nginx将数据流发到浏览器,这点和lighttpd有点不同,lighttpd是将后端数据完全接收后才发送到浏览器。

 

Squid作为网页服务器的前置cache服务器,可以代理用户向web服务器请求数据并进行缓存,也可以用在局域网中,使局域网用户通过代理上网。Squid与Linux下其它的代理软件如Apache、Socks、TIS FWTK和delegate相比,下载安装简单,配置简单灵活,支持缓存和多种协议。用ipchains+Squid的解决方案,就可以获得通过缓存高性能的同时能够无缝的访问Internet。

 

小结:apache和squid的反向会增加后端web的负担,因为每个用户请求都会在proxy上与后端server建立的长久链接,知道数据取完前,连接都不会消失。因为wan速度与lan速度的不同,虽然lan之间的速度是极度快的,但是用户的wan连接决定了这个时间长。而lighttpd和nginx的异步模式,是不管你用户要求的数据有多大,都是先收下来,再与后端联系,这是非常迅速的速度,所以proxy与后端连接时间也会很短,几十M的东西也是几秒内。后端不需要维护这么多连接。而lighttpd也和nginx不同的异步,lighttpd是先收完再转向客户浏览器,而nginx是边收数据边转向用户浏览器。

 

那么这到底有什么好处呢?

1. 假设用户执行一个上传文件操作,因为用户网速又比较慢,因此需要花半个小时才能把文件传到服务器。squid的同步代理在用户开始上传后就和后台建立了连接,半小时后文件上传结束,由此可见,后台服务器连接保持了半个小时;而nginx异步代理就是先将此文件收到nginx上,因此仅仅是nginx和用户保持了半小时连接,后台服务器在这半小时内没有为这个请求开启连接,半小时后用户上传结束,nginx才将上传内容发到后台,nginx和后台之间的带宽是很充裕的,所以只花了一秒钟就将请求发送到了后台,由此可见,后台服务器连接保持了一秒。同步传输花了后台服务器半个小时,异步传输只花一秒,可见优化程度很大。

2. 在上面这个例子中,假如后台服务器因为种种原因重启了,上传文件就自然中断了,这对用户来说是非常恼火的一件事情,想必各位也有上传文件传到一半被中断的经历。用nginx代理之后,后台服务器的重启对用户上传的影响减少到了极点,而nginx是非常稳定的并不需要常去重启它,即使需要重启,利用kill -HUP就可以做到不间断重启nginx。

3. 异步传输可以令负载均衡器更有保障,为什么这么说呢?在其它的均衡器(lvs/haproxy/apache等)里,每个请求都是只有一次机会的,假如用户发起一个请求,结果该请求分到的后台服务器刚好挂掉了,那么这个请求就失败了;而nginx因为是异步的,所以这个请求可以重新发往下一个后台,下一个后台返回了正常的数据,于是这个请求就能成功了。还是用用户上传文件这个例子,假如不但用了nginx代理,而且用了负载均衡,nginx把上传文件发往其中一台后台,但这台服务器突然重启了,nginx收到错误后,会将这个上传文件发到另一台后台,于是用户就不用再花半小时上传一遍。

4. 假如用户上传一个10GB大小的文件,而后台服务器没有考虑到这个情况,那么后台服务器岂不要崩溃了。用nginx就可以把这些东西都拦在nginx上,通过nginx的上传文件大小限制功能来限制,另外nginx性能非常有保障,就放心的让互联网上那些另类的用户和nginx对抗去吧。

用异步传输会造成问题:

后台服务器有提供上传进度的功能的话,用了nginx代理就无法取得进度,这个需要使用nginx的一个第三方模块来实现。

 

针对高可用(HA)通常做是主备或者集群,也是分布式集群的中的很重要一环,直接避免单点故障。目前使用较多的HA软件有:Keepalived、Heartbeat、 Piranha、Pacemaker;

 

Keepalived和Heartbeat对比:

 

Keepalived使用的vrrp协议方式,虚拟路由冗余协议 (Virtual Router Redundancy Protocol,简称VRRP)。Heartbeat是基于主机或网络的服务的高可用方式;
keepalived的目的是模拟路由器的双机。heartbeat的目的是用户service的双机;
lvs的高可用建议用keepavlived。业务的高可用用heartbeat

 

Piranha 提供了一套解决方案,包括对服务状态的监控、业务服务器的监控和负载服务器本身热备。

 

Pacemaker 是一个集群资源管理器。它利用你喜欢的集群基础构件(OpenAIS 或heartbeat)提供的消息和成员管理能力来探测并从节点或资源级别的故障中恢复,以实现群集服务(亦称资源)的最大可用性。
它可以做几乎任何规模的集群,并带有一个强大的依赖模式,让管理员能够准确地表达的群集资源之间的关系(包括顺序和位置)。几乎任何可以编写的脚本,都可以作为管理起搏器集群的一部分。尤为重要的是Pacemaker不是一个heartbeat的工具,可能有人存在这样的误解。Pacemaker是一个延续CRM(亦称V2资源管理器)的项目。最初开发的项目是heartbeat,已经成为该项目的子项目。

 



已有 0人发表留言,猛击->> 这里<<-参与讨论


ITeye推荐



HTML5移动应用开发的生态环境简介

$
0
0

我本人是HTML5的大粉丝,因为它可以给我带来满足我创造力的开发速度。

但自从移动平台崛起以来,这项技术所涉及的开发就开始变得复杂起来。在桌面平台看来,一切都非常清楚。网站开发就是一场不断持续的进化,即便如此还是有人对其了如指掌。但是在移动平台这就是场噩梦。开发者们被各种开发HTML5移动应用的方法搞得晕头转向,所以我希望这个指南可以帮助他们。

正如我在 前一篇文章中提到过,如果想要实现一个移动应用的话,你首先得是一个web开发者。

在开始给大家介绍现有的不同平台和框架之前,我必须声明我并不认为Titanium Mobile是一个HTML5解决方案。如果想要知道为什么请参阅我的前一篇文章。

目前有四个解决方案(其他新的解决方案也在不断出现,但都还处于初期状态)可以用于开发HTML5移动应用。

Web App

这是最直白的方法。简单来说,就是一个通过浏览器访问的网站。Android和iOS都提供将网站链接添加到桌面的功能。这样的应用通过恰当的配置可以以全屏状态运行,并且配合Appcache可以实现离线运行。

更新: Daniel Appelquist提醒大家在Firefox OS,Android上的Firefox以及今后的Chrome都会为用户提供将web app添加到移动设备的功能。前提是你需要为你的web app声明一个配置清单。嗯,挺好。

对我来说,这并不是一个可靠的方案:

利用Phonegap / Cordova 集成开发平台

这个是目前来讲,最有效的妥协方案。现在已经有一整套相关生态系统包括工具,论坛,开发者。你能通过它来利用HTML5的API以及原生API。到最后,你得到的会是一个真正的APP。此平台也遵从HTML5规范以协助web应用的转化。

手工接入本地环境

这个方案针对的是那些规模较大并对设备原生代码颇具了解的团队。很多大公司就采用的这种方式。它可以将高性能的原生UI组件与高灵活性的HTML搭配使用。

如果你感兴趣的话,你可以看看这些链接:

 

使用Intel XDK基础开发环境

说实话我不能给这个方案一个准确的评价。在我第一次安装这个编辑器后,它的复杂程度让我惊呆了,所以我也没有动力再去研究它。就我所了解的,它和Phonegap应该遵从的同样的精神不过他们专门打造了一个完整的IDE。我并不确切地知道具体地差别在哪。如果哪位在Intel工作的老兄读到这篇文章,麻烦你给我提供一下更多相关细节好吧?

原生HTML

这个是完美的解决方案。操作系统直接执行HTML5代码而不是通过桥接的方式链接HTML和原生代码。你能使用所有的API,debug工具也能完美的使用。而实际上,目前只有 Firefox OSTizen拥有这样的系统。

------------------------------

现在你知道了这些不同的方案,我们可以摆一摆移动HTML5应用的八卦。当乔布斯在第一代iPhone发布会上宣布有移动HTML5之后,其相关开发就开始了。Safari和Firefox在当时是最好的HTML5浏览器(Google Chrome那时还没出来)。

但是一年之后,应用商店上线了,但是只能用Objective-C开发应用。该死的乔布斯。

之后没过多久,一帮开发者就创造了Phonegap。我还记得当时他们拿一个wiki当主页。它当时bug无数,虽然的确是个天才的想法。但问题是与此同时开发者们也纷纷开始制作移动HTML5应用。所以许多人被它搞得很恼火然后到处说它坏话。

自那以后,又发生了很多事情:智能手机的CPU越来越强大,CSS渲染可以通过GPU完成,HTML5的规范更加精准,浏览器引擎更加强大。

前端开发也同样有了很大的改进。我们的JS代码不再是一个巨大的 $(document).ready函数。我们开始使用更加标准化的框架(AngularJS, BackboneJS, EmberJS, Polymer, ReactJS)而且我们的debug工具也不再弱于那些原生debug工具。我们也开始使用构建系统,包管理器,以及代码风格。

HTML5移动开发自2009年以后就完全变样了。

所以到最后,HTML5的问题是什么?就是 UI

有些读者已经知道, 我真的很讨厌jQuery Mobile,然而很不幸的是,大多数开发者都用它来做移动开发。Bootstrap也没法解决这个问题。它确实是响应式的但是并不是针对的移动平台。原生应用开发者用他们的原生组件来和HTML/CSS相比较,这明显是很不公平的。

原生平台提供很多“拖来就用”的组件,而且是经过全面的测试,优化,并已经包含了性能优势。iOS提供的原生长列表组件会自动隐藏那些看不到的元素,但是在HTML/CSS里面并非如此。

Web UI是开发者心中永远的痛因为Apple或Google从未提供过Web UI的框架。想像一下如果有种“Bootstrap”可以拥有所有原生组件的特性(性能,渐变,个性化等等)。他们本来可以做到,但这并不是他们优先考虑的。然而现在情况不同了。

Windows Metro

微软是这方面第一让我有深刻印象的。他们的Metro UI无论是在C++,C# 还是 HTML里都有同样的特性:

HTML5中的ListView的一个例子:

  • http://msdn.microsoft.com/en-US/library/windows/apps/br211837.aspx
  • http://code.msdn.microsoft.com/windowsapps/Universal-Windows-app-cb3248c3

Firefox OS

Firefox OS更加有意思。Mozilla自己同第三方开发者使用同一套CSS。说实话这真是最棒的想法了。你可以直接 去GitHub进行贡献

  • https://github.com/mozilla-b2g/gaia
  • http://buildingfirefoxos.com/index.html

那么Google呢?

Google是最后一个但也很不错。他们采用了另一种方式。他们给我们带来了AngularJS以及最新的Polymer。Polymer是是一个让你可以轻易创建web组件的框架。

在他们完成开发web应用底层结构之后,他们开始专注于UI。现在的成果就是Material Design(译注 这里是相关介绍),他们的想法是创造完全响应式的设计,而并不是简单的缩放元素大小,这样可以使得应用在每个屏幕尺寸上看起来都很性感。他们使用Polymer来提供这些组件。

  • http://www.polymer-project.org/components/paper-elements/demo.html#core-toolbar
  • http://www.polymer-project.org/docs/start/tutorial/intro.html

同时现在还有其他的UI框架!

Ionic Framework

这个是个人最爱。其设计与iOS很相近,但不像某些人,它在Android上看起来也很棒(看什么看我说的就是你jQuery Mobile)。他们带有AngularJS的指令集,现装现用,性能优化,自带动画,等等。简而言之,这货就是春哥附体。下拉刷新,侧边菜单,无限滑滚,支持超长列表(没错,超过1000条元素),选项夹,等等。

这个截图是我正在开发的一个应用

Drifty,这个开发了Ionic Framework的公司,正在同其他开发者一起研发Angular Material,一个类似于Polymer中Material Design的东西不过是基于AngularJS。

还有其他更多不错选择,不过目前还达不到Ionic那么好。不过大家还是可以关注一下,我相信很快他们都会改进:

那么Apple呢?我觉得他们还是更倾向于迫使人们用Swift或者Obj-C进行原生开发。万幸的是,我之前提到的大多数框架都支持iOS。SB了吧,Tim!

我希望现在你对HTML5移动开发能够有了更多的了解。这个指南还没有完成,我只是想到哪写到哪。如果你发现我有什么地方写的不对,请尽管给我留言或者通过你方便的方式联系我: http://www.yrezgui.com

美国“程序员世界”无门槛

$
0
0

宋冰

想在美国当程序员?可能没你想象的那么难。就算没钱去正经大学念个计算机科学,也有其他出路。

最近,越来越多的在线学习编程学校在美国火了起来。许多真实的案例都为一些有志于此的人指出了一条光明大道:无论你是想找工作的穷学生,还是想改行的中年危机男,程序员的世界都欢迎你。

“闪电战”编程课程

西雅图的“代码伙伴”(Code Fellows)学校,就非常确信他们能够帮助学生找到工作。他们为学生提供六个星期的“闪电战”编程课程,让学生能够完成从零基础达到基本入门状态,收费 1.2 万美元——如果还是找不到工作,学费可以全退。

类似学校的兴起背后,是美国互联网市场的日渐繁荣,这导致了程序员供不应求的局面。据美国劳工部的数据预测,2020 年美国大约会空出 100 万个程序员职位。而且许多传统高校对计算机课程的不怎么上心,正在让这个缺口越来越大。

比如今年华盛顿大学的计算机系,就只招了1/4 完全够格的申请者。这样的事情在全美高校现在比比皆是。无论是报考计算机系,还是在校生选修计算机课程的比例,都在火箭式上升。

对于那些没能成功申请上一个计算机课程的学生来说,好在在程序员的世界里,学位并不是通向工作的唯一途径。

比如业界标杆谷歌公司里,一些团队就有 14% 的程序员没有相关正式学位。放大到全美来看,67% 的编程岗位都是来自非科技类公司,这就意味着编程之外,还需要其他正常商业技能。

从这个角度来看,和焊接工或者木匠一样,编程其实就是一门手艺。是一门任何人都可以在几周或者几个月内稍加学习就具备基础技能的手艺。而且一旦那些刚刚开始的编程菜鸟们靠着这些基本技能混到了第一个工作,此后的职业发展道路上,他们就和其他正规学校出来的程序员同行们获得了相等的机会,只要各凭本事就好。

以脸谱网(Facebook)为例,每一个工程师在进入该公司要做的第一件事,就是 6 个星期的集中训练,大部分的课程自然都和编程相关。公司设立这个规定流程,是因为在大部分的高校里,计算机系都更注重理论学习而不是实打实的编程。后者其实包括了各种最流行的编程语言、项目管理与合作等一系列庞杂知识,这意味着一个合格的程序员往往需要和几十个其他程序员以及几百万运行程序同时打交道。

那些在线编程短训学校们,就试图帮助这些有意进入程序员世界的门外汉,从一开始就跳过单调而不实用的理论,直击那些公司最关注的实际技能——比如网站维护或者做一个 APP。

这倒不是有意忽视基于大学教育基础之上的计算机学位的价值。如果一个学生能够负担得起这样的教育当然很好,但是从美国学生财务数据上来看不太乐观。目前美国学生贷款已经创下了 1.2 万亿美元的纪录,其中许多都注定会变成坏账。

程序员或终被替代

计算机学位有助于理论学习并且帮助那些顶级工程师继续磨练这门艺术,但在这个互联网如此普及的时代,要求每一个程序员都要有一个计算机学位,就相当于要求每一个砌砖工有一个建筑学位一样。

另一家在线编程学校“代码学院”(Codecademy),号称已经有 2400 万的全球用户注册使用其课程。不过这所学校的联合创始人扎克·西姆斯不太想把代码学院看成是一个职业学校。

“树屋”(Treehouse)的联合创始人卡森则认为,自己那张十几年前获得的计算机学位完全没有用。一日千里的互联网科技让工程师们必须持续学习新的模型和语言,这让很多半路出家的人有时也能站在同一起跑线上,只要他们愿意终其一生磨练这门技能。

“几乎所有我们现在能触摸到的东西都能和一个什么软件连上,这是人类历史上的头一遭。”卡森说。这就如硅谷一句最流行的话所言:“未来只有两种人,知道如何编程的人,和只能遵从机器指令的人。”

当然,就算已经出现了各种令人惊叹的成功个案,所有这些编程速成学校都还没有办法提供毕业生就业率的数据。当然这些学校也都是这两年刚刚开始进入市场,还要考虑到其中一些免费的在线学校中辍学率惊人。在上个月,“代码学院”有 88% 的学员顺利毕业,但是“代码学院”对学员的筛选非常严格。

“你并不需要特别的天才或者学术教育,来成为一个优秀的程序开发者。”卡森说。从“树屋”毕业需要学员支付每个月 25 美元的学费,以及将近一年的时间成本。

随着互联网科技注定要向人类社会的每一方面继续快速渗透,程序员岗位也会像其他被其所代替的劳动分工一样,越来越形形色色。

本文链接

李彦宏寄语高考状元:独立思考和理想塑造

$
0
0

8 月 4 日,来自北京、山西、浙江、吉林等 7 省的 12 名新科状元走进百度公司,并与百度创始人李彦宏进行了一场以“新状元、新起点”为主题的交流对话。

面对这些即将开始大学生活的最聪明的年轻人,坦言喜欢和聪明人打交道的李彦宏,与他们畅谈了人生成长、理想情怀以及对时代的洞察和理解。山西文科状元、和李彦宏一样出自阳泉中学的李天表示,“学长很有亲和力,儒雅帅气。让我印象最深的是他对我们如何从聪明到优秀提出的一些建议,而且他对每位同学的提问都给予了充分细致的解答,大家受益匪浅。希望在未来,我也可以按照他指点的方向努力、发展。”

学会独立思考

对于这样一群在高考独木桥脱颖而出、即将迈入大学校门的年轻人,李彦宏首先和大家分享了他对大学的理解。“在中学,大家基本都是随波逐流的状态,对于人生规划不会想太多。但在大学四年的时间里,很重要的一点是要形成独立思考的能力。在大学里,你能够见识更多优秀的人、听到不同的声音,所以在这个过程中,更重要的是要培养自己的独立思想,知道自己要成为什么样的人。”

北京文科状元、即将进入北京大学元培学院学习的孙一先对此感触颇深,“大学重在培养人的独立性。李彦宏让我们知道在大学最需要关注的是什么,比如形成独立思考的能力,这真的改变了我对上大学的看法,怎样做出正确的选择,做自己,不随波逐流。”孙一先颇有一种顿悟的感觉,“我上大学之后的第一步就是要先找到理想,积累能力,形成自己的价值观。”

除了形成独立思考的能力,李彦宏还表示高考状元都是聪明的人,也非常勤奋,但是从“聪明”到“优秀”有一个过程。“在这个过程中,需要不断锻炼自己的情商、性格,更好地适应这个社会。未来你们在大学里,以及职业生涯里会不断地经受各种考验,希望你们把握这些机会,在未来对性格方面的磨砺有足够的关注。”

改变小环境,适应大环境

而对于如今很多人抱怨整体社会环境不尽如人意,大环境掣肘了个人能力的展现,李彦宏建议大家应该去“改变小环境,适应大环境”。在他看来,“大的环境很难以一人之力改变,需要去适应,可以改变的是自己周围的小环境。如果能改变自己身处的小环境、以更加建设性的角度看待,社会就能进步。”

其实,在李彦宏眼里,如今的“大环境”让他时常会非常兴奋和激动。“现在技术创新的步伐在非常快地加速,过去几千年,人们所使用的技术没有特别大的变化,但是最近这十多年,技术和创新给人们生活带来的变化,是非常非常巨大的。”正是因为如此,李彦宏向高考状元们表示,“我们生活在一个非常幸运的年代,我们可以参与到其中,不仅可以见证人类创新加速发展的过程,还可以在里面扮演重要的角色。”确实,无论是对于青年大学生还是立志创业的人来说,他们都有很多的机会从一文不名成长为各行各业卓越的代表,只要他们真的能够不负时代,处理好小环境和大环境的关系。

河北理科状元、即将进入清华大学建筑系学习的李榕榕,下定决心在未来四年的大学生活中,多拿出时间做兼职,参加社会实践,开阔自己的视野,使他有更好的锻炼以适应外部环境,以实际行动来体会李彦宏提出的“改变小环境,适应大环境”的建议。

心怀远大理想

面对这样一个时代,李彦宏鼓励这些高考状元要心怀远大理想。李彦宏表示,“随着一个人年龄的增长,阅历会越来越丰富,知道的东西会越来越杂。从人生的发展历程来讲,首先要找到什么才是真正的能让你兴奋、并让你为之奋斗很多年的东西。一个没有理想的人是很悲哀的。而很多人之所以挣扎,就是因为理想没有想清楚。在理想逐步清晰的过程之中,达成理想的愿望越迫切,成功的概率就越大。”

实际上,早在两年前,在一场与大学生的对话当中,李彦宏就点出了理想的重要性,“当你心中有理想时,艰苦条件都变得不重要了。当你不再相信理想时,就会发现周围全部是特别黑暗的东西,会特别不舒服。”

在这次与高考状元的对话中,李彦宏还表示,百度和他的理想一直没有变过,是为了“让人们最平等、便捷地获取信息,找到所求”。这个理想,较之百度创立之初,尽管已经实现了很多,但是李彦宏依然还不满意。“不仅不满意,而且知道有哪些地方可以改进,用什么样的技术可以改进。今天这个时代创新步伐飞快,我们不仅可以见证人类创新加速发展的过程,还可以在里面扮演适合的角色。所以,每每想起这些,我就会非常兴奋、非常激动。”

本文链接


PIG JOIN 的replicated后标写入内存用法

$
0
0
'''一句话总结:PIG 在2个表JOIN的时候,如果使用Using 'replicated' 会将后面的表分段读到内存中,从而加快JOIN的效率。但是如果load 到内存的数据超过JVM的限制就会报错==>

java.lang.OutOfMemoryError: Java heap space
内存溢出'''
情节:

    年前写了一个用户session处理的PIG脚本,各种测试通过,数据OK,然后就Happy的回家过年了。T T悲剧的是,过年几天每天都发报错信息,还好依赖这个数据的后台没正是上线,不然死定了。回到公司查问题,发现总是执行到某一个JOIN的时候卡住,然后超过1200 s ,就被kill掉了。
2013-02-16 12:40:23,520 [main] INFO  org.apache.pig.backend.hadoop.executionengine.mapReduceLayer.MapReduceLauncher - More inf ormation at: http://hd09:50030/jobdetails.jsp?jobid=job_201301221227_72618
 2013-02-16 13:47:50,157 [main] INFO  org.apache.pig.backend.hadoop.executionengine.mapReduceLayer.MapReduceLauncher - 80% comp lete
 2013-02-16 13:47:52,171 [main] INFO  org.apache.pig.backend.hadoop.executionengine.mapReduceLayer.MapReduceLauncher - job job_ 201301221227_72618 has failed! Stop running all dependent jobs
 2013-02-16 13:47:52,171 [main] INFO  org.apache.pig.backend.hadoop.executionengine.mapReduceLayer.MapReduceLauncher - 100% com plete
 2013-02-16 13:47:52,175 [main] ERROR org.apache.pig.tools.pigstats.SimplePigStats - ERROR 2997: Unable to recreate exception f rom backed error: Task attempt_201301221227_72618_m_000000_1 failed to report status for 1201 seconds. Killing!
 2013-02-16 13:47:52,176 [main] ERROR org.apache.pig.tools.pigstats.PigStatsUtil - 1 map reduce job(s) failed!
 2013-02-16 13:47:52,178 [main] INFO  org.apache.pig.tools.pigstats.SimplePigStats - Script Statistics:

再看详细报错信息:
Exception in thread "Thread for syncLogs" java.lang.OutOfMemoryError: Java heap space
        at java.util.Arrays.copyOf(Arrays.java:2894)
        at java.lang.AbstractStringBuilder.expandCapacity(AbstractStringBuilder.java:117)
        at java.lang.AbstractStringBuilder.append(AbstractStringBuilder.java:589)
        at java.lang.StringBuilder.append(StringBuilder.java:220)
        at java.io.UnixFileSystem.resolve(UnixFileSystem.java:108)
        at java.io.File.<init>(File.java:329)
        at org.apache.hadoop.mapred.TaskLog.getAttemptDir(TaskLog.java:267)
        at org.apache.hadoop.mapred.TaskLog.getAttemptDir(TaskLog.java:260)
        at org.apache.hadoop.mapred.TaskLog.getIndexFile(TaskLog.java:237)
        at org.apache.hadoop.mapred.TaskLog.writeToIndexFile(TaskLog.java:316)
        at org.apache.hadoop.mapred.TaskLog.syncLogs(TaskLog.java:369)
        at org.apache.hadoop.mapred.Child$3.run(Child.java:141)
Exception in thread "LeaseChecker" java.lang.OutOfMemoryError: Java heap spac

擦!!怎么回事内存溢出呢!!以前都是好端端的没事呀。LIMIT 减少数据量试试===》数据出来了。
再看PIG语句
A = LOAD 'A/dt=2013-02-14' USING PigStorage('\u0001') AS (id:int,name:chararray);
B = LOAD 'B/*' USING PigStorage('\u0001') AS (id:int,gender:chararray);                                                                                              
C = FOREACH (JOIN A BY id , B BY id USING 'replicated') GENERATE  A::id, A::name, A::gender;

Using 'replicated' ?这个语法是在join的时候把后面表也就是B的数据读到内存,会加快JOIN的速度。  我好像发现了什么,内存啊,内存,内存溢出。靠!!干掉Using 'replicated' ,再跑。===》数据出来了  。再和维护Hadoop集群的同事联系,果然,过年的时候为了减少集群的压力,修改了很多东西,真相大白。
成也萧何,败也萧何!Using 'replicated' 要慎用啊。最好还是不用,因为隐患太大,B表一直增长的话肯定会超过JVM限制的。

已有 0人发表留言,猛击->> 这里<<-参与讨论


ITeye推荐



impala测试报告

$
0
0
机器环境:
4个slave节点
10.200.187.86 cslave1 4核 3G
10.200.187.87 cslave2 2核 4G
10.200.187.88 cslave3 2核 4G
10.200.187.89 cslave4 2核 6G
测试效果:
[img]

[/img]
总结:
1.在内存够用并且是简单sql条件下,impala相比hive执行效率高很多,简单的sql在百万级别数据中运行,耗时几秒甚至不用一秒。
2.impala性能如何,与数据的存储格式关系很大,百万级别text格式与hbase格式相差十几倍,千万级别parquet格式与text格式相差百倍。
3.在当前集群配置下,百万级别impala join略比hive性能高(3~4倍),但在千万级别时impala大表的join执行失败(内存不足)。
4.impala采用parquet存储(列式),select部分字段+where条件查询效率很高。

问题:
官方表示impala新版本可以在生产环境中使用,但根据业界人反馈,会有很多问题,重点问题是出现内存溢出情况。官方推荐impala节点的内存是128G。

建议使用场景:
部署于生产环境,可应用于运维,做简单查数据工作,效率高。但有一定的内存占用,不建议使用复杂sql例如大表join等。
imapla实时查询,如上可以看到,相对hive性能是有很大提高的,但它也不能达到关系型数据库的效果,所以根据实际业务场景需求而定。


部分资料:
适用面:
Hive: 复杂的批处理查询任务,数据转换任务。
Impala:实时数据分析,因为不支持UDF,能处理的问题域有一定的限制,与Hive配合使用,对Hive的结果数据集进行实时分析。
优点:
支持SQL查询,快速查询大数据。
可以对已有数据进行查询,减少数据的加载,转换。
多种存储格式可以选择(Parquet, Text, Avro, RCFile, SequeenceFile)。
可以与Hive配合使用。
缺点:
不支持用户定义函数UDF。
不支持text域的全文搜索。
不支持Transforms。
不支持查询期的容错。
对内存要求高。
补充:
ERRORS报错情况

create table testjoinparquet as
                > select a.tid,a.buyer_nick,b.status,b.adjust_fee,b.buyer_email
                > from (select tid,buyer_nick from s_trade_big_parquet) a
                > join
                > (select tid,status,adjust_fee,buyer_email from s_trade_big_parquet) b
                > on (a.tid=b.tid);
Query: create table testjoinparquet as select a.tid,a.buyer_nick,b.status,b.adjust_fee,b.buyer_email from (select tid,buyer_nick from s_trade_big_parquet) a join (select tid,status,adjust_fee,buyer_email from s_trade_big_parquet) b on (a.tid=b.tid)
Query aborted.
ERRORS ENCOUNTERED DURING EXECUTION:
Backend 3:Memory Limit Exceeded
Query Limit: Consumption=1.35 GB
  Fragment dd496e82ab98ee40:19f71d48047534a2: Consumption=16.00 KB
    UDFs: Consumption=0.00
    EXCHANGE_NODE (id=4): Consumption=0.00
    DataStreamMgr: Consumption=0.00
    HdfsTableSink: Consumption=0.00
  Fragment dd496e82ab98ee40:19f71d48047534a6: Consumption=1.27 GB
    UDFs: Consumption=0.00
    HASH_JOIN_NODE (id=2): Consumption=1.07 GB
    HDFS_SCAN_NODE (id=0): Consumption=207.88 MB
    EXCHANGE_NODE (id=3): Consumption=1.70 MB
    DataStreamMgr: Consumption=1.70 MB
    DataStreamSender: Consumption=2.45 KB
  Fragment dd496e82ab98ee40:19f71d48047534aa: Consumption=82.39 MB
    UDFs: Consumption=0.00
    HDFS_SCAN_NODE (id=1): Consumption=82.19 MB
    DataStreamSender: Consumption=8.00 KB
说明:内存已经用完,导致部分节点读取异常,parquet格式表写入很耗内存,因为parquet以1G为单位,1G得全部加载到内存中再写入。

相关文档:
开源中国:http://my.oschina.net/weiqingbin/blog/196143#OSC_h2_31,里边也有很多Impala框架优化应用方面的翻译文档。
hive与impala对比,sql差异参看http://www.cloudera.com/content/cloudera-content/cloudera-docs/Impala/latest/Installing-and-Using-Impala/ciiu_langref_unsupported.html#langref_unsupported,
中文:http://my.oschina.net/weiqingbin/blog/189414

已有 0人发表留言,猛击->> 这里<<-参与讨论


ITeye推荐



使用Java VisualVM监控远程JVM

$
0
0
我们经常需要对我们的开发的软件做各种测试, 软件对系统资源的使用情况更是不可少, 目前有多个监控工具, 相比JProfiler对系统资源尤其是内存的消耗是非常庞大,JDK1.6开始自带的VisualVM就是不错的监控工具.
这个工具就在JAVA_HOME\bin\目录下的jvisualvm.exe, 双击这个文件就能看到一个比较直观的界面


使用Java VisualVM监控远程JVM - liuyb_94242 - 我的空间我做主

从左边Applications树中可以知道,不光可以监控本地JVM运行情况, 还可以监控远程机器上的JVM运行情况.
本地监控:只要打开某个JAVA程序就会自动的加入到本地监控中.

因为本地监控无需配置, 所以这里主要介绍监控远程JVM
要进行远程监控, 本机的VisualVM就必须和远程的JVM要进行通信, Visualvm目前支持两种remote connection方式.
分别是jstatd和JMX方式: 这里我主要介绍的是通过JMX方式.

通过JMX连接远程机器, 需要经过下面的配置:
1. 修改远程机器JDK配置文件 (我这里远程机器是linux).
   a.进入JAVA_HOME\jre\lib\management\目录
   b.拷贝jmxremote.password.template这个文件到当前目录, 并改名为jmxremote.password
     c.打开jmxremote.password文件,去掉 # monitorRole  QED 和 # controlRole  R&D 这两行前面的注释符号

2. 修改远程机器上需要被监控的程序的配置文件 (我这里是监控Tomcat容器内部署的应用).
   a.进入TOMCAT_HOME\bin目录
     b.打开catalina.sh文件,加入如下信息:
        JAVA_OPTS="$JAVA_OPTS -Djava.rmi.server.hostname=192.168.0.237
                                                     -Dcom.sun.management.jmxremote.port=18999
                                                     -Dcom.sun.management.jmxremote.ssl=false
                                                     -Dcom.sun.management.jmxremote.authenticate=false"
   c.重启Tomcat服务.

3. 客户端VisualVM配置 (我客户端用的是WinXP).
     a.直接反键点击Remote,选择Add Remote Host...
     b.在弹出的界面中输入远程机器的IP地址(192.168.0.237),这个IP地址会加入到Remote节点下.
     c.反键点击这个IP地址,选择Add JMX Connection, 在弹出的界面中输入刚配置的端口号(18999), 这个连接会加入到该IP节点下.
     d.反键点击这个连接,选择Open.

此时就可以看到监控的界面, 从界面上我们可以看到CPU信息, 内存信息, 统计加载类数量,线程信息.

已有 0人发表留言,猛击->> 这里<<-参与讨论


ITeye推荐



用集算器实现跨数据库关联报表

$
0
0
实际应用中很多报表的数据来源于多个不同类型的 数据库,报表数据源跨数据库是报表开发中的常态。目前实现这类跨库关联报表的方式有多种,但都会存在这样那样的问题。
   使用报表工具自身多源关联功能
  现在大多数主流报表工具都支持多数据源关联,这在某些方面确实为报表用户带来了便利。然而我们也经常会遇到通过报表自身的多源关联功能很难实现一些跨库关联的报表(由于数据结构和业务本身决定)。这当然容易理解,报表工具主要是来做数据展现的,而对数据计算本身来说并不擅长。
  即使有的能实现,在报表中做跨库关联计算的效率也较低,远远不如数据库的性能,而且经常因为在实现过程中使用了大量隐藏行列进一步降低报表性能并加大内存占用。
  于是一般会采用下面的两种方式。
   将数据统一到一个数据库中
  将不同数据库的数据统一到一个数据库中,这种做法在各类应用中很常见,目的是使用数据库( SQL)强大的计算能力。然而,这种做法会增加额外的成本开销,将多个数据库中的数据统一到一个数据库中势必会占用昂贵的数据库空间,并造成该数据库数据过多、管理困难、压力增大等问题,而且还可能负担额外的数据库购买成本以及管理成本。另外,完成ETL迁移数据也是一份不小的 工作量,对实时性要求较高的报表还得用触发器方式来做ETL(一般ETL是定时的),会严重影响原数据库的性能。
   使用高级语言实现跨库关联为报表准备数据
  基于上面提到两种方式中存在的问题,有些用户使用高级语言(Java等)编程完成跨库运算,为报表自定义数据源。这种做法的优点是灵活,理论上任何运算通过程序都能完成;缺点是太难写。很多像Java这样的高级语言缺乏对集合运算的有效支持,没有相应的类库,导致完成个简单的group也要写很多(循环)代码,更不用说关联以后还要再进行分组汇总等其他运算了。
  这种情况下,使用集算器来实现跨库关联报表就是个不错的选择。
   集算器如何实现跨库关联报表?
  我们通过一个例子来看集算器是如何快速实现跨库关联报表的。
   业务描述
  企业员工每月应发工资跟员工的基本工资、考勤以及绩效有关,考勤信息来源于人力部门的考勤系统(hsql数据库),基本工资和绩效信息则存储在财务系统(mysql数据库)中。需要将这两类信息合起来计算员工的工资。
   实现步骤
   编写脚本(crossDB.dfx)完成跨库关联计算,为报表准备数据
  
  在A1、A2中通过connect分别连接hsql和mysql数据源
  在A3、A4、A5中通过query语句分别从两个数据库中取出用到的数据,此时数据已全部取出,不再需要与数据库交互,在A6、A7中关闭两个数据库连接
  在A8中使用join完成三表的连接
  在A9中计算应发工资,算法为:基本工资*(1-考勤系数+绩效系数)
  最后通过A10的result生成供报表使用的结果集
  报表调用集算器脚本完成报表展现
  集算器的类包封装成标准的JDBC,允许报表工具以类存储过程的调用方式调用集算器脚本,如本例中在报表工具中像配置数据库连接一样配置起好集算器的JDBC,然后建立存储过程数据集后使用 call crossDB()即可完成调用。
  这里以BIRT为例说明调用过程:
  1、 复制集算器JDBC驱动包到相应目录
  2、 配置报表数据源
  
  3、 设置DataSet,调用集算器脚本
  
  简单几步完成调用,BIRT即可使用集算器的计算结果直接展现输出。
  结语
  通过这个例子可以看到,集算器擅长完成跨库计算,并将计算后的结果以标准ResultSet方式返回为报表提供数据源,而报表采用类存储过程调用的方式调用集算器脚本非常简单。
  还有一个重点需要关注,就是价格。集算器是个需要付费的商业软件,好在只针对大数据的集群才收费,用作报表数据源功能是免费的,不需要增加成本就能轻松解决多数据库关联报表问题。


顺其自然EVO 2014-08-07 12:17 发表评论

Android App启动画面的制作

$
0
0

  安卓软件启动时,都会有一个全屏的带LOGO,软件名称,版本号的启动屏幕。这个屏幕是怎么做出来的呢!!下面就一步一步的来!

 

一、新建项目

打开eclipse,新建一个Android项目,不建Activity。这时就出现一个空白的项目。

1、新建Activity文件

点击项目管理里的res,进入layout,右键点击NEW-》Project-》Android-》Android XML Layout File 按步骤新建一个Activity的XML文件

我是选择新建了一个RelativeLayout,起名为index_layout.xml。

2、新建Activity对应的java文件

点击项目管理里的src,建立一个Package,然后在其上新建一个Class,对应上面新建的Activity。我新建的Class名为Index.java

3、新建颜色文件

点击项目管理里的values,建立Android XML Values File文件,用于存放颜色。我是建的名为color.xml,点击Add,选择Color,Name=white,Value=#ffffff

 

新建完后,点击index_layout.xml进入,这是Activity界面,我们需要它变成全屏的,同时背景为color.xml定义的白色。

代码如下:

<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:background="@color/white"><TextView 
    android:layout_width="fill_parent"
    android:layout_height="match_parent"
    android:text="@string/app_name"
    /></RelativeLayout>


android:layout_width="fill_parent"

android:layout_height="fill_parent"

android:background="@color/white"

这三行是比较重要的,layout_width和layout_height必须为fill_parent,不然无法全屏。当然,有这两个并不能全屏,还需要在AndroidManifest.xml里添加一句,这里先暂时不说,说第三句,这里就是设置从color.xml里调用色彩,改变Activity背景颜色的。TextView这里就根据你的需要进行设计。

现在来说说AndroidManifest.xml里使Activity全屏的关键一句!

AndroidManifest.xml代码如下:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="landian.cihusport"
    android:versionCode="1"
    android:versionName="1.0" ><uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="19" /><application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@android:style/Theme.NoTitleBar.Fullscreen"><activity android:name="landian.cihusport.Index"><intent-filter><action android:name="android.intent.action.MAIN"></action><category android:name="android.intent.category.LAUNCHER"></category> </intent-filter>  </activity>   </application></manifest>


 

上面代码,在<application里的android:theme="@android:style/Theme.NoTitleBar.Fullscreen",是Activity全屏的关键语句。没有这个,无法全屏,切记。

<activity内为定义Activity启动的。

 

在看Index.java

package landian.cihusport;

import android.app.Activity;
import android.os.Bundle;

public class Index extends Activity {

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		// TODO Auto-generated method stub
		super.onCreate(savedInstanceState);
		setContentView(R.layout.index_layout);
	}

}


 

上面代码,大多自动生成,extends Activity为手动添加,onCreate方法为手动程序自动添加,添加方法为:在编辑区右建->source->Override/Implement Methods  在里面找到onCreate()方法,确定就成。setContentView(R.layout.index_layout);为手动添加,意思为启动index_layout这个Activity

 

至此,就做完了,可以启动虚拟机查看了。

下面在把color.xml的代码贴出。

<?xml version="1.0" encoding="utf-8"?><resources><color name="Green">#ffffff</color></resources>


 

 

作者:x123jing 发表于2014-8-7 16:01:59 原文链接
阅读:43 评论:0 查看评论

Java GC日志查看

$
0
0

 

 

Java GC类型

Java中的GC有哪几种类型?

 

参数

描述

UseSerialGC

虚拟机运行在Client模式的默认值,打开此开关参数后,

使用Serial+Serial Old收集器组合进行垃圾收集。

UseParNewGC

打开此开关参数后,使用ParNew+Serial Old收集器组合进行垃圾收集。

UseConcMarkSweepGC

打开此开关参数后,使用ParNew+CMS+Serial Old收集器组合进行垃圾收集。Serial Old作为CMS收集器出现Concurrent Mode Failure的备用垃圾收集器。

UseParallelGC

虚拟机运行在Server模式的默认值,打开此开关参数后,使用Parallel Scavenge+Serial Old收集器组合进行垃圾收集。

UseParallelOldGC

打开此开关参数后,使用Parallel Scavenge+Parallel Old收集器组合进行垃圾收集。

 

在Java程序启动完成后,通过jps观察进程来查询到当前运行的java进程,使用

jinfo –flag UseSerialGC 进程

 

的方式可以定位其使用的gc策略,因为这些参数都是boolean型的常量,如果使用该种gc策略会出现+号,否则-号。

 

使用-XX:+上述GC策略可以开启对应的GC策略。

 

 

GC日志查看

可以通过在java命令种加入参数来指定对应的gc类型,打印gc日志信息并输出至文件等策略。

 

GC的日志是以替换的方式(>)写入的,而不是追加(>>),如果下次写入到同一个文件中的话,以前的GC内容会被清空。

 

对应的参数列表

-XX:+PrintGC 输出GC日志
-XX:+PrintGCDetails 输出GC的详细日志
-XX:+PrintGCTimeStamps 输出GC的时间戳(以基准时间的形式)
-XX:+PrintGCDateStamps 输出GC的时间戳(以日期的形式,如 2013-05-04T21:53:59.234+0800)
-XX:+PrintHeapAtGC 在进行GC的前后打印出堆的信息
-Xloggc:../logs/gc.log 日志文件的输出路径

 

 

这里使用如下的参数来进行日志的打印:

-XX:+PrintGCDateStamps -XX:+PrintGCDetails -Xloggc:./gclogs

  

对于新生代回收的一行日志,其基本内容如下:

2014-07-18T16:02:17.606+0800: 611.633: [GC 611.633: [DefNew: 843458K->2K(948864K), 0.0059180 secs] 2186589K->1343132K(3057292K), 0.0059490 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]

 

 

其含义大概如下:

2014-07-18T16:02:17.606+0800(当前时间戳): 611.633(时间戳): [GC(表示Young GC) 611.633: [DefNew(单线程Serial年轻代GC): 843458K(年轻代垃圾回收前的大小)->2K(年轻代回收后的大小)(948864K(年轻代总大小)), 0.0059180 secs(本次回收的时间)] 2186589K(整个堆回收前的大小)->1343132K(整个堆回收后的大小)(3057292K(堆总大小)), 0.0059490 secs(回收时间)] [Times: user=0.00(用户耗时) sys=0.00(系统耗时), real=0.00 secs(实际耗时)]

 

 

老年代回收的日志如下:

2014-07-18T16:19:16.794+0800: 1630.821: [GC 1630.821: [DefNew: 1005567K->111679K(1005568K), 0.9152360 secs]1631.736: [Tenured:
2573912K->1340650K(2574068K), 1.8511050 secs] 3122548K->1340650K(3579636K), [Perm : 17882K->17882K(21248K)], 2.7854350 secs] [Times: user=2.57 sys=0.22, real=2.79 secs]

 

 

gc日志中的最后貌似是系统运行完成前的快照:

Heap
 def new generation   total 1005568K, used 111158K [0x00000006fae00000, 0x000000073f110000, 0x0000000750350000)
  eden space 893888K,  12% used [0x00000006fae00000, 0x0000000701710e90, 0x00000007316f0000)
  from space 111680K,   3% used [0x0000000738400000, 0x000000073877c9b0, 0x000000073f110000)
  to   space 111680K,   0% used [0x00000007316f0000, 0x00000007316f0000, 0x0000000738400000)
 tenured generation   total 2234420K, used 1347671K [0x0000000750350000, 0x00000007d895d000, 0x00000007fae00000)
   the space 2234420K,  60% used [0x0000000750350000, 0x00000007a2765cb8, 0x00000007a2765e00, 0x00000007d895d000)
 compacting perm gen  total 21248K, used 17994K [0x00000007fae00000, 0x00000007fc2c0000, 0x0000000800000000)
   the space 21248K,  84% used [0x00000007fae00000, 0x00000007fbf92a50, 0x00000007fbf92c00, 0x00000007fc2c0000)
No shared spaces configured.

 

 

GC日志的离线分析

可以使用一些离线的工具来对GC日志进行分析,比如sun的gchisto( https://java.net/projects/gchisto),gcviewer( https://github.com/chewiebug/GCViewer),这些都是开源的工具,用户可以直接通过版本控制工具下载其源码,进行离线分析。

 

下面就已gcviewer为例,简要分析一下gc日志的离线分析,gcviewer源代码工程是maven结构的,可以直接用maven进行package,这里编译的是1.34版本,本版本的快照已经上传至附件中。

 

需要说明的是,gcviewer支持多种参数生成的gc日志,直接通过java –jar的方式运行,加载生成的gc日志即可:

 

 

 





已有 0人发表留言,猛击->> 这里<<-参与讨论


ITeye推荐



Redis的Java客户端Jedis的八种调用方式(事务、管道、分布式等)介绍

$
0
0

        redis是一个著名的key-value存储系统,而作为其官方推荐的java版客户端jedis也非常强大和稳定,支持事务、管道及有jedis自身实现的分布式。

        在这里对jedis关于事务、管道和分布式的调用方式做一个简单的介绍和对比:

一.普通同步方式

        最简单和基础的调用方式

@Test
public void test1Normal() {
    Jedis jedis = new Jedis("localhost");
    long start = System.currentTimeMillis();
    for (int i = 0; i < 100000; i++) {
        String result = jedis.set("n" + i, "n" + i);
    }
    long end = System.currentTimeMillis();
    System.out.println("Simple SET: " + ((end - start)/1000.0) + " seconds");
    jedis.disconnect();
}

        很简单吧,每次set之后都可以返回结果,标记是否成功。

 

二.事务方式(Transactions)

        redis的事务很简单,他主要目的是保障,一个client发起的事务中的命令可以连续的执行,而中间不会插入其他client的命令。

        看下面例子:

@Test
public void test2Trans() {
    Jedis jedis = new Jedis("localhost");
    long start = System.currentTimeMillis();
    Transaction tx = jedis.multi();
    for (int i = 0; i < 100000; i++) {
        tx.set("t" + i, "t" + i);
    }
    List<Object> results = tx.exec();
    long end = System.currentTimeMillis();
    System.out.println("Transaction SET: " + ((end - start)/1000.0) + " seconds");
    jedis.disconnect();
}

        我们调用jedis.watch(…)方法来监控key,如果调用后key值发生变化,则整个事务会执行失败。另外,事务中某个操作失败,并不会回滚其他操作。这一点需要注意。还有,我们可以使用discard()方法来取消事务。

 

三.管道(Pipelining)

        有时,我们需要采用异步方式,一次发送多个指令,不同步等待其返回结果。这样可以取得非常好的执行效率。这就是管道,调用方法如下:

@Test
public void test3Pipelined() {
    Jedis jedis = new Jedis("localhost");
    Pipeline pipeline = jedis.pipelined();
    long start = System.currentTimeMillis();
    for (int i = 0; i < 100000; i++) {
        pipeline.set("p" + i, "p" + i);
    }
    List<Object> results = pipeline.syncAndReturnAll();
    long end = System.currentTimeMillis();
    System.out.println("Pipelined SET: " + ((end - start)/1000.0) + " seconds");
    jedis.disconnect();
}

 

四.管道中调用事务

        就Jedis提供的方法而言,是可以做到在管道中使用事务,其代码如下:

@Test
public void test4combPipelineTrans() {
    jedis = new Jedis("localhost"); 
    long start = System.currentTimeMillis();
    Pipeline pipeline = jedis.pipelined();
    pipeline.multi();
    for (int i = 0; i < 100000; i++) {
        pipeline.set("" + i, "" + i);
    }
    pipeline.exec();
    List<Object> results = pipeline.syncAndReturnAll();
    long end = System.currentTimeMillis();
    System.out.println("Pipelined transaction: " + ((end - start)/1000.0) + " seconds");
    jedis.disconnect();
}

        但是经测试(见本文后续部分),发现其效率和单独使用事务差不多,甚至还略微差点。

 

五.分布式直连同步调用

@Test
public void test5shardNormal() {
    List<JedisShardInfo> shards = Arrays.asList(
            new JedisShardInfo("localhost",6379),
            new JedisShardInfo("localhost",6380));

    ShardedJedis sharding = new ShardedJedis(shards);

    long start = System.currentTimeMillis();
    for (int i = 0; i < 100000; i++) {
        String result = sharding.set("sn" + i, "n" + i);
    }
    long end = System.currentTimeMillis();
    System.out.println("Simple@Sharing SET: " + ((end - start)/1000.0) + " seconds");

    sharding.disconnect();
}

        这个是分布式直接连接,并且是同步调用,每步执行都返回执行结果。类似地,还有异步管道调用。

 

六.分布式直连异步调用

@Test
public void test6shardpipelined() {
    List<JedisShardInfo> shards = Arrays.asList(
            new JedisShardInfo("localhost",6379),
            new JedisShardInfo("localhost",6380));

    ShardedJedis sharding = new ShardedJedis(shards);

    ShardedJedisPipeline pipeline = sharding.pipelined();
    long start = System.currentTimeMillis();
    for (int i = 0; i < 100000; i++) {
        pipeline.set("sp" + i, "p" + i);
    }
    List<Object> results = pipeline.syncAndReturnAll();
    long end = System.currentTimeMillis();
    System.out.println("Pipelined@Sharing SET: " + ((end - start)/1000.0) + " seconds");

    sharding.disconnect();
}

 

七.分布式连接池同步调用

        如果,你的分布式调用代码是运行在线程中,那么上面两个直连调用方式就不合适了,因为直连方式是非线程安全的,这个时候,你就必须选择连接池调用。

@Test
public void test7shardSimplePool() {
    List<JedisShardInfo> shards = Arrays.asList(
            new JedisShardInfo("localhost",6379),
            new JedisShardInfo("localhost",6380));

    ShardedJedisPool pool = new ShardedJedisPool(new JedisPoolConfig(), shards);

    ShardedJedis one = pool.getResource();

    long start = System.currentTimeMillis();
    for (int i = 0; i < 100000; i++) {
        String result = one.set("spn" + i, "n" + i);
    }
    long end = System.currentTimeMillis();
    pool.returnResource(one);
    System.out.println("Simple@Pool SET: " + ((end - start)/1000.0) + " seconds");

    pool.destroy();
}

        上面是同步方式,当然还有异步方式。

 

八.分布式连接池异步调用

@Test
public void test8shardPipelinedPool() {
    List<JedisShardInfo> shards = Arrays.asList(
            new JedisShardInfo("localhost",6379),
            new JedisShardInfo("localhost",6380));

    ShardedJedisPool pool = new ShardedJedisPool(new JedisPoolConfig(), shards);

    ShardedJedis one = pool.getResource();

    ShardedJedisPipeline pipeline = one.pipelined();

    long start = System.currentTimeMillis();
    for (int i = 0; i < 100000; i++) {
        pipeline.set("sppn" + i, "n" + i);
    }
    List<Object> results = pipeline.syncAndReturnAll();
    long end = System.currentTimeMillis();
    pool.returnResource(one);
    System.out.println("Pipelined@Pool SET: " + ((end - start)/1000.0) + " seconds");
    pool.destroy();
}

 

九.需要注意的地方

        事务和管道都是异步模式。在事务和管道中不能同步查询结果。比如下面两个调用,都是不允许的:

Transaction tx = jedis.multi();
for (int i = 0; i < 100000; i++) {
    tx.set("t" + i, "t" + i);
}
System.out.println(tx.get("t1000").get());  //不允许

List<Object> results = tx.exec();
Pipeline pipeline = jedis.pipelined();
long start = System.currentTimeMillis();
for (int i = 0; i < 100000; i++) {
pipeline.set("p" + i, "p" + i);
}
System.out.println(pipeline.get("p1000").get()); //不允许

List<Object> results = pipeline.syncAndReturnAll();

        事务和管道都是异步的,个人感觉,在管道中再进行事务调用,没有必要,不如直接进行事务模式。

        分布式中,连接池的性能比直连的性能略好(见后续测试部分)。

        分布式调用中不支持事务。

        因为事务是在服务器端实现,而在分布式中,每批次的调用对象都可能访问不同的机器,所以,没法进行事务。

 

十.测试

        运行上面的代码,进行测试,其结果如下:

Simple SET: 5.227 seconds
Transaction SET: 0.5 seconds
Pipelined SET: 0.353 seconds
Pipelined transaction: 0.509 seconds
Simple@Sharing SET: 5.289 seconds
Pipelined@Sharing SET: 0.348 seconds
Simple@Pool SET: 5.039 seconds
Pipelined@Pool SET: 0.401 seconds

        另外,经测试分布式中用到的机器越多,调用会越慢。上面是2片,下面是5片:

Simple@Sharing SET: 5.494 seconds
Pipelined@Sharing SET: 0.51 seconds
Simple@Pool SET: 5.223 seconds
Pipelined@Pool SET: 0.518 seconds

        下面是10片:

Simple@Sharing SET: 5.9 seconds
Pipelined@Sharing SET: 0.794 seconds
Simple@Pool SET: 5.624 seconds
Pipelined@Pool SET: 0.762 seconds

        下面是100片:

Simple@Sharing SET: 14.055 seconds
Pipelined@Sharing SET: 8.185 seconds
Simple@Pool SET: 13.29 seconds
Pipelined@Pool SET: 7.767 seconds

        分布式中,连接池方式调用不但线程安全外,根据上面的测试数据,也可以看出连接池比直连的效率更好。

 

十一.完整的测试代码

package com.bijian.study;

import java.util.Arrays;
import java.util.List;

import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPoolConfig;
import redis.clients.jedis.JedisShardInfo;
import redis.clients.jedis.Pipeline;
import redis.clients.jedis.ShardedJedis;
import redis.clients.jedis.ShardedJedisPipeline;
import redis.clients.jedis.ShardedJedisPool;
import redis.clients.jedis.Transaction;

import org.junit.FixMethodOrder;
import org.junit.runners.MethodSorters;

@SuppressWarnings("unused")
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class TestJedis {

	private static Jedis jedis;
	private static ShardedJedis sharding;
	private static ShardedJedisPool pool;

	@BeforeClass
	public static void setUpBeforeClass() throws Exception {
		List<JedisShardInfo> shards = Arrays.asList(new JedisShardInfo("192.168.128.129", 6379), new JedisShardInfo("192.168.128.129",6379)); // 使用相同的ip:port,仅作测试

		jedis = new Jedis("192.168.128.129");
		sharding = new ShardedJedis(shards);

		pool = new ShardedJedisPool(new JedisPoolConfig(), shards);
	}

	@AfterClass
	public static void tearDownAfterClass() throws Exception {
		jedis.disconnect();
		sharding.disconnect();
		pool.destroy();
	}

	@Test
	public void test1Normal() {
		long start = System.currentTimeMillis();
		for (int i = 0; i < 100000; i++) {
			String result = jedis.set("n" + i, "n" + i);
		}
		long end = System.currentTimeMillis();
		System.out.println("Simple SET: " + ((end - start) / 1000.0)
				+ " seconds");
	}

	@Test
	public void test2Trans() {
		long start = System.currentTimeMillis();
		Transaction tx = jedis.multi();
		for (int i = 0; i < 100000; i++) {
			tx.set("t" + i, "t" + i);
		}
		// System.out.println(tx.get("t1000").get());

		List<Object> results = tx.exec();
		long end = System.currentTimeMillis();
		System.out.println("Transaction SET: " + ((end - start) / 1000.0)
				+ " seconds");
	}

	@Test
	public void test3Pipelined() {
		Pipeline pipeline = jedis.pipelined();
		long start = System.currentTimeMillis();
		for (int i = 0; i < 100000; i++) {
			pipeline.set("p" + i, "p" + i);
		}
		// System.out.println(pipeline.get("p1000").get());
		List<Object> results = pipeline.syncAndReturnAll();
		long end = System.currentTimeMillis();
		System.out.println("Pipelined SET: " + ((end - start) / 1000.0)
				+ " seconds");
	}

	@Test
	public void test4combPipelineTrans() {
		long start = System.currentTimeMillis();
		Pipeline pipeline = jedis.pipelined();
		pipeline.multi();
		for (int i = 0; i < 100000; i++) {
			pipeline.set("" + i, "" + i);
		}
		pipeline.exec();
		List<Object> results = pipeline.syncAndReturnAll();
		long end = System.currentTimeMillis();
		System.out.println("Pipelined transaction: " + ((end - start) / 1000.0)
				+ " seconds");
	}

	@Test
	public void test5shardNormal() {
		long start = System.currentTimeMillis();
		for (int i = 0; i < 100000; i++) {
			String result = sharding.set("sn" + i, "n" + i);
		}
		long end = System.currentTimeMillis();
		System.out.println("Simple@Sharing SET: " + ((end - start) / 1000.0)
				+ " seconds");
	}

	@Test
	public void test6shardpipelined() {
		ShardedJedisPipeline pipeline = sharding.pipelined();
		long start = System.currentTimeMillis();
		for (int i = 0; i < 100000; i++) {
			pipeline.set("sp" + i, "p" + i);
		}
		List<Object> results = pipeline.syncAndReturnAll();
		long end = System.currentTimeMillis();
		System.out.println("Pipelined@Sharing SET: " + ((end - start) / 1000.0)
				+ " seconds");
	}

	@Test
	public void test7shardSimplePool() {
		ShardedJedis one = pool.getResource();

		long start = System.currentTimeMillis();
		for (int i = 0; i < 100000; i++) {
			String result = one.set("spn" + i, "n" + i);
		}
		long end = System.currentTimeMillis();
		pool.returnResource(one);
		System.out.println("Simple@Pool SET: " + ((end - start) / 1000.0)
				+ " seconds");
	}

	@Test
	public void test8shardPipelinedPool() {
		ShardedJedis one = pool.getResource();

		ShardedJedisPipeline pipeline = one.pipelined();

		long start = System.currentTimeMillis();
		for (int i = 0; i < 100000; i++) {
			pipeline.set("sppn" + i, "n" + i);
		}
		List<Object> results = pipeline.syncAndReturnAll();
		long end = System.currentTimeMillis();
		pool.returnResource(one);
		System.out.println("Pipelined@Pool SET: " + ((end - start) / 1000.0)
				+ " seconds");
	}
}

运行结果:


Simple SET: 24.316 seconds
Transaction SET: 2.641 seconds
Pipelined SET: 1.016 seconds
Pipelined transaction: 1.484 seconds
Simple@Sharing SET: 29.287 seconds
Pipelined@Sharing SET: 1.953 seconds
Simple@Pool SET: 31.537 seconds
Pipelined@Pool SET: 1.156 seconds

直接查看redis数据库:

[root@localhost bin]# /usr/local/redis/bin/redis-cli
127.0.0.1:6379> dbsize
(integer) 800000
127.0.0.1:6379> 

 

PS:如上实例是基于jedis-2.1.0.jar、commons-pool-1.6.jar、junit-4.11.jar、hamcrest-core-1.3.jar运行的。

 

文章来源:http://www.blogways.net/blog/2013/06/02/jedis-demo.html





已有 0人发表留言,猛击->> 这里<<-参与讨论


ITeye推荐




js onkeypress与onkeydown 事件区别详细说明

$
0
0

本文将详细介绍js onkeypress与onkeydown 事件区别:一个放开一个没有放开,onkeydown先于onkeypress 发生,需要的朋友可以参考下:

onkeypress 和 onkeydown 是有区别,下面将讲解 onkeypress 与 onkeydown 事件的区别。 
onkeypress 事件在用户按下并放开任何字母数字键时发生。但是系统按钮(例如:箭头键、功能键)无法得到识别。 
onkeydown 事件在用户按下任何键盘键(包括系统按钮)时发生。 
具体区别: 
1. 一个放开一个没有放开,onkeydown 先于 onkeypress 发生。 
2.onkeypress 无法系统按钮。 
2.onkeydown 捕获的 keyCode 不区分字母大小,而 onkeypress 区分。 

onkeypress是在用户按下并放开任何字母数字键时发生。系统按钮(例如,箭头键和功能键)无法得到识别。 
onkeyup 是在用户放开任何先前按下的键盘键时发生。 
onkeydown 是在用户按下任何键盘键(包括系统按钮,如箭头键和功能键)时发生。 

onkeypress 
As of Microsoft® Internet Explorer 4.0, the onkeypress event fires and can be canceled for the following keys:

Letters: A - Z (uppercase and lowercase) 
Numerals: 0 - 9 
Symbols: ! @ # $ % ^ & * ( ) _ - + = < [ ] { } , . / ? \ | ' ` " ~ 
System: ESC, SPACEBAR, ENTER 

onkeydown 
As of Microsoft® Internet Explorer 4.0, the onkeydown event fires for the following keys: 

Editing: DELETE, INSERT 
Function: F1 - F12 
Letters: A - Z (uppercase and lowercase) 
Navigation: HOME, END, LEFT ARROW, RIGHT ARROW, UP ARROW, DOWN ARROW 
Numerals: 0 - 9 
Symbols: ! @ # $ % ^ & * ( ) _ - + = < [ ] { } , . / ? \ | ' ` " ~ 
System: ESC, SPACEBAR, SHIFT, TAB 

As of Internet Explorer 5, the event also fires for the following keys: 

Editing: BACKSPACE 
Navigation: PAGE UP, PAGE DOWN 
System: SHIFT+TAB 

As of Internet Explorer 5, this event can be canceled for the following keys and key combinations by specifying event.returnValue=false: 

Editing: BACKSPACE, DELETE 
Letters: A - Z (uppercase and lowercase) 
Navigation: PAGE UP, PAGE DOWN, END, HOME, LEFT ARROW, RIGHT ARROW, UP ARROW, DOWN ARROW 
Numerals: 0 - 9 
Symbols: ! @ # $ % ^ & * ( ) _ - + = < [ ] { } , . / ? \ | ' ` " ~ 
System: SPACEBAR, ESC, TAB, SHIFT+TAB 

You can cancel all keys that fire the onkeydown event in HTML Applications, including most accelerator keys, such as ALT+F4. 

In Internet Explorer 4.0, you cannot cancel the onkeydown event, but you can use the onkeypress event to cancel keyboard events. 

两个一起按,可以这样: 

if( window.event.shiftKey && event.keyCode==xx) 

function document_onpress() 
{ 

if(event.keyCode=='13') 
{ 
document.all.div_Line.style.pixelLeft=document.all.div_Line.style.pixelLeft+1; 
document.all.div_Q.style.pixelLeft=document.all.div_Q.style.pixelLeft+1; 
document.all.div_T.style.pixelLeft=document.all.div_T.style.pixelLeft+1; 

} 

 



已有 0人发表留言,猛击->> 这里<<-参与讨论


ITeye推荐



Java远程通讯可选技术及原理

$
0
0
转自:淘宝毕玄博客
在分布式服务框架中,一个最基础的问题就是远程服务是怎么通讯的,在Java领域中有很多可实现远程通讯的技术,例如:RMI、MINA、ESB、Burlap、Hessian、SOAP、EJB和JMS等,这些名词之间到底是些什么关系呢,它们背后到底是基于什么原理实现的呢,了解这些是实现分布式服务框架的基础知识,而如果在性能上有高的要求的话,那深入了解这些技术背后的机制就是必须的了,在这篇blog中我们将来一探究竟,抛砖引玉,欢迎大家提供更多的实现远程通讯的技术和原理的介绍。

基本原理
要实现网络机器间的通讯,首先得来看看计算机系统网络通信的基本原理,在底层层面去看,网络通信需要做的就是将流从一台计算机传输到另外一台计算机,基于传输协议和网络IO来实现,其中传输协议比较出名的有http、tcp、udp等等,http、tcp、udp都是在为某类应用场景而定义出的传输协议,网络IO,主要有bio、nio、aio三种方式,所有的分布式应用通讯都基于这个原理而实现,只是为了应用的易用,各种语言通常都会提供一些更为贴近应用易用的应用层协议。

应用级协议
远程服务通讯,需要达到的目标是在一台计算机发起请求,另外一台机器在接收到请求后进行相应的处理并将结果返回给请求端,这其中又会有诸如one way request、同步请求、异步请求等等请求方式,按照网络通信原理,需要实现这个需要做的就是将请求转换成流,通过传输协议传输至远端,远端计算机在接收到请求的流后进行处理,处理完毕后将结果转化为流,并通过传输协议返回给调用端。
原理是这样的,但为了应用的方便,业界推出了很多基于此原理之上的应用级的协议,使得大家可以不用去直接操作这么底层的东西,通常应用级的远程通信协议会提供:
1、为了避免直接做流操作这么麻烦,提供一种更加易用或贴合语言的标准传输格式;
2、网络通信机制的实现,就是替你完成了将传输格式转化为流,通过某种传输协议传输至远端计算机,远端计算机在接收到流后转化为传输格式,并进行存储或以某种方式通知远端计算机。
所以在学习应用级的远程通信协议时,我们可以带着这几个问题进行学习:
1、传输的标准格式是什么?
2、怎么样将请求转化为传输的流?
3、怎么接收和处理流?
4、传输协议是?
不过应用级的远程通信协议并不会在传输协议上做什么多大的改进,主要是在流操作方面,让应用层生成流和处理流的这个过程更加的贴合所使用的语言或标准,至于传输协议则通常都是可选的,在java领域中知名的有:RMI、XML-RPC、Binary-RPC、SOAP、CORBA、JMS,来具体的看看这些远程通信的应用级协议:

RMI
RMI是个典型的为java定制的远程通信协议,我们都知道,在single vm中,我们可以通过直接调用java object instance来实现通信,那么在远程通信时,如果也能按照这种方式当然是最好了,这种远程通信的机制成为RPC(Remote Procedure Call),RMI正是朝着这个目标而诞生的。
来看下基于RMI的一次完整的远程通信过程的原理:
1、客户端发起请求,请求转交至RMI客户端的stub类;
2、stub类将请求的接口、方法、参数等信息进行序列化;
3、基于tcp/ip将序列化后的流传输至服务器端;
4、服务器端接收到流后转发至相应的skelton类;
5、skelton类将请求的信息反序列化后调用实际的处理类;
6、处理类处理完毕后将结果返回给skelton类;
7、Skelton类将结果序列化,通过tcp/ip将流传送给客户端的stub;
8、stub在接收到流后反序列化,将反序列化后的Java Object返回给调用者。
来看jboss-remoting对于此过程的一个更好的图示:


根据原理来回答下之前学习应用级协议带着的几个问题:
1、传输的标准格式是什么?
      是Java ObjectStream。
2、怎么样将请求转化为传输的流?
      基于Java串行化机制将请求的java object信息转化为流。
3、怎么接收和处理流?
      根据采用的协议启动相应的监听端口,当有流进入后基于Java串行化机制将流进行反序列化,并根据RMI协议获取到相应的处理对象信息,进行调用并处理,处理完毕后的结果同样基于java串行化机制进行返回。
4、传输协议是?
      tcp/ip。

XML-RPC
XML-RPC也是一种和RMI类似的远程调用的协议,它和RMI的不同之处在于它以标准的xml格式来定义请求的信息(请求的对象、方法、参数等),这样的好处是什么呢,就是在跨语言通讯的时候也可以使用。
来看下XML-RPC协议的一次远程通信过程:
1、客户端发起请求,按照XML-RPC协议将请求信息进行填充;
2、填充完毕后将xml转化为流,通过传输协议进行传输;
3、接收到在接收到流后转换为xml,按照XML-RPC协议获取请求的信息并进行处理;
4、处理完毕后将结果按照XML-RPC协议写入xml中并返回。
图示以上过程:

同样来回答问题:
1、传输的标准格式是?
      标准格式的XML。
2、怎么样将请求转化为传输的流?
      将XML转化为流。
3、怎么接收和处理流?
      通过监听的端口获取到请求的流,转化为XML,并根据协议获取请求的信息,进行处理并将结果写入XML中返回。
4、传输协议是?
      Http。

Binary-RPC
Binary-RPC看名字就知道和XML-RPC是差不多的了,不同之处仅在于传输的标准格式由XML转为了二进制的格式。
同样来回答问题:
1、传输的标准格式是?
      标准格式的二进制文件。
2、怎么样将请求转化为传输的流?
      将二进制格式文件转化为流。
3、怎么接收和处理流?
      通过监听的端口获取到请求的流,转化为二进制文件,根据协议获取请求的信息,进行处理并将结果写入XML中返回。
4、传输协议是?
      Http。

SOAP
SOAP原意为Simple Object Access Protocol,是一个用于分布式环境的、轻量级的、基于XML进行信息交换的通信协议,可以认为SOAP是XML RPC的高级版,两者的原理完全相同,都是http+XML,不同的仅在于两者定义的XML规范不同,SOAP也是Webservice采用的服务调用协议标准,因此在此就不多加阐述了。

CORBA
Common Object Request Broker Architecture(公用对象请求代理[调度]程序体系结构),是一组用来定义“分布式对象系统”的标准,由OMG(Object Menagement Group)作为发起和标准制定单位。CORBA的目的是定义一套协议,符合这个协议的对象可以互相交互,不论它们是用什么样的语言写的,不论它们运行于什么样的机器和操作系统。
CORBA在我看来是个类似于SOA的体系架构,涵盖可选的远程通信协议,但其本身不能列入通信协议这里来讲,而且CORBA基本淘汰,再加上对CORBA也不怎么懂,在此就不进行阐述了。

JMS
JMS呢,是实现java领域远程通信的一种手段和方法,基于JMS实现远程通信时和RPC是不同的,虽然可以做到RPC的效果,但因为不是从协议级别定义的,因此我们不认为JMS是个RPC协议,但它确实是个远程通信协议,在其他的语言体系中也存在着类似JMS的东西,可以统一的将这类机制称为消息机制,而消息机制呢,通常是高并发、分布式领域推荐的一种通信机制,这里的主要一个问题是容错(详细见ErLang论文)。
来看JMS中的一次远程通信的过程:
1、客户端将请求转化为符合JMS规定的Message;
2、通过JMS API将Message放入JMS Queue或Topic中;
3、如为JMS Queue,则发送中相应的目标Queue中,如为Topic,则发送给订阅了此Topic的JMS Queue。
4、处理端则通过轮训JMS Queue,来获取消息,接收到消息后根据JMS协议来解析Message并处理。
回答问题:
1、传输的标准格式是?
      JMS规定的Message。
2、怎么样将请求转化为传输的流?
      将参数信息放入Message中即可。
3、怎么接收和处理流?
      轮训JMS Queue来接收Message,接收到后进行处理,处理完毕后仍然是以Message的方式放入Queue中发送或Multicast。
4、传输协议是?
      不限。
基于JMS也是常用的实现远程异步调用的方法之一。

可选实现技术
当然,在上面的原理中并没有介绍到所有的java领域可选的远程通信协议了,例如还有EJB采用的ORMI、Spring自己定义的一个简单的Http Invoker等等。
看完原理后我们再来看看目前java领域可用于实现远程通讯的框架或library,知名的有:JBoss-Remoting、Spring-Remoting、Hessian、Burlap、XFire(Axis)、ActiveMQ、Mina、Mule、EJB3等等,来对每种做个简单的介绍和评价,其实呢,要做分布式服务框架,这些东西都是要有非常深刻的了解的,因为分布式服务框架其实是包含了解决分布式领域以及应用层面领域两方面问题的。
当然,你也可以自己根据远程网络通信原理(transport protocol+Net IO)去实现自己的通讯框架或library。
那么在了解这些远程通讯的框架或library时,会带着什么问题去学习呢?
1、是基于什么协议实现的?
2、怎么发起请求?
3、怎么将请求转化为符合协议的格式的?
4、使用什么传输协议传输?
5、响应端基于什么机制来接收请求?
6、怎么将流还原为传输格式的?
7、处理完毕后怎么回应?

JBoss-Remoting
Jboss-remoting是由jboss编写的一个java领域的远程通讯框架,基于此框架,可以很简单的实现基于多种传输协议的java对象的RPC。
直接来回答问题:
1、是基于什么协议实现的?
      JBoss-Remoting是个通讯框架,因此它支持多种协议方式的通信,例如tcp/ip+io方式、rmi方式、http+io方式等。
2、怎么发起请求?
      在JBoss-Remoting中,只需将需要发起的请求参数对象传入jboss-remoting的InvocationRequest对象即可,也可根据协议基于InvocationRequest封装符合需求的InvocationRequest对象。
3、怎么将请求转化为符合协议的格式的?
      JBoss-Remoting基于Java串行化机制或JBoss自己的串行化实现来将请求转化为对象字节流。
4、使用什么传输协议传输?
      支持多种传输协议,例如tcp/ip、http等。
5、响应端基于什么机制来接收请求?
      响应端只需将自己的处理对象注册到JBoss-Remoting提供的server端的Connector对象中即可。
6、怎么将流还原为传输格式的?
      JBoss-Remoting基于java串行化机制或jboss自己的串行化实现来将请求信息还原为java对象。
7、处理完毕后怎么回应?
      处理完毕后将结果对象直接返回即可,jboss-remoting会将此对象按照协议进行序列化,返回至调用端。
另外,jboss-remoting支持多种通信方式,例如同步/异步/单向通信等。

Spring-Remoting
Spring-remoting是Spring提供java领域的远程通讯框架,基于此框架,同样也可以很简单的将普通的spring bean以某种远程协议的方式来发布,同样也可以配置spring bean为远程调用的bean。
1、是基于什么协议实现的?
      和JBoss-Remoting一样,作为一个远程通讯的框架,Spring通过集成多种远程通讯的library,从而实现了对多种协议的支持,例如rmi、http+io、xml-rpc、binary-rpc等。
2、怎么发起请求?
      在Spring中,由于其对于远程调用的bean采用的是proxy实现,发起请求完全是通过服务接口调用的方式。
3、怎么将请求转化为符合协议的格式的?
      Spring按照协议方式将请求的对象信息转化为流,例如Spring Http Invoker是基于Spring自己定义的一个协议来实现的,传输协议上采用的为http,请求信息是基于java串行化机制转化为流进行传输。
4、使用什么传输协议传输?
      支持多种传输协议,例如rmi、http等等。
5、响应端基于什么机制来接收请求?
      响应端遵循协议方式来接收请求,对于使用者而言,则只需通过spring的配置方式将普通的spring bean配置为响应端或者说提供服务端。
6、怎么将流还原为传输格式的?
      按照协议方式来进行还原。
7、处理完毕后怎么回应?
      处理完毕后直接返回即可,spring-remoting将根据协议方式来做相应的序列化。

Hessian
Hessian是由caucho提供的一个基于binary-RPC实现的远程通讯library。
1、是基于什么协议实现的?
      基于Binary-RPC协议实现。
2、怎么发起请求?
      需通过Hessian本身提供的API来发起请求。
3、怎么将请求转化为符合协议的格式的?
      Hessian通过其自定义的串行化机制将请求信息进行序列化,产生二进制流。
4、使用什么传输协议传输?
      Hessian基于Http协议进行传输。
5、响应端基于什么机制来接收请求?
      响应端根据Hessian提供的API来接收请求。
6、怎么将流还原为传输格式的?
      Hessian根据其私有的串行化机制来将请求信息进行反序列化,传递给使用者时已是相应的请求信息对象了。
7、处理完毕后怎么回应?
      处理完毕后直接返回,hessian将结果对象进行序列化,传输至调用端。

Burlap
Burlap也是有caucho提供,它和hessian的不同在于,它是基于XML-RPC协议的。
1、是基于什么协议实现的?
      基于XML-RPC协议实现。
2、怎么发起请求?
      根据Burlap提供的API。
3、怎么将请求转化为符合协议的格式的?
      将请求信息转化为符合协议的XML格式,转化为流进行传输。
4、使用什么传输协议传输?
      Http协议。
5、响应端基于什么机制来接收请求?
      监听Http请求。
6、怎么将流还原为传输格式的?
      根据XML-RPC协议进行还原。
7、处理完毕后怎么回应?
      返回结果写入XML中,由Burlap返回至调用端。

XFire、Axis
XFire、Axis是Webservice的实现框架,WebService可算是一个完整的SOA架构实现标准了,因此采用XFire、Axis这些也就意味着是采用webservice方式了。
1、是基于什么协议实现的?
      基于SOAP协议。
2、怎么发起请求?
      获取到远端service的proxy后直接调用。
3、怎么将请求转化为符合协议的格式的?
      将请求信息转化为遵循SOAP协议的XML格式,由框架转化为流进行传输。
4、使用什么传输协议传输?
      Http协议。
5、响应端基于什么机制来接收请求?
      监听Http请求。
6、怎么将流还原为传输格式的?
      根据SOAP协议进行还原。
7、处理完毕后怎么回应?
      返回结果写入XML中,由框架返回至调用端。

ActiveMQ
ActiveMQ是JMS的实现,基于JMS这类消息机制实现远程通讯是一种不错的选择,毕竟消息机制本身的功能使得基于它可以很容易的去实现同步/异步/单向调用等,而且消息机制从容错角度上来说也是个不错的选择,这是Erlang能够做到容错的重要基础。
1、是基于什么协议实现的?
      基于JMS协议。
2、怎么发起请求?
      遵循JMS API发起请求。
3、怎么将请求转化为符合协议的格式的?
      不太清楚,猜想应该是二进制流。
4、使用什么传输协议传输?
      支持多种传输协议,例如tcp/ip、udp、http等等。
5、响应端基于什么机制来接收请求?
      监听符合协议的端口。
6、怎么将流还原为传输格式的?
      同问题3。
7、处理完毕后怎么回应?
      遵循JMS API生成消息,并写入JMS Queue中。
基于JMS此类机制实现远程通讯的例子有Spring-Intergration、Mule、Lingo等等。

Mina
Mina是Apache提供的通讯框架,在之前一直没有提到网络IO这块,之前提及的框架或library基本都是基于BIO的,而Mina是采用NIO的,NIO在并发量增长时对比BIO而言会有明显的性能提升,而java性能的提升,与其NIO这块与OS的紧密结合是有不小的关系的。
1、是基于什么协议实现的?
      可选的传输协议+NIO。
2、怎么发起请求?
      通过Mina提供的Client API。
3、怎么将请求转化为符合协议的格式的?
      Mina遵循java串行化机制对请求对象进行序列化。
4、使用什么传输协议传输?
      支持多种传输协议,例如tcp/ip、http等等。
5、响应端基于什么机制来接收请求?
      以NIO的方式监听协议端口。
6、怎么将流还原为传输格式的?
      遵循java串行化机制对请求对象进行反序列化。
7、处理完毕后怎么回应?
      遵循Mina API进行返回。
MINA是NIO方式的,因此支持异步调用是毫无悬念的。

EJB
EJB最突出的在于其分布式,EJB采用的是ORMI协议,和RMI协议是差不多的,但EJB在分布式通讯的安全控制、transport pool、smart proxy等方面的突出使得其在分布式领域是不可忽视的力量。
1、是基于什么协议实现的?
      基于ORMI协议。
2、怎么发起请求?
      EJB调用。
3、怎么将请求转化为符合协议的格式的?
      遵循java串行化机制对请求对象进行序列化。
4、使用什么传输协议传输?
      tcp/ip。
5、响应端基于什么机制来接收请求?
      监听协议端口。
6、怎么将流还原为传输格式的?
      遵循java串行化机制对请求对象进行反序列化。
7、处理完毕后怎么回应?
      直接返回处理对象即可。

在之前的分布式服务框架系列的文章中对于jndi有误导的嫌疑,在这篇blog中也顺带的提下jndi的机制,由于JNDI取决于具体的实现,在这里只能是讲解下jboss的jndi的实现了。
在将对象实例绑定到jboss jnp server后,当远程端采用context.lookup()方式获取远程对象实例并开始调用时,jboss jndi的实现方法是从jnp server上获取对象实例,将其序列化回本地,然后在本地进行反序列化,之后在本地进行类调用。
通过这个机制,就可以知道了,本地其实是必须有绑定到jboss上的对象实例的class的,否则反序列化的时候肯定就失败了,而远程通讯需要做到的是在远程执行某动作,并获取到相应的结果,可见纯粹基于JNDI是无法实现远程通讯的。
但JNDI也是实现分布式服务框架一个很关键的技术点,因为可以通过它来实现透明化的远端和本地调用,就像ejb,另外它也是个很好的隐藏实际部署机制(就像datasource)等的方案。

总结
由上一系列的分析可知,在远程通讯领域中,涉及的知识点还是相当的多的,例如有:通信协议或远程调用协议(tcp/http/udp/rmi/xml-rpc etc.)、消息机制、网络IO(BIO/NIO/AIO)、MultiThread、本地调用与远程调用的透明化方案(涉及java classloader、Dynamic Proxy、Unit Test etc.)、异步与同步调用、网络通信处理机制(自动重连、广播、异常、池处理等等)、Java Serialization (各种协议的私有序列化机制等)、各种框架的实现原理(传输格式、如何将传输格式转化为流的、如何将请求信息转化为传输格式的、如何接收流的、如何将流还原为传输格式的等等),要精通其中的哪些东西,得根据实际需求来决定了,只有在了解了原理的情况下才能很容易的做出选择,甚至可以根据需求做私有的远程通讯协议,对于从事分布式服务平台或开发较大型的分布式应用的人而言,我觉得至少上面提及的知识点是需要比较了解的。

已有 0人发表留言,猛击->> 这里<<-参与讨论


ITeye推荐



mysql java hibernate类型对应

$
0
0
[html]  view plaincopy
 
  1. 类型名称 显示长度 数据库类型 JAVA类型 JDBC类型索引(int) 描述   
  2.    
  3. VARCHAR  L+N  VARCHAR  java.lang.String 12   
  4. CHAR N CHAR java.lang.String 1  字符型  
  5. BLOB L+N BLOB java.lang.byte[] -4  二进制型  
  6. TEXT 65535 VARCHAR java.lang.String -1 text文本型  
  7.   
  8. INTEGER 4 INTEGER UNSIGNED java.lang.Long 4  整型  
  9. TINYINT 3 TINYINT UNSIGNED java.lang.Integer -6  微整型   
  10. SMALLINT 5 SMALLINT UNSIGNED java.lang.Integer 5     
  11. MEDIUMINT 8 MEDIUMINT UNSIGNED java.lang.Integer 4    
  12. BIT 1 BIT java.lang.Boolean -7   
  13. BIGINT 20 BIGINT UNSIGNED java.math.BigInteger -5    
  14. FLOAT 4+8 FLOAT java.lang.Float 7   
  15. DOUBLE 22 DOUBLE java.lang.Double 8    
  16. DECIMAL 11 DECIMAL java.math.BigDecimal 3   
  17. BOOLEAN 1 同TINYINT   
  18.   
  19. ID 11 PK (INTEGER UNSIGNED) java.lang.Long 4 ?   
  20.   
  21. DATE 10 DATE java.sql.Date 91   
  22. TIME 8 TIME java.sql.Time 92    
  23. DATETIME 19 DATETIME java.sql.Timestamp 93    
  24. TIMESTAMP 19 TIMESTAMP java.sql.Timestamp 93    
  25. YEAR 4 YEAR java.sql.Date 91  
  26.   
  27.   
  28.    

 

 

1.常规Hibernate 映射

 

integer 或者 int

int 或者 java.lang.Integer

INTEGER

4 字节

long

long Long

BIGINT

8 字节

short

short Short

SMALLINT

2 字节

byte

byte Byte

TINYINT

1 字节

float

float Float

FLOAT

4 字节

double

double Double

DOUBLE

8 字节

big_decimal

java.math.BigDecimal

NUMERIC

NUMERIC(8,2)8 位

character

char Character String

CHAR(1)

定长字符

string

String

VARCHAR

变长字符串

boolean

boolean Boolean

BIT

布尔类型

yes_no

boolean Boolean

CHAR(1) (Y-N)

布尔类型

true_false

boolean Boolean

CHAR(1) (T-F)

布尔类型

 

2 、 Java 时间和日期类型的 Hibernate 映射

 

映射类型

Java 类型

标准 SQL 类型

描述

date

util.Date 或者 sql.Date

DATE

YYYY-MM-DD

time

Date Time

TIME

HH:MM:SS

timestamp

Date Timestamp

TIMESTAMP

YYYYMMDDHHMMSS

calendar

calendar

TIMESTAMP

YYYYMMDDHHMMSS

calendar_date

calendar

DATE

YYYY-MM-DD

 

3 、 Java 大对象类型的 Hibernate 映射类型

 

映射类型

Java 类型

标准 SQL 类型

MySQL 类型

Oracle 类型

binary

byte[]

VARBINARY( 或 BLOB)

BLOB

BLOB

text

String

CLOB

TEXT

CLOB

serializable

Serializable 接口任意实现类

VARBINARY( 或 BLOB)

BLOB

BLOB

clob

java.sql.Clob

CLOB

TEXT

CLOB

blob

java.sql.Blob

BLOB

BLOB

BLOB

 

在程序中通过 Hibernate 来保存 java.sql.Clob 或者 java.sql.Blob 实例时,必须包含两个步骤:

1.在一个数据库事务中先保存一个空的 Blob 或 Clob 实例。

2.接着锁定这条记录,更新上面保存的 Blob 或 Clob 实例,把二进制数据或文本数据写到 Blob 或 Clob 实例中



已有 0人发表留言,猛击->> 这里<<-参与讨论


ITeye推荐



ZeroMQ--使用jzmq进行编程

$
0
0

http://my.oschina.net/cloudcoder/blog/200989

 

一、环境搭建

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
wget http://download.zeromq.org/zeromq-2.1.7.tar.gz
tar -xzf zeromq-2.1.7.tar.gz
cd zeromq-2.1.7
./configure
make
sudo make install
 
git clone https://github.com/nathanmarz/jzmq.git
cd jzmq
./autogen.sh
./configure
make
sudo make install
 
如果没有安装libtool、libuuid-devel则需要先安装,否则安装失败
yum install libtool
yum install libuuid-devel

常见问题:

出现java.lang.UnsatisfiedLinkError: /usr/local/lib/libjzmq.so.0.0.0: libzmq.so.1: cannot open shared object file: No such file or directory异常 
原因是未找到zmq动态链接库。 
解决方法1:export LD_LIBRARY_PATH=/usr/local/lib 
解决方法2:编辑/etc/ld.so.conf文件,增加一行:/usr/local/lib。再执行sudo ldconfig命令 

Exception in thread "main" java.lang.UnsatisfiedLinkError: no jzmq in java.library.path 
未设置native library 
在eclipse设置native library为/usr/local/lib 
或在jvm增加参数 
-Djava.library.path=/usr/local/lib 
或在启动脚本中增加 
java -Djava.library.path=/usr/local/lib

二、使用jzmq进行编程

    1.创建maven项目,pom.xml的内容参见pom.xml

      注意:jzmq的版本不能太高,建议使用2.1.0,目前storm也是使用这个版本的jzmq-2.1.0.jar

      否则报: java.lang.UnsatisfiedLinkError: org.zeromq.ZMQ$Socket.nativeInit()V

    2.编写Publisher.java,Subscriber.java,参见源代码

    Publisher.java  

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
packagecom.catt.mqtest.pubsub;
 
 
importorg.slf4j.Logger;
importorg.slf4j.LoggerFactory;
importorg.zeromq.ZMQ;
importorg.zeromq.ZMQ.Context;
importorg.zeromq.ZMQ.Socket;
 
publicclassPublisher {
 
    // 等待10个订阅者
    privatestaticfinalintSUBSCRIBERS_EXPECTED = 10;
    // 定义一个全局的记录器,通过LoggerFactory获取
    privatefinalstaticLogger log = LoggerFactory.getLogger(Publisher.class);
 
    publicstaticvoidmain(String[] args) throwsInterruptedException{
        Context context = ZMQ.context(1);
        Socket publisher = context.socket(ZMQ.PUB);
        publisher.bind("tcp://*:5557");
        try{
            // zmq发送速度太快,在订阅者尚未与发布者建立联系时,已经开始了数据发布
            Thread.sleep(1000);
        } catch(InterruptedException e) {
            e.printStackTrace();
        }
 
        publisher.send("send start......".getBytes(), 0);
        for(inti = 0; i < 10; i++) {
            publisher.send(("Hello world "+i).getBytes(), ZMQ.NOBLOCK);
        }
        publisher.send("send end......".getBytes(), 0);
 
        publisher.close();
        context.term();
    }
}

Subscriber.java

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
packagecom.catt.mqtest.pubsub;
 
importorg.slf4j.Logger;
importorg.slf4j.LoggerFactory;
importorg.zeromq.ZMQ;
importorg.zeromq.ZMQ.Context;
importorg.zeromq.ZMQ.Socket;
 
publicclassSubscriber {
 
    // 定义一个全局的记录器,通过LoggerFactory获取
    privatefinalstaticLogger log = LoggerFactory.getLogger(Subscriber.class);
 
    publicstaticvoidmain(String[] args) {
        Context context = ZMQ.context(1);
        Socket subscriber = context.socket(ZMQ.SUB);
        subscriber.connect("tcp://192.168.230.128:5557");
        subscriber.subscribe("".getBytes());
        inttotal = 0;
        while(true) {
            byte[] stringValue = subscriber.recv(0);
            String string = newString(stringValue);
            if(string.equals("send end......")) {
                break;
            }
            total++;
            System.out.println("Received "+ total + " updates. :"+ string);
        }
 
        subscriber.close();
        context.term();
    }
}

pom.xml

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<projectxmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
 
    <groupId>com.catt</groupId>
    <artifactId>mqtest</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>
 
    <name>mqtest</name>
    <url>http://maven.apache.org</url>
 
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>
 
    <dependencies>
        <dependency>
            <groupId>org.zeromq</groupId>
            <artifactId>jzmq</artifactId>
            <version>2.1.0</version>
        </dependency>
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.1.1</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.10</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
</project>


已有 0人发表留言,猛击->> 这里<<-参与讨论


ITeye推荐



ZeroMQ(java)中监控Socket

$
0
0

基本上ZeroMQ(java)中基本的代码都算是过了一遍了吧,不过觉得它在日志这一块貌似基本没有做什么工作,也就是我们通过日志来知道ZeroMQ都发生了什么事情。。

而且由于ZeroMQ中将连接的建立和重连接都进行了隔离,用户不需要做什么事情来维护连接,当然这样做的好处是使程序员的编码工作变少了,但是当然也有不好的地方,那就是用户失去了对ZeroMQ整个运行阶段的控制。。

例如,当我们主动去连接一个远程地址,或者连接中断之后,没有日志告诉我们都这些事情发生了。。。当时对于一个消息通信系统来说,这些日志,或者说事件的监控都是至关重要的。

当然没有日志来记录这些内容,并不代表我们就无法知道当前运行情况都发生了什么事情,ZeroMQ中采用了另外一种方法来监控Socket的情况,不过这种方法比较恶心,需要建立额外的Socket来监控自己感兴趣的Socket。。。

这里先不说这些闲话了,来看看ZeroMQ中都定义了哪些监听事件:

    public static final int EVENT_CONNECTED = zmq.ZMQ.ZMQ_EVENT_CONNECTED;   //当主动建立连接建立成功之后的事件
    public static final int EVENT_DELAYED = zmq.ZMQ.ZMQ_EVENT_CONNECT_DELAYED;   //连接延迟
    public static final int EVENT_RETRIED = zmq.ZMQ.ZMQ_EVENT_CONNECT_RETRIED;    //尝试重新连接
    public static final int EVENT_CONNECT_FAILED = zmq.ZMQ.ZMQ_EVENT_CONNECT_FAILED;   //连接失败

    public static final int EVENT_LISTENING = zmq.ZMQ.ZMQ_EVENT_LISTENING;    //建立了监听
    public static final int EVENT_BIND_FAILED = zmq.ZMQ.ZMQ_EVENT_BIND_FAILED;  //bind失败

    public static final int EVENT_ACCEPTED = zmq.ZMQ.ZMQ_EVENT_ACCEPTED;   //接收到accept事件
    public static final int EVENT_ACCEPT_FAILED = zmq.ZMQ.ZMQ_EVENT_ACCEPT_FAILED;   //accept出错的事件

    public static final int EVENT_CLOSED = zmq.ZMQ.ZMQ_EVENT_CLOSED;   //关闭事件
    public static final int EVENT_CLOSE_FAILED = zmq.ZMQ.ZMQ_EVENT_CLOSE_FAILED;     //关闭失败
    public static final int EVENT_DISCONNECTED = zmq.ZMQ.ZMQ_EVENT_DISCONNECTED;   //连接断开

    public static final int EVENT_ALL = zmq.ZMQ.ZMQ_EVENT_ALL;   //所有的事件

上面是定义的所有可能发生的事件,具体每一种事件代表什么意思后面的注释都已经说明了,当然这里面我觉得最重要的事件有连接的断开,连接的建立,以及重连接等事件。。。

接下来我们来看看如何在ZeroMQ(java)中来监控这些事件吧,直接上代码了:

import org.zeromq.ZMQ;

import zmq.ZMQ.Event;

public class Request {
	public static void main (String args[]) {
		ZMQ.Context context = ZMQ.context(1);
		ZMQ.Socket req = context.socket(ZMQ.REQ);
		
		req.monitor("inproc://reqmoniter", ZMQ.EVENT_CONNECTED | ZMQ.EVENT_DISCONNECTED);  //这段代码会创建一个pair类型的socket,专门来接收当前socket发生的事件
		
		final ZMQ.Socket moniter = context.socket(ZMQ.PAIR);   //这里创建一个pair类型的socket,用于与上面建立的moniter建立连接
		moniter.connect("inproc://reqmoniter");  //连接当前socket的监听
		
		new Thread(new Runnable(){

			public void run() {
				// TODO Auto-generated method stub
				while (true) {
					Event event = Event.read(moniter.base());  //从当前moniter里面读取event
					System.out.println(event.event +  "  " + event.addr);
				}
			}
		}).start();
		req.connect("tcp://127.0.0.1:5000");
		while (true) {
			req.send("aaa");
			req.recv();
		}
	}
}

package monit;

import org.zeromq.ZMQ;

public class Response {
	public static void main(String args[]) {
		final ZMQ.Context context = ZMQ.context(1);
		

	
		ZMQ.Socket response = context.socket(ZMQ.REP);
		response.bind("tcp://*:5000");
		while (!Thread.currentThread().isInterrupted()) {
			response.recv();
			response.send("hello".getBytes());
			try {
				Thread.currentThread().sleep(100);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		response.close();
		context.term();
	}
}

这里代码用req/rep来举例子的,其实用起来还算是比较的简单,当连接建立之后,将会输出:

1  tcp://127.0.0.1:5000

1就是代表连接建立的事件,后面是建立连接的地址,

这个时候如果关闭response,那么将会输出如下:

512  tcp://127.0.0.1:5000

512代表的就是连接断开的事件。。。


嗯,至于说监控的源码是怎么实现的,这里就不细说了,其实还是非常的简单的,如果有兴趣可以自己去看看。。


到此ZeroMQ(java)的代码就算是读的差不多了,算是告一段落吧,接下来好好看看书。。。另外有想 再搞搞C/C++方面的东西。。。初步计划看看Redis的源码吧。。。。

作者:fjs_cloud 发表于2014-1-3 15:31:43 原文链接
阅读:74 评论:0 查看评论
Viewing all 15843 articles
Browse latest View live


<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>