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

Apache James搭建内网邮件服务器

$
0
0

前言

        大概之前两个礼拜的日子,讨论会介绍了关于了.net内网邮件服务器的搭建。所以自己也很有必要来尝试一把邮件服务器的搭建,这里选取的是james这个工具。

 

为什么要使用内网邮件服务器?

a.安全这里仅限个人观点。对于任何一个企业来说,必要安全保密是非常重要的。

b.不受internet的限制虽然说现在到处都是wifi,但是有一个能够自己来控制和使用的邮件服务器肯定是不错的选择。

什么是apache james?

a.一个支持多协议的企业级邮件服务器

b.开源、多平台

开源的项目意味着不存在版本的问题,减少了诸多在法律上的问题,也保证了对于平台的扩展性的保持;纯java的实现也就不会存在window和linux等系统不兼容的问题了。

 

最新下载地址

  1. Apache james 3.0测试版
  2. Apche james 2.3.2稳定版

 本次选用2.3.2.


配置步骤


1.环境配置


a.jdk


Jdk 1.7 ,当前最好的是配置好相关的环境变量,这样就不用去每次到文件内去配置相关的java_home和jre_home了。


b.james


将下载好的zip文件解压到你喜欢的目录下


1.启动

在bin文件下找到run.bat文件

显示成功,如图


 


2.使用telnet工具远程到4555端口,并添加用户

.telnet localhost 4555;

.输入登录用户及密码默认为root root

.adduser cfl cfl(添加用户用户名 密码)

.adduser cfltest cfltest

添加成功,如图




2.xml配置


在文件james-2.3.1\apps\james\SAR-INF下的 config.xml 文件,需要注意的时。该文件是在启动之后才出现的。

a.邮件服务器名的配置


<span style="font-size:18px;"><postmaster>Postmaster@localhost</postmaster>   
如<postmaster>Postmaster@chenfanglin.com</postmaster>  <servernames autodetect="true" autodetectIP="true">   <servername>localhost</servername>   </servernames>  </span>

 

 b.注释mailet 


<span style="font-size:18px;"><!--mailet match="RemoteAddrNotInNetwork=127.0.0.1" class="ToProcessor">   <processor> relay-denied </processor>   <notice>550 - Requested action not taken: relaying denied</notice>   </mailet--!> </span>


maillet类似于servlet会对邮件做一些简单的处理,这里我们不去实现这个接口


c.打开身份验证authRequired


<span style="font-size:18px;"><authRequired>true</authRequired></span>


之上配置两个客户端 cfl@chenfanglin.comcfltest@chenfanglin.com .我在自己的foxmail做了一个简单的测试



配置账户


 



效果

1.发送邮件

 



2.接收邮件





3.部分问题

 

      在执行telnet时有时会出现telnet不是内部命令,这是因为telnet服务器没有开启,在window功能项内启用该功能即可

如图





总结


总的来说,配置过程不是很困难。当然这只是最为基础的邮件搭建,为了也是去了解这样一个比较好的开源工具。我想扩展和更多的实现才是最令人期待。

 

作者:chenfanglincfl 发表于2014-8-20 16:52:17 原文链接
阅读:70 评论:0 查看评论

Web 前端测试

$
0
0

Web网站测试流程和方法(转载)

1测试流程与方法
1.1测试流程
进行正式测试之前,应先确定如何开展测试,不可盲目的测试。一般网站的测试,应按以下流程来进行:
1)使用HTML Link Validator将网站中的错误链接找出来;
2)测试的顺序为:自顶向下、从左到右;
3)查看页面title是否正确。(不只首页,所有页面都要查看);
4)LOGO图片是否正确显示;
5)LOGO下的一级栏目、二级栏目的链接是否正确;
6)首页登录、注册的功能是否实现;
7)首页左侧栏目下的文章标题、图片等链接是否正确;
8)首页中间栏目下的文章标题、图片等链接是否正确;
9)首页右侧栏目下的文章标题、图片等链接是否正确;
10)首页最下方的【友情链接】、【关于我们】等链接是否正确;
11)进入一级栏目或二级栏目的列表页。查看左侧栏目名称,右侧文章列表是否正确;
12)列表页的分页功能是否实现、样式是否统一;
13)查看文章详细页面的内容是否存在乱码、页面样式是否统一;
14)站内搜索(各个页面都要查看)功能是否实现;
15)前后台交互的部分,数据传递是否正确;
16) 默认按钮要支持Enter及选操作,即按Enter后自动执行默认按钮对应操作。
1.2 UI测试
UI测试包括的内容有如下几方面:
1)各个页面的样式风格是否统一;
2)各个页面的大小是否一致;同样的LOGO图片在各个页面中显示是否大小一致;页面及图片是否居中显示;
3)各个页面的title是否正确;
4)栏目名称、文章内容等处的文字是否正确,有无错别字或乱码;同一级别的字体、大小、颜色是否统一;
5)提示、警告或错误说明应清楚易懂,用词准确,摒弃模棱两可的字眼;
6)切换窗口大小,将窗口缩小后,页面是否按比例缩小或出现滚动条;各个页面缩小的风格是否一致,文字是否窜行;
7)父窗体或主窗体的中心位置应该在对角线焦点附近;子窗体位置应该在主窗体的左上角或正中;多个子窗体弹出时应该依次向右下方偏移,以显示出窗体标题为宜;
8)按钮大小基本相近,忌用太长的名称,免得占用过多的界面位置;避免空旷的界面上放置很大的按钮;按钮的样式风格要统一;按钮之间的间距要一致;
9)页面颜色是否统一;前景与背景色搭配合理协调,反差不宜太大,最好少用深色或刺目的颜色;
10)若有滚动信息或图片,将鼠标放置其上,查看滚动信息或图片是否停止;
11)导航处是否按相应的栏目级别显示;导航文字是否在同一行显示;
12)所有的图片是否都被正确装载,在不同的浏览器、分辨率下图片是否能正确显示(包括位置、大小);
13)文章列表页,左侧的栏目是否与一级、二级栏目的名称、顺序一致;
14) 调整分辨率验证页面格式是否错位现象;
15)鼠标移动到Flash焦点上特效是否实现,移出焦点特效是否消失;
16) 文字颜色与页面配色协调,不使用与背景色相近的颜色。
17) 每个非首页静态页面含图片字节不超过300K,全尺寸banner第一个场景控制在200k以内二个场景在300K,三个场景在400K以此类推
18) 同一界面上的控件数最好不要超过10个,多于10个时可以考虑使用分页界面显示。
19) 超过一屏的内容,在底部应有go top按钮
20) 超过三屏的内容,应在头部设提纲,直接链接到文内锚点
21) 首页,各栏目一级页面之间互链,各栏目一级和本栏目二级页面之间互链
22) 导航的文字要简明扼要,字数限制在一行以内
23) 报表显示时应考虑数据显示宽度的自适应或自动换行。
24) 所有有数据展现的界面(如统计、查询、编辑录入、打印预览、打印等),必须使测试数据的记录数超过一屏/一页,以验证满屏/页时其窗体是否有横向、纵向滚动条或换页打(L)印,界面显示是否正常;
25) 如有多个系统展现同一数据源时,应保证其一致性;
26) 对于报表中的所有字段值都应该有明确的定义,对于无意义的字段值,不应该显示空,应显示“--”或“/”,表示该字段值无意义。
27) 对统计的数据应按用户习惯进行分类、排序。
28) 界面内容更新后系统应提供刷新功能。
29) 用户在退出系统后重新登陆时应考虑是否需要自动返回到上次退出系统时的界面;
30)在多个业务功能组成的一个业务流程中,如果各个功能之间的执行顺序有一定的制约条件,应通过界面提示用户。
31)用户提示信息应具有一定的指导性,在应用程序正在进行关键业务的处理时,应考虑在前台界面提示用户应用程序正在进行的处理,以及相应的处理过程,在处理结束后再提示用户处理完毕。
32)在某些数据输入界面,如果要求输入的数据符合某项规则,应在输入界面提供相应的规则描述;当输入数据不符合规则时应提示用户是否继续。
33)在对任何配置信息修改后,都应该在用户退出该界面时提示用户保存(如果用户没有主动保存的情况下);
34)在对某些查询功能进行测试时,应考虑查询条件的设置的合理性以及查询结果的互补性。如某些后台处理时间不应该作为查询条件。
35)界面测试时,应考虑某一界面上按钮先后使用的顺序问题,以免用户对此产生迷惑。例如只能在查询成功后显示执行按钮。
36)界面测试时,应验证窗口与窗口之间、字段与字段之间的浏览顺序是否正确;
37)在某些对数据进行处理的操作界面,应考虑用户可能对数据进行处理的频繁程度和工作量,考虑是否可以进行批量操作。
38)界面测试时应验证所有窗体中的对象状态是否正常,是否符合相关的业务规则需要。
49)应验证各种对象访问方法(Tab 健、鼠标移动和快捷键)是否可正常使用,并且在一个激活界面中快捷键无重复;
40)界面测试不光要考虑合理的键盘输入,还应考虑是否可以通过鼠标拷贝粘贴输入。
41)对于统计查询功能的查询结果应验证其是否只能通过界面上的查询或刷新按键人工触发,应避免其他形式的触发。
42)对界面上的任何对象进行拖拉,然后进行查询、打印,应保证查询打印结果不变;
43)确保数据精度显示的统一:如单价0元,应显示为0.00元;
44)确保时间及日期显示格式的统一;
45)确保相同含义属性/字段名的统一;
46)对所有可能产生的提示信息界面内容和位置进行验证,确保所有的提示信息界面应居中。

1.3链接测试
链接测试主要分为以下几个方面:
1)页面是否有无法连接的内容;图片是否能正确显示,有无冗余图片,代码是否规范,页面是否存死链接(可以用HTML Link Validator工具查找);
2)图片上是否有无用的链接;点击图片上的链接是否跳转到正确的页面;
3)首页点击LOGO下的一级栏目或二级栏目名称,是否可进入相应的栏目;
4)点击首页或列表页的文章标题的链接,是否可进入相应的文章的详细页面;
5)点击首页栏目名称后的【更多】链接,是否正确跳转到相应页面;
6)文章列表页,左侧的栏目的链接,是否可正确跳转到相应的栏目页面;
7)导航链接的页面是否正确;是否可按栏目级别跳转到相应的页面;
(例:【首页->服务与支持->客服中心】,分别点击“首页”、“服务与支持”、“客服中心”,查看是否可跳转到相应页面;)
8) 新闻、信息类内容通常用新开窗口方式打开。
9) 顶部导航、底部导航通常采取在本页打开。
1.4搜索测试
搜索测试主要分为以下几个方面:
1)搜索按钮功能是否实现;
2)输入网站中存在的信息,能否正确搜索出结果;
3)输入键盘中所有特殊字符,是否报错;特别关注:_ ? ’ . • \  / -- ;特殊字符
4)系统是否支持键盘回车键、Tab键;
5)搜索出的结果页面是否与其他页面风格一致;
6)在输入域输入空格,点击搜索系统是否报错;
7)本站内搜索输入域中不输入任何内容,是否搜索出的是全部信息或者给予提示信息;
8)精确查询还是模糊查询,如果是模糊查询输入:中%国。查询结果是不是都包含中国两个字的信息;
9)焦点放置搜索框中,搜索框内容是否被清空;
10)搜索输入域是否实现回车键监听事件;
1.5表单测试
表单测试主要分为以下几个方面:
1)注册、登录功能是否实现;
2)提交、清空按钮功能是否实现;
3)修改表单与注册页面数据项是否相同,修改表单是否对重名做验证;
4)提交的数据是否能正确保存到后台数据库中(后台数据库中的数据应与前台录入内容完全一致,数据不会丢失或被改变);
5)表单提交,删除,修改后是否有提示信息;提示、警告、或错误说明应该清楚、明了、恰当。
6)浏览器的前进、后退、刷新按钮,是否会造成数据重现或页面报错;
7)提交表单是否支持回车键和Tab键;Tab键的顺序与控件排列顺序要一致,目前流行总体从上倒下,同时行间从左到右的方式
8)下拉列表功能是否实现和数据是否完整(例如:省份和市区下拉列表数据是否互动);
1.6输入域测试
输入域测试主要分为以下几个方面:
1)对于手机、邮箱、证件号等的输入是否有长度及类型的控制;
2)输入中文、英文、数字、特殊字符(特别注意单引号和反斜杠)及这四类的混合输入,是否会报错;
3)输入空格、空格+数据、数据+空格,是否报错;
4)输入html语言的<head>,是否能正确显示;
5)输入全角、半角的英文、数字、特殊字符等,是否报错;
6)是否有必填项的控制;不输入必填项,是否有友好提示信息;
7)输入超长字段,页面是否被撑开;
8)分别输入大于、等于、小于数据表规定字段长度的数据,是否报错;
9)输入非数据表中规定的数据类型的字符,是否有友好提示信息;
10)在文本框中输入回车键,显示时是否回车换行;
11) 非法的输入或操作应有足够的提示说明。
1.7分页测试
分页测试主要分为以下几个方面:
1)当没有数据时,首页、上一页、下一页、尾页标签全部置灰;
2)在首页时,“首页”“上一页”标签置灰;在尾页时,“下一页”“尾页”标签置灰;在中间页时,四个标签均可点击,且跳转正确;
3)翻页后,列表中的数据是否扔按照指定的顺序进行了排序;
4)各个分页标签是否在同一水平线上;
5)各个页面的分页标签样式是否一致;
6)分页的总页数及当前页数显示是否正确;
7)是否能正确跳转到指定的页数;
8)在分页处输入非数字的字符(英文、特殊字符等),输入0或超出总页数的数字,是否有友好提示信息;
9)是否支持回车键的监听;
1.8 交互性数据测试
1)前台的数据操作是否对后台产生相应正确的影响
   (如:查看详细信息时,需扣除用户相应的授权点数);
2)可实现前后台数据的交互(如:在线咨询,能否实现数据的交互实时更新);数据传递是否正确;前后台大数据量信息传递数据是否丢失(如500个字符);多用户交流时用户信息控制是否严谨;
3)用户的权限,是否随着授权而变化;
4)数据未审核时,前台应不显示;审核通过后,前台应可显示该条数据;

功能测试中还需注意以下几点内容:
1)点击【收藏我们】,标题是否出现乱码;收藏的url与网站的url是否一致;能否通过收藏夹来访问网站;
2)对于修改、删除等可能造成数据无法恢复的操作必须提供确认信息,给用户放弃选择的机会;
3)在文章详细页面,验证字体大小改变、打印、返回、关闭等功能是否实现;
2安全性测试
2.1目录设置
目录测试主要分为以下几个方面:
1)在测试路径上出现: http://218.61.30.17:7001/dzgh/xwzx/khzl/2008/11/13/58127.html把/2008/11/13/58127.html去掉,看是否能出现目录下文件;
2)访问文件目录如果出现403错误,说明网页加以限制拒绝访问;
3)访问文件目录如果出现SSH其他根目录路径,说明有漏洞缺陷;
4)用X-Scan-v3.2-cn工具对网站服务器扫描。可以对网站参透出开启的端口号,SSH弱口令,网站是否存在高风险;比如:在扫描参数中输入测试网站的地址,点击扫描。如果扫描出网站端口号高风险或SSH弱口令可以与开发人员沟通进行修改;
5)测试有效和无效的用户名和密码,要注意到是否大小写敏感,可以试多少次的限制,是否可以不登陆而直接浏览某个页面等。
6)Web应用系统是否有超时的限制,也就是说,用户登陆后在一定时间内(例如15分钟)没有点击任何页面,是否需要重新登陆才能正常使用。
7)为了保证Web应用系统的安全性,日志文件是至关重要的。需要测试相关信息是否写进了日志文件、是否可追踪。
8)当使用了安全套接字时,还要测试加密是否正确,检查信息的完整性。
9)服务器端的脚本常常构成安全漏洞,这些漏洞又常常被黑客利用。所以,还要测试没有经过授权,就不能在服务器端放置和编辑脚本的问题。
10)网页加载速度测试可以采用HttpWatch软件等,可以知道那些内容影响网站整体速度。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

一、界面测试公共测试用例

界面测试一般包括页面文字,控件使用,少图,CSS,颜色等。

<!--[if !supportLists]-->1.     <!--[endif]-->文字

内容一致性:

1)公司要求文字的一致性,例如各种宣传文字、注册的协议条款、版权信息等;

2)各处相同含义文字的一致性,例如标题栏文字、页面主题文字、弹出窗口文字、菜单名称、功能键文字等。

样式一致性

1)(通常分类包括)各类文字字体、字号、样式、颜色、文字间距、对齐方式;

2)按钮的文字间距,按钮长度一定前提下,2个字的按钮,需要中间空一格(或者其它约定,需要统一);

3)链接文字,同一类,菜单、小标题、页角文字链接,在点击时颜色变化要相同;

4)对齐方式,页面上文字的对齐,例如表单、菜单列、下拉列表中文字的对齐方式(左、右、居中等要统一)

语言习惯:

1)中文:文字简单,含义明确,无歧异,无重复,无别字,正确运用标点符号。

2)英文。

3)日文。

<!--[if !supportLists]-->2.     <!--[endif]-->按钮

1)button的样式整体要统一,例如突出、扁平、3D效果等只能选其一;

2)采用的图片表述相同功能,要采用单一图标。

<!--[if !supportLists]-->3.     <!--[endif]-->文本框

1)录入长度限制,根据 数据库的设计,页面直接限定录入长度(特殊处屏蔽复制、粘贴);

2)文本框自身的长度限制,主要考虑页面样式。

<!--[if !supportLists]-->4.     <!--[endif]-->单选框

1)默认情况要统一,已选择,还是未选。

<!--[if !supportLists]-->5.     <!--[endif]-->日期控件

1)图标、控件颜色、样式统一;

2)点击控件、文本框均应弹出日期选择框。

<!--[if !supportLists]-->6.     <!--[endif]-->下拉选择框

1)默认是第一个选项,还是提示请选择一个。

<!--[if !supportLists]-->7.     <!--[endif]-->提示信息

1)静态文字与它的提示信息一致性,例如静态文字为‘ID’,出错信息显示‘用户ID’;

2)空值时,出错信息需要统一,例如可以采用“静态文字”+不能为空;

3)出现录入错误时,例如可以统一采用“静态文字”+格式不符合要求;

4)提示信息标点符号是否标识;点击上一步,返回的页面上不应残留出错信息;

5)静态提示信息,在录入框右侧,应有录入信息的相应要求的提示文字,达到方便操作的目的;

6)必输项提示信息,必输项提示信息采用统一的标志。

<!--[if !supportLists]-->8.     <!--[endif]-->导航测试

死导航、乱导航、操作复杂等。

<!--[if !supportLists]-->9.     <!--[endif]-->链接测试

1)发现404错误。

2)避免死链接情况,执行完相应操作应有返回按钮,返回到相应页面;例如:操作成功后,进入成功提示信息页面,但页面没有返回按钮,无法及时进入操作之前的页面。

<!--[if !supportLists]-->10.   <!--[endif]-->IE的后退

退出系统,无论直接关闭浏览器或点击后退键,退出都不应再返回系统。

<!--[if !supportLists]-->11.   <!--[endif]-->分辨率

页面文字显示、样式等要支持常见分辨率,例如CRT显示器的1024*768,LCD的1280*1024。

<!--[if !supportLists]-->12.   <!--[endif]-->重复提交问题

1)功能操作完成后,鼠标右键点击所在页面,选择弹出菜单的刷新功能,容易出现重复提交问题。

2)功能操作完成后,通过IE的后退键进行重复操作,容易出现重复提交问题。

3)某功能键反应时间延迟时(限制客户端网络带宽等方式来模拟实现),在短时间内重复点击该功能键,容易出现重复提交问题;

<!--[if !supportLists]-->13.   <!--[endif]-->防止 SQL注入式攻击

1)不允许任何直接在jsp页面调用SQL语句,这种情况常发生在系统的后期修改中。

<!--[if !supportLists]-->14.   <!--[endif]-->用户非授权页面访问

1)每个页面都需要安全验证,防止用户通过直接拷贝具体页面地址等方式,访问系统;

2)页面过期的时间设定,用户在设定时间内未进行任何操作,不允许访问系统。

二、文本框公共测试用例

<!--[if !supportLists]-->1.     <!--[endif]-->文本框为字符型

必填项非空校验:

1)必填项未输入--程序应提示错误;

2)必填项只输入若干个空格,未输入其它字符--程序应提示错误;

字段唯一性校验:(不是所有字段都作此项校验,视实际项目情况而定)

1)新增时输入重复的字段值--必须提示友好信息;

2)修改时输入重复的字段值--必须提示友好信息;

字段长度校验:

1)输入[最小字符数-1]--程序应提示错误;

2)输入[最小字符数]--OK;

3)输入[最小字符数+1]--OK;

4)输入[最大字符数-1]--OK;

5)输入[最大字符数]--OK;

6)输入[最大字符数+1]--程序应提示错误;

字段为特殊字符校验:

1)输入域如对某些字符禁止输入时,限制是否成功,提示信息是否友好;

2)中文、英文、空格,数字,字符,下划线、单引号等所有特殊字符的组合;

3)所有特殊字符都必须进行测试(!~@#$^&*()_+{}|:“<>?/.,;‘[]\=-`¥……()--:《》?、。,;’【】、=-• )

字段为特殊代码校验:

1)输入html代码:比如”你好”;--必须以文本的形式将代码显示出来。

2)输入JavaScript代码:比如;--必须以文本的形式将代码显示出来。

多行文本框输入:

1)是否允许回车换行;

2)保存后再显示能够保持输入时的格式;

3)仅输入回车换行,检查能否正确保存;若能,查看保存结果。若不能,查看是否有正确提示;

4)仅输入空格,检查能否正确保存;若能,查看保存结果。若不能,查看是否有正确提示。

<!--[if !supportLists]-->2.     <!--[endif]-->文本框为数值型

边界值:

1)输入[最小值-1]--程序应提示错误;

2)输入[最小值]--OK;

3)输入[最大值]--OK;

4)输入[最大值+1]--程序应提示错误;

位数:

1)输入[限制位数]--OK;

2)输入[限制位数+1]--根据实际项目而定,是否自动四舍五入成限制位数,还是提示信息;

3)输入[限制位数-1]--OK;

异常值、特殊值:

1)输入非数值型数据:汉字、字母、字符--程序应提示错误;

2)输入负数--根据实际项目而定,如果不允许输入负数,必须提示友好信息;

3)字段禁止直接输入非数值型数据时,使用“粘贴”、“拷贝”功能尝试输入,并测试能否正常提交保存--只能使用“粘贴”、“拷贝”方法输入的特殊字符应无法保存,并应给出相应提示;

4)全角数字和半角数字的情况--全角数字不能保存,提示友好信息,半角数字正常保存;

5)首位为零的数值:如01=1--视实际项目情况而定;

<!--[if !supportLists]-->3.     <!--[endif]-->文本框为日期型

合法性检查:

1)日输入[0日]--程序应提示错误; 

2)日输入[1日]--OK;

3)日输入[32日]--程序应提示错误;

4)月输入[1、3、5、7、8、10、12月]、日输入[31日]--OK;

5)月输入[4、6、9、11月]、日输入[30日]--OK;

6)月输入[4、6、9、11月]、日输入[31日]--程序应提示错误;

7)输入非闰年,月输入[2月]、日输入[28日],比如2009.2.28--OK;

8)输入非闰年,月输入[2月]、日输入[29日],比如2009.2.29--程序应提示错误;

9)(闰年)月输入[2月]、日输入[29日],比如2008.2.29--OK;

10)(闰年)月输入[2月]、日输入[30日],比如2008.2.30--程序应提示错误;

12)月输入[1月]--OK;

13)月输入[12月]--OK;

14)月输入[13月] --程序应提示错误;

格式检查:

1)不合法格式:2009-09、 2009-09 -、200-2-2;

2)视具体项目而定是否合法:2009/09/01、2009.09.01 、20090901、2009-09-01 ;

异常值、特殊值:

1)输入汉字、字母、字符--程序应提示错误;

<!--[if !supportLists]-->4.     <!--[endif]-->文本框为时间型

合法性检查:

1)时输入[24时] --程序应提示错误; 

2)时输入[00时] --OK;

3)分输入[60分] --程序应提示错误;

4)分输入[59分] --OK;

5)分输入[00分] --OK;

6)秒输入[60秒] --程序应提示错误;

7)秒输入[59秒] --OK;

8)秒输入[00秒] --OK;

格式检查:

1)不合法格式:12:30:、 123000;

2)视具体项目而定是否合法:12:30、 1:3:0;

异常值、特殊值:

1)输入汉字、字母、字符--程序应提示错误;

2)系统中所涉及时间是否取服务器时间;

三、上传和导出公共测试用例

<!--[if !supportLists]-->1.     <!--[endif]-->上传图片

对于上传的文件,假设系统要求上传的文件为jpg或gif格式图片,大小为<=5M的文件,我们在设计测试用例时,应该从以下几个方面进行考虑:

1)文件类型正确,文件大小合适的校验

例如:上传一种jpg或gif的格式图片,文件大小为4.9M,结果为上传成功

2)文件类型正确,文件大小合适的校验

例如:上传一种jpg或gif的格式图片,文件大小为5M,结果为上传成功

3)文件类型正确,文件大小不合适的校验

例如:上传一种jpg或gif的格式图片,文件大小为5.1M,提示为:“上传的附件中大小不能超过5M”

4)文件类型错误,文件大小合适的校验

例如:上传.doc、.xls、ppt、bmp、jpeg、psd、tiff、tga、png、swf、svg、pcx、dxf、wmf、emf、lic、eps、.txt等格式文件,文件大小合适,提示“只能上传jpg或gif格式图片”

5)文件类型和文件大小合法,上传一个0kb的图片,提示信息:“请重新上传文件,或者是不能上传0kb的图片”

6)文件类型和文件大小合法,上传一个正在使用中的图片(即打开该图片,再上传该图片),上传成功

7)文件类型和文件大小合法,手动输入一个存在的图片地址,点击上传,上传成功

8)文件类型和文件大小合法,手动输入一个不存在的图片地址,点击上传,提示:“请正确选择要上传的文件”

9)文件类型和大小都合法,手动输入一个存在的图片名称,点击上传,一般情况下系统会提示:“请正确选择要上传的文件的路径”

<!--[if !supportLists]-->2.     <!--[endif]-->文件导出

1)验证导出文件名长度,根据具体情况而定

2)验证导出文件为空的情况 

3)验证导出文件名为特殊字符的情况

4)验证导出全部资料的情况,导出的信息是否正确  

5)验证导出部分资料的情况,导出的信息是否正确 

6)验证导出大量数据时的时间是否在合理的时间范围内  

7)验证导出目的磁盘空间已满的情况下,导出是否有友好的处理方式  

8)验证导出目的的文件夹为只读的情况下,导出时是否有友好的的提示信息

<!--[if !supportLists]-->3.     <!--[endif]-->文件上传

页面

1)页面美观性、易用性(键盘和鼠标的操作、tab跳转的顺序是否正确)  

2)按钮文字正确性 

3)说明文字是否正确  

4)正确/错误的提示文字是否正确 

5)提示当前位置是否正确,并且和其他页面保持一致格式  

6)必添项的标示是否正确

功能

1)路径是否可以手工输入(手工输入的时候有没有限长)  

2)上传文件超过最大值是在提交前校验还是提交后校验 

3)上传文件格式是否全部支持(图片:gif/jpg/bmp...文档:doc/sxw/xls...压缩包:zip/rar...安装文件:exe/msi) 

4)上传文件是否支持中文名称

5)文件名称的最大值、最小值、特殊字符(包含空格)、使用程序语句是否会对其造成影响、中文名称是否能正常显示

<!--[if !supportLists]-->4.     <!--[endif]-->文件下载

功能

1)右键另存为是否可以正确下载文件,并且记录下载次数

•工具下载是否正确,并且记录下载次数

2)单击下载是提示下载还是在页面打开

•直接打开是否显示正确

•对于本机没有安装工具的文件是否能够打开,是否能给出正确的提示

•对于直接在页面内打开的内容是否能够显示正常,页面美观性

•保存到本地是否能正确显示• 取消下载是否会纪录下载次数

3)下载次数是否被正确记录

四、列表公共测试用例

<!--[if !supportLists]-->1.     <!--[endif]-->列表页面显示

1)确认页面的默认排序方式,字段+升降续;

2)含link的列,验证其有效性,即,点击后的跳转是否正确;

3)第一列的选择框,“全选”和“部分选择”需有效;部分选中时,全选按钮应自动取消。

<!--[if !supportLists]-->2.     <!--[endif]-->顶部搜索功能

1)逐个测试每个搜索条件的有效性;

2)做2-3个组合条件的查询,验证结果;合计共有N+3个搜索条件的测试。

3)有时间区间的,验证列表项的开始到结束时间和选择区间有交叉,则为有效,且包含所选日期的记录;

4)条件中,开始时间不能大于结束时间;

5)搜索条件,在分页显示时,需始终保持有效;

6)点击名为“显示全部”的按钮,需清除所有条件,并显示所有记录。

7)每一次新的搜索执行,都应该去除分页,显示第一页、并回到进入页面时的默认排序方式。

<!--[if !supportLists]-->3.     <!--[endif]-->右侧或底部的按钮

按功能分成多个用例:

1)单选,多选、全选的情况下,点击按钮执行某个功能,如暂停服务、恢复服务的按钮; 

2)跨页选择,在一些选择成员的列表中是应有效的,需进行确认。

<!--[if !supportLists]-->4.     <!--[endif]-->列表数据的验证

验证从数据库中得到的列表项中每列数据的正确性,要求覆盖不同情况下的值,比如“开通”、“暂停”的服务状态;已使用空间大小和总空间大小等数字的正确性。可考虑结合其他用例来描述,但必须覆盖到。

 

<!--[if !supportLists]-->5.     <!--[endif]-->列表按标题的排序

1)检查每个列标题,要求点击后能按其进行排序:第一次点击为正序,以后每次点击为升、降续的切换。

2)进入下一页、上一页,以及任意分页显示时,条件需始终保持有效。

<!--[if !supportLists]-->6.     <!--[endif]-->分页

1)“第2页/共8页每页 10条/共 79条”中的分页数据必须正确;

2)第一页、上一页、下一页、最后一页的link在当前上下文有意义时显示,否则隐藏或显示为文本标签;

3)填入某个数字,点击“跳转到”按钮,到正确的页数;

 

另外请考虑每个文本框输入的有效性,比如日期、域名、跳转到某页的文本框的能接受的值,具体可参考需求文档。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Web测试需要注意点  

2012-01-19 15:09:37|  分类: 测试人生 |  标签: |字号大中小 订阅

一、功能测试

测试用例是测试的核心,测试用例的设计是一种思维方式的体现,在用例的设计中,用的比较多的方法是边界值分析法和等价类划分法,下面主要从输入框,搜索功能,添加、修改功能,删除功能,注册、登录功能以及上传图片功能等11个方面进行总结说明。

1、输入框

输入框是测试中最容易出现bug的地方,所以在测试时,一定要多加注意。

核查点

大分类

小分类

检查内容

 

输入框

字符型输入框

字符种类

英文全角字符

英文半角字符

数字

汉字

空或空格

特殊字符“~!@#$%^&*()_+-={}[]|\:;”’<>,./?;”等可能导致系统错误的字符,特别要注意单引号和&符号。

禁止直接输入特殊字符时,使用“粘贴”、“拷贝”功能尝试输入,并测试能否正常提交保存。

长度检查

最小长度-1

最小长度

最大长度

最大长度+1

输入超长字符:比如把整篇word文档copy过去

空格检查

输入的字符间有空格

字符前有空格

字符后有空格

字符前后都有空格

多行文本框输入

允许回车换行

保存后再显示能够保持输入时的格式

仅输入回车换行,检查能否正确保存;若能,查看保存结果。若不能,查看是否有正确提示

安全性检查

输入特殊字符串:null、NULL、 、javascript、<script>、</script>、<title>、<html>、<td>等

输入脚本函数:<script>alter("abc")</script>、document.write("abc")、<b>hello</b>

数值型输入框

边界值

最小值-1

最小值

最大值

最大值+1

位数

最小位数+1

最小位数

最大位数

最大位数+1

输入超长值

异常值、特殊值

输入[空白(NULL)]、空格或‘“~!@#$%^&*()_+-={}[]|\:;”’<>,./?;”等可能导致系统错误的字符

禁止直接输入特殊字符时,使用“粘贴”、“拷贝”功能尝试输入,并测试能否正常提交保存。

word中的特殊功能,通过剪贴板拷贝到输入框:分页符,分节符,类似公式的上下标等

输入负整数、负小数、分数

输入字母或汉字

带符号的数值:带正号的正数,带负号的负数

小数:小数点前零舍去的情况,如.12;多个小数点的情况;0值:0.0,0.,.0

首位为零的数值:如01、02

科学技术法是否支持:如 1.0E2

全角数字和半角数字的情况

数字与字母的混合:16进制数值,8进制数值

货币型输入项:允许小数点后几位

安全性检查同上

不能直接输入,就copy

日期型

合法性检查

日输入[0日]

日输入[1日]

日输入[32日]

月输入[1、3、5、7、8、10、12月]、日输入[31日]

月输入[4、6、9、11月]、日输入[30日]

月输入[4、6、9、11月]、日输入[31日]

输入非闰年,月输入[2月]、日输入[28日]

输入非闰年,月输入[2月]、日输入[29日]

(闰年)月输入[2月]、日输入[29日]

(闰年)月输入[2月]、日输入[30日]

月输入[0月]

月输入[1月]

月输入[12月]

月输入[13月]

异常值、特殊值

输入[空白(NULL)]或“~!@#$%^&*()_+-={}[]|\:;”’<>,./?;”等可能导致系统错误的字符

安全性检查同上

 

 

  2、搜索功能

(1)比较长的名称是否能查到?

(2)空格 或空

(3)名称中含有特殊字符,如:' $ % & *以及空格等

(4)关键词前面或后面有空格

(5)如果支持模糊查询,搜索名称中任意一个字符是否能搜索到

(6)输入系统中不存在与之匹配的条件

(7)两个查询条件是否为2选1,来回选择是否出现页面错误

(8)输入脚本语言,如:<script>alter(“abc”)</script>等

 

3、添加、修改功能

(1)是否支持tab键

(2)是否支持enter键

(3)不符合要求的地方是否有错误提示

(4)保存后,是否也插入到数据库中?

(5)字段唯一的,是否可以重复添加

(6)对编辑页列表中的每个编辑项进行修改,点击保存,是否保存成功?

(7)对于必填项,修改为空、空格或其他特殊符号,是否可以编辑成功

(8)在输入框中,直接回车

(9)是否能够连续添加

(10)在编辑的时候,要注意编辑项的长度限制,有时,添加时有长度限制,但编辑时却没有(添加和修改规则是否一致)

(11)添加时,字段是唯一的,不允许重复,但有时,编辑时,却可以修改为相同字段(相同字段包括是否区分大小写以及在输入内容的前后输入空格)

(12)添加含有特殊符号或空格的内容

(13)对于有图片上传功能的编辑框,对于没有上传的图片,查看编辑页面时,是否显示默认图片,如果上传了图片,是否显示为上传图片?

 

4、删除功能

(1)输入正确数据前加空格,看是否能正确删除?

(2)是否支持enter键

(3)是否能连续删除多个产品?当只有一条数据时,能否成功删除?

(4)删除一条数据后,能否再添加相同的数据?

(5)当提供能一次删除多条信息的功能时,注意,删除的数据是否正确?

(6)不选择任何信息,直接点击删除按钮,看有什么错误提示?

(7)删除某条信息时,应该有错误提示信息

 

5、注册、登录模块

(1)注册成功,但登录失败:注册时,密码设置为一些特殊符号,但登录时,失败

(2)注册时,连续点击提交按钮

(3)注册成功后,页面应该以登录状态跳转到首页

(3)登录时,没区分大小写,注册时,是小写字母,但登录时,用大写字母也能登录进去

(4)登录时,当页面刷新或重新输入新数据时,验证码是否也随之更新

(5)对密码的修改,当把密码修改为很长,或含有特殊符号时,能够修改成功,但却不能成功登录。

 

6、上传图片测试

 (1)文件类型正确,文件大小合适

(2)文件类型正确,文件大小不合适

(3)文件类型错误,文件大小合适

(4)文件类型和大小都合适,上传一个正在使用中的图片

(5)文件类型和大小合适,手动输入一个存在的图片地址来上传

(6)文件类型和大小合适,手动输入一个不存在的图片地址上传

(7)文件类型和大小都合适,手动输入图片名称来上传

 

7、返回键检查

(1)一条已经成功提交的记录,返回后再提交,看系统是否做了处理

(2)检查多次使用返回键的情况,在有返回键的地方,返回到原来页面重复多次,看是否会出错

8、回车键检查

在输入结束后,直接按回车键,看系统处理如何,是否会报错

9、刷新键检查

在web系统中,使用浏览器的刷新键,看系统处理如何,是否会报错

10、直接URL链接检查

在web系统中,直接输入各功能页面的URL地址,看系统如何处理

11、其他

(1)在测试时,有与网络有关的步骤必须考虑到断网的情况

(2)每个页面都有相应的页面title

(3)在测试的时候要尽量考虑在页面出现滚动条时(滚动条上下滚动下),页面显示是否正常

(4)URL不区分大小写

 

12、测试中,并发情况的考虑

总结了以下两种情况:

(1)某个字段是唯一的,当多个用户并发点击产生该字段时,检查系统是怎么处理的

(2)对于电子商务网站,当两个或多个用户并发购买量总和大于产品库存量时,能否购买成功

二、界面和易用性测试

1、界面测试,主要测试网站的界面是否和设计一致,是否有错别字,页面布局是否合理,格式是否正确,是否有相应的错误提示信息等。

2、易用性测试,主要是考察所开发出的功能是否人性化,是否易用,是否符合大多数用户的使用习惯等。

3、对Tab和Enter键的测试。

三、兼容性测试

兼容性测试不只是指界面在不同操作系统或浏览器下的兼容,有些功能方面的测试,也要考虑到兼容性,比如涉及到ajax、jquery、javascript等技术的,都要考虑到不同浏览器下的兼容性问题。

四、链接测试

主要是保证链接的可用性和正确性,它也是网站测试中比较重要的一个方面。

五、业务流程测试

业务流程,一般会涉及到多个模块的数据,所以在对业务流程测试时,首先要保证单个模块功能的正确性,其次就要对各个模块间传递的数据进行测试,这往往是容易出现问题的地方,测试时一定要设计不同的数据进行测试。

六、安全性测试

(1)SQL注入

(2)XSS跨网站脚本攻击:程序或数据库没有对一些特殊字符进行过滤或处理,导致用户

所输入的一些破坏性的脚本语句能够直接写进数据库中,浏览器会直接执行这些脚本语句,破坏网站的正常显示,或网站用户的信息被盗,构造脚本语句时,要保证脚本的完整性。

document.write("abc")

<script>alter("abc")</script>

(3)URL地址后面随便输入一些符号

(4)验证码更新问题

 

 

 

 

 

 

 

 

web测试中容易忽略的问题

   很多时候,基于需求的测试和针对web特有的浏览器兼容性测试、cookie失效的验证,对于测试人员并不陌生。但实际上,与浏览器相关的测试内容远不止这些。

    举一个例子来说,很多时候我们都非常明确页面上的所有入口,并对这些入口设计了大量的用例,而浏览器的地址栏却常常会被我们忽略。实际上,url的输入意义远比我们意识中的重要,忽略了url的测试,很容易造成安全上的隐患。

    再进一步的说,浏览器的前进、后退、刷新按钮同样是测试人员需要关注的点。前进、后退在用户登录、注销信息的测试中应用最为频繁。而刷新,往往容易被忽视,但其同样是bug的“温床”。在最近的一次测试中,我就遇到过在我删除某条记录系统提示删除成功后,点击“刷新”按钮,页面提示出错的情况。出现该现象的原因就在于页面试图去取已删除的内容,导致出现异常。其实这个问题应该隐藏了比较久的时间,但是却一直未被发现,足可见我们都忽视了“刷新”的测试。

    除了上述的内容外,我相信一定还存在很多我们在测试中忽视的内容,而这些点的补充,是我们每一个人的责任!

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

<!--[if !supportLists]--> 1、<!--[endif]--> 相关性检查:

增加/删除一些功能,是否对其他项有影响;

增加某个数据项后,该数据某字段内容过长,查询显示回事数据列表变形;

字符串长度、类型检查。

<!--[if !supportLists]--> 2、<!--[endif]--> 标点符号检查:

把空格键当成一个字符处理,但查询时空格被屏蔽,查询不到添加的内容;

查询时输入特殊字符“_”,程序返回所有记录。

<!--[if !supportLists]--> 3、<!--[endif]--> 检查添加与修改是否一致:

添加要求必填项,修改也应该是必填项

<!--[if !supportLists]--> 4、<!--[endif]--> 脚本错误(IFrameJSAjax)易造成浏览器兼容性问题

<!--[if !supportLists]--> 5、<!--[endif]--> 查询列表,如果有重复信息(distinct)去重

<!--[if !supportLists]--> 6、<!--[endif]--> 登录信息,cookies缓存保留

<!--[if !supportLists]--> 7、<!--[endif]--> JS格式控制验证处理,注意验证条件,验证未知,触发时间及验证的必要性

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

软件测试中常见问题分类说明

 

<!--[if !supportLists]--> 一、    <!--[endif]--> 规范化问题

包括软件规范和业务规范两大类,软件规范问题主要指操作过程中显而易见的错误或缺陷,非人性化设计、友好度较差等;业务规范问题主要指使用非标准或非惯例的业务术语、以及概念错位等。

㈠ 软件规范问题

<!--[if !supportLists]-->1、<!--[endif]-->操作指示不明确

 提示存在二意性、提示操作项 “忽略”、“取消”、“退出”等含义不明确。 (轻度)

<!--[if !supportLists]-->2、<!--[endif]-->简单界面规范问题

①按钮图片丢失、按钮图片不配套、按钮大小排列不美观; (轻度)

②在引用数据窗口的下拉框中,没有根据实际数据来调整下拉框显示的%的大小和垂直滚动条,导致文本只显示了一部分; (一般)

③界面中存在色块; (轻度)

④菜单排列顺序有误; (轻度)

⑤窗体最小化以后在屏幕上找不到了,无法恢复原窗体; (轻度)

<!--[if !supportLists]-->3、<!--[endif]-->操作过程缺乏人性化考虑

①选项过于烦琐且不必要、设置不合适导致使用者遗漏、常规按钮排列顺序不一致 (轻度)

②常用功能不支持键盘操作。 (一般)

③单据处理中当由于存在空行时,提示用户输完其余内容,而没有自动删除空行。 (一般)

<!--[if !supportLists]-->4、<!--[endif]-->帮助文件规范问题

①联机帮助字体、背景风格不统一; (细微)

②点击“ ”按钮打开帮助文件,没有直接定位到内容; (细微)

③内容定位错误; (轻度)

④帮助文件内部链接没有做全; (细微)

⑤文档内容排版错误; (一般)

⑥其他帮助错误。 (轻度)

5、软件风格规范问题

①控件的切换顺序有误、DataWindow的切换顺序有误;

(视控件使用频繁程度设为 (一般)(轻度)

②DataWindow内容的对齐方式不正确(数值右对齐、日期中对齐、文字左对齐); (细微)

③数值的EditMask(掩膜)设置有误、日期的EditMask(掩膜)设置有误、日期的默认格式非YYYY.MM.DD、默认日期存在1900.00.00现象或其他不合理的值 (轻度)

④弹出窗口不在屏幕中间位置、退出系统缺少提示; (细微)

⑤重大操作(月结、恢复、修复等)缺少提示、重大操作没有自动弹出备份提示; (轻度)

⑥快捷按钮定义不准确、快捷字母或数字重复、工具栏快捷键定义错误 (轻度),工具栏常用快捷键缺少 (细微)

⑦违反窗口录入标准(一般可录入内容为白底蓝字、不可录入内容为白底黑字或灰底)、主窗口关闭后未关闭下属窗口; (轻度)

⑧进入界面缺少焦点、焦点位置不合理、回车键切换焦点顺序错误、记录或条件选择不方便; (一般)

⑨窗口标题、版本号、版权标识、系统图片不统一; (细微)

⑩补丁、紧急放行版未加PN号; (细微)

⑾存在无明显用途或不必要的消息窗。 (轻度)

  ㈡业务规范问题

<!--[if !supportLists]-->1、<!--[endif]-->业务术语规范问题

概念偷换、业务名词混用、业务术语出现错别字、生造业务术语、同一功能指向使用不同术语、多个功能指向使用同一术语。 (轻度)

<!--[if !supportLists]-->2、<!--[endif]-->操作提示用语不规范

缺少必要的提示、提示语句描述不规范、语序随意、叙述风格不统一、口语化、对操作的必然后果或可能产生的后果没有提示、提示有误。 (轻度)

3、用例错误

引用业务规范错误、引用政策法律相关数据过时、引用相关公式错误、报表格式不符合业务规范或过时、报表或查询窗口中条目或款项设计不全导致信息失真或不可用。 (严重)

4、默认设置不规范

数量或金额长度不符合日常应用、默认编码方案不可行或不科学、系统建表后自动插入的数据错误、各种默认的数据或编码体系彼此不统一。 (一般)

<!--[if !supportLists]--> 二、    <!--[endif]--> 常规录入错误

         主要指数据录入、修改、保存、删除等常规操作过程中出现的各类弹出式出错信息,数据控制疏漏、数据编辑无效、设置无效等。

 ㈠ 数据编辑无效

        1、由于建表失败导致的无法设置现象。 (严重)

         2、各种设置完成后立即查询发现设置有不符现象。 (一般)

         3、数据编辑保存后,在其他相关功能中查询此数据,不符。 (严重)

         4、数据经过变动、保存后,在其他功能中查询,变动没有及时体现。 (严重)

         5、出现如“按!定位”等变量没有替换的错误、定位或搜索不可用。 (一般)

㈡ 出现Data Window Error

         1、出现主键冲突导致的错误提示。(试图存入已存在的代码,数据库弹出提示未被程序接管。) (一般)

2、由于字段类型和赋值范围控制疏漏导致的Data. Window Error。(录入界面允许n+m位,字段实际宽度为n位,或由于数值掩膜设置出错导致数据库弹出错误提示未被程序接管。) (一般)

3、由于建表错误导致数据无法保存产生Data. Window Error。 (严重)

4、在同一操作界面中反复进行修改、查询、删除等编辑操作使驻留内存的数据与数据库中的数据不对应导致的Data Window Error。 (一般)

5、极限数据录入产生的Data Window Error。 (一般)

6、其他操作出现的Data Window Error。 (一般)

㈢ 出现非法操作提示(WIN98)或应用程序错误提示(WIN2000)

1、报表或查询的条件录入中由于使用%、(、)等特殊符号产生的非法操作提示。 (轻度)

2、对某一功能、某一组功能的常规操作出现非法操作提示。 (严重)

3、对某几个功能的组合操作、或一个功能较复杂的应用出现非法操作提示。 (一般)

㈣ .NET错误

         包含所有的Microsoft Visual Studio .NET 2003 Error、或表现为“第××行代码错误”的提示。此类提示在程序任何地方都可能出现。(普通操作就出现的 (严重),复杂操作出现的 (一般)

  ㈤ 残留的编译信息未及时清除

         主要是开发员在开发过程中方便观察程序运行状态而留下的一些提示窗口,表现形式往往是弹出一个或几个标注感叹号( )、问号( )的消息框。 (一般)

  ㈥ 出现WINDOWS 系统提示

         比如:文件删除失败、内存不够、无法执行此项任务、Out of Memory等 (严重)

㈦ 系统停止响应

         在没有并发操作的前提下出现程序停止响应状况、或者长时间停顿,需要点击Ctrl+Alt+Delete中止的现象 (海量数据恢复除外)。 (严重)

㈧ 非正常的失败或操作错误提示

        1、操作过程中出现本不应该有的失败提示,如“数据库已被改乱,请到核算单位重新再建”、“数据保存失败”、“处理失败,请重试”等 (严重)

        2、提示与出错的实际原因牛头不对马嘴,实际是A错误,显示B提示。 (一般)

<!--[if !supportLists]-->三、<!--[endif]-->流程错误

         主要指程序运行过程中由于需求分析、功能设计中对产品功能缺少深入的考虑、或者在编码过程中的疏漏等原因,产生的逻辑控制错误或失败、数据控制错误等。

  ㈠ 逻辑控制错误

       1、初始通过时没有自动检测初始化设置的核心内容、或者检测错误。 (严重)

         2、该禁止的操作流程未被禁止、不该禁止的操作流程被禁止。 (严重)

3、对已使用的条款、或存在记录的类别可以作删除操作。(如删除有固定资产的部门、删除已有员工发薪的员工大类等)。 (严重)

4、编码缺少必要的分级政策,直接导致后面流程取数及统计工作的正确性。 (严重)

5、数据恢复前未强行关闭当前工作窗口。 (严重)

6、初始化前事关流程走向的选项在初始化完成后仍旧可以改动。 (严重)

7、流程环节设计不合理、不规范。 (一般)

8、流程设计缺少重要的数据出口。

9、对应可能出现的流程中意外情况,缺少可行的解决办法。(如不支持作废、重开、冲红等)。 (一般)

10、设计中对特定的流程及相应的单据缺乏检查、追踪及统计的功能。 (一般)

11、单据的处理流程前后因果关联错误。(如修改、审核、删除、作废之间的关系) (严重)

12、公式设置出现闭环、或几个公式间出现互为因果的现象,而能够设置成功。 (严重)

13、公式保存没有必要的合法性检查。 (一般)

14、短期使用版未控制 (严重)或控制时间过长 (一般)、正版有时间限制 (严重)

15、软件无法安装或安装失败。 (严重)

 ㈡ 数据控制错误

         1、取上一环节数据出错。 (严重)

         2、下一环节取数后反填错误。未将所取的值记录下、未加上已取数的状态标志,出现统计出错、取数无限制、无法继续取剩余值等错误。 (严重)

         3、下一环单据变动后反填错误。如对于单据删除、作废、修改等变动,上一环节未同步变动。 (严重)

         4、公式设置出现闭环。 (一般)

         5、公式计算出错。 (严重)

         6、单据录入四舍五入错误。 (严重)

         7、上下流单据处理中四舍五入错误。(如订单开提货单、提货单开发票等一对一、一对多处理过程。) (严重)

<!--[if !supportLists]-->四、<!--[endif]-->报表和查询出错

         1、报表取数错误。 (严重)

         2、对报表进行过滤、筛选等操作,出现数据错误。 (一般)

3、报表分级汇总错误。 (严重)

4、报表分类统计错误。 (严重)

5、报表非数据元素显示错误。(如表头、制表日期、相关部门等) (一般)

6、项目属性修改导致统计错误。(比如业务员的部门转移、部门的调整、固定资产摊销部门的变化等统计条件变更导致计算错误。) (严重)

7、部分报表可以通过单击字段名排序,在此过程中出现的界面刷新错误、合计汇总错误等。   (一般)

8、表与表之间同种指标数据不统一。(由于统计口径不同导致。) (一般)

9、初始数据未计算到相关报表。 (一般)

10、报表数据四舍五入错误。

   ①由单据(或其他数据录入界面)汇总计算而来。 (一般)

②从其他报表取数或计算而来。 (一般)

③报表自身元素计算而来。 (严重)

         11、对报表某一记录、元素深入查询出错。(比如在总表下查询明细表等,主要针对报表界面中的其他查询按钮) (严重)       

<!--[if !supportLists]-->五、<!--[endif]-->打印及打印相关操作错误

         在程序中,用到打印功能的相当多,由于许多打印用类库处理,因此错误有较大的相似性,打印相关操作主要涉及打印机设置、打印字体设置、宽度设置、纸张设置。打印包括打印预览、套打、分页打印、满页打印、普通打印等

   ㈠ 打印相关操作出错。

          1、打印机及打印纸设置有误。 (一般)

          2、打印页面参数设置无效。 (轻度)

          3、打印页面参数保存无效。 (轻度)

          4、打印格式选择无效。 (一般)

          5、套打格式设置无效。 (一般)

 

           6、打印效果转换输出无效。 (轻度)

          7、打印标题及表头、表尾设置无效或错误。 (一般)

          8、同样的内容在不同打印机上显示效果不同(指数据正确的前提下) (细微)

   ㈡ 打印预览和打印问题

          通常情况下,打印预览和打印的现象是一致的,如果非特殊指明的,下面的问题包含打印及预览两个方向。(所有打印必须在两种或两种以上打印机上通过测试。)

          1、表头消失或错位。 (轻度)

          2、表格线不全。 (细微)

          3、信息打印表格出边界、打印内容有重叠效果。 (一般)

          4、打印标题与报表查看不一致。 (轻度)

          5、报表打印时其他信息与查看不一致。 (轻度)

          6、存在焦点时,打印效果异常。(比如选中区域为黑色、焦点不能预览或打印。) (细微)

          7、打印预览工具条和查看窗口操作后切换有问题。(如停止响应等) (细微)

          8、查看窗口退出后,打印工具条仍然可以使用。 (细微)

          9、实际打印时跳行、走纸。 (一般)

          10、打印预览中能够编辑。 (细微)

          11、页码打印错误。 (轻度)

          12、打印实际效果与预览有差异。 (细微)

          13、满页打印错误。 (一般)

          14、鼠标拖拉报表列头使之调整宽度、或隐藏某列后预览及打印效果出错。 (细微)

     15、同样的内容在不同打印机上显示效果不同(指数据正确的前提下) (细微)

          16、先预览后打印和直接打印数据或内容不同 (严重)

<!--[if !supportLists]-->六、<!--[endif]-->接口及数据转移中的问题

         1、各模块之间生成单据错误。 (严重)

         2、各模块之间可以重复取数、或放弃取数(取数失败)后不能再取 (严重)

         3、各模块交叉查询数据出错。 (严重)

4、各模块之间传入传出、导入导出、汇入汇出错误。(数据传出与导入效果不同) (严重)

5、传出到第三方的数据格式不符合要求。 (一般)

6、第三方数据导入不能完全接收、或接收错误。 (严重)

<!--[if !supportLists]-->8、<!--[endif]-->切换网络服务器过程中产生的错误。 (一般)    

<!--[if !supportLists]-->9、<!--[endif]-->不同数据库之间的数据查询失败或错误。 (严重)

<!--[if !supportLists]-->10、<!--[endif]-->其他网络、数据库之间通讯失败。 (一般)

<!--[if !supportLists]-->七、<!--[endif]-->权限及安全问题

         1、匿名登录成功。 (严重)

         2、明码登录。 (严重)

         3、重大系统操作不强制重新登录。(如恢复数据完成、切换年度、年结完成等) (严重)

         4、对不可逆的操作缺少安全性提示。(如改动资产月末计提) (一般)

         5、没有遵循逐级授权的原则。 (细微)

         6、权限设置中存在互为因果的同级项目、存在逻辑错误。 (一般)

7、某操作员没有某权限,但依然能够进行该种操作。 (一般)

8、只有针对一部分对象的权限,但能够进行全部对象的操作。(如部门权限失效等) (轻度)

9、只有查询权的情况下,可以编辑成功。 (一般)

10、没有某权限,但通过快捷菜单能够绕开。 (轻度)

11、对权限进行多种组合,出现控制出错的现象。 (轻度)

12、默认状态下权限设置不合理。 (细微)

13、数据成批处理没有考虑到与权限设置存在冲突。 (轻度)

14、缺少必要的权限。 (严重)

15、备份出来的数据未经压缩或加密,利用计事本就可以打开文件查阅信息。 (一般)

<!--[if !supportLists]-->八、<!--[endif]-->备份与恢复问题

          1、极限宽度的数据备份恢复失败。 (严重)

          2、备份恢复数据比较,设置内容不正确。 (严重)

          3、备份恢复数据比较,存在记录丢失现象。 (严重)

          4、在各个数据库中,数据小数位长度不一。 (严重)

          5、数据库中原有数据的,恢复后部分数据未覆盖。 (严重)

          6、备份恢复过程中产生其他出错信息。 (严重)

          7、集中备份恢复与普通备份恢复结果不同。 (严重)

          8、大数据量备份恢复记录条数丢失。 (严重)

<!--[if !supportLists]-->九、<!--[endif]-->并发问题

          并发错误指两人或多人同时对同一流程、同一单据(或相关流程、相关单据)操作所引起的存取错误、系统停止响应等问题。 (视相关单据和流程的重要性和并发操作的可能性划分问题严重程度)

          1、多人同时录入同类单据,出现单据号重复现象或出错提示。

          2、多人同时对同一张单据进行同一流程处理,出现数据控制失败现象或出错提示。

          3、多人同时对同一单据作不同操作(如审核、修改、删除、作废等),出现控制失败或出错提示。

          4、按上问题,继续查询此单据,出现错误提示。

          5、多人同时录入、编辑同一记录,出现出错信息、或数据保存错误。<!--[if gte vml 1]><v:shapetype id="_x0000_t202" coordsize="21600,21600" o:spt="202" path="m,l,21600r21600,l21600,xe"><v:stroke joinstyle="miter"/><v:path gradientshapeok="t" o:connecttype="rect"/></v:shapetype><v:shape id="_x0000_s1042" type="#_x0000_t202" style='position:absolute; left:0;text-align:left;margin-left:275.1pt;margin-top:596.75pt;width:37.65pt; height:19pt;text-indent:0;z-index:251661312; mso-position-horizontal-relative:text;mso-position-vertical-relative:text' stroked="f"><v:textbox style='mso-next-textbox:#_x0000_s1042'/></v:shape><![endif]--><!--[if !vml]-->

<!--[endif]--><!--[if !mso]-->
<!--[endif]-->

严重

<!--[if !mso]-->
<!--[endif]--><!--[if !mso & !vml]--> <!--[endif]--><!--[if !vml]-->

 

          6、由于并发产生的提示错误。

          7、在不同流程(不同单据)的同步处理中,由于操作涉及同一数据(表)导致的并发问题。

          8、在不同模块的操作中,由于操作涉及同一数据(表)导致的并发问题。(如销售和库存同时调取存货结存数量)

 

<!--[if gte vml 1]><v:group id="_x0000_s1026" style='position:absolute;left:0;text-align:left; margin-left:62.75pt;margin-top:11.45pt;width:220.75pt;height:170.25pt; z-index:251660288' coordorigin="2389,11970" coordsize="4267,3230"><v:line id="_x0000_s1027" style='position:absolute;flip:y' from="3393,12160" to="3393,14440"><v:stroke endarrow="block"/></v:line><v:group id="_x0000_s1028" style='position:absolute;left:2389;top:11970; width:4267;height:3230' coordorigin="2389,11970" coordsize="4267,3230"><v:line id="_x0000_s1029" style='position:absolute' from="3393,14440" to="6656,14440"><v:stroke endarrow="block"/></v:line><v:group id="_x0000_s1030" style='position:absolute;left:2389;top:11970; width:4016;height:3230' coordorigin="2389,11970" coordsize="4016,3230"><v:rect id="_x0000_s1031" style='position:absolute;left:3393;top:14440; width:3012;height:760' filled="f" stroked="f"><v:textbox style='mso-next-textbox:#_x0000_s1031'><![if !mso]><table cellpadding=0 cellspacing=0 width="100%"><tr><td><![endif]><div><p class=MsoNormal><span style='font-size:9.0pt;font-family:楷体_GB2312; mso-ascii-font-family:"Times New Roman"'>低</span><span lang=EN-US style='font-size:9.0pt'><span style='mso-spacerun:yes'>            </span></span><span style='font-size:9.0pt;font-family:楷体_GB2312; mso-ascii-font-family:"Times New Roman"'>中</span><span lang=EN-US style='font-size:9.0pt'><span style='mso-spacerun:yes'>         </span></span><span style='font-size:9.0pt;font-family:楷体_GB2312;mso-ascii-font-family:"Times New Roman"'>高</span><span lang=EN-US style='font-size:9.0pt'><o:p></o:p></span></p><p class=MsoNormal><span style='font-family:楷体_GB2312;mso-ascii-font-family: "Times New Roman"'>重要性</span><span lang=EN-US><o:p></o:p></span></p></div><![if !mso]></td></tr></table><![endif]></v:textbox></v:rect><v:rect id="_x0000_s1032" style='position:absolute;left:2389;top:11970; width:1255;height:2470;rotation:180' filled="f" stroked="f"><v:textbox style='layout-flow:vertical;mso-layout-flow-alt:bottom-to-top; mso-next-textbox:#_x0000_s1032'><![if RotText]><![if !mso]><table cellpadding=0 cellspacing=0 width="100%"><tr><td><![endif]><div><p class=MsoNormal style='text-indent:70.0pt;mso-char-indent-count:5.0'><span style='font-family:楷体_GB2312;mso-ascii-font-family:"Times New Roman"'>可能性</span><span lang=EN-US><span style='mso-spacerun:yes'>     </span></span><span style='font-size:10.5pt;font-family:楷体_GB2312;mso-ascii-font-family: "Times New Roman"'>低</span><span lang=EN-US style='font-size:10.5pt'><span style='mso-spacerun:yes'>       </span></span><span style='font-size: 10.5pt;font-family:楷体_GB2312;mso-ascii-font-family:"Times New Roman"'>中</span><span lang=EN-US style='font-size:10.5pt'><span style='mso-spacerun:yes'>      </span></span><span style='font-size:10.5pt;font-family:楷体_GB2312; mso-ascii-font-family:"Times New Roman"'>高</span> <span lang=EN-US><o:p></o:p></span></p></div><![if !mso]></td></tr></table><![endif]><![endif]></v:textbox></v:rect><v:shape id="_x0000_s1033" type="#_x0000_t202" style='position:absolute; left:3644;top:13870;width:753;height:380' stroked="f"><v:textbox style='mso-next-textbox:#_x0000_s1033'><![if !mso]><table cellpadding=0 cellspacing=0 width="100%"><tr><td><![endif]><div><p class=MsoNormal><b style='mso-bidi-font-weight:normal'><span style='font-size:9.0pt;font-family:楷体_GB2312;mso-ascii-font-family:"Times New Roman"; color:red'>细微</span></b><b style='mso-bidi-font-weight:normal'><span lang=EN-US style='font-size:9.0pt;color:red'><o:p></o:p></span></b></p></div><![if !mso]></td></tr></table><![endif]></v:textbox></v:shape><v:shape id="_x0000_s1034" type="#_x0000_t202" style='position:absolute; left:5652;top:12160;width:753;height:380' stroked="f"><v:textbox style='mso-next-textbox:#_x0000_s1034'><![if !mso]><table cellpadding=0 cellspacing=0 width="100%"><tr><td><![endif]><div><p class=MsoNormal><b style='mso-bidi-font-weight:normal'><span style='font-size:9.0pt;font-family:楷体_GB2312;mso-ascii-font-family:"Times New Roman"; color:red'>严重</span></b><b style='mso-bidi-font-weight:normal'><span lang=EN-US style='font-size:9.0pt;color:red'><o:p></o:p></span></b></p></div><![if !mso]></td></tr></table><![endif]></v:textbox></v:shape><v:shape id="_x0000_s1035" type="#_x0000_t202" style='position:absolute; left:4648;top:12160;width:753;height:380' stroked="f"><v:textbox style='mso-next-textbox:#_x0000_s1035'><![if !mso]><table cellpadding=0 cellspacing=0 width="100%"><tr><td><![endif]><div><p class=MsoNormal><b style='mso-bidi-font-weight:normal'><span style='font-size:9.0pt;font-family:楷体_GB2312;mso-ascii-font-family:"Times New Roman"; color:red'>严重</span></b><b style='mso-bidi-font-weight:normal'><span lang=EN-US style='font-size:9.0pt;color:red'><o:p></o:p></span></b></p></div><![if !mso]></td></tr></table><![endif]></v:textbox></v:shape><v:shape id="_x0000_s1036" type="#_x0000_t202" style='position:absolute; left:5652;top:13110;width:753;height:380' stroked="f"><v:textbox style='mso-next-textbox:#_x0000_s1036'><![if !mso]><table cellpadding=0 cellspacing=0 width="100%"><tr><td><![endif]><div><p class=MsoNormal><b style='mso-bidi-font-weight:normal'><span style='font-size:9.0pt;font-family:楷体_GB2312;mso-ascii-font-family:"Times New Roman"; color:red'>严重</span></b><b style='mso-bidi-font-weight:normal'><span lang=EN-US style='font-size:9.0pt;color:red'><o:p></o:p></span></b></p></div><![if !mso]></td></tr></table><![endif]></v:textbox></v:shape><v:shape id="_x0000_s1037" type="#_x0000_t202" style='position:absolute; left:5652;top:13870;width:753;height:380' stroked="f"><v:textbox style='mso-next-textbox:#_x0000_s1037'><![if !mso]><table cellpadding=0 cellspacing=0 width="100%"><tr><td><![endif]><div><p class=MsoNormal><b style='mso-bidi-font-weight:normal'><span style='font-size:9.0pt;font-family:楷体_GB2312;mso-ascii-font-family:"Times New Roman"; color:red'>轻度</span></b><b style='mso-bidi-font-weight:normal'><span lang=EN-US style='font-size:9.0pt;color:red'><o:p></o:p></span></b></p></div><![if !mso]></td></tr></table><![endif]></v:textbox></v:shape><v:shape id="_x0000_s1038" type="#_x0000_t202" style='position:absolute; left:3644;top:13096;width:753;height:380' stroked="f"><v:textbox style='mso-next-textbox:#_x0000_s1038'><![if !mso]><table cellpadding=0 cellspacing=0 width="100%"><tr><td><![endif]><div><p class=MsoNormal><b style='mso-bidi-font-weight:normal'><span style='font-size:9.0pt;font-family:楷体_GB2312;mso-ascii-font-family:"Times New Roman"; color:red'>轻度</span></b><b style='mso-bidi-font-weight:normal'><span lang=EN-US style='font-size:9.0pt;color:red'><o:p></o:p></span></b></p></div><![if !mso]></td></tr></table><![endif]></v:textbox></v:shape><v:shape id="_x0000_s1039" type="#_x0000_t202" style='position:absolute; left:3644;top:12160;width:753;height:570' stroked="f"><v:textbox style='mso-next-textbox:#_x0000_s1039'><![if !mso]><table cellpadding=0 cellspacing=0 width="100%"><tr><td><![endif]><div><p class=MsoNormal><b style='mso-bidi-font-weight:normal'><span style='font-size:9.0pt;font-family:楷体_GB2312;mso-ascii-font-family:"Times New Roman"; color:red'>一般</span></b><b style='mso-bidi-font-weight:normal'><span lang=EN-US style='font-size:9.0pt;color:red'><o:p></o:p></span></b></p></div><![if !mso]></td></tr></table><![endif]></v:textbox></v:shape><v:shape id="_x0000_s1040" type="#_x0000_t202" style='position:absolute; left:4648;top:13096;width:753;height:380' stroked="f"><v:textbox style='mso-next-textbox:#_x0000_s1040'><![if !mso]><table cellpadding=0 cellspacing=0 width="100%"><tr><td><![endif]><div><p class=MsoNormal><b style='mso-bidi-font-weight:normal'><span style='font-size:9.0pt;font-family:楷体_GB2312;mso-ascii-font-family:"Times New Roman"; color:red'>一般</span></b><b style='mso-bidi-font-weight:normal'><span lang=EN-US style='font-size:9.0pt;color:red'><o:p></o:p></span></b></p></div><![if !mso]></td></tr></table><![endif]></v:textbox></v:shape><v:shape id="_x0000_s1041" type="#_x0000_t202" style='position:absolute; left:4648;top:13870;width:753;height:380' stroked="f"><v:textbox style='mso-next-textbox:#_x0000_s1041'><![if !mso]><table cellpadding=0 cellspacing=0 width="100%"><tr><td><![endif]><div><p class=MsoNormal><span style='font-size:9.0pt;font-family:楷体_GB2312; mso-ascii-font-family:"Times New Roman";color:red'>细微</span><span lang=EN-US style='font-size:9.0pt;color:red'><o:p></o:p></span></p></div><![if !mso]></td></tr></table><![endif]></v:textbox></v:shape></v:group></v:group></v:group><![endif]--><!--[if !vml]-->

 
 <!--[endif]--><!--[if !RotText]--> 文本框: 可能性     低       中      高 <!--[endif]--><!--[if !vml]-->

<!--[endif]--> <!--[endif]--> 

 

 

 

 

 

 

 

 

 

 


                                                                 

<!--[if !supportLists]-->十、<!--[endif]-->升级问题

          1、恢复以前版本数据没有出现“正在调整数据库”提示。 (一般)

          2、由于版本之间表结构差异造成的数据无法恢复。 (严重)

          3、以前版本数据恢复内容不全。 (严重)

          4、在以前版本上覆盖安装之后无法进入程序、或进入程序后出错。 (严重)

          5、在以前版本上覆盖安装,进入程序后没有出现“调整数据库”提示。 (一般)

          6、升级完成之后核对后台表数据,出现表内容丢失现象。(空表或记录不全) (严重)

 

          7、升级完成之后核对后台表数据,出现数据错误现象。 (严重)

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

【页面布局方面】

1)各页面整体布局、按钮、对话框、提示信息、下拉菜单等风格一致

2)帮助信息和错误提示、成功提示、异常提示等提示信息中出现的标点均为汉字全角并且提示信息以叹号结束

3)输入框输入内容过长的话,会导致页面文字排列错乱、页面布局混乱

4)页面显示一行内容超长时是否进行换行处理(这种情况要把所有合理输入的情况都要测试到,如数字和英文不换行而汉字换行);

 

【页面元素方面】

1)输入域的提示信息不明确(如:输入框没有合法输入长度、格式等的提示信息);

2)输入框是否允许粘贴入内容,对粘贴内容的合法校验

3)输入框中输入包含html字符时,可能处理出现异常

 

 

【功能方面】

1)输入内容不正确改正后要两次点击“确定”按钮才可以完成操作(

2)以最长的合法输入为条件查询时没有查询结果(后台定义的存放name的空间过短),

3)在列表内进行修改、删除操作后页面是跳转到当前页,还是首页。一般情况下,修改记录后,页面应该跳转到被修改记录显示的页面

4)合理的操作导致网页报JS错误,之后无法继续相关操作

5)任意页面退出登录的情况下,其他页面的所有需登录后才能进行的操作应不可执行,提示请先登录

6)查询时输入与已有查询条件同音的字

7)登录后打开多个页面,其中一个页面做修改或删除操作,其他页面不刷新的情况下在改动处做操作,查看处理情况

8)多个已经登录的页面中一个页面退出登录(该页面显示为尚未登录状态),刷新其他页面重新登录,之前显示为尚未登录状态的页面中的操作应该不提示尚未登录

9)相关页面相关功能做交替操作,看是否有逻辑处理矛盾的问题(如bug345)?10)?如果使用多任务,是否所有的窗口被实时更新

 

 

【其他】  

1) 数据库出现问题时报错到网页显示

2) 不同的异常要有不同的异常提示,不能出现500或404错误

3) 用户登录后,在浏览器地址栏修改任何已存在的用户的email或tripid等,可以任意切换到其他用户的信息

4) 各页面字符编码不统一

 

 

 

 

 

1、相关性检查:

增加/删除一些功能,是否对其他项有影响;

增加某个数据项后,该数据某字段内容过长,查询显示回事数据列表变形;

字符串长度、类型检查。

 

2、标点符号检查:

把空格键当成一个字符处理,但查询时空格被屏蔽,查询不到添加的内容;

查询时输入特殊字符“_”,程序返回所有记录。

 

3、检查添加与修改是否一致:

添加要求必填项,修改也应该是必填项

 

4、脚本错误(IFrame,JS,Ajax)易造成浏览器兼容性问题

 

5、查询列表,如果有重复信息(distinct)去重

 

6、登录信息,cookies缓存保留

 

7、JS格式控制验证处理,注意验证条件,验证未知,触发时间及验证的必要性

 

 

 

 

 

 

 

 



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


ITeye推荐



【Thrift二】Thrift版的Hello World

$
0
0

本篇,不考虑细节问题和为什么,先照葫芦画瓢写一个Thrift版本的Hello World,了解Thrift RPC服务开发的基本流程

 

1. 在Intellij中创建一个Maven模块,加入对Thrift的依赖,同时还要加上slf4j依赖,如果不加slf4j依赖,在后面启动Thrift Server时会报错

<dependency><groupId>org.apache.thrift</groupId><artifactId>libthrift</artifactId><version>0.9.1</version></dependency><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-api</artifactId><version>1.7.7</version></dependency>

 

2. 在resources目录下创建接口定义文件helloworld.thrift文件,内容如下

namespace java com.tom.thrift.hello

service  IHelloWorldService {
  string sayHello(1:string username)
}

 

3.在命令号终端cd到helloworld.thrift所在的目录,执行如下命令

  

thrift -r -gen java helloworld.thrift

 

4. 命令执行完成后,在当前目录下生成一个gen-java目录,其目录结构为 gen-java/com/tom/thrift/hello/IHelloWorldService.java,这么一个简单的接口声明,自动生成了957行代码。。复杂!!!

 

5.使用cp -r命令将com/tom/thrift/hello/IHelloWorldService.java目录连同文件copy到Maven模块的src/java/main下面

 

6.在Maven模块中,自定义IHelloWorldService的实现类HelloWorldService,需要实现IHelloWorldService.Iface接口,不出意料,果然仅仅需要实现sayHello方法,类定义如下:

package com.tom.thrift.hello;

import org.apache.thrift.TException;

public class HelloWorldService implements IHelloWorldService.Iface {
    @Override
    public String sayHello(String username) throws TException {
        return "Hi, " + username + ", Welcome to the Thrift world, enjoy it!";
    }
}

 

 10.自定义单线程模式的ThriftServer用于响应客户端的rpc请求,注意一点,IHelloWorldService.Iface的实现类在服务器端进行了实例化

 

package com.tom.thrift.hello;

import org.apache.thrift.TProcessor;
import org.apache.thrift.protocol.TBinaryProtocol;
import org.apache.thrift.server.TServer;
import org.apache.thrift.server.TSimpleServer;
import org.apache.thrift.transport.TServerSocket;

public class HelloWorldSimpleServer {
    public static final int SERVER_PORT = 8090;

    public void startServer() {
        try {
            System.out.println("HelloWorld TSimpleServer start ....");

            TProcessor tprocessor = new IHelloWorldService.Processor<IHelloWorldService.Iface>(
                    new HelloWorldService());
            // 简单的单线程服务模型,一般用于测试
            TServerSocket serverTransport = new TServerSocket(SERVER_PORT);
            TServer.Args tArgs = new TServer.Args(serverTransport);
            tArgs.processor(tprocessor);
            tArgs.protocolFactory(new TBinaryProtocol.Factory());
            // tArgs.protocolFactory(new TCompactProtocol.Factory());
            // tArgs.protocolFactory(new TJSONProtocol.Factory());
            TServer server = new TSimpleServer(tArgs);
            server.serve();

        } catch (Exception e) {
            System.out.println("Server start error!!!");
            e.printStackTrace();
        }
    }

    /**
     * @param args
     */
    public static void main(String[] args) {
        HelloWorldSimpleServer server = new HelloWorldSimpleServer();
        server.startServer();
    }

}

 

 11.自定义HelloWorld的客户端,用于远程调用第10步Thrift Server提供的IHelloWorldService服务

 

package com.tom.thrift.hello;

import org.apache.thrift.TException;
import org.apache.thrift.protocol.TBinaryProtocol;
import org.apache.thrift.protocol.TProtocol;
import org.apache.thrift.transport.TSocket;
import org.apache.thrift.transport.TTransport;
import org.apache.thrift.transport.TTransportException;

public class HelloWorldSimpleClient {

	public static final String SERVER_IP = "localhost";
	public static final int SERVER_PORT = 8090;//Thrift server listening port
	public static final int TIMEOUT = 30000;

	/**
	 *
	 * @param userName
	 */
	public void startClient(String userName) {
		TTransport transport = null;
		try {
			transport = new TSocket(SERVER_IP, SERVER_PORT, TIMEOUT);
			// 协议要和服务端一致
			TProtocol protocol = new TBinaryProtocol(transport);
			// TProtocol protocol = new TCompactProtocol(transport);
			// TProtocol protocol = new TJSONProtocol(transport);
			IHelloWorldService.Client client = new IHelloWorldService.Client(protocol);
			transport.open();
			String result = client.sayHello(userName);
			System.out.println("Thrift client result =: " + result);
		} catch (TTransportException e) {
			e.printStackTrace();
		} catch (TException e) {
			e.printStackTrace();
		} finally {
			if (null != transport) {
				transport.close();
			}
		}
	}

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		HelloWorldSimpleClient client = new HelloWorldSimpleClient();
		client.startClient("Tom");
	}
}

 

12.启动HelloWorldSimpleServer,控制台输出HelloWorld TSimpleServer start ....,同时,HelloWorldSimpleServer作为Server一直处于运行过程中

 

13.启动HelloWorldSimpleClient,控制台输出Thrift client result =: Hi, Tom, Welcome to the Thrift world, enjoy it! 执行完后,客户端进程结束

 

总结

 前面一步一步的完成了Thrift版本的Hello World,对Thrift开发RPC服务器,有了一个基本的了解。Thrift本身的细节和更深入的学习,将在后面继续。

 

本文参考:http://www.micmiu.com/soa/rpc/thrift-sample/

 

 



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


ITeye推荐



【Thrift一】Thrift编译安装

$
0
0

什么是Thrift

The Apache Thrift software framework, for scalable cross-language services development, combines a software stack with a code generation engine to build services that work efficiently and seamlessly between C++, Java, Python, PHP, Ruby, Erlang, Perl, Haskell, C#, Cocoa, JavaScript, Node.js, Smalltalk, OCaml and Delphi and other languages

 

上面这段话选自Apache对Thrift的一句话介绍,Thrift是一个高性能的RPC服务框架。在技术选型时,有如下三方面的需求时,考虑使用Thrift

1.高并发

2.请求和响应的数据传输量大

3.业务系统跨多种语言

个人认为在没有特别strong的理由情况下,慎用Thrift。HTTP请求通常都能够满足需求,使用Thrift带来很多开发上的额外的工作量,一个简单的服务,就要写客户端代码,.thrift接口定义以及服务器端的服务响应代码,简单的事情复杂化

 

Thrift安装

以在Ubuntu上安装为例

参考:

http://thrift.apache.org/docs/install/debian

http://thrift.apache.org/docs/BuildingFromSource

 

 

1.下载Thrift安装包

http://www.apache.org/dyn/closer.cgi?path=/thrift/0.9.1/thrift-0.9.1.tar.gz

2.安装Thrift编译和安装所以来的工具和库

 

sudo apt-get install libboost-dev libboost-test-dev libboost-program-options-dev libevent-dev automake libtool flex bison pkg-config g++ libssl-dev

 

3.解压thrift-0.9.1.tar.gz

tar -xzvf thrift-0.9.1.tar.gz

 

4.进入Thrift的解压目录

 

5.在终端命令行执行命令

./configure JAVAC=/software/devsoftware/jdk1.7.0_55/javac

 --JAVAC选项表示显式的指定javac命令的位置,而不需thrift在编译时根据系统配置进行猜测

 

配置过程提示信息如下,等Thrift熟悉了,再来看看这个过程应该是比较有意思的

 

tom$ ./configure JAVAC=/software/devsoftware/jdk1.7.0_55/javac
checking for a BSD-compatible install... /usr/bin/install -c
checking whether build environment is sane... yes
checking for a thread-safe mkdir -p... /bin/mkdir -p
checking for gawk... no
checking for mawk... mawk
checking whether make sets $(MAKE)... yes
checking how to create a ustar tar archive... gnutar
checking for pkg-config... /usr/bin/pkg-config
checking pkg-config is at least version 0.9.0... yes
checking for gcc... gcc
checking whether the C compiler works... yes
checking for C compiler default output file name... a.out
checking for suffix of executables... 
checking whether we are cross compiling... no
checking for suffix of object files... o
checking whether we are using the GNU C compiler... yes
checking whether gcc accepts -g... yes
checking for gcc option to accept ISO C89... none needed
checking for style of include used by make... GNU
checking dependency style of gcc... gcc3
checking how to run the C preprocessor... gcc -E
checking for g++... g++
checking whether we are using the GNU C++ compiler... yes
checking whether g++ accepts -g... yes
checking dependency style of g++... gcc3
checking build system type... x86_64-unknown-linux-gnu
checking host system type... x86_64-unknown-linux-gnu
checking how to print strings... printf
checking for a sed that does not truncate output... /bin/sed
checking for grep that handles long lines and -e... /bin/grep
checking for egrep... /bin/grep -E
checking for fgrep... /bin/grep -F
checking for ld used by gcc... /usr/bin/ld
checking if the linker (/usr/bin/ld) is GNU ld... yes
checking for BSD- or MS-compatible name lister (nm)... /usr/bin/nm -B
checking the name lister (/usr/bin/nm -B) interface... BSD nm
checking whether ln -s works... yes
checking the maximum length of command line arguments... 1572864
checking whether the shell understands some XSI constructs... yes
checking whether the shell understands "+="... yes
checking how to convert x86_64-unknown-linux-gnu file names to x86_64-unknown-linux-gnu format... func_convert_file_noop
checking how to convert x86_64-unknown-linux-gnu file names to toolchain format... func_convert_file_noop
checking for /usr/bin/ld option to reload object files... -r
checking for objdump... objdump
checking how to recognize dependent libraries... pass_all
checking for dlltool... no
checking how to associate runtime and link libraries... printf %s\n
checking for ar... ar
checking for archiver @FILE support... @
checking for strip... strip
checking for ranlib... ranlib
checking command to parse /usr/bin/nm -B output from gcc object... ok
checking for sysroot... no
checking for mt... mt
checking if mt is a manifest tool... no
checking for ANSI C header files... yes
checking for sys/types.h... yes
checking for sys/stat.h... yes
checking for stdlib.h... yes
checking for string.h... yes
checking for memory.h... yes
checking for strings.h... yes
checking for inttypes.h... yes
checking for stdint.h... yes
checking for unistd.h... yes
checking for dlfcn.h... yes
checking for objdir... .libs
checking if gcc supports -fno-rtti -fno-exceptions... no
checking for gcc option to produce PIC... -fPIC -DPIC
checking if gcc PIC flag -fPIC -DPIC works... yes
checking if gcc static flag -static works... yes
checking if gcc supports -c -o file.o... yes
checking if gcc supports -c -o file.o... (cached) yes
checking whether the gcc linker (/usr/bin/ld -m elf_x86_64) supports shared libraries... yes
checking whether -lc should be explicitly linked in... no
checking dynamic linker characteristics... GNU/Linux ld.so
checking how to hardcode library paths into programs... immediate
checking whether stripping libraries is possible... yes
checking if libtool supports shared libraries... yes
checking whether to build shared libraries... yes
checking whether to build static libraries... yes
checking how to run the C++ preprocessor... g++ -E
checking for ld used by g++... /usr/bin/ld -m elf_x86_64
checking if the linker (/usr/bin/ld -m elf_x86_64) is GNU ld... yes
checking whether the g++ linker (/usr/bin/ld -m elf_x86_64) supports shared libraries... yes
checking for g++ option to produce PIC... -fPIC -DPIC
checking if g++ PIC flag -fPIC -DPIC works... yes
checking if g++ static flag -static works... yes
checking if g++ supports -c -o file.o... yes
checking if g++ supports -c -o file.o... (cached) yes
checking whether the g++ linker (/usr/bin/ld -m elf_x86_64) supports shared libraries... yes
checking dynamic linker characteristics... (cached) GNU/Linux ld.so
checking how to hardcode library paths into programs... immediate
checking whether make sets $(MAKE)... (cached) yes
checking for bison... bison -y
checking for flex... flex
checking lex output file root... lex.yy
checking lex library... -lfl
checking whether yytext is a pointer... yes
checking whether ln -s works... yes
checking for gawk... (cached) mawk
checking for ranlib... (cached) ranlib
checking for boostlib >= 1.40.0... yes
checking for libevent >= 1.0... yes
checking for zlib >= 1.2.3... yes
checking for QT... no
checking for GLIB... no
checking for GOBJECT... no
checking for MONO... no
checking for MONO... no
checking for javac and java... no
checking for ant... no
checking for ant version > 1.7... expr: syntax error
no
checking for erl... no
checking for erlc... no
checking for a Python interpreter with version >= 2.4... python
checking for python... /usr/bin/python
checking for python version... 2.7
checking for python platform... linux2
checking for python script directory... ${prefix}/lib/python2.7/dist-packages
checking for python extension module directory... ${exec_prefix}/lib/python2.7/dist-packages
checking for trial... /usr/bin/trial
checking for perl... /usr/bin/perl
checking for perl module Bit::Vector... no
checking for php... no
checking for php-config... no
checking for phpunit... no
checking for ruby... no
checking for rake... no
checking for bundle... no
checking for cabal... no
checking for runhaskell... no
checking for go... no
checking for DMD... no
checking for library containing strerror... none required
checking for an ANSI C-conforming const... yes
checking for inline... inline
checking for working volatile... yes
checking for stdbool.h that conforms to C99... yes
checking for _Bool... no
checking for ANSI C header files... (cached) yes
checking whether time.h and sys/time.h may both be included... yes
checking for sys/wait.h that is POSIX.1 compatible... yes
checking return type of signal handlers... void
checking arpa/inet.h usability... yes
checking arpa/inet.h presence... yes
checking for arpa/inet.h... yes
checking sys/param.h usability... yes
checking sys/param.h presence... yes
checking for sys/param.h... yes
checking fcntl.h usability... yes
checking fcntl.h presence... yes
checking for fcntl.h... yes
checking for inttypes.h... (cached) yes
checking limits.h usability... yes
checking limits.h presence... yes
checking for limits.h... yes
checking netdb.h usability... yes
checking netdb.h presence... yes
checking for netdb.h... yes
checking netinet/in.h usability... yes
checking netinet/in.h presence... yes
checking for netinet/in.h... yes
checking pthread.h usability... yes
checking pthread.h presence... yes
checking for pthread.h... yes
checking stddef.h usability... yes
checking stddef.h presence... yes
checking for stddef.h... yes
checking for stdlib.h... (cached) yes
checking sys/socket.h usability... yes
checking sys/socket.h presence... yes
checking for sys/socket.h... yes
checking sys/time.h usability... yes
checking sys/time.h presence... yes
checking for sys/time.h... yes
checking sys/un.h usability... yes
checking sys/un.h presence... yes
checking for sys/un.h... yes
checking sys/poll.h usability... yes
checking sys/poll.h presence... yes
checking for sys/poll.h... yes
checking sys/resource.h usability... yes
checking sys/resource.h presence... yes
checking for sys/resource.h... yes
checking for unistd.h... (cached) yes
checking libintl.h usability... yes
checking libintl.h presence... yes
checking for libintl.h... yes
checking malloc.h usability... yes
checking malloc.h presence... yes
checking for malloc.h... yes
checking openssl/ssl.h usability... yes
checking openssl/ssl.h presence... yes
checking for openssl/ssl.h... yes
checking openssl/rand.h usability... yes
checking openssl/rand.h presence... yes
checking for openssl/rand.h... yes
checking openssl/x509v3.h usability... yes
checking openssl/x509v3.h presence... yes
checking for openssl/x509v3.h... yes
checking sched.h usability... yes
checking sched.h presence... yes
checking for sched.h... yes
checking wchar.h usability... yes
checking wchar.h presence... yes
checking for wchar.h... yes
checking for pthread_create in -lpthread... yes
checking for clock_gettime in -lrt... yes
checking for setsockopt in -lsocket... no
checking for BN_init in -lcrypto... yes
checking for SSL_ctrl in -lssl... yes
checking for int16_t... yes
checking for int32_t... yes
checking for int64_t... yes
checking for int8_t... yes
checking for mode_t... yes
checking for off_t... yes
checking for size_t... yes
checking for ssize_t... yes
checking for uint16_t... yes
checking for uint32_t... yes
checking for uint64_t... yes
checking for uint8_t... yes
checking for ptrdiff_t... yes
checking whether struct tm is in sys/time.h or time.h... time.h
checking whether AI_ADDRCONFIG is declared... yes
checking for working alloca.h... yes
checking for alloca... yes
checking for pid_t... yes
checking vfork.h usability... no
checking vfork.h presence... no
checking for vfork.h... no
checking for fork... yes
checking for vfork... yes
checking for working fork... yes
checking for working vfork... (cached) yes
checking for stdlib.h... (cached) yes
checking for GNU libc compatible malloc... yes
checking for working memcmp... yes
checking for stdlib.h... (cached) yes
checking for GNU libc compatible realloc... yes
checking sys/select.h usability... yes
checking sys/select.h presence... yes
checking for sys/select.h... yes
checking for sys/socket.h... (cached) yes
checking types of arguments for select... int,fd_set *,struct timeval *
checking whether lstat correctly handles trailing slash... yes
checking whether stat accepts an empty string... no
checking whether strerror_r is declared... yes
checking for strerror_r... yes
checking whether strerror_r returns char *... yes
checking for strftime... yes
checking for vprintf... yes
checking for _doprnt... no
checking for strtoul... yes
checking for bzero... yes
checking for ftruncate... yes
checking for gethostbyname... yes
checking for gettimeofday... yes
checking for memmove... yes
checking for memset... yes
checking for mkdir... yes
checking for realpath... yes
checking for select... yes
checking for socket... yes
checking for strchr... yes
checking for strdup... yes
checking for strerror... yes
checking for strstr... yes
checking for strtol... yes
checking for sqrt... yes
checking for alarm... yes
checking for clock_gettime... yes
checking for sched_get_priority_min... yes
checking for sched_get_priority_max... yes
checking the behavior of a signed right shift... arithmetic
configure: creating ./config.status
config.status: creating Makefile
config.status: creating compiler/cpp/Makefile
config.status: creating compiler/cpp/version.h
config.status: creating compiler/cpp/src/windows/version.h
config.status: creating lib/Makefile
config.status: creating lib/cpp/Makefile
config.status: creating lib/cpp/test/Makefile
config.status: creating lib/cpp/thrift-nb.pc
config.status: creating lib/cpp/thrift-z.pc
config.status: creating lib/cpp/thrift-qt.pc
config.status: creating lib/cpp/thrift.pc
config.status: creating lib/c_glib/Makefile
config.status: creating lib/c_glib/thrift_c_glib.pc
config.status: creating lib/c_glib/test/Makefile
config.status: creating lib/csharp/Makefile
config.status: creating lib/d/Makefile
config.status: creating lib/d/test/Makefile
config.status: creating lib/erl/Makefile
config.status: creating lib/go/Makefile
config.status: creating lib/go/test/Makefile
config.status: creating lib/hs/Makefile
config.status: creating lib/java/Makefile
config.status: creating lib/js/test/Makefile
config.status: creating lib/perl/Makefile
config.status: creating lib/perl/test/Makefile
config.status: creating lib/php/Makefile
config.status: creating lib/php/test/Makefile
config.status: creating lib/py/Makefile
config.status: creating lib/rb/Makefile
config.status: creating test/Makefile
config.status: creating test/cpp/Makefile
config.status: creating test/hs/Makefile
config.status: creating test/nodejs/Makefile
config.status: creating test/php/Makefile
config.status: creating test/perl/Makefile
config.status: creating test/py/Makefile
config.status: creating test/py.twisted/Makefile
config.status: creating test/py.tornado/Makefile
config.status: creating test/rb/Makefile
config.status: creating tutorial/Makefile
config.status: creating tutorial/cpp/Makefile
config.status: creating tutorial/go/Makefile
config.status: creating tutorial/java/Makefile
config.status: creating tutorial/js/Makefile
config.status: creating tutorial/py/Makefile
config.status: creating tutorial/py.twisted/Makefile
config.status: creating tutorial/py.tornado/Makefile
config.status: creating tutorial/rb/Makefile
config.status: creating config.h
config.status: config.h is unchanged
config.status: creating lib/cpp/src/thrift/config.h
config.status: lib/cpp/src/thrift/config.h is unchanged
config.status: executing depfiles commands
config.status: executing libtool commands

thrift 0.9.1

Building C++ Library ......... : yes
Building C (GLib) Library .... : no
Building Java Library ........ : no
Building C# Library .......... : no
Building Python Library ...... : yes
Building Ruby Library ........ : no
Building Haskell Library ..... : no
Building Perl Library ........ : no
Building PHP Library ......... : no
Building Erlang Library ...... : no
Building Go Library .......... : no
Building D Library ........... : no

C++ Library:
   Build TZlibTransport ...... : yes
   Build TNonblockingServer .. : yes
   Build TQTcpServer (Qt) .... : no

Python Library:
   Using Python .............. : /usr/bin/python

If something is missing that you think should be present,
please skim the output of configure to find the missing
component.  Details are present in config.log.

 6. 在终端执行make命令进行编译

 

make

 

 7.  执行命令make check执行完整性检查测试

make check

 

8. 执行命令sh test/test.sh执行单元测试

sh test/test.sh

 

9. 执行命令make install完成最后安装

sudo make install

 

 10.执行which thrift查看thrift的安装路径

whcih thrift

 

 默认,thrift安装在/usr/local/bin/thrift

 

11.执行thrift --help查看thrift命令的选项

 

Usage: thrift [options] file
Options:
  -version    Print the compiler version
  -o dir      Set the output directory for gen-* packages
               (default: current directory)
  -out dir    Set the ouput location for generated files.
               (no gen-* folder will be created)
  -I dir      Add a directory to the list of directories
                searched for include directives
  -nowarn     Suppress all compiler warnings (BAD!)
  -strict     Strict compiler warnings on
  -v[erbose]  Verbose mode
  -r[ecurse]  Also generate included files
  -debug      Parse debug trace to stdout
  --allow-neg-keys  Allow negative field keys (Used to preserve protocol
                compatibility with older .thrift files)
  --allow-64bit-consts  Do not print warnings about using 64-bit constants
  --gen STR   Generate code with a dynamically-registered generator.
                STR has the form language[:key1=val1[,key2,[key3=val3]]].
                Keys and values are options passed to the generator.
                Many options will not require values.

Available generators (and options):
  as3 (AS3):
    bindable:          Add [bindable] metadata to all the struct classes.
  c_glib (C, using GLib):
  cocoa (Cocoa):
    log_unexpected:  Log every time an unexpected field ID or type is encountered.
    validate_required:
                     Throws exception if any required field is not set.
  cpp (C++):
    cob_style:       Generate "Continuation OBject"-style classes.
    no_client_completion:
                     Omit calls to completion__() in CobClient class.
    templates:       Generate templatized reader/writer methods.
    pure_enums:      Generate pure enums instead of wrapper classes.
    dense:           Generate type specifications for the dense protocol.
    include_prefix:  Use full include paths in generated files.
  csharp (C#):
    async:           Adds Async support using Task.Run.
    asyncctp:        Adds Async CTP support using TaskEx.Run.
    wcf:             Adds bindings for WCF to generated classes.
    serial:          Add serialization support to generated classes.
    nullable:        Use nullable types for properties.
    hashcode:        Generate a hashcode and equals implementation for classes.
    union:           Use new union typing, which includes a static read function for union types.
  d (D):
  delphi (delphi):
    ansistr_binary:  Use AnsiString for binary datatype (default is TBytes).
    register_types:  Enable TypeRegistry, allows for creation of struct, union
                     and container instances by interface or TypeInfo()
  erl (Erlang):
  go (Go):
    package_prefix= Package prefix for generated files.
    thrift_import=  Override thrift package import path (default:git.apache.org/thrift.git/lib/go/thrift)
  gv (Graphviz):
    exceptions:      Whether to draw arrows from functions to exception.
  hs (Haskell):
  html (HTML):
    standalone:      Self-contained mode, includes all CSS in the HTML files.
                     Generates no style.css file, but HTML files will be larger.
  java (Java):
    beans:           Members will be private, and setter methods will return void.
    private-members: Members will be private, but setter methods will return 'this' like usual.
    nocamel:         Do not use CamelCase field accessors with beans.
    hashcode:        Generate quality hashCode methods.
    android_legacy:  Do not use java.io.IOException(throwable) (available for Android 2.3 and above).
    java5:           Generate Java 1.5 compliant code (includes android_legacy flag).
    sorted_containers:
                     Use TreeSet/TreeMap instead of HashSet/HashMap as a implementation of set/map.
  javame (Java ME):
  js (Javascript):
    jquery:          Generate jQuery compatible code.
    node:            Generate node.js compatible code.
  ocaml (OCaml):
  perl (Perl):
  php (PHP):
    inlined:         Generate PHP inlined files
    server:          Generate PHP server stubs
    oop:             Generate PHP with object oriented subclasses
    rest:            Generate PHP REST processors
  py (Python):
    new_style:       Generate new-style classes.
    twisted:         Generate Twisted-friendly RPC services.
    tornado:         Generate code for use with Tornado.
    utf8strings:     Encode/decode strings using utf8 in the generated code.
    slots:           Generate code using slots for instance members.
    dynamic:         Generate dynamic code, less code generated but slower.
    dynbase=CLS      Derive generated classes from class CLS instead of TBase.
    dynexc=CLS       Derive generated exceptions from CLS instead of TExceptionBase.
    dynimport='from foo.bar import CLS'
                     Add an import line to generated code to find the dynbase class.
  rb (Ruby):
    rubygems:        Add a "require 'rubygems'" line to the top of each generated file.
  st (Smalltalk):
  xsd (XSD):

 

 

 

 

 

 

 

 



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


ITeye推荐



Java线程池应用

$
0
0

1.减少了创建和销毁线程的次数,每个工作线程都可以被重复利用,可执行多个任务。

2.可以根据系统的承受能力,调整线程池中工作线线程的数目,防止因为消耗过多的内存,而把服务器累趴下(每个线程需要大约1MB内存,线程开的越多,消耗的内存也就越大,最后死机)。

Java里面线程池的顶级接口是Executor,但是严格意义上讲Executor并不是一个线程池,而只是一个执行线程的工具。真正的线程池接口是ExecutorService。

1. newSingleThreadExecutor

创建一个单线程的线程池。这个线程池只有一个线程在工作,也就是相当于单线程串行执行所有任务。如果这个唯一的线程因为异常结束,那么会有一个新的线程来替代它。此线程池保证所有任务的执行顺序按照任务的提交顺序执行。

2. newFixedThreadPool

创建固定大小的线程池。每次提交一个任务就创建一个线程,直到线程达到线程池的最大大小。线程池的大小一旦达到最大值就会保持不变,如果某个线程因为执行异常而结束,那么线程池会补充一个新线程。

3. newCachedThreadPool

创建一个可缓存的线程池。如果线程池的大小超过了处理任务所需要的线程,

那么就会回收部分空闲(60秒不执行任务)的线程,当任务数增加时,此线程池又可以智能的添加新线程来处理任务。此线程池不会对线程池大小做限制,线程池大小完全依赖于操作系统(或者说JVM)能够创建的最大线程大小。

4. newScheduledThreadPool

创建一个大小无限的线程池。此线程池支持定时以及周期性执行任务的需求


下面我用2个实例来说明一下 ,线程池的简单实用

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;


public class ThreadPool {
     public static void main(String[] args) {
    	 //ExecutorService ThreadPool =  Executors.newFixedThreadPool(3);
    	 //ExecutorService ThreadPool = Executors.newCachedThreadPool();
    	  ExecutorService ThreadPool = Executors.newSingleThreadExecutor();
    	 for(int i=0;i<=4;i++){
    		 final int task = i;
         ThreadPool.execute(new Runnable() {
			@Override
			public void run() {
                for(int j=0;j<=10;j++){
                	try {
						Thread.sleep(20);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
                	System.out.println(Thread.currentThread().getName() + " is loopping of " + j + " for task of " + task);
                }				
			}
		});
       }
    	 //ThreadPool.shutdownNow();
    	 Executors.newScheduledThreadPool(3).scheduleAtFixedRate(new Runnable() {
			@Override
			public void run() {
				System.out.println("boombing!!");
			}
		}, 5, 2, TimeUnit.SECONDS);
	}
}

publicclass TestScheduledThreadPoolExecutor {
    publicstaticvoid main(String[] args) {
        ScheduledThreadPoolExecutor exec = new ScheduledThreadPoolExecutor(1);
        exec.scheduleAtFixedRate(new Runnable() {//每隔一段时间就触发异常
                      @Override
                      publicvoid run() {
                           //throw new RuntimeException();
                           System.out.println("================");
                      }
                  }, 1000, 5000, TimeUnit.MILLISECONDS);
        exec.scheduleAtFixedRate(new Runnable() {//每隔一段时间打印系统时间,证明两者是互不影响的
                      @Override
                      publicvoid run() {
                           System.out.println(System.nanoTime());
                      }
                  }, 1000, 2000, TimeUnit.MILLISECONDS);
    }
}


作者:u012516914 发表于2014-8-20 23:27:18 原文链接
阅读:176 评论:0 查看评论

Android响应式布局

$
0
0

由于目前在做的一款app需要适配手机和平板,所以我在研究怎么构建可适应所有屏幕尺寸的布局方法。

在web的响应式布局上我有很多经验,比如使用网格流,CSS3中的media queries属性等等,这些都可以实现web上的响应式布局,所以我想在Android上试试看。

在Android上,是通过 configuration qualifiers的方式来加载不同的资源,基于不同的手机屏幕尺寸或者屏幕的朝向(竖直还是水平),而我最大的目标就是创建一个可以自动缩放的布局,而不用根据不同的屏幕尺寸加载不同的布局文件。

除了为每种设备尺寸分别制作不同的布局文件外,我发现一种更简单的方法,就是为不同屏幕尺寸的设备重载 style.xml文件。

也许你会觉得它很像CSS样式,首先可以定义一个基本的style文件,代表普通设备尺寸,它的路径位于 values/styles.xml,然后还可以定义中等设备尺寸,在 values-sw600dp/styles.xml(7寸平板), values-sw600dp-land/styles.xml表示水平方向的屏幕, values-sw720dp/styles.xml表示十寸的平板等等。

在CSS中的响应式网格系统中,我们可以布局一个宽是960像素的 .container类(没有margin),而在手机上,我们也可以布局一个100%宽的 .container(也是没有margin的)。

我们可以在Android上使用相同的方法实现,首先,需要建立一个基类样式。

res/values/styles.xml

<style name="Container"><item name="android:layout_margin">0dp</item><item name="android:padding">16dp</item><item name="android:layout_width">match_parent</item><item name="android:layout_height">match_parent</item><item name="android:orientation">vertical</item><item name="android:background">@drawable/container_background</item></style>

对于平板(竖直的)来说,我们可以添加一些外边距,因为屏幕够大。

res/values-sw600dp/styles.xml

<style name="Container"><item name="android:layout_margin">0dp</item><item name="android:padding">32dp</item><item name="android:layout_width">match_parent</item><item name="android:layout_height">match_parent</item><item name="android:orientation">vertical</item><item name="android:background">@drawable/container_background</item></style>

在平板上竖直和水平的最大区别在于,我们会加上margin值,这样内容就不会充满整个屏幕了、我们还可以给父视图加一个背景图片,来填充空白区域。

res/values-sw600dp-land/styles.xml

<style name="Container"><item name="android:layout_marginRight">130dp</item><item name="android:layout_marginLeft">130dp</item><item name="android:padding">32dp</item><item name="android:layout_width">match_parent</item><item name="android:layout_height">match_parent</item><item name="android:orientation">vertical</item><item name="android:background">@drawable/container_background</item></style>

然后我们可以在不同的屏幕上,这样使用样式文件:

<LinearLayout style="@style/Container">
    ... buttons, edit texts, text views, etc ...</LinearLayout>

这是在四寸屏幕手机的效果:

responsive_android_phone

这是在七寸平板上的效果:

responsive_android_tablet

这是在七寸平板的横屏效果:

responsive_android_tablet_landscape

还有一些在CSS里面非常方便的属性(比如bootstrap),它们是一些帮助类,如 .visible-phone, .hidden-phone, .visible-tablet等等,在Android上也可以这么做。

<!-- Device Visibility --><style name="PhoneOnly"><item name="android:visibility">gone</item></style><style name="TabletOnly"><item name="android:visibility">visible</item></style><style name="TabletPortraitOnly"><item name="android:visibility">gone</item></style><style name="TabletLandscapeOnly"><item name="android:visibility">visible</item></style>

把这些样式放在对应的配置文件夹中,然后就可以在需要的时候隐藏显示相应的控件了。

<LinearLayout android:id="@+id/column_one">
      ... some content ...</LinearLayout><LinearLayout android:id="@+id/column_two"
      style="@style/TabletLandscapeOnly">
      ... some extra content since we have space ...</LinearLayout>

对于平板(水平的)来说,此样式会显示两列,但是对于大多数设备来说,第二列是不会显示的。

仅仅用了几行xml代码,我们就能够创建一个迷你的布局框架了,我们还可以扩展这种技术,根据需要去实现一个通用的样式文件,以后可以用到项目中。

很遗憾的是,很难把Android的资源打包进jar包中(非Gradle的话),所以在Android上很难像bootstrap那样去构建一个框架(不要被这些项目误导了 ,如: http://www.androidbootstrap.com/,它们没有你想象的那么强大),还好Android正在向Gradle迁移,这样可以使得制作Android前端的布局框架就更加方便了。

Android响应式布局,首发于 博客 - 伯乐在线

mysql记录耗时的sql

$
0
0

author:skate
time:2012/02/17

mysql记录耗时的sql

mysql可以把耗时的sql或未使用索引的sql都记录在slow log里,供优化分析使用。

1.mysql慢查询日志启用:

mysql慢查询日志对于跟踪有问题的查询非常有用,可以分析出当前程序里有很耗费资源的sql语句,那如何打开mysql的慢查询日志记录呢?

mysql> show variables like 'log_slow_queries';
+------------------+-------+
| Variable_name    | Value |
+------------------+-------+
| log_slow_queries | OFF   | 
+------------------+-------+
1 row in set (0.01 sec)

mysql> 

这说明slow log功能没有启用,要启用需要修改mysql的配置文件,在配置文件"[mysqld]"里添加如下俩参数:

long_query_time=1
log-slow-queries=/var/mysql/logs/slow.log

说明
long_query_time
此参数表示的是慢查询的度量时间,单位是秒,最小是1,缺省值是10,凡是执行时间超过long_query_time的sql语句都会记录到慢查询日志中

log-slow-queries[=file_name]
file_name参数可选,缺省值是host_name-slow.log,如果指定了file_name参数的话,mysql就会把慢查询的日志记录到file_name所设定的文件中,如果file_name提供的是一个相对路径,mysql会把日志记录到mysql的data目录中,这个参数只能在配置文件里添加,无法在命令行里执行。

2.将未使用索引查询也记录到slow log中的配置
在mysql的启动配置文件或命令行参数中增加“log_queries_not_using_indexes” 参数就可以把未使用索引查询语句添加到slow log里了。

样例如下:
[root@localhost mysqlsla-2.03]# more /etc/my.cnf 
[mysqld]
datadir=/var/lib/mysql
log_bin=/tmp/mysql/bin-log/mysql-bin.log
log_bin=ON
socket=/var/lib/mysql/mysql.sock
user=mysql
# Default to using old password format for compatibility with mysql 3.x
# clients (those using the mysqlclient10 compatibility package).
old_passwords=1


log_slow_queries=/tmp/127_slow.log
long_query_time=1
log_queries_not_using_indexes

.......

重启mysql后,检查结果如下:

mysql> show variables like 'log_slow_queries';
+------------------+-------+
| Variable_name    | Value |
+------------------+-------+
| log_slow_queries | ON    | 
+------------------+-------+
1 row in set (0.00 sec)

mysql> show variables like 'long_query_time';
+-----------------+-------+
| Variable_name   | Value |
+-----------------+-------+
| long_query_time | 2     | 
+-----------------+-------+
1 row in set (0.00 sec)

mysql>

 

 

--------end------

 

 

转自: http://blog.csdn.net/wyzxg/article/details/7269020



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


ITeye推荐



如何在无显示器的ubuntu下跑selenium

$
0
0

Selenium是一个web自动化测试框架。用它可以实现web应用自动化测试。不过,我不只是用它来做测试,我还用它从电子商务网站签到页面爬取javascript生成的或AJAX的内容。

作为程序员,我不满足于使用Selenium IDE来记录和重放宏记录。那样很蹩脚,而且不适合部署到多台服务器。这时,你需要Selenium WebDriver,它又灵活,而且通过Selenium headless,运行Selenium在服务器上不需要显示设备。

为什么要运行Headless Selenium 测试?

当你希望能在服务器上运行的健壮的自动化操作,而其操作又依赖于 27X7,同时还希望它是稳定的,这时,Selenium是你唯一的选择。但是,Selenium需要运行在浏览器上。所以,你得骗Selenium,让它觉得,它正跑在一台带有显示器的机器上。这样,你就可以不间断的跑自动化测试,同时又不失稳定性和扩展性。

如何在ubuntu上运行Selenium headless

本教程的目标是在使用Mozilla Firefox作为主浏览器的ubuntu上配置和运行selenium headless。

安装Firefox headless

确认你的ubuntu安装的是最新版本的Firefox。我遇到过Selenium的版本和Firefox的版本不兼容问题。如果你没有安装Firefox或者使用的是老版本的Firefox,可按以下步骤升级Firefox:

在/etc/apt/sources.list加入:

ppa:mozillateam/firefox-stable

运行以下命令升级或安装Firefox

sudo apt-get update

sudo apt-get install firefox

运行成功后,ubuntu上就应该安装好最新版本的Firefox了。

安装Xvfb——一个X虚拟框架

这个仿真框架使用虚拟内存能让X-Server运行在没有显示设备的机器上。这样,浏览器就可以运行了。在ubuntu和Debian上安装xvfb,只要运行:

  1. sudo apt-get install xvfb 

现在,可以运行xvfb服务上一个带有数字的显示设备上,这样是为了防止你在下阶段添加设备时引发冲突。本教程,我们分配一个显示设备 10..

  1. sudo Xvfb :10 -ac 

-ac代表关闭xvfb的访问控制。好了,服务器可以运行了。

启动浏览器

在你运行浏览器前,你首先要设置DISPLAY环境变量,以指定xvfb运行在哪个显示设备上。在加入环境变量前,我们检查一下所有的这些都如我们所料:

  1. export DISPLAY=:10   
  2. firefox 

如果终端(terminal)没有显示错误,就说明你已经成功运行Firefox在无显示设备的ubuntu上了。它会一直运行,直到你使用ctrl + C或其它类似方法来终止其运行。同时,它不会有任何输出。

如果你能成功运行以上的步骤,那么接下来的部分就是轻而易举了。现在,我们可以在ubuntu服务器上运行selenium,如同你在本地运行一样。本教程的下一部分,我展示了如何运行一个独立selenium服务器,同时使用PHP的selenium webdriver去连接。

小结

很久以前,我也使用selenium做自动化的集成测试,使用HtmlUnit的webdriver,所以不需要显示器。但是HtmlUnit的表现总是有些不如意。而最近在项目中发现这篇文章,解决我长久以来的问题:在没有显示器的服务器上运行Firefox的集成测试。

而本文,我更多尝试的是意译。有不对的地方,谢谢斧正!

英文原文: http://www.installationpage.com/selenium/how-to-run-selenium-headless-firefox-in-ubuntu/

译文链接: http://my.oschina.net/zjzhai/blog/295288

转发: http://os.51cto.com/art/201407/446726.htm



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


ITeye推荐




黑客是如何远程攻破你的Android手机的

$
0
0

“你走进一个咖啡店坐下来。等咖啡的时候,你拿出你的智能手机开始玩一款你前些天下载的游戏。接着,你继续工作并且在电梯里收邮件。在你不知情下,有攻击者获取了公司网络的地址并且不断地感染你所有同事的智能手机。

等下, 什么?

我们在Bromium实验室博客上不会谈论Android太多。但是不时地我们喜欢修修补补。近来,我的同事Thomas Coudray 和我探索了下Android远程代码执行的易损性,想弄明白易损性在现实应用中是多大的问题。

尽管权限提升技术在Android上很普遍(并形成了“root”设备的惯例),但远程代码执行是一种罕见且危险得多的漏洞。它允许攻击者不经授权就在用户设备上执行特定代码。这个Bug特别另人关注,因为,即使在它被修复后过了18个月,在安装了所有补丁的最新型的Android设备上仍可被利用。我们想看看,如果这是真的,利用此漏洞需要付出多少努力。我们发现上述场景完全可能发生。

我们用了两种不同的方法研究此Bug。首先,我们尝试在类似公共WIFI的环境中利用它,也就是你可能在咖啡店中遇到到环境。我们启动了一些Android设备和廉价的网络设备,开始攻击。第二步是估计普通用户有多大的可能遇到这种最坏的情形。为此,我们使用了统计分析技术,看看有多少有漏洞的App和设备。

在开始细节之前,先了解一下此Bug的背景知识:

背景知识

它始于2012年的Javascript在addJavascriptInterface API中的远程代码执行Bug,CVE-2012-6636(详情见 此处此处)。此Bug允许Javascript代码获得访问系统的更大权限,这并非开发者的本意。至此,如此糟糕。 MWR的研究人员在几个月后的 研究结果显示有大量App使用了广告供应商的框架程序,而这些框架程序通常受此Bug影响而且还在运行时下载Javascript代码。

这些因素结合起来意味着,大量的App采用不安全的方式从互联网下载Javascript代码,因此恶意攻击者劫持下载并发动远程代码执行的攻击并不难。

还没修复?

Android 4.2修复了这个潜在的javascript漏洞。不幸的是,由于向后兼容的原因,修复只意味着在特定的场景中关闭了漏洞。现实中的Android版本碎片化和Android上的广告商业模式意味着这些场景并不常见。我们检查了Google Play上的100,000个APK文件,发现大约有12%即使运行在最新的Android设备上仍然有漏洞风险。

Breakdown of APKs using addJavascriptInterface()

APK分析结果:一半没有漏洞风险,因为它们的目标SDK版本大于或等于17;剩下的31%没有使用存在漏洞的API;7%由于APK混淆或分析出错而没有分析。

另外,不管此漏洞是否被修复, 超过50%的Android设备仍旧使用着低于4.2的版本。对于这些设备,没有修复程序,它们依旧存在漏洞风险。

技术点

为了修复成功,调用addJavascriptInterface的程序必须编译为API 17及以上,也就是说你的目标Android版本必须是4.2及以后的。为了兼容更多的设备,App和框架程序经常用尽可能低的API版本编译。重点就是即使运行在打了补丁程序的Android 4.2, 4.3或4.4的设备上,App仍存在漏洞攻击风险。

广告商业模式在Android中很流行:也就是App免费,开发者通过向用户展示广告而获得收入。在Android中,有超过50个不同的广告框架程序,这使得开发者很容易实现广告功能,事实上他们经常在App中使用不只一个广告框架程序。有的App发现使用了20个之多(见 此处的图4)。这些框架程序大都有这种行为——当app第一次运行时,它们通过HTTP下载javascript库。这也就是说App通常不安全地下载了未验证的javascript代码,而这些代码运行在可执行任意代码的环境中。

代码的执行意味着对设备的无限制访问

迄今为止,这个漏洞仅仅允许一个攻击者在一个安卓应用环境中去执行代码。这很糟糕,但是仍然被安卓权限系统限制在单独的应用中去访问数据。然而,一旦一个攻击者有了一个在系统中的立足点,这就类似于他们可能获得额外的特权。以futex漏洞为例(CVE-2014-3153),它影响当前使用的每个Linux内核版本,包括安卓系统以及最近第一次被成功 root的Galaxy S5。尽管他们不是等价的,但我们还是应该养成“远程代码执行”与“root权限”在严重等级上等价的习惯,因为迟早,一个下定决心的黑客将可能从一个地方蹦到另一个地方,获取设备的完全控制权。

真实世界中的漏洞利用

我们谈了如何利用漏洞和漏洞为什么如此严重。现在我们撇开分析,验证一下漏洞到底有多容易被利用。

五月中旬,我们从Play Store随机下载了102,189个免费的app,并通过统计分析发现其中的12.8%存在潜在的漏洞风险,正如上图所示。这些APK同时使用了过低的目标API版本和addJavascriptInterface API。这些APK调用addJavascriptInterface时的漏洞 实上可以通过中间人攻击的方式利用,当从互联网不安全地下载的javascript脚本时可以发起中间人攻击。

我们会测试通过中间人攻击劫持非安全的javascript下载,并注入一些javascript脚本来探查addJavascriptInterface漏洞。

测试app的漏洞

我们设置了一个充当透明web代理中间人的wifi无线接入点(AP)。它被设置为对任何接入此AP的设备在通过HTTP请求任何脚本时都注入恶意代码。AP设置了密码,以防有人误用,但本方法可以用到公开访问的AP。即使当AP不受控制时,DNS毒化或ARP缓存欺骗等技术也可以用来实现中间人代理。或者可以安装一个模仿成合法AP的假AP。也就是说,有各种方法实现中间人代理,使用wifi的任何人都将通过我们的代理访问网络。

Man in the middle setup

javascript的动态性意味着我们不需要检测特定的应用程序或广告框架程序以作为目标。当运行时,恶意代码扫描整个javascript命名空间中的对象,查找不正确地使用了addJavascriptInterface API的对象,然后对每个进行漏洞测试。如果没有找到漏洞,它就静悄悄地退出,不影响app的运行。如果成功了,它将运行一个shell命令启动计算器app(这是漏洞揭露中的一个传统,表明你完成了代码运行——如何你可以启动计算器,你就证明了可以执行任何代码)。

注入的 javascript片断

function findVulnerableObject() {
   for (var prop in window) {
       try {
           // If getClass() doesn’t throw, the object is vulnerable
           window[prop].getClass();
           return window[prop];
       }
       catch(err) { }
   }
   return null;
}

我设置好AP后,从13,119个标明有潜在漏洞的app中随机选了一些,把它们安装到接入了AP的一台Nexus 5(运行4.4.3)和一台三星XE700t(运行AOSP 4.2的x86平板)。我们只不过是启动每个App,做些简单的交互操作,就成功地在超过半数的应用中触发了远程代码执行,它们加载了通过中间人代理注入的恶意代码。

为了好玩,我们把注入到一个app中javascript代码反复修改,直到显示Bromium的标志替换了原有广告。

被扰乱而显示了Bromium标志的app的UI截屏。

全是广告惹得祸

通过查看TCP/IP包的轨迹,很快发现广告框架程序就是联合使用了addJavascriptInterface和非安全HTTP下载的罪魁祸首。在我们调查的框架程序中没有一个使用HTTPS,也就意味着任何使用这些框架程序的app在非安全地下载javascript时也易受到攻击。以往的研究显示有17%的app虽然使用了HTTPS,但 用法不当,但这是另一回事了。

我们认真地检查了一些app,看看使用用了哪些广告框架。AdMob是用得最多的(通常也是更新最频繁的),但我们发现用到的大量框架仍然在不安全地使用addJavascriptInterface。在检查的app中,有超过80%的非付费app包含了至少一款广告框架。总体上讲,在识别的2140个app中出现了4190个广告框架。

问题有多严重?

Google在Play Store上公布了所有app的大致下载量。仅就我们 手工确认了存在漏洞的小部分用例,就有超过1.5亿的下载量。这并不是说就保证会有150,000,000部有漏洞的设备,因为一台设备可能安装多个不同的有漏洞的应用。但考虑到我们在分析中发现的比例——10%的app有潜在的风险,其中有50%的有风险的app被实地测试可以被攻击——这就存在 非常多有漏洞的设备。

而且,别忘了有57%的Android设备运行在低于4.2的版本上。所以即使明天所有有漏洞的app和框架打上了基于4.2的补丁,仍然有超过一半的Android设备不能修复这个漏洞。

一旦你实现了远程代码的执行,结束之前在咖啡店所描述的灾难情形,不是什么大的进步。初始化一个匹配的root权限(不幸的是,相当一部分在安卓平台上),一个被损害的设备会变成某种中间人,它随后会进入任何网络。因此,攻击开始传播,举例来说,在自带移动设备的世界里,共同的wifi网络是那样地受欢迎。

合并设备分析器(Device Analyser)的数据

设备分析器(Device Analyser)是另外一个用于统计安卓设备的(数据)来源。其中的一项功能就是它追踪用户启动不同的应用的频繁程度。他们用足够地耐心去相互参照潜在缺陷应用的列表上的数据,给出了下面的结果:

每天每用户打开潜在缺陷应用的平均数量

过去一年左右的时间,设备分析器(Device Analyser)的数据显示设备的使用者们每天平均打开0.4-0.5个潜在漏洞的应用。或者换言之,平均一周内就有几次收到(漏洞)攻击。我们不能假设应用的版本比我们分析过存在漏洞的版本新,因此,当我们的示例数据已不再是最新版本,与图形对应也就表现为急剧下降。如果我们对最近的APK版本重新进行我们的分析,我们很有可能看到它仍在0.4分。DA( 设备分析器: Device Analyser)的数据是一个相当小的样本,让它去引导更多地关于安卓设备的结论,在整体上是困难的。

结论

我们发现,通过使用相对简单的中间人代理技术,无需特定的应用程序或设备可以远程运行有危害的应用程序,即使 Android设备安装了完全补丁。使用静态分析我们发现,相当大比例的应用很可能仍然脆弱,我们证实,通过随机测试超过一半的应用确实缺乏抵抗力。

因此,我们建议当连接到一个不可信的wi-fi无线网络时不要使用任何Android应用程序显示广告。

我们感谢Evozi提供他们的APK库,和剑桥大学的设备分析数据。

程序员生存定律-打造属于自己的稀缺性

$
0
0

  假设说你想在江湖里谋求一定的地位,那么你可以练习独孤九剑成为超一流高手,也可以练习医术,成为绝世神医。这两者在江湖里都是有地位的,也都是稀缺的,一者是因为杀伤力,二者是因为人都有山高水长。

  程序员也一样,增值也好,改善表达力也好,最终都要在某种环境下达成一定的稀缺性,这样一个人才有价值。稀缺性同时受两个维度上的力量影响:一个是自身的努力,比如前文所提到的增值和表达力;一个是大环境的变化以及对这种变化的适应。在这一章里主要关注的是后者。

  稀缺性可带给你什么

  既然稀缺性对个人有如此大的影响,那稀缺性到底可以带给一个人什么样的影响,我们来看一个简单的例子:

  在日本曾经有这样一个故事。一个人在某电信公司负责一个大型系统的维护,收入虽然不菲,但时间一长,这个人就对薪资发展不太满意,因此最终选择了离开。结果他一离开,这大型系统立时跑的磕磕绊绊,无奈之下,这家电信公司只得以高职厚薪把这个人请了回来。可以想见为了达到这一目的,这家电信公司,无论在收入还是职位上必然都开出了让这个人无法拒绝的条件。

  这是稀缺性起作用的一个典型例子。大型系统因为关联到庞大的用户群体而必须要用,同时这一系统的维护没有这个人又不行,这就使这个人的稀缺性变得非常突出。

  这事其实很有意思,因为在这里事实上是不好的软件成就了一个人的价值和稀缺性。这虽然不是很好,但其实这类情形并不罕见。从市场的角度来看,它并不关注一个程序的内部逻辑是否清晰,是否有足够的注释,它只关注这东西能不能运作好。所以使用中的垃圾代码一样有巨大的价值,也就是说商业上的考量对稀缺性的影响更大。

  为防止上述文字被曲解,这里补充一点说明。上述道路并非是一条非常值得模仿的道路。因为对上述那个人而言,事实上他的价值绑定于特定的一套系统,这会导致可流动性几乎没有,这就会限制住一个人的成就,并使未来存在很大风险。

  改善稀缺性的途径

  为了改善自己的稀缺性,通常需要同时做两个方面的工作:一是提升自己;一是顺应时势。提升自己可以让自己稀缺这点很好理解,但如果没有顺应时势相配合,就很容易让这种稀缺性无法很好的实现。在 2013 年精通 DOS 编程的人无疑是稀缺的,可这不一定能产生价值。下面我们将从上述两个方面对稀缺性做一点说明。

  1、奔向程序世界里的价值高地

  投资大师巴菲特先生说过一句流传很广的话:有的企业有高耸的护城河,河里头还有凶猛的鳄鱼、海盗与鲨鱼守护着,这才是你应该投资的企业。这句话非常传神的描述了价值高地的外在形象。

  对于企业而言,护城河可以是很多东西:高难的技术(波音飞机)、难以攻破的用户粘度(QQ)、独占的资源(中石油)、独特的企业文化(苹果)等等。

  护城河使企业拥有一种无可取代的价值,从供给上看这就是营造企业自身价值的稀缺性:缺了它不行,你又没有更多选择。这就是价值高地,当企业在这上面时,他相对安全。也正因此,大公司最终都会试图主导一种秩序与生态系统,只有如此大公司才能掌控稀缺性。

  这道理同样适用于个人。稀缺本身可以有很多来源,可以来源于时机,也可以来源于高度。来源于时机的稀缺性更像一种偶然,很容易被打破,往往并不具备长久的价值,相对于人的一生而言,这并非是一种有力支撑。比如:Erlang 可能比较稀少,但单纯的语言壁垒并没有想的那么高,如果真的有巨大需求,这个世界上可以在一个月间多出几百万 Erlang 程序员。

  当一个人经营自己的稀缺性时,确实要找到一个有鳄鱼、海盗和鲨鱼守护的地方,这才是价值高地。当然鳄鱼之类很难是你放的,这与企业不同。在这点上管理方向上和技术方向上的程序员所面临的选择和所需要采取的措施不同。

  对于技术方向上的程序员而言,走向上述这类价值高地本身可以有两种方法:

  一是达到一定高度横向展开。比如:编程语言,(金融)业务逻辑,外语,网络知识等组合在一起就可以成为一个高地,这里面编程语言上一个人可能不如天才程序员,业务逻辑上可能不如银行员工,外语可能不如专职翻译,但每多一重过滤,就会导致高地的海拔拔高一分,最终转换为稀缺性。

  一是彻底的专家型道路。有的岗位可能不需要把面扩的很宽,比如做 TTS,OCR 的算法,有些人甚至编程语言都可能不是了解的很熟,但确实可以是某一方面的专家。这同样是一种价值高地。在这个方向上,一旦真的达到一定高度,那就不是单纯的累积数量可以超越的。比如:认为 100 个或多少个平庸的科学家等价于一个爱因斯坦无疑的是愚蠢的。

  不管是那种方向,最终都要达成这样一种效果:你可以完整的搞定一件很有商业价值的事情,而这件事情大多数人搞不定。比如说:

  • 我可以主导开发一款手机,因为我即懂软件又懂硬件,也还知道如果开发一款良好的产品。现在来看,如果真牛,可以去搞定锤子的问题。
  • 我可以把 OCR 的识别率提高1%。
  • 我可以主导架起百万级并发的网站。
  • 我可以带领队伍搞定这个银行的整个系统。
  • ... ...

  这个时候最好不要用单纯的技术观点来衡量自己,比如我擅长 Java,我会用 PHP,我知道 TCP/IP 协议等等。不是说这没有价值,而是说这种视角有点低端。只有能完整搞定一件事情才会与商业利益直接挂钩,才可能有真正的稀缺性。

  对于管理方向上的程序员,走向上述这类价值高地似乎只有一种途径:

  要努力做出让人记得住的成绩,这个成绩可以是一个产品,也可以是某种业绩。今时今日,提到微信相信大家都会想到张小龙。这是因为微信本身在不到两年的时间里吸引了 2 亿用户,并且口碑很好,实在是个奇迹。

  关于价值高地,有一个典型的陷阱:不含复杂度的,特属于某个公司的经验,往往让人误以为是价值高地,但其实不是,因为只要环境相对的公开,这类东西往往可以在短时间内被攻破。比如:一个公司可能定义了自己的流程,其中很多东西较为模糊,新人一做就处处碰壁。这很容易让然误解为掌握流程本身有较高的价值,但其实这是由于流程不完善所造成的,是特定场景下的一种偶然。这确实导致稀缺性,但基本不具备可流动性,大多时候未必是好的选择。

  需求开发算价值高地么?

  在偏敏捷的组织里程序员往往离需求很近,但在比较传统的开发方法中,做需求的和程序员往往是有段距离的。做需求开发的可能不太会写程序,写程序的不太会写需求。

  那需求开发算价值高地么?

  很多纯粹的程序员可能觉得单纯的文档工作没什么技术含量,似乎谁都能写,因此可能认为这算不上什么价值高地。但从商业价值来看,当一个人摸透某个行业的业务(懂技术更好),那么这还真是价值高地。

  这可以来做个类比,天猫只做平台,各个商家卖东西,那么天猫有价值么?当然有价值,天猫 11/11 的销售额 100 多亿比美国的黑色星期五还高,怎么可能没有价值。

  那为什么天猫有价值?因为终端客户的眼里是先有天猫,再有各个商家,天猫垄断了入口,所以天猫更有价值。

  需求与开发的关系与此类似。当一个人做某个产品的需求时,在外人的眼里,这个人做的需求才表征着这个产品,透过产品才能看到程序员的贡献。外部人员思考的思路是先需求开发人员再程序员。

  其中比较极端的一种实践是需求开发人员主导整个项目,所有其他人员在需求开发人员的领导下工作。

  这个时候钻牛角尖是没意义的,比如:有的人可能认为没程序员那有产品,这就和争论没店家那来天猫一样,毫无意义。在现实中当然两者都有存在价值,这里讨论的只是说这是否算是一块价值高地。

  2、走在技术大潮的前面或里面

  IT 世界里,城头变幻大王旗来的特别的快,而每一次变幻时事实上都将导致某种技术的兴起或者某种技术的衰落。

  当年 WPS97 的开发时间非常长,对此百度百科上对此的描述是:Windows 有很多新东西,我们还没有熟悉过来,微软又升级了。很多技术资料,也很难找到。微软掌握着 Windows,而我们什么都要靠自己从头做起,这导致了 WPS97 难产。如果 WPS97 能在 1995 年推出,直接和 Word6.0 竞争,Word6.0 肯定没戏。

  这很生动的记述了一门新技术兴起时所造成的稀缺性,从侧面也可看出来,在 95 年的时候企业对高端 Windows 开发人员是何等的渴望。这种稀缺性是行业周期背后的技术更迭所造成的。而在今天,借助搜索引擎,初入行的程序员也可以解决大部分 Windows 编程的问题。

  面对这种技术潮流,比较合适的办法是基于现实勇敢拥抱新技术。

  基于现实是指考虑技能的可流动性,考虑实践和学习的不可以分离特质,选择自己认为前景好的新技术,并投入时间。但这里面有个陷阱,一提到新技术很多人可能会联想到新编程语言,但编程语言太基础了,壁垒太低,并不是一个足够大的考量区域。视角如果限在这个尺度上,看到的东西就会太多,而不容易聚焦,这时候需要把自己考量的单位适当放大一点,英文中常用 Tech Stack 这个词来描述这一组技术。

  比如说:LAMP (Linux+Apache+MySQL+Perl/PHP/Python)可以是一种考量单位,Windows 编程 +ASP.NET 也可以是一种考量单位,大数据处理相关种种也可以是一种考量单位。

  如果回望十年,我们就会发现,先有 PC 客户端程序的鼎盛,接下来是互联网的兴起,再接下来则是移动客户端的兴旺。以当下而论,无疑的移动客户端和互联网要比传统的 PC 客户端来的更有吸引力。而在云的时代里,壁垒比较分明的两套 Tech Stack 则是基于闭源的一系列技术(主要是由微软提供)和基于开源的一系列技术。在这里面如果那个 Tech Stack 的技术逐渐取得优势,那么无疑的在相应的 Tech Stack 中有积累的人会有比较好的稀缺性。

  虽然眼下看来,两者似乎没有明显差别,但在这点上,我个人认为未来开源 Tech Stack 会逐渐取得优势。在 Quora (quora.com)和 High Scalability (highscalability.com)上,我们可以查找到国外大部分新兴的、市值超过 10 亿美元 Web2.0 网站的技术架构,如:Flickr,Pinterest,Instagram 等。如果用心来读这些技术架构,就会发现他们一个根本的共同点:他们都是基于开源技术构建的。

  这种不约而同的选择背后有一定的必然性。当希望一定的定制性并且不愿意支付高额成本时开源 Tech Stack 几乎是一种唯一的选择,尤其是当开源的技术有越来越多成功实例的时候,这种优势就越来越明显。

  如果非要在客户端(iOS,Android,WinRT)和互联网中选择,我个人认为互联网比客户端更有优势。

  技术落潮所伴随的风险

  很多人会讲微软在 2002 到 2012 这 10 年里几乎无所作为,也会谈论从股票上来看如果 10 年前买入的是微软股票那么现在只能赚 30~40%,而如果是买的苹果股票那就要赚 3 倍多。我个人偶尔思维发散,想到的却不只是这个,而是如果微软再失去 10 年,那挂掉的不只是微软,还有同微软绑在一起的各种公司和个人,包括很多资深的 Windows 程序员。

  在 PC 的世界里微软是无疑的霸主,但如果 PC 的时代过去了,那么这个霸主如果无法转型成功,那么无疑也要随之殉葬。而那个时候无数在微软平台上花了半生心血的人却还都在,他们又该何去何从?

  技术大潮的兴起会使潮头的很多人称为耀眼的明星,而某波潮水的退去,同样会带走与之相伴的一些人的光环。所不同的是前者轰轰烈烈,而后者寂寂无声。

  在这种情境下,还真就只能与时俱进。

  检查自己的稀缺性

  从社会需要的角度检查自己的稀缺性非常困难,因为相关的各种数据总是非常缺乏。但有个简单的方法可以很快的让一个人认清自己的稀缺性:假设一个毕业生很努力的学,那么多久他可以取代你的工作?比如一个毕业生只要努力,那么可以在一两年取代你,而你的年纪已经接近 30 岁,那么稀缺性必然非常不好。

  而与这个相反,如果一个毕业生即使很努力,也要五年才有你的技术水平,同时如果没有特定的机缘,怎么也无法取代你,那么即使你已经 30 岁,你的稀缺性也会非常好。这里的机缘可以是指某些特别的实践机会。

  如果想比较系统的评估自己的稀缺性,那么需要依次考虑如下问题:

   自己所掌握的技术是即将过时的技术么?

  技术大潮总是会定时的淘汰各种技术,不同的时间点淘汰的对象也不太相同。有的虽然不是完全淘汰,但至少他们不再像当年那么辉煌了,如果以 2013 为界限而回看 10 年,那这样的技术有:Flash,MFC,Delphi 等。

  为保持对技术动向的敏感度,定期阅读别人的架构非常关键。

  当然可能过时的技术不单指通用的技术,还指老旧的可能会为新解决方案所替代的系统。比如说:曾经很多公司使用 Lotus Notes 来做知识管理的,但很少人使用这样的系统了。

   自己所掌握的技能究竟有多少人会?

  考察这点时要像前文所描述的,更多的从公司的视角去考虑,而不是个人的视角。单纯的会使用某个语言或者框架这种程度,稀缺性一定没有。比如:单纯的会用 ASP.net 开发网页几乎没有较高的技术壁垒,但对数据库的设计有相当程度的掌握、能够较好的通过负载均衡、缓存等手段保证系统的性能就可以使自己的稀缺性上个台阶。

谷歌上市10周年 员工总结6条成功经验

$
0
0

昨天是谷歌上市 10 周年的纪念日(美国时间是今天),时间真的是过得很快,回想起来还感觉像昨天一样,当年的各种媒体不看好,到各种不遵守传统规矩的上市方式(荷兰式拍卖融资),都引起很多争议,但 10 年过去了,谷歌的股价升了十几倍,从金融的角度已经是无容置疑了,但这个成功的公司背后其实也是经历了无数波折,我是 2000 年进入谷歌的美国总部,当时它还是一家小公司(我是 103 号员工),有很多鲜为人知的事情。

商业模式往往是摸出来的

我是谷歌 Adwords 广告系统的第一个工程师,当年刚刚进去的时候我老板说“咱们该试试把赚钱这个事情规范了”,今天广告收入占了谷歌绝大部分的收入,但是当年公司还不确定广告是个未来,甚至我们三个做 Adwords 的工程师都自己互相问了个很傻的问题:这种广告你会点击吗?我们没有一个人点击过广告,也觉得自己这辈子也不会去点击广告,那这个事情还有意义吗?可是事实证明,我们不点不代表普通大众不点!

没有完美的产品

第一代的 Adwords 广告系统只有三个工程师(有一个还是兼职的),加上一个 UI 设计师,没有产品经理,是的,那个年代谷歌还没有产品经理这个角色,很多人早期看见谷歌的产品都觉得做得很好很人性化,但这些产品都是没有产品经理去负责的,就是三种人把产品死啃出来的:UI 设计师,工程师,小组经理。没有产品经理确实有很多问题,但产品照样做出来了,而且无比快速,三个月就完成了(包括测试,运维,前期还试用了 PHP,中间还有 Lisp 的实验!)。第一代产品确实有很多问题,但这些问题都不重要,因为没有太多用户!

“技术很强”

大家都认为谷歌的技术是互联网公司里面最强的,各种算法和数据,大牛们都爱加入,但其实在早期的时候谷歌很多技术是很差的(起码从今天的角度来看),谷歌的第一行 Java 代码是我提交的,当时也没有正式的 code review,没有单元测试,代码规范才刚刚开始有,而且没有 bug tracking 数据库!估计今天的软件公司很难想象没有这样子的数据库是怎么管理 bugs 的,但当年的谷歌也活的好好的!所以在这里给所有的技术大牛一个忠告:谷歌也只是“足够好”就可以了,用户体验才是最重要!

交流成本几乎为零

早期的时候几乎没什么邮件来回,也没什么会议(最多也就三个人讨论),很多事情就记录在便签上(纸质的,不是软件),因为没有 bug tracking 数据库,也不需要花时间去把 bugs 过一遍。没有报告,没有流程,我当时的老板甚至连电脑都几乎可以不用(她是斯坦福计算机博士毕业的)。回想起来确实有点乱,但出来的产品还是挺好的!其实很多人都不会写邮件,不是因为他们的写作能力有问题,而是邮件是一个没有发送成本的工具,比如要是发一封邮件需要发件人付款 10 块的话,再夸张点是每 100 字 10 块,我相信很多公司的交流成本会大幅下降,因为每个人发邮件之前都会先仔细想想自己想说什么。很多人没有意识到发邮件花时间,其实看邮件可能更花时间,因为写的是一个人(比如花 5 分钟),看的可能是 10 个人(每人花 1 分钟),对公司来说就是看的时间比写的时间多。

管理是实验出来的

我进入谷歌的时候管理层有三层:CEO,VP,经理。后来 Larry Page 想试试更扁平化,就变成:CEO,VP。当 100 个工程师汇报给一个 VP 不行以后才把产品经理和管理经理这些角色给慢慢建立起来。也是经历了这些以后才摸索出来单元测试和很多流程的东西,回想起来真的是很乱,但也没有对业务造成大问题。

对每个人要信赖

第一代的 Adwords 广告系统上线的时候运维就基本上只有我,还有一个很有经验的运维带着我,但他只能给我一点点时间(他是每天睡四个小时的人),产品上线的流程是。。。没有流程!我写了个简单的文件和脚本,其他人过了一下就上线了!我当时犯了无数错误(毕竟我没做过运维),有一些公司都没人知道(否则可能当时就被解雇了,比如我曾经把一部分用户的数据不小心清空了,还好找回备份了),但是因为公司给了我很大的信任,所以我犯了错马上就改。创业公司一定是会犯很多错误,很多人的方法论是尽量去避免这些错误的发生,所以会出来很多流程的东西,但是当用户量不多的时候,更重要的是做好准备出错,先想想出错了以后弥补的方法。

作者目前为 B2C 网站 lightinthebox 天使投资人。

本文链接

solrCloud+tomcat+zookeeper集群配置

$
0
0

概述:

     SolrCloud是基于Solr和Zookeeper的分布式搜索方案,它的主要思想是使用Zookeeper作为集群的配置信息中心。

它有几个特色功能:

1)集中式的配置信息

2)自动容错

3)近实时搜索

4)查询时自动负载均衡

 

安装zookeeper

   上面也说了  SolrCloud是基于Solr和Zookeeper的分布式搜索方案,所有要部署solrCloud+tomcat+zookeeper的集群,必须先安装zookeeper

安装环境:

   Liux: CentOS release 6.4

   JDK:1.7.0_55

   因为我研究的是solr最新的版本,所以研究的是solr4.8.0然后solr4.8.0必须跑在jdk1.7以上的版本

1、zookeeper是个什么玩意?

答:顾名思义zookeeper就是动物园管理员,他是用来管hadoop(大象)、Hive(蜜蜂)、pig(小猪)的管理员, Apache Hbase和 Apache Solr 的分布式集群都用到了zookeeper;Zookeeper:是一个分布式的、开源的程序协调服务,是hadoop项目下的一个子项目;

2、zookeeper伪集群安装

        因为我演示的这套安装是单机版的安装,所以采用伪集群的方式进行安装,如果是真正的生成环境,将伪集群的ip改下就可以了,步骤是一样的,学会了伪集群安装,真正生产的多环境安装不会,那是不可能的一件事情。

第一步:下载最新的zooper软件:http://www.apache.org/dyn/closer.cgi/zookeeper/



 

第二步:为了测试真实我在我linux上面部署三个zookeeper服务

创建zookeeper的安装目录
[root@localhost solrCloud]# mkdir /usr/solrcould

 

     将下载的zookeeper-3.3.6.tar.gz复制到该目录下,同时在/usr/solrcould目录下新建三个文件夹:如下所示:

[root@localhost solrcoulud]# ls
service1  service2  servive3  zookeeper-3.3.6.tar.gz

 

   然后在每个文件夹里面解压一个zookeeper的下载包,并且还建了几个文件夹,总体结构如下:

[root@localhost service1]# ls
data  datalog  logs  zookeeper-3.3.6

 

   首先进入data目录,创建一个myid的文件,里面写入一个数字,比如我这个是server1,那么就写一个 1,server2对应myid文件就写入2,server3对应myid文件就写个3然后进入zookeeper/conf目录,如果是刚下过来,会有3个文件,configuration.xml, log4j.properties,zoo_sample.cfg,我们首先要做的就是在这个目录下创建一个zoo.cfg的配置文件,当然你可以把zoo_sample.cfg文件改成zoo.cfg,配置的内容如下所示:

 service1 的zoo.cfg:

# The number of milliseconds of each tick
tickTime=2000
# The number of ticks that the initial 
# synchronization phase can take
initLimit=5
# The number of ticks that can pass between 
# sending a request and getting an acknowledgement
syncLimit=2
# the directory where the snapshot is stored.
dataDir=/usr/solrcould/service1/data
dataLogDir=/usr/solrcould/service1/datalog
# the port at which the clients will connect
clientPort=2181
server.1=192.168.238.133:2888:3888
server.2=192.168.238.133:2889:3889
server.3=192.168.238.133:2890:3890

 

service2 的zoo.cfg:

# The number of milliseconds of each tick
tickTime=2000
# The number of ticks that the initial 
# synchronization phase can take
initLimit=5
# The number of ticks that can pass between 
# sending a request and getting an acknowledgement
syncLimit=2
# the directory where the snapshot is stored.
dataDir=/usr/solrcould/service2/data
dataLogDir=/usr/solrcould/service2/datalog
# the port at which the clients will connect
clientPort=2182
server.1=192.168.238.133:2888:3888
server.2=192.168.238.133:2889:3889
server.3=192.168.238.133:2890:3890

 

 service3 的zoo.cfg:

# The number of milliseconds of each tick
tickTime=2000
# The number of ticks that the initial 
# synchronization phase can take
initLimit=5
# The number of ticks that can pass between 
# sending a request and getting an acknowledgement
syncLimit=2
# the directory where the snapshot is stored.
dataDir=/usr/solrcould/service3/data
dataLogDir=/usr/solrcould/service3/datalog
# the port at which the clients will connect
clientPort=2183
server.1=192.168.238.133:2888:3888
server.2=192.168.238.133:2889:3889
server.3=192.168.238.133:2890:3890

 参数说明:

tickTime:zookeeper中使用的基本时间单位, 毫秒值.

initLimit: zookeeper集群中的包含多台server, 其中一台为leader, 集群中其余的server为follower。 initLimit参数配置初始化连接时, follower和leader之间的最长心跳时间. 此时该参数设置为5, 说明时间限制为5倍tickTime, 即5*2000=10000ms=10s.

syncLimit: 该参数配置leader和follower之间发送消息, 请求和应答的最大时间长度. 此时该参数设置为2, 说明时间限制为2倍tickTime, 即4000ms.

dataDir: 数据存放目录. 可以是任意目录.但是我喜欢这么干

dataLogDir: log目录, 同样可以是任意目录. 如果没有设置该参数, 将使用和dataDir相同的设置

clientPort: 监听client连接的端口号.

server.X=A:B:C 其中X是一个数字, 表示这是第几号server. A是该server所在的IP地址. B配置该server和集群中的leader交换消息所使用的端口. C配置选举leader时所使用的端口. 由于配置的是伪集群模式, 所以各个server的B, C参数必须不同.

 

   配置说明:

      需要注意的是clientPort这个端口如果你是在1台机器上部署多个server,那么每台机器都要不同的clientPort,比如我server1是2181,server2是2182,server3是2183,dataDir和dataLogDir也需要区分下。

      最后几行唯一需要注意的地方就是 server.X 这个数字就是对应 data/myid中的数字。你在3个server的myid文件中分别写入了1,2,3,那么每个server中的zoo.cfg都配server.1,server.2,server.3就OK了。因为在同一台机器上,后面连着的2个端口3个server都不要一样,否则端口冲突,其中第一个端口用来集群成员的信息交换,第二个端口是在leader挂掉时专门用来进行选举leader所用。

  

到这里zookeeper的配置就这么配玩了,你没有看错,就是这么简单!

第四步:当然是启动zookeeper

     进入zookeeper-3.3.2/bin 目录中,./zkServer.sh start启动一个server,这时会报大量错误?其实没什么关系,因为现在集群只起了1台server,zookeeper服务器端起来会根据zoo.cfg的服务器列表发起选举leader的请求,因为连不上其他机器而报错,那么当我们起第二个zookeeper实例后,leader将会被选出,从而一致性服务开始可以使用,这是因为3台机器只要有2台可用就可以选出leader并且对外提供服务(2n+1台机器,可以容n台机器挂掉)。

[root@bogon bin]# sh zkServer.sh start  #启动
JMX enabled by default
Using config: /usr/solrcould/service3/zookeeper-3.3.6/bin/../conf/zoo.cfg
Starting zookeeper ... STARTED 
[root@bogon bin]# sh zkServer.sh status #查看当前状态,他会报异常,不要紧,因为是集群,其他两台没有起来,无法进行相互连接,当然报错,启动另外两台就不会报错了!
JMX enabled by default
Using config: /usr/solrcould/service3/zookeeper-3.3.6/bin/../conf/zoo.cfg
Error contacting service. It is probably not running

 

 
 进入不同的zookeeper的bin,分别启动,常用命令如下

启动ZK服务:       sh zkServer.sh start
 查看ZK服务状态:   sh zkServer.sh status
 停止ZK服务:       sh zkServer.sh stop
 重启ZK服务:       sh zkServer.sh restart

 

3、补充单机配置,和实际集群配置

单机部署:进入zookeeper/conf目录,如果是刚下过来,会有3个文件,configuration.xml, log4j.properties,zoo_sample.cfg,这3个文件我们首先要做的就是在这个目录下创建一个zoo.cfg的配置文件,当然你可以把zoo_sample.cfg文件改成zoo.cfg,配置的内容如下所示:

tickTime=2000  
dataDir=/Users/apple/zookeeper/data  
dataLogDir=/Users/apple/zookeeper/logs  
clientPort=4180

 进入zookeeper-3.3.2/bin 目录中,./zkServer.sh start启动,单机便完成安装

 

实际集群部署:集群模式的配置和伪集群基本一致,由于集群模式下, 各server部署在不同的机器上, 因此各server的conf/zoo.cfg文件可以完全一样.

下面是一个示例:

tickTime=2000  
initLimit=5  
syncLimit=2  
dataDir=/home/zookeeper/data  
dataLogDir=/home/zookeeper/datalog  
clientPort=4180
server.43=10.1.39.43:2888:3888
server.47=10.1.39.47:2888:3888  
server.48=10.1.39.48:2888:3888
需要注意的是, 各server的dataDir目录下的myid文件中的数字必须不同.

 

 

 

solr集群部署 

    我的理解,其实安装solrCloud非常的简单,就是先安装zookeeper然后安装solr 最后将zookeeper和tomcat进行关联就ok了,如此的简单。

第一步:准备软件

    Jdk、tomcat这些安装在我的文档里面是省略的,如果这两个东西都不会安装,你来安装solr集群,那就是非常扯淡的一件事情

    再次提醒,如果是solr4.8或者以上的版本,记得把jdk升级到1.7以上,否则tomcat起不来。

第二步:在tomcat部署solr,可以参考我的另外一篇博客地址如下:

  http://eksliang.iteye.com/blog/2096478,参考上面的企业级安装

  你可以参考下我的目录结构

[root@bogon solrcould]# ls
service1  service2  service3  tomcat1  tomcat2  tomcat3  tomcat4

 

   这一步就是简单的在4个tomcat上面部署solr,没有做其他任何操作,因为是在同一台机子上面的部署,请记得修改tomcat的端口号。

第三步:配置zookeeper和各个tomcat进行关联

      修改solr的所在tomcat所在服务器,在${tomcat_home}/bin/目录下修改catalina.sh

      在第一行添加:

      这是我的实例:

    tomcat1:配置如下:

JAVA_OPTS="$JAVA_OPTS -DzkHost=192.168.238.133:2181,192.168.238.133:2182,192.168.238.133:2183 -Dbootstrap_confdir=/usr/solrcould/tomcat1/display/solrhome/collection1/conf -Dcollection.configName=myconf  -DnumShards=3"

 

   其他tomcat:配置如下:

JAVA_OPTS="$JAVA_OPTS -DzkHost=192.168.238.133:2181,192.168.238.133:2182,192.168.238.133:2183 -DnumShards=3"

 

参数说明:

-DzkRun  在Solr中启动一个内嵌的zooKeeper服务器,该服务会管理集群的相关配置。单机版(测试)使用,如果是集群,用下面的-DzkHost来替换,含义一样

例如:

JAVA_OPTS="$JAVA_OPTS -DzkRun  -Dbootstrap_conf=true -DnumShards=2"

 

-DzkHost 跟上面参数的含义一样,允许配置一个ip和端口来指定用那个zookeeper服务器进行协调

   例如:

JAVA_OPTS = "$JAVA_OPTS 
-DzkHost=192.168.56.11:2181,192.168.56.12:2181,192.168.56.13:2181
-Dbootstrap_conf=true
-DnumShards=2"

 

 -Dbootstrap_confdir :zooKeeper需要准备一份集群配置的副本,所以这个参数是告诉SolrCloud这些     配置是放在哪里。同时作为整个集群共用的配置文件

-Dcollection.configName 是在指定你的配置文件上传到zookeeper后的名字,建议和你所上传的核心名字一致,这样容易识别,当然你也可以在满足规范的情况下自己起名。

-bootstrap_conf=true将会上传solr/home里面的所有数据到zookeeper的home/data目录,也就是所有的core将被集群管理

-DnumShards=2 配置你要把你的数据分开到多少个shard中  

-Djetty.port =8080 这个端口跟你所在端口保持一致,这个就是jetty的监听端口,实现集群之间进行通信的,如果这个端口不这样配置,那么就是搜索不到数据

当然这个参数也可以再solr/home/solr.xml下面配置:如下所示

<solrcloud><str name="host">${host:}</str><int name="hostPort">${jetty.port:8080}</int><str name="hostContext">${hostContext:solr}</str><int name="zkClientTimeout">${zkClientTimeout:30000}</int><bool name="genericCoreNodeNames">${genericCoreNodeNames:true}</bool></solrcloud>

 默认是8983,如果在catalina.sh中指定了,会覆盖上图solr.xml中配置的

 

注意

 

 -DnumShards, -Dbootstrap_confdir和-Dcollection.configName参数只需要在第一次将Solr运行在SolrCloud模式的时候声明一次。它们可以把你的配置加载到     zooKeeper中;如果你在日后重新声明了这些参数重新运行了一次,将会重新加载你的配置,这样你在原来配置上所做的一些修改操作可能会被覆盖。所以官方推荐只在第一个tomcat里面加入这几个参数,其他集群的tomcat里面不加,启动的第一个Solr的端口号,它是你的SolrCloud集群的overseer节点 

 

 第四步:修改jetty的监听端口

    修改solr.xml,该文件在你部署solr时自己定的工作目录,例如我的配置在如下地址:

<env-entry><env-entry-name>solr/home</env-entry-name><env-entry-value>usr/solrcould/tomcat4/display/solrhome</env-entry-value><env-entry-type>java.lang.String</env-entry-type></env-entry>

 

 改动如下:

<int name="hostPort">${jetty.port:8983}</int>  改为跟你所在tomcat的端口改成一样
<int name="hostPort">${jetty.port:8080}</int>

 

这个端口的作用: -Djetty.port =8080 这个端口跟你所在端口保持一致,这个就是jetty的监听端口,实现集群之间进行通信的,如果这个端口不这样配置,那么就是搜索不到数据

 

然后依次启动tomcat



 看到了没有,这就是启动了,一个有三个节点的集群

 

 

   参考文献:http://my.oschina.net/zengjie/blog/197960#OSC_h2_1

 



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


ITeye推荐



loosejar原理简要分析

$
0
0
 loosejar这个小工具可以动态分析出应用中有每个jar包的实际使用情况,详情请参阅 《通过loosejar清理应用中冗余的jar包》基本原理是利用instrumentation的特性用 Instrumentation,开发者可以构建一个独立于应用程序的代理程序(Agent),用来监测和协助运行在 JVM 上的程序,甚至能够替换和修改某些类的定义。有了这样的功能,开发者就可以实现更为灵活的运行时虚拟机监控和 Java 类操作了。关于instrumentation的详细介绍,可以参阅这篇文章 《Java SE 6 新特性: Instrumentation 新功能》

private Map<ClassLoader, List<String>> createClassLoaderMap()
  {
    //创建一个map,key是classloader,value是由这个classloader所加载的类的名称组成的一个list
    Map<ClassLoader, List<String>> map = new HashMap();
    //instrumentation这个方法可以的得到由所有被classloader加载的类组成的一个数组
    Class<?>[] loadedClasses = this.instrumentation.getAllLoadedClasses();
//格式化打印出上面方法返回数组的长度
    Logger.log(String.format("Found %d classes loaded in the JVM.", new Object[] { Integer.valueOf(loadedClasses.length) }));
    //遍历所有被加载的类
for (Class<?> c : loadedClasses)
    {
      //获取加载当前类的classloader
 ClassLoader cl = c.getClassLoader();
 //如果当前类的加载器不为null,就判断map中是否已经有这个加载器了
      if (cl != null) {
//如果map中已经有了这个classloader,就将当前类的名字添加到与classloader对应的list当中
        if (map.containsKey(cl))
        {
          ((List)map.get(cl)).add(c.getName());
        }
//如果map中没有这个classloader,就创建一个新的list,将当前类的名称放到list中
//然后将classloader和这个list添加到map中
        else
        {
          List<String> classNames = new ArrayList();
          classNames.add(c.getName());
          map.put(cl, classNames);
        }
      }
    }
//格式化打印出map中classloader的数量
    Logger.log(String.format("Found %d various ClassLoader(s) inside the JVM.", new Object[] { Integer.valueOf(map.size()) }));
    //返回map
return map;
  } 


作者:Derek_BMW 发表于2014-8-21 22:09:04 原文链接
阅读:145 评论:0 查看评论

Spring4.1新特性——Spring MVC增强

$
0
0

目录

Spring4.1新特性——综述

Spring4.1新特性——Spring核心部分及其他

Spring4.1新特性——Spring缓存框架增强

Spring4.1新特性——异步调用和事件机制的异常处理

Spring4.1新特性——数据库集成测试脚本初始化

Spring4.1新特性——Spring MVC增强

Spring4.1新特性——页面自动化测试框架Spring MVC Test HtmlUnit简介

Spring4.1新特性——静态资源处理增强

 

Spring 4.1对Spring MVC部分做的增强是最多的,提供了一些视图解析器的mvc标签实现简化配置、提供了GroovyWebApplicationContext用于Groovy web集成、提供了Gson、protobuf的HttpMessageConverter、提供了对groovy-templates模板的支持、JSONP的支持、对Jackson的@JsonView的支持等。

 

1、GroovyWebApplicationContext 

在Spring 4.1之前没有提供Web集成的ApplicationContext,在《 Spring4新特性——Groovy Bean定义DSL》中我们自己去实现的com.sishuok.spring4.context.support.WebGenricGroovyApplicationContext,而4.1其已经提供了相应实现,直接把《 Spring4新特性——Groovy Bean定义DSL》配置中的相应类改掉即可。

 

2、视图解析器标签

之前我们都是这样定义视图解析器:

<bean id="mvcVelocityEngine" class="org.springframework.web.servlet.view.velocity.VelocityConfigurer"><property name="resourceLoaderPath" value="/WEB-INF/vm/,classpath:com/github/zhangkaitao" /></bean><bean id="viewResolver" class="org.springframework.web.servlet.view.velocity.VelocityViewResolver"><property name="prefix" value=""/><property name="suffix" value=".vm"/><property name="cache" value="false"/></bean>

而现在我们可以使用MVC标签定义: 

<mvc:velocity-configurer resource-loader-path="/WEB-INF/vm/,classpath:com/github/zhangkaitao"/><mvc:view-resolvers><mvc:velocity cache-views="false" prefix="" suffix=".vm"/></mvc:view-resolvers>

 

再来看一个更复杂的例子: 

<mvc:velocity-configurer resource-loader-path="/WEB-INF/vm/,classpath:com/github/zhangkaitao"/><mvc:groovy-configurer resource-loader-path="classpath:templates/" cache-templates="false"/><mvc:view-resolvers><mvc:content-negotiation><mvc:default-views><bean class="org.springframework.web.servlet.view.json.MappingJackson2JsonView"><property name="jsonpParameterNames"><set><value>jsonp</value><value>callback</value></set></property></bean></mvc:default-views></mvc:content-negotiation><mvc:velocity cache-views="false" prefix="" suffix=".vm"/><mvc:groovy cache-views="false" suffix=".tpl"/></mvc:view-resolvers>

mvc:content-negotiation用于定义内容协商的视图解析器,且内部可以定义默认视图;然后我们又定义了mvc:velocity和mvc:groovy两个视图解析器;它们会按照顺序进行解析。另外几个视图解析器是:

 

mvc:freemarker

mvc:bean-name

mvc:jsp

 

这种方式有一个很大的问题就是只能做默认配置,如果想自定义其属性值就搞不定了,估计当时开发的人考虑不全或没有经验。

 

3、控制器标签

Spring 4.1提供了更丰富的控制器标签:

3.1、重定向视图控制器标签

<mvc:redirect-view-controller
            path="/redirect"
            redirect-url="/status"
            context-relative="true"
            status-code="301"
            keep-query-params="true"/>

3.2、状态控制器标签

<mvc:status-controller path="/status" status-code="200"/>

3.3、带状态的视图控制器标签

<mvc:view-controller path="/error/**" status-code="200"/>

   

4、Groovy Template引擎集成

Spring 4.1提供了对 Groovy Template模板引擎的集成,其是一种DSL风格的模板引擎,其也是最早在Spring Boot中引入的。

4.1、Spring配置文件    

<mvc:groovy-configurer resource-loader-path="classpath:templates/" cache-templates="false"/><mvc:view-resolvers><mvc:groovy cache-views="false" suffix=".tpl"/></mvc:view-resolvers>

4.2、模板heelo.tpl

yieldUnescaped '<!DOCTYPE html>'
html {
  head {
    title('hello groovy templates')
  }
  body {
      div("hello $user.name")
  }
}

具体语法请参考官方文档。

 

5、 Jackson @JsonView支持 

可以使用@JsonView来分组渲染JSON数据,按需展示JSON数据。

5.1、模型

public class User implements Serializable {
    public static interface OnlyIdView {}
    public static interface OnlyNameView {}
    public static interface AllView extends OnlyIdView, OnlyNameView {}

    @JsonView(OnlyIdView.class)
    private Long id;

    @JsonView(OnlyNameView.class)
    private String name;  
    ……
}

定义了三个视图:OnlyIdView、OnlyNameView和AllView。

 

5.2、控制器

@RestController
public class JacksonJsonViewController {

    @RequestMapping("/jackson1")
    @JsonView(User.OnlyIdView.class)
    public User test1() {
        return new User(1L, "zhangsan");
    }

    @RequestMapping("/jackson2")
    @JsonView(User.OnlyNameView.class)
    public User test2() {
        return new User(1L, "zhangsan");
    }

    @RequestMapping("/jackson3")
    @JsonView(User.AllView.class) //可以省略
    public User test3() {
        return new User(1L, "zhangsan");
    }
}

使用@JsonView控制渲染哪些数据。

 

6、Jsonp支持  

6.1、MappingJackson2JsonView提供的支持 

<bean class="org.springframework.web.servlet.view.json.MappingJackson2JsonView"><property name="jsonpParameterNames"><set><value>jsonp</value><value>callback</value></set></property></bean>

然后访问如http://localhost:8080/json?callback=callback即可得到JSONP响应:callback({"user":{"id":1,"name":"zhangsan"}});。

 

6.2、对使用HttpMessageConverter的@ResponseBody的支持 

@Order(2)
@ControllerAdvice(basePackages = "com.github")
public class JsonpAdvice extends AbstractJsonpResponseBodyAdvice {
    public JsonpAdvice() {
        super("callback", "jsonp"); //指定jsonpParameterNames
    }
}

访问http://localhost:8080/jackson1?callback=callback即可看到JSONP响应。 

 

@ContollerAdvice的作用请参考《 Spring3.2新注解@ControllerAdvice》,basePackages用于指定对哪些包里的Controller起作用。

 

6.3、ResponseBodyAdvice

我们之前实现的JsonpAdvice其继承自AbstractJsonpResponseBodyAdvice,而AbstractJsonpResponseBodyAdvice继承自ResponseBodyAdvice,其作用是在响应体写出之前做一些处理: 

@Order(1)
@ControllerAdvice(basePackages = "com.github")
public class MyResponseBodyAdvice implements ResponseBodyAdvice<Object> {

    @Override
    public boolean supports(MethodParameter methodParameter, Class<? extends HttpMessageConverter<?>> converterType) {
        return methodParameter.getMethod().getReturnType().isAssignableFrom(User.class);
    }

    @Override
    public Object beforeBodyWrite(
            Object obj, MethodParameter methodParameter, MediaType mediaType,
            Class<? extends HttpMessageConverter<?>> converterType,
            ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {

        User user = ((User)obj);
        user.setName("---" + user.getName() + "---");
        return user;
    }
}

1、supports指定支持哪些类型的方法进行处理,此处是返回值为User的;2、我们得到User对象然后在名字前后拼上”---“ ;3、可以指定多个ResponseBodyAdvice,使用@Order指定顺序。访问http://localhost:8080/jackson2?callback=callback可以看到效果。

 

7、Gson HttpMessageConverter

7.1、Spring配置 

<mvc:annotation-driven><mvc:message-converters><bean class="org.springframework.http.converter.json.GsonHttpMessageConverter"/></mvc:message-converters></mvc:annotation-driven>

使用方式和Jackson Json类似。本文使用的是<gson.version>2.2.4</gson.version>版本。

 

8、Protobuf HttpMessageConverter

8.1、Spring配置 

<mvc:annotation-driven><mvc:message-converters><bean class="org.springframework.http.converter.protobuf.ProtobufHttpMessageConverter"><constructor-arg><bean class="com.github.zhangkaitao.web.controller.MyExtensionRegistryInitializer"/></constructor-arg></bean></mvc:message-converters></mvc:annotation-driven>

 

8.2、定义protobuf message(proto/user.proto)

package com.github.zhangkaitao.pb;
 option java_package = "com.github.zhangkaitao.pb";
 option java_outer_classname = "UserProtos";
 message User {
   optional int64 id = 1;
   optional string name = 2;
 }

 

8.3、添加maven插件自动把protobuf message转化成Java代码

<plugin><groupId>com.google.protobuf.tools</groupId><artifactId>maven-protoc-plugin</artifactId><version>0.1.10</version><executions><execution><id>generate-sources</id><goals><goal>compile</goal></goals><phase>generate-sources</phase><configuration><protoSourceRoot>${basedir}/src/main/proto/</protoSourceRoot><includes><param>**/*.proto</param></includes></configuration></execution></executions><configuration><protocExecutable>D:/software/protoc.exe</protocExecutable></configuration></plugin>

 

8.4、测试控制器 

@RestController
public class ProtobufController {
    @RequestMapping("/proto/read")
    public ResponseEntity<UserProtos.User> protoRead() {
        return ResponseEntity.ok(UserProtos.User.newBuilder().setId(1).setName("zhangsan").build());
    }
    @RequestMapping("/proto/write")
    public ResponseEntity<UserProtos.User> protoRead(RequestEntity<UserProtos.User> requestEntity) {
        System.out.println("server===\n" + requestEntity.getBody());
        return ResponseEntity.ok(requestEntity.getBody());
    }
}

 

8.5、测试用例(com.github.zhangkaitao.proto.ProtoTest)   

    @Test
    public void testRead() {
        HttpHeaders headers = new HttpHeaders();
        RequestEntity<UserProtos.User> requestEntity =
                new RequestEntity<UserProtos.User>(headers, HttpMethod.POST, URI.create(baseUri + "/proto/read"));

        ResponseEntity<UserProtos.User> responseEntity =
                restTemplate.exchange(requestEntity, UserProtos.User.class);

        System.out.println(responseEntity.getBody());
    }

    @Test
    public void testWrite() {
        UserProtos.User user = UserProtos.User.newBuilder().setId(1).setName("zhangsan").build();
        HttpHeaders headers = new HttpHeaders();
        RequestEntity<UserProtos.User> requestEntity =
                new RequestEntity<UserProtos.User>(user, headers, HttpMethod.POST, URI.create(baseUri + "/proto/write"));

        ResponseEntity<UserProtos.User> responseEntity =
                restTemplate.exchange(requestEntity, UserProtos.User.class);
        System.out.println(responseEntity.getBody());
    }

测试用例知识请参考《 Spring MVC测试框架详解——服务端测试》和《 Spring MVC测试框架详解——客户端测试》。

测试过程中会抛出:

Caused by: java.lang.UnsupportedOperationException
	at java.util.Collections$UnmodifiableMap.put(Collections.java:1342)
	at org.springframework.http.HttpHeaders.set(HttpHeaders.java:869)
	at org.springframework.http.converter.protobuf.ProtobufHttpMessageConverter.setProtoHeader(ProtobufHttpMessageConverter.java:196)

这是因为ProtobufHttpMessageConverter会修改响应头,但是ResponseEntity构造时HttpHeaders是不允许修改的。暂时解决办法是注释掉:

//setProtoHeader(outputMessage, message);

 

9、RequestEntity/ResponseEntity

Spring 4.1提供了ResponseEntity配对的RequestEntity,使用方式和HttpEntity一样。具体可以参考com.github.zhangkaitao.web.controller.RequestResponseEntityController。

 

10、MvcUriComponentsBuilder

其作用可以参考《 Spring4新特性——注解、脚本、任务、MVC等其他特性改进》,Spring 4.1又提供了一个新的方法MvcUriComponentsBuilder.fromMappingName用于根据控制器方法来生成请求URI。

 

@RestController
public class MvcUriComponentsBuilderController {

    @RequestMapping("/uri")
    public String mvcUriComponentsBuilder1() {
        return MvcUriComponentsBuilder.fromMappingName("MUCBC#mvcUriComponentsBuilder1").build();
    }
    @RequestMapping("/uri/{id}")
    public String mvcUriComponentsBuilder2(@PathVariable Long id) {
        return MvcUriComponentsBuilder.fromMappingName("MUCBC#mvcUriComponentsBuilder2").arg(0, "123").build();
    }
}

规则是“控制器所有大写字母#方法名”找到相应的方法。 另外可以直接在页面中使用如下方式获取相应的URI:

${s:mvcUrl('MUCBC#mvcUriComponentsBuilder2').arg(0,"123").build()}

如上方式只能在正常EL 3.0的容器中运行,可参考《 Expression Language 3.0新特性》。 

 

11、MockRestServiceServer

MockRestServiceServer目前提供了对AsyncRestTemplate的支持,使用方式和RestTemplate一样。可参考《 Spring MVC测试框架详解——客户端测试》。

 

12、MockMvcConfigurer

Spring 4.1提供了MockMvcConfigurer用于进行一些通用配置,使用方式如下:

mockMvc = MockMvcBuilders.webAppContextSetup(context).apply(defaultSetup()).build(); 

MockMvcConfigurer实现: 

    private MockMvcConfigurer defaultSetup() {
        return new MockMvcConfigurer() {
            @Override
            public void afterConfigurerAdded(ConfigurableMockMvcBuilder<?> configurableMockMvcBuilder) {
                configurableMockMvcBuilder.alwaysExpect(status().isOk());
            }
            @Override
            public RequestPostProcessor beforeMockMvcCreated(ConfigurableMockMvcBuilder<?> configurableMockMvcBuilder, WebApplicationContext webApplicationContext) {
                return new RequestPostProcessor() {
                    @Override
                    public MockHttpServletRequest postProcessRequest(MockHttpServletRequest mockHttpServletRequest) {
                        mockHttpServletRequest.setAttribute("aa", "aa");
                        return mockHttpServletRequest;
                    }
                };
            }
        };
    }

可以在如上实现中进行一些通用配置,如安全(往Request中扔安全对象之类的)。测试用例可参考com.github.zhangkaitao.proto.ProtoTest2。

 

 

相关文章

http://beta.groovy-lang.org/docs/groovy-2.3.0-SNAPSHOT/html/documentation/markup-template-engine.html

https://spring.io/blog/2014/05/28/using-the-innovative-groovy-template-engine-in-spring-boot

Spring4新特性——Groovy Bean定义DSL

Spring3.2新注解@ControllerAdvice

Spring MVC测试框架详解——服务端测试

Spring MVC测试框架详解——客户端测试

Spring4新特性——注解、脚本、任务、MVC等其他特性改进

 

Spring4新特性

Spring4新特性——泛型限定式依赖注入

Spring4新特性——核心容器的其他改进

Spring4新特性——Web开发的增强

Spring4新特性——集成Bean Validation 1.1(JSR-349)到SpringMVC 

Spring4新特性——Groovy Bean定义DSL

Spring4新特性——更好的Java泛型操作API 

Spring4新特性——JSR310日期API的支持

Spring4新特性——注解、脚本、任务、MVC等其他特性改进 

 

源码下载

https://github.com/zhangkaitao/spring4-1-showcase/tree/master/spring4.1-groovy

https://github.com/zhangkaitao/spring4-1-showcase/tree/master/spring4.1-mvc

 

 



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


ITeye推荐



linux(Centos)上memcacheq成功安装及使用

$
0
0

一:安装memcached

1.下载memcached包
    下载地址:http://www.memcached.org (最新包就在首页,点击下载就OK)
    解压包:# tar -zxvf memcached-1.4.13.tar.gz (根据自身的情况解压到目录)
    进入目录:# cd memcached-1.4.13

2.安装libevent    
    检查一下有没有安装libevent: ls -al /usr/lib |grep libevent
    如果没有就安装libevent ,下载地址:http://www.libevent.org (首页 Download–Stable releases)
    解压:# tar -zxvf libevent-***-.tar.gz
          #cd libevent-***-
          #./configure --prefix=/usr
          #make && make install
    安装完检测下  ls -al /usr/lib |grep libevent
    lrwxrwxrwx   1 root root        21 02-06 20:26 libevent-1.4.so.2 -> libevent-1.4.so.2.1.3
    .................................
    -rw-r--r--   1 root root     11838 04-13 14:03 libevent_pthreads.a    
    -rwxr-xr-x   1 root root       996 04-13 14:03 libevent_pthreads.la
    lrwxrwxrwx   1 root root        30 04-13 14:03 libevent_pthreads.so -> libevent_pthreads-2.0.so.5.1.6
    lrwxrwxrwx   1 root root        21 04-13 14:03 libevent.so -> libevent-2.0.so.5.1.6
    
3.安装memcached
    预安装:#./configure --prefix=/usr/local/memcached --with-libevent=/usr
        注意:在没有安装libevent的情况下,会报错( If it's already installed, specify its path using --with-libevent=/dir/);
    编译并且安装:# make && make install
    OK安装成功.
    
    启动memcached:
            # /usr/local/memcached/bin/memcached -l 192.168.1.144 -d -p 11211 -u nobody -m 1024
            说明:上面的命令中-d表示用 daemon 的方式启动 memcached,-l和-p组合表示监听在 192.168.1.144 的 11212 端口上(如果不用-p指定端口号,则memcached将运行在11211端口    上),-u表示运行用户为 nobody,-m表示为其分配1024MB 的内存。
    
    连接 memcached: # telnet 192.168.1.144 11211
    到这里 memcached就已经安装好了。

增加到开机启动
    # vi /etc/rc.local
        增加:
            /usr/local/memcached/bin/memcached -l 192.168.1.144 -d -p 11211 -u nobody -m 1024

二:安装memcacheq
1.下载memcacheq包
    下载地址:http://code.google.com/p/memcacheq/downloads/list
    解压包:# tar -zxvf memcacheq.0.2.tar.gz (根据自身的情况解压到目录)
    进入目录:# cd memcacheq-0.2.0
    
2.安装 BerkeleyDB
    下载地址:http://www.oracle.com/technetwork/products/berkeleydb/downloads/index.html

下载地址请求:wget wget http://download.oracle.com/berkeley-db/db-5.3.15.tar.gz  (成功)


    解压包:# tar -zxvf db-5.3.15.tar.gz (根据自身的情况解压到目录)
    进入目录:# cd db-5.3.15
              # cd build_unix
              #../dist/configure --prefix=/usr/local/BerkeleyDB.5.3
              # make && make install
              #vi /etc/ld.so.conf
                增加:
                /usr/local/lib
                /usr/local/BerkeleyDB.5.3/lib
              #vi /etc/profile
                增加
                export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/lib:/usr/local/BerkeleyDB.5.3/lib

3.安装memcacheq (注: 下文中的5.3是berkeleyDB的版本  请根据实际情况操作)
    预安装:./configure --prefix=/usr/local/memcacheq --enable-threads --with-libevent=/usr/local/libevent
        注意:在没有安装BerkeleyDB的情况下,会报错( configure: error: cannot find libdb.so in /usr/local/BerkeleyDB.5.3/lib);


我的提示configure: error: cannot find libdb.so in /usr/local/BerkeleyDB.5.3/lib报错,我的解决方法:
    装berkeley-db
wget http://download.oracle.com/berkeley-db/db-4.7.25.tar.gz
tar zxf db-4.7.25.tar.gz
cd db-4.7.25/build_unix/
../dist/configure
make
make install




#编译完成,将Berkeley Db运行库的路径添加到系统配置里面
echo "/usr/local/BerkeleyDB.4.7/lib/" >> /etc/ld.so.conf
ldconfig




    测试:/usr/local/memcacheq/bin/memcachq -h
            运行报:
            memcacheq: error while loading shared libraries: libdb-5.3.so: cannot open shared object file: No such file or directory
        解决方法:ln -s /usr/local/BerkeleyDB.5.3/lib/libdb-5.3.so /usr/lib/libdb-5.3.so


     连接:/usr/local/memcacheq/bin/memcacheq  -d -r -uroot -p12002 -H /var/mcq/data -N -R -v -L 1024 -B 1024 > /var/mcq/logs/mq_error.log 2>&1


其中过程遇到了很多问题,例如动态库位置,环境变量


inux上启动Memcache报错:

Shell代码   收藏代码
  1. [root@localhost memcached]# ./bin/memcached -d -m 2048 -p 11211 -u root  
  2. ./bin/memcached: error while loading shared libraries: libevent-1.4.so.2: cannot open shared object file: No such file or directory  

原因一般有两个, 一个是操作系统里确实没有包含该共享库(lib*.so.*文件)或者共享库版本不对, 遇到这种情况那就去网上下载并安装上即可.

另外一个原因就是已经安装了该共享库, 但执行需要调用该共享库的程序的时候, 程序按照默认共享库路径找不到该共享库文件.

 

因为我已经安装了libevent,所以应该是程序按照默认共享路径库去找,但是没有找到导致的。

 

首先使用find命令找到libevent-1.4.so.2文件在哪儿

Shell代码   收藏代码
  1. [root@localhost memcached]# find /usr -name libevent-1.4.so.2  
  2. /usr/libevent/lib/libevent-1.4.so.2 

根据debug日志可以看到,程序只会去/lib 和/usr/lib下去寻找需要的共享链接库。

而我的libevent是安装在/usr/libevent/lib/下,所以memcache启动的时候并不知道该去这下面找,所以会报错

 

所以安装共享库后要注意共享库路径设置问题, 如下:

1)如果共享库文件安装到了/lib或/usr/lib目录下, 那么需执行一下ldconfig命令

         ldconfig命令的用途, 主要是在默认搜寻目录(/lib和/usr/lib)以及动态库配置文件/etc/ld.so.conf内所列的目录下, 搜索出可共享的动态链接库(格式如lib*.so*), 进而创建出动态装入程序(ld.so)所需的连接和缓存文件. 缓存文件默认为/etc/ld.so.cache, 此文件保存已排好序的动态链接库名字列表. 

 

2)如果共享库文件安装到了/usr/local/lib(很多开源的共享库都会安装到该目录下)或其它"非/lib或/usr/lib"目录下, 那么在执行ldconfig命令前, 还要把新共享库目录加入到共享库配置文件/etc/ld.so.conf中, 如下:

Shell代码   收藏代码
  1. [root@localhost memcached]# cat /etc/ld.so.conf  
  2. include ld.so.conf.d/*.conf  

如上所示:/etc/ld.so.conf配置文件中内容只有一行,

ld.so.conf.d/*.conf的意思就是包含ld.so.conf.d/目录下以.conf为后缀的文件

所以我们可以在/etc/ld.so.conf.d目录下新建一个libevent.conf的配置文件,然后把libevent安装路径配置好

我的libevent内容如下:

Shell代码   收藏代码
  1. [root@localhost ld.so.conf.d]# cat libevent.conf  
  2. /usr/libevent/lib  

配置完后执行以下ldconfig命令

Shell代码   收藏代码
  1. [root@localhost ~]#ldconfig   

3)如果共享库文件安装到了其它"非/lib或/usr/lib" 目录下,  但是又不想在/etc/ld.so.conf中加路径(或者是没有权限加路径). 那可以export一个全局变量LD_LIBRARY_PATH, 然后运行程序的时候就会去这个目录中找共享库.

     LD_LIBRARY_PATH的意思是告诉loader在哪些目录中可以找到共享库. 可以设置多个搜索目录, 这些目录之间用冒号分隔开. 比如安装了一个mysql到/usr/local/mysql目录下, 其中有一大堆库文件在/usr/local/mysql/lib下面, 则可以在.bashrc或.bash_profile或shell里加入以下语句即可:

export LD_LIBRARY_PATH=/usr/local/mysql/lib:$LD_LIBRARY_PATH

一般来讲这只是一种临时的解决方案, 在没有权限或临时需要的时候使用.


启动

/usr/local/memcacheq/bin/memcacheq  -d -r -uroot -p12002 -H /var/mcq/data -N -R -v -L 1024 -B 1024 > /var/mcq/logs/mq_error.log 2>&1




附带介绍ruby相关的安装:
   Starling是一个支持MemCache协议的轻量级持久化服务器。Starling是让创建网络访问队列或者多个队列异常简单,也就是说多点和多台机器间的异步工作进程。它是著名微博客网站Twitter开发用来处理大量的队列消息,以及保持服务的响应。Starling已经在生产环境中使用,不仅是Twitter在使用,FiveRuns同样在使用。FiveRuns甚至还根据自己的应用做了改进 ,他们认为网站速度快了很多.
   这是一个支持memcache协议的轻量级持久化服务器,因此使用php/perl/ruby/java等多种客户端都没问题,可以将较慢的处理逻辑通过消息队列放在后台处理,同时也支持多点分布式处理。
   由于starling是目前twitter在生产环境中运行的,经过实践检验过,稳定性应该不成问题。



安装:
   1.安装linux下的开发工具包,最好使用red hat的添加删除程序安装.
 (1)在可视化窗口下载打开"添加删除程序",找到"开发->开发工具"打钩,更新.插入 对应的linux安装盘.
   2.安装ruby和ruby gem
 (1)安装钱的准备
 检查系统是否已经安装了 ruby,
 #rpm -qa | egrep '(ruby)|(irb)'
 如果已安装,而且不是你所要的版本,则需要先卸载她,如,
 #rpm -e ruby-docs-1.8.1-7.EL4.2 \
 ruby-1.8.1-7.EL4.2 \
 irb-1.8.1-7.EL4.2 \
 ruby-libs-1.8.1-7.EL4.2 \
 ruby-mode-1.8.1-7.EL4.2 \
 ruby-tcltk-1.8.1-7.EL4.2 \
 ruby-devel-1.8.1-7.EL4.2

 (2)安装 Ruby
 假设 Ruby 安装到 /usr/local/ruby
 #mkdir /usr/local/ruby
 #tar -zxvf ruby-1.8.4.tar.gz
 #cd ruby-1.8.4
 #./configure --prefix=/usr/local/ruby
 #make
 #make install


 (3)设置路径
 #vi /etc/profile
 在该文件中加入,
 RUBY_HOME=/usr/local/ruby
 PATH=$PATH:$RUBY_HOME/bin
 export RUBY_HOME PATH

 (4)检查是否安装成功
 重新登录,
 #ruby -v
 如果能显示 ruby 的版本信息(ruby 1.8.4 (2005-12-24) [i686-linux]),则说明已安装成功。

 (5)安装 Ruby Gems
 #tar -zxvf rubygems-0.9.0.tgz
 #cd rubygems-0.9.0
 #ruby setup.rb

我是用成功的方法是:yum install rubygems

 (6)检查是否安装成功
 #gem -v
 如果能显示 gem 的版本信息(0.9.0),则说明已安装成功。


本文参考来源: http://www.cnblogs.com/sunzy/archive/2012/04/13/2446234.html

http://blog.csdn.net/li_yang98/article/details/6208223等


作者:zhanjianshinian 发表于2014-8-22 16:07:51 原文链接
阅读:0 评论:0 查看评论

HADOOP SHUFFLE(转载)

$
0
0
Shuffle过程是MapReduce的核心,也被称为奇迹发生的地方。要想理解MapReduce,Shuffle是必须要了解的。我看过很多相关的资料,但每次看完都云里雾里的绕着,很难理清大致的逻辑,反而越搅越混。前段时间在做MapReduce job性能调优的工作,需要深入代码研究MapReduce的运行机制,这才对Shuffle探了个究竟。考虑到之前我在看相关资料而看不懂时很恼火,所以在这里我尽最大的可能试着把Shuffle说清楚,让每一位想了解它原理的朋友都能有所收获。如果你对这篇文章有任何疑问或建议请留言到后面,谢谢!
Shuffle的正常意思是洗牌或弄乱,可能大家更熟悉的是Java API里的Collections.shuffle(List)方法,它会随机地打乱参数list里的元素顺序。如果你不知道MapReduce里Shuffle是什么,那么请看这张图:



  这张是官方对Shuffle过程的描述。但我可以肯定的是,单从这张图你基本不可能明白Shuffle的过程,因为它与事实相差挺多,细节也是错乱的。后面我会具体描述Shuffle的事实情况,所以这里你只要清楚Shuffle的大致范围就成-怎样把map task的输出结果有效地传送到reduce端。也可以这样理解, Shuffle描述着数据从map task输出到reduce task输入的这段过程。

  在Hadoop这样的集群环境中,大部分map task与reduce task的执行是在不同的节点上。当然很多情况下Reduce执行时需要跨节点去拉取其它节点上的map task结果。如果集群正在运行的job有很多,那么task的正常执行对集群内部的网络资源消耗会很严重。这种网络消耗是正常的,我们不能限制,能做的就是最大化地减少不必要的消耗。还有在节点内,相比于内存,磁盘IO对job完成时间的影响也是可观的。从最基本的要求来说,我们对Shuffle过程的期望可以有:
? 完整地从map task端拉取数据到reduce端。
? 在跨节点拉取数据时,尽可能地减少对带宽的不必要消耗。
? 减少磁盘IO对task执行的影响。

  OK,看到这里时,大家可以先停下来想想,如果是自己来设计这段Shuffle过程,那么你的设计目标是什么。我想能优化的地方主要在于减少拉取数据的量及尽量使用内存而不是磁盘。

  我的分析是基于Hadoop0.21.0的源码,如果与你所认识的Shuffle过程有差别,不吝指出。我会以WordCount为例,并假设它有8个map task和3个reduce task。从上图看出,Shuffle过程横跨map与reduce两端,所以下面我也会分两部分来展开。
先看看map端的情况,如下图:



  上图可能是某个map task的运行情况。拿它与官方图的左半边比较,会发现很多不一致。官方图没有清楚地说明partition,sort与combiner到底作用在哪个阶段。我画了这张图,希望让大家清晰地了解从map数据输入到map端所有数据准备好的全过程。

  整个流程我分了四步。简单些可以这样说,每个map task都有一个内存缓冲区,存储着map的输出结果,当缓冲区快满的时候需要将缓冲区的数据以一个临时文件的方式存放到磁盘,当整个map task结束后再对磁盘中这个map task产生的所有临时文件做合并,生成最终的正式输出文件,然后等待reduce task来拉数据。

  当然这里的每一步都可能包含着多个步骤与细节,下面我对细节来一一说明:

  1.在map task执行时,它的输入数据来源于HDFS的block,当然在MapReduce概念中,map task只读取split。Split与block的对应关系可能是多对一,默认是一对一。在WordCount例子里,假设map的输入数据都是像“aaa”这样的字符串。

  2.在经过mapper的运行后,我们得知mapper的输出是这样一个key/value对: key是“aaa”, value是数值1。因为当前map端只做加1的操作,在reduce task里才去合并结果集。前面我们知道这个job有3个reduce task,到底当前的“aaa”应该交由哪个reduce去做呢,是需要现在决定的。

  MapReduce提供Partitioner接口,它的作用就是根据key或value及reduce的数量来决定当前的这对输出数据最终应该交由哪个reduce task处理。默认对key hash后再以reduce task数量取模。默认的取模方式只是为了平均reduce的处理能力,如果用户自己对Partitioner有需求,可以订制并设置到job上。

  在我们的例子中,“aaa”经过Partitioner后返回0,也就是这对值应当交由第一个reducer来处理。接下来,需要将数据写入内存缓冲区中,缓冲区的作用是批量收集map结果,减少磁盘IO的影响。我们的key/value对以及Partition的结果都会被写入缓冲区。当然写入之前,key与value值都会被序列化成字节数组。

  整个内存缓冲区就是一个字节数组,它的字节索引及key/value存储结构我没有研究过。如果有朋友对它有研究,那么请大致描述下它的细节吧。

  3.这个内存缓冲区是有大小限制的,默认是100MB。当map task的输出结果很多时,就可能会撑爆内存,所以需要在一定条件下将缓冲区中的数据临时写入磁盘,然后重新利用这块缓冲区。这个从内存往磁盘写数据的过程被称为Spill,中文可译为溢写,字面意思很直观。这个溢写是由单独线程来完成,不影响往缓冲区写map结果的线程。溢写线程启动时不应该阻止map的结果输出,所以整个缓冲区有个溢写的比例spill.percent。这个比例默认是0.8,也就是当缓冲区的数据已经达到阈值(buffer size * spill percent = 100MB * 0.8 = 80MB),溢写线程启动,锁定这80MB的内存,执行溢写过程。Map task的输出结果还可以往剩下的20MB内存中写,互不影响。

  当溢写线程启动后,需要对这80MB空间内的key做排序(Sort)。排序是MapReduce模型默认的行为,这里的排序也是对序列化的字节做的排序。

  在这里我们可以想想,因为map task的输出是需要发送到不同的reduce端去,而内存缓冲区没有对将发送到相同reduce端的数据做合并,那么这种合并应该是体现是磁盘文件中的。从官方图上也可以看到写到磁盘中的溢写文件是对不同的reduce端的数值做过合并。所以溢写过程一个很重要的细节在于,如果有很多个key/value对需要发送到某个reduce端去,那么需要将这些key/value值拼接到一块,减少与partition相关的索引记录。

  在针对每个reduce端而合并数据时,有些数据可能像这样:“aaa”/1, “aaa”/1。对于WordCount例子,就是简单地统计单词出现的次数,如果在同一个map task的结果中有很多个像“aaa”一样出现多次的key,我们就应该把它们的值合并到一块,这个过程叫reduce也叫combine。但MapReduce的术语中,reduce只指reduce端执行从多个map task取数据做计算的过程。除reduce外,非正式地合并数据只能算做combine了。其实大家知道的,MapReduce中将Combiner等同于Reducer。

  如果client设置过Combiner,那么现在就是使用Combiner的时候了。将有相同key的key/value对的value加起来,减少溢写到磁盘的数据量。Combiner会优化MapReduce的中间结果,所以它在整个模型中会多次使用。那哪些场景才能使用Combiner呢?从这里分析,Combiner的输出是Reducer的输入,Combiner绝不能改变最终的计算结果。所以从我的想法来看,Combiner只应该用于那种Reduce的输入key/value与输出key/value类型完全一致,且不影响最终结果的场景。比如累加,最大值等。Combiner的使用一定得慎重,如果用好,它对job执行效率有帮助,反之会影响reduce的最终结果。

  4.每次溢写会在磁盘上生成一个溢写文件,如果map的输出结果真的很大,有多次这样的溢写发生,磁盘上相应的就会有多个溢写文件存在。当map task真正完成时,内存缓冲区中的数据也全部溢写到磁盘中形成一个溢写文件。最终磁盘中会至少有一个这样的溢写文件存在(如果map的输出结果很少,当map执行完成时,只会产生一个溢写文件),因为最终的文件只有一个,所以需要将这些溢写文件归并到一起,这个过程就叫做Merge。Merge是怎样的?如前面的例子,“aaa”从某个map task读取过来时值是5,从另外一个map 读取时值是8,因为它们有相同的key,所以得merge成group。什么是group。对于“aaa”就是像这样的:{“aaa”, [5, 8, 2, …]},数组中的值就是从不同溢写文件中读取出来的,然后再把这些值加起来。请注意,因为merge是将多个溢写文件合并到一个文件,所以可能也有相同的key存在,在这个过程中如果client设置过Combiner,也会使用Combiner来合并相同的key。
至此,map端的所有工作都已结束,最终生成的这个文件也存放在TaskTracker够得着的某个本地目录内。每个reduce task不断地通过RPC从JobTracker那里获取map task是否完成的信息,如果reduce task得到通知,获知某台TaskTracker上的map task执行完成,Shuffle的后半段过程开始启动。
简单地说,reduce task在执行之前的工作就是不断地拉取当前job里每个map task的最终结果,然后对从不同地方拉取过来的数据不断地做merge,也最终形成一个文件作为reduce task的输入文件。见下图:



  如map 端的细节图,Shuffle在reduce端的过程也能用图上标明的三点来概括。当前reduce copy数据的前提是它要从JobTracker获得有哪些map task已执行结束,这段过程不表,有兴趣的朋友可以关注下。Reducer真正运行之前,所有的时间都是在拉取数据,做merge,且不断重复地在做。如前面的方式一样,下面我也分段地描述reduce 端的Shuffle细节:

  1.Copy过程,简单地拉取数据。Reduce进程启动一些数据copy线程(Fetcher),通过HTTP方式请求map task所在的TaskTracker获取map task的输出文件。因为map task早已结束,这些文件就归TaskTracker管理在本地磁盘中。
  2.Merge阶段。这里的merge如map端的merge动作,只是数组中存放的是不同map端copy来的数值。Copy过来的数据会先放入内存缓冲区中,这里的缓冲区大小要比map端的更为灵活,它基于JVM的heap size设置,因为Shuffle阶段Reducer不运行,所以应该把绝大部分的内存都给Shuffle用。这里需要强调的是,merge有三种形式:1)内存到内存  2)内存到磁盘  3)磁盘到磁盘。默认情况下第一种形式不启用,让人比较困惑,是吧。当内存中的数据量到达一定阈值,就启动内存到磁盘的merge。与map 端类似,这也是溢写的过程,这个过程中如果你设置有Combiner,也是会启用的,然后在磁盘中生成了众多的溢写文件。第二种merge方式一直在运行,直到没有map端的数据时才结束,然后启动第三种磁盘到磁盘的merge方式生成最终的那个文件。
  3.Reducer的输入文件。不断地merge后,最后会生成一个“最终文件”。为什么加引号?因为这个文件可能存在于磁盘上,也可能存在于内存中。对我们来说,当然希望它存放于内存中,直接作为Reducer的输入,但默认情况下,这个文件是存放于磁盘中的。至于怎样才能让这个文件出现在内存中,之后的性能优化篇我再说。当Reducer的输入文件已定,整个Shuffle才最终结束。然后就是Reducer执行,把结果放到HDFS上。(完)

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


ITeye推荐



交易系统的历史回测应该注意什么

$
0
0

交易系统必须能通过历史回测才可以投入使用。无法通过历史回测的交易系统不可能在实际交易中获利。历史回测是交易系统投入实盘的必要前置环节。能通过历史回测的交易系统不一定是好用的交易系统,但不能通过历史回测,则一定不是好用的交易系统。

一般地,回测交易系统,需要从稳健性(Robustness)分析的角度特别留意以下四点。

第一,历史回测的期间必须足够长。

一般来讲,对于国内的股票、商品,应该回测5年以上的数据,对于新上市的品种,至少也要回测3年。对于上市较早的品种或国际市场的黄金、美元指数等商品,则应至少回测一个牛熊周期,一般应该在10年–15年以上。回测的期间足够长久,回测的成绩才足够可靠。对于不能满足这个要求的品种,则应在开仓时将R值适当加权处理,主动降低风险暴露。

第二,分析回测成绩,应予以“断代”处理。

一个稳定、可靠的交易系统,在一定期间范围内,成绩应该相对稳定。仅靠一两波大行情拉高整体回测成绩的,会使使用者高估系统的价值。例如,回测上证指数时,如果仅仅将2005年–2007年的大牛市纳入总成绩,而没有逐年的回测数据,很可能会因为一次牛市而高估了一个本来绩效一般的系统。我的经验是,按年予以断代,分析各年的回测绩效。完全平均的回测成绩是不可能的,一个优秀的系统应该满足两个条件:单一年度不出现巨大亏损;各年整体稳定盈利,偶尔出现超额获利。

第三,回测系统后应该防止“过度优化”,尽量减少参数变量,防止“参数孤岛”。

过度优化(Curve Fitting,也可称为“曲线拟合”)是交易系统回测的最大敌人。一个交易系统应以简洁为上,少用参数变量。对于采取了变量参数的系统,最优参数附近的参数也应具备不错的绩效,形成“参数高原”。应防止过度优化后的“参数孤岛”。

第四,交易系统应经历多品种回测检验

一个可靠的交易系统应该具备普适性,不能仅仅适用于个别交易品种。只能用于一个品种的交易系统,往往是过度优化的产物。需要特别说明的是,不同品种间可以结合品种特性进行一些针对单一品种的微调。比如结合不同品种的ATR情况,根据日K线的振幅过滤一些非常态下的开仓信号等。这种根据具体品种采取的个性化调整不属于过度优化。

原文来自: 风云居 | 康健的博客
本文链接: http://kangjian.net/blog/1482/



— 完 —
本文作者: 康健

【知乎日报】 你都看到这啦,快来点我嘛 Σ(▼□▼メ)

有关云架构建设和选型的思考

$
0
0

  最近在负责公司内部私有云的建设,一直在思考怎么搞云计算,怎么才能够把云架构设计得好一些。本文尽量全面的列出了云架构建设和选型的考量因素。

  我们主要从五个层面逐步评估云架构的建设和选型,分别是:

  1. 行业生态
  2. 企业需求
  3. 云计算的能力
  4. 潜在的挑战
  5. 如何建设

   一、行业生态

  计算机云经过多年的发展,由一开始的概念,慢慢发展成熟并能够推向市场,提供多种多样的服务,市场空间非常之大。

  在云的发展过程中,亚马逊经过多年的深耕积累,发展成为了云行业的标杆企业,甚至可以说是建立了云解决方案的标准。之后,Google、IBM、思科、Oracle、HP、Intel、华为等IT巨头先后参与进来,在软件和硬件方面提供专门的面向企业的解决方案,纷纷打着云计算、大数据、智能等概念来吸引客户,拓展市场。

  另外一方面,基于大数据、存储、云服务等,市场上也先后出现一些创新企业,如Dropbox、Rackspace,国内的七牛、青云、UnitedStack等。

  当前的IT世界有一个常见的现象,就是只要某一个领域有一套成熟的商业软件,就同时也会有一套开源的解决方案,如Windows之于Linux,Google的MapReduce、GFS、大表之于Hadoop等。在云领域也存在相应的开源解决方案,目前最为著名的有Openstack和Cloudstack。开源行业的领导者RedHat此前在企业操作系统的市场已经做的很好,RHEL的各个版本在企业级系统市场有相当高的市场份额。现在的RedHat特别重视云的发展,并将云操作系统作为未来10年的发展战略重点,在最近两年先后收购了Gluster以及Ceph等存储企业,以壮大自己在云领域的影响力。

  随着云领域的发展,市场上也逐渐形成了面向企业提供硬件和软件产品的提供商、面向企业提供服务的提供商、面向市场初创企业提供基础服务的提供商、面向个人提供业务服务的提供商等一系列行业生态。

   二、企业需求

  需求是什么,也就是what people need这个问题。我们所说的people,即人或者公司实体,该对象的划分并不单纯,可粗浅的从三个角度来进行分类:

  从企业角度看:

  1)小型企业

  小型企业的技术储备不多,人员缺乏,没有独立的IT部门,但是在构建自己的IT系统过程中需要购置各种产品和服务,包括服务器、网络、CDN等等,而要完成这样的工作,需要投入大量的人力和财力。通过购买云服务可以更加方便快捷,简单的完成系统的搭建。

  2)中型企业

  中型企业有一定的规模,需要在信息化、管理方面有所注重,一般内部都设立IT部门,但是和小型企业一样,IT部门大多数都是为了解决自身需求,很难能够有一个完整的解决方案。这样在服务器、网络、CDN、企业管理软件等等的需求还是比较大的。

  3)大型企业

  大型企业人数规模在万人以上,特别是高新企业,都有一个实力不错的IT支撑部门,通过部门就可以完善对企业内部信息化建设。

  从企业性质范围来看:

  1)传统行业企业

  传统行业大多数是以服务业、制造业、生产性企业为主,在IT信息化方面相对比较落后,属于重资产行业。

  2)互联网企业

  互联网行业是基于IT作为解决方案的

  3)IT服务企业

  以销售软件、硬件、以及技术咨询服务为主的企业。

  针对市场中存在的企业、个体等的需求特点,市场上一般对软件服务进行如下分类:

  1. 提供软件的服务,解决企业内部信息化问题,如ERP系统、进销存管理系统、人力资源管理系统、行政系统、财务系统等等。(SaaS)
  2. 提供平台服务,解决行业共性问题,将SaaS迁移到云端,提供平台类的服务。如淘宝的开放平台、Facebook的开放平台、基于Salesforce的销售系统、云笔记、云盘等。(PaaS)
  3. 提供基础设施服务。基础设施包括软件和硬件方面的,包括存储、虚拟机、网络、防火墙、缓存、负载均衡、数据库等等。(IaaS)

  从企业内部人员角色来看:

  企业内部,尤其是互联网企业内部,一般将角色分为如下几类:

  1. 开发
  2. 测试
  3. 运维
  4. DBA
  5. 产品
  6. 项目管理人员
  7. 客服
  8. 业务人员(销售、市场、BD、人力资源、行政等等)

  不同的角色对于软件服务的需求也是不同的,下图大致描绘了互联网行业各个角色对云平台的需求:

   三、云计算的能力

  云计算能够解决什么,也就是what cloud offer这个问题。目前的云计算在应用中主要提供了以下八个能力:

  1. 封装:将计算能力和软件放在云端,可以减少重复建设,将通用的服务封装起来,达到重用,减少资源的浪费,提高生产效率,并提供成熟的解决方案。在云端,云提供商可以建立软件的标准,提供发布包的方式,用户可以通过软件包的方式进行购买使用,譬如目前开源领域的Docker。
  2. 安全:云计算将数据和存储,软件逻辑都集中于云端,更能方便的统一构建安全体系,通过Iptables实现网络过滤,并在服务端做安全组件实现安全策略,并能够通过海量集群应对DDOS攻击等。
  3. 灵活:云计算提供灵活的软件和服务端架构,用户不再需要自己构建应用运行环境,对资源的使用能够按需购买,并能够升级,并自由组合。举例来说:用户可以选用不同的存储方式(mysql、oracle,文件系统,kv等等)
  4. 性能:通过集群的能力和云端的集成能够提高集群的性能处理,通过专业的云解决提供商,在云端的性能扩展更加方便,技术上更加专业。譬如服务端可以在用户毫不察觉的情况下完成添加机器、存储扩容等操作。
  5. 伸缩能力:在存储和计算能力方面提供弹性的资源管理,能够按需使用,在使用过程中,可以通过动态的添加和减少物理资源,来提高响应能力或节约成本。
  6. 运维:云计算在IaaS角度来看,重要的是运维,能够将运维更加集中化管理,并完全智能化,大大降低人力成本
  7. 充分利用物理资源:通过云建设,能够将物理资源进行虚拟化处理,屏蔽物理硬件底层,并能够完成物理资源软化进行逻辑管理和分配调度
  8. 大数据:大数据保存于云端,能够提供数据分析和智能处理

  当然,云计算还有很多很多好处,给我们带来很多想像空间和IT技术的革命。

   公有云与私有云

  行业内将云分为“公有云”和“私有云”。在我们之前的需求分析过程中,大致了解了云的需求,“公有云”和“私有云”的差别最大的是需求的差异,因为需求的差异,导致了技术方案和产品决策的差异。

  公有云需求上由于用户多种多样,导致需求存在不一样,特别需要更多的定制化,譬如:

  1. 存储个性化

    云存储方面大概分为块存储和对象存储,块存储适合于vm运行环境,对象存储提供了KV的访问方式提供了海量扩展存储文件的能力,用户可以根据自己的需求选择不同的存储方式,选用不同的容量。在存储物理介质方面来说,因为存在不同的物理介质,对性能和安全的要求,可以采用传统的SATA硬盘,或者SSD存储等。

  2. 内存使用

    内存方面,需要提供动态扩展内存的方式,用户能够自由扩展

  3. 网络的定制化

    公有云用户需要能够构建自己的内部网络,并能够自动组网

  4. 数据库使用

    公有云的用户分属不同的公司团体,各自的技术差异存在,因而有不同的数据库类型,譬如mysql,sqlserver,oracle等等。并能够定义存储大小,内存运行大小等等。并提供数据备份、恢复、高可用服务等

  5. 缓存使用

    公有云的用户可以选择不同的缓存方式,譬如增加CDN,采用不同的KV缓存方式并选择容量。

  6. 安全问题

    公有云对于云的安全和私有云差别较大,私有云大多数在安全问题上不需要公有云那么严格,大多数是内部系统之间的交互

  以上仅限于IaaS层面的考虑,当然对于公有云来说还有很多细化的个性化需求,例如:数据分析,业务对接服务等等。

   四、潜在的挑战

  计算机自从诞生以来,一直按照冯.诺伊曼的体系发展在硬件的基础上的操作系统,也分为网络协议体系的实现、内存管理、文件管理体系等等。大致的抽象图如下:

  要建设云,有几个重要的问题需要解决:

  1. 管理问题

    云计算的实施首先要解决运维的问题,在云环境下后端是大规模数量的物理节点的集群,对于同时维护数以千计算的计算节点,以及部署结构的复杂,需求的变化,光靠增加人力也难以解决复杂的问题。从而需要构建高效的计算资源管理系统,能够灵活简单的管理运系统,并能够及时的发现问题。

  2. 计费问题(公有云)

    对于公有云而言,因为是面向公众的,必然产生费用的问题,常用的收费方式多种多样,也因为产品的不同而计费方式不同,譬如:网络、存储、cpu、数据库容量等等

  3. 资源隔离问题

    云计算运行在云端,是通过虚拟化体系建立的,虚拟化是建立在硬件之上,多个虚拟化资源同时运行于同一节点(host)中,存在着资源的共享争用问题,

    这样就存在着资源使用的公平性问题,导致同一Host上的资源使用相互影响。为了使得彼此资源使用相互独立,我们要建立相应的隔离机制。资源的隔离包括:存储、内存、cpu、数据库、网络等,其中网络是最难控制的。

  4. 安全问题

    在云端的应用和基于客户端的安全,面临的环境不一样,客户端方面大多数是病毒问题引起的,而在云端,也存在一些服务器攻击的问题,以及数据相互独立相互影响的问题,以及一些服务端编程的安全问题等。

  5. 性能问题

    对于云来说,需要保证云端的性能问题,包括CPU处理性能,IO处理能力,资源的就近访问,资源数据同步的速度,还需要解决系统底层的性能问题,包括文件处理Cache,存储介质的优化,采用SSD等,或者采用SATA+SSD的混合方式节约资源和降低成本。

  6. 存储问题

    对于云来说,由于云端是将客户端的数据和运算转移到云端,必须要有足够的存储能力以及足够稳定的存储系统,保证用户数据的安全,对于存储来说,有提供VM虚拟机运行环境的block device(块存储),以及提供KV方式的对象访问存储,这些都需要保证数据复制、数据读写访问的性能和数据永久可用的能力

  7. 网络问题

    对于公有云以及私有云的一些应用场景,需要能够提供网络的逻辑隔离(SDN)或物理隔离,以及对网络的访问灵活问题。构建虚拟化网络,由于物理条件的限制,我们不得不从L2-L4层进行处理,我们常用的方式是:bridge,vlan,gre,sdn(openflow,opendaylight),以及一些厂家的产品等等。

  8. 高可用问题

    高可用问题是在分布式系统中必须要处理的问题,正因为集群的问题,我们必须要从多方面考虑解决的问题,包括保证云管理系统的高可用性,存储介质的高可用性,网络的高可用性,虚拟机高可用问题等等。

  9. 提高资源利用率问题

    对于物理资源的虚拟化,我们有很多种解决方法,KVM、Vmware、xen、Hyperv、LXC等等,在HVM的方式下,对于VM本身的启动需要占用大量的内存、cpu和存储资源,导致系统内存和cpu使用有一定的浪费,基于LXC的解决方案因为是机基于Host OS进程,通过namespace的方式进行隔离的,是一种轻量级的实现,能够在资源初始化,资源利用率方面能够最大化,对于各个应用场景来说,我们可以选用合适的解决方案。

   五、如何建设

  58同城经过多年的发展,探索了一条适合自身发展的技术架构体系。随着业务和技术的发展,团队规模不断壮大,在技术和管理上面临越来越多的挑战。在项目需求管理,开发效率、代码管理和质量建设,测试,线上发布,运维管理等方面需要有一套完整的解决方案,来提升公司的协作能力和整体能效。

  58同城目前所有的应用在线上都是跑在物理机器上,采用物理机的方式,一方面会导致服务器资源得不到充分和合理的使用,譬如:有些物理机器cpu使用长期在10%以下,有些内存使用剩余很多;另外一方面,由于互联网的特点,存在着时段内的访问高峰问题,需要解决资源使用的伸缩问题;基于以上问题,架构部对现有的技术体系进行梳理和分析,采用资源虚拟化的方式进行私有云的建设,并在这基础上,完善公司整体技术体系,包括:开发、测试、上线、运维等一系列自动化和智能化方面的建设。

  私有云的目标

  1. 提高物理资源的利用率
  2. 一套云管理系统,降低运维的复杂度,提高运维工作效率
  3. 构建灵活的开发、测试集成环境
  4. 提供海量的存储体系
  5. 建立完善的监控体系
  6. 建立基础应用环境、方便测试
  7. 统一架构
  8. 智能资源调度

  实施方案:OpenStack

  对于云计算来说,也存在着多种解决方案,如CloudStack和OpenStack等。在两种方案的比较之后,我们最终选择了OpenStack的解决方案。主要是出于以下几点原因:

  1. OpenStack的社区成熟度:OpenStack经过几年的发展,社区已经越来越成熟,很多大公司都参与进来帮助完善,红帽公司未来十年也将OpenStack作为发展的战略重点。
  2. 架构设计的选择:OpenStack采用了Python语言编写,并且设计上采用组件化的方式,各个组件独立发展,并相互解耦
  3. OpenStack提供了更加完整成熟的方案,能够满足多样的需求,同时已经有不少公司采用,已经经过生产上的验证
  4. 文档问题:OpenStack文档化做的不错,网上能够找到多种多样的问题处理办法
  5. 人员招聘问题,经过多年的发展和市场的培育,了解OpenStack的人越来越多,对于开发维护的人才建设和招聘相对成熟一些。
  6. 发展比较迅速

  下图是我们大致的架构规划

  文章观点仅一家之言,欢迎大家一起交流探讨。我计划在下一篇文章《58同城私有云建设实践》中详细介绍我们私有云建设的思路和过程,中间遇到的问题,希望跟大家一起探讨。

调查:成功创业者的15个特征,你拥有几个?

$
0
0

如果有人要你形容一下创业者,你会用什么词?充满激情的?专注敬业的?积极乐观的?当然,这些都可以。不过用“不安分”和“找麻烦”更贴切一些。下面提到的 15 个特征、特点、性格能否用来描述你?如果可以的话,你将可能成为一名伟大的创业者(如果没有行动,那就是伟大的口头创业者)。

1、 能立刻采取行动

Barbara Corcoran,Corcoran 集团创始人,《创智赢家》中的联合主演。在《鲨鱼智慧:我是如何把 1000 美元变成十亿美元生意的》这本书中她提到,那些头脑中有想法但是对于具体的策略细节不清楚的人,更有可能成为创业者。她说,“我讨厌有精美商业计划的创业者”。

她说,需要的时候再创造,不要把时间花在伏案写计划上。实际上,她认为有生活经验的人都有一个特点,他们具备解决问题的能力、认为站在自己的立场和资源上思考比看书有用。那些研究商业案例的人可能会花更多时间来过分解读形势,而不去采取行动来解决问题。

✓ 我具有这种特征

2、觉得安全感低

Corcoran 说,“许多被人称为有野心的创业者其实内心安全感很低。“当谈到投资的时候,她还说,“我会给很担心、很害怕的创业者投资”。那些对失败很紧张的人,在创业过程中会更加集中注意力,愿意拼尽全力去成功。如果感觉自己安全感不高,那就用这种感觉来驱使自己实现商业目标。

✓ 我具有这种特征

3、很机智

Zappos 总裁 Tony Hsieh 说,“我最喜欢的电视节目之一就是《百战天龙》,因为男主角马盖先自己没有那么多资源,但是却可以用最普通的东西化解各种危机”。

Hsieh 一辈子都在创业,他开办过蚯蚓农场,做过纽扣生意,卖过披萨,所以他很欣赏集创新、乐观和街头智慧的马盖先。“所以,我认为成为创业者就应该向马盖先一样”。他解释说,创业者不需要有足够的资源,但是一定要足智多谋。

✓ 我具有这种特征

4、整天想的就是现金流

在创办 Brainshark 之前,Jeo Gustafson 曾经创立过一家名为 Relational Courseware 的风险投资基金。他说,“我那时候做的所有事情都是和现金流动和偿债能力有关的。在风投 8 年的时间里,我有7次发现自己没有足够的资金来维持基金的运营”。

他是如何应对的?“一开始,你会用自己的信用卡来补上空缺,但并不是长远之计。即便你的公司是最好的公司,收账能力全球第一,那也需要现金,这样才能让公司继续开下去”。Gustafson 还给出了另外一个建议,那就是创业的时候找一个合伙人,让他为项目提前提供现金,与供应商保持密切交流。

✓ 我具有这种特征

5、经常遇到麻烦

Vancouver 公司总裁、创始人 Stephane Bourques 说,真正的创业者追求宽容,不求批准,他们宁愿让某人去做一件错事,也不希望他在征得上一级领导的同意后才去做一件事。

Bourque 说,“创业者对现状永不满意”。以前,他在别的公司工作的时候,经常会给领导提出一些新的、更好的方法,但是却被解读成是对公司的批评,这让他觉得自己不适合在企业工作。现在,他说,“我希望我的员工能遇到更多麻烦”,因为这样他们才能找到机会来提高自己,提高公司的运营水平。

✓ 我具有这种特征

6、无所畏惧

美国知名食品企业创业者 Robert Irvine 说,绝大多数人避免风险,创业者却在风险中看到机遇。创业者不怕变卖房产、信用卡套现来获得现金为企业注资。从一定程度上来讲,创业者是最乐观的人,因为他们深信他们投入的时间和金钱最后都能获得回报。

✓ 我具有这种特征

7、坐不住

即便员工已经下班了,创业者依旧有充分地动力激励着他们去工作。正是因他们这种对企业的渴望、冲动和干劲让他们脱颖而出。

✓ 我具有这种特征

8、可塑性强

硅谷连锁发型机构 Halo Blow Dry Bars 总裁 Rosemary Camposano 提醒说,“如果你的心中只有一个可以接受的结果,那么你创业成功的几率会很小”。如果你愿意聆听,你的客户会告诉你他们觉得哪个产品或服务最有价值。

Camposano 一开始想让自己的发型设计店兼做礼品店,“可以让忙碌的女人同时完成多件事情”。但是很快她发现,在发型设计店里卖礼品会给顾客造成困惑,所以她取消了礼品服务,换成了最好的发型设计设备。聪明的创业者会不断地进行改革,根据市场的反馈不断调正企业产品。

✓ 我具有这种特征

9、有欣赏/好奇的眼光

Little Nest Protraits 公司创始人 Laura Novak Meyer 说,因为没有直接的管理人,创业者需要适应自己,衡量自己的表现。这需要创业者具备“从身边的人征求意见来自我提高的意志”,同时也要注意到不请自来的反馈,比如说消费者的抱怨或者被竞争对手超越。Little Nest Portraits 公司会向每一名客户发送问卷,试图在问卷的答案中找到自我提升的机会。

✓ 我具有这种特征

10、喜欢接受挑战的激励

当遇到问题的时候,许多员工会绕过问题或者不去处理问题。而创业者则需要面对问题。Sky Zone 总裁 Jeff Platt 说,“因为挑战,所以创业者会工作得更加努力。一名合格的创业者不会觉得有什么问题是无法克服的”。

Sprinkles Cupcakes 的创始人 Candace Nelson 对此表示同意。尽管在本世纪初期有人对她的烘焙事业表示怀疑,但是她坚持了下来,现在她的纸杯蛋糕已经在美国 8 个州畅销。而且 Nelson 还是这一行业最成功的一批人,她的成功还引发了纸杯蛋糕的创业风潮。

✓ 我具有这种特征

11、把自己当外行

“创业者不总是容易被人接受,”J.P Licks 冰淇淋连锁创始人 Vincent Petryk 如是说。创业者可能固执己见,可能古怪,可能很苛刻,但这不是坏事。“他们因为行事不同而经常被拒绝,但这只能让他们更加努力。“Petryk 的前雇主不认可他在职权之外的冰激凌质量的研究,所以他便离职开始自己创办公司。Petryk 并没有模仿同行中的其他人的做法,向供货商要原材料进行加工,而是自己研发原料。他有没有竞争者?有,那就是外行的他自己。

✓ 我具有这种特征

12、能快速恢复

有人曾经说过,成功的创业者倒下之后能快速爬起来。上面提到的 Corcoran 的创业秘诀就是:如果你创业失败了,不要让自己觉得对不起自己;也不要深陷于悲伤中,赶紧起身前往下一个大目标!

✓ 我具有这种特征

13、能满足消费者需求

许多人都能发现市场的空缺,只有成功的创业者才能将创意变成现实。纽约女性社交网络 Savor the Success 合伙人 Jennifer Dawn 说,“创业者能发现解决问题的方法,然后去解决问题。他们是创新者”。当 Savor 的女性社交网络开始征求联合创始人 Angela Jia Kim 的意见时,她和 Dawn 创造了新的产品:Savor 圈子。这种圈子让 4 个人组合在一起,相互传授经验和专业技能;而且,这个新产品还给 Savor the Success 带来了全新的盈利方式。

✓ 我具有这种特征

14、周边人都是顾问

婴儿、家庭、个人护理产品企业 The Honest Company 的联合创始人、主席 Jessica Alba 说,“你的身边能有一群比你聪明的人,而且你也愿意听他们的想法,这一点很重要。我对于别人的观点、我不知道的内容很开放,因为我认为创业需要沟通、协作,有时候还需要失败”。

换句话说,真正的创业者与有经验、有研究的人交流,能够获得足够的信息,这样才能做出正确的决定,而不是摸着石头过河。

✓ 我具有这种特征

15、工作努力

在线兼职市场 Fiverr 创始人 Micha Kaufman 说,“跟体育比赛一样,创业成功的关键是让自己的注意力高度集中”。他们在产品上线后做的最多的事情不是寻找商机,而是解决了每个市场中都存在的最大的挑战:让市场流通起来。没有流通,就没有市场。这就好像,你还不会滑雪就开始担心自己会不会向前 360°空翻一样。要先学会滑雪,再去弄高难度的东西。

✓ 我具有这种特征

本文题图来自《创业邦》杂志(北京)

jQuery插件实现网页底部自动加载-类似新浪微博

$
0
0

要实现滚动条滚到底部自动加载后续内容到内容到底部的功能,用jQuery非常方便的,只要知道什么时候滚动到了底部就好办了。

 

$(document).scrollTop() //获取垂直滚动条到顶部的距离
$(document).height()//整个网页的高度
$(window).height()//浏览器窗口的高度
 

 

文档的高度减去窗口的高度就是滚动条可滚动的范围了。那么

$(window).scrollTop() + $(window).height()  >= $(document).height()
 

 

滚动条就到底部了,我们只要在$(window).scroll()中判断和加载内容就可以了:

$(function(){
  $(window).scroll(function() {
	  //当内容滚动到底部时加载新的内容
	  if ($(this).scrollTop() + $(window).height() + 20 >= $(document).height() && $(this).scrollTop() > 20) {
		  //当前要加载的页码
		  LoadPage(currPage);
	  }
  });
});
 

 

代码中的20是我设置的偏移量,如果底部有其它内容,要在看到底部内容时就加载,而不是必须滚动到底部,就需要这个偏移量了,$(this).scrollTop() > 20是为了不让页面还没有滚动就触发加载;至于页面要加载的内容当然是AJAX处理了,都在LoadPage()中处理就行了!

 

源自: http://www.playcode.cn/jquery-shi-xian-gun-dong-dao-di-bu-zi-dong-jia-zai-nei-rong-gun-dong-fan-ye.html

 

新浪微博网页自动底部加载的效果很酷吧?其实这种叫做“ 无限滚动的翻页技术”,当你页面滑到列表底部时候无需点击就自动加载更多的内容。

 

其实有很多jQuery的插件都已经实现了这个效果,我们来介绍几个吧!

 

1、jQuery ScrollPagination

jQuery ScrollPagination plugin 是一个jQuery 实现的支持无限滚动加载数据的插件。

地址: http://andersonferminiano.com/jqueryscrollpagination/

他的demo下载: http://andersonferminiano.com/jqueryscrollpagination/jqueryscrollpagination.zip

 

实例代码:

$(function(){
$('#content').scrollPagination({'contentPage': 'democontent.html', // the url you are fetching the results'contentData': {}, // these are the variables you can pass to the request, for example: children().size() to know which page you are'scrollTarget': $(window), // who gonna scroll? in this example, the full window'heightOffset': 10, // it gonna request when scroll is 10 pixels before the page ends'beforeLoad': function(){ // before load function, you can display a preloader div
$('#loading').fadeIn();
},'afterLoad': function(elementsLoaded){ // after loading content, you can use this function to animate your new elements
$('#loading').fadeOut();
var i = 0;
$(elementsLoaded).fadeInWithDelay();
if ($('#content').children().size() > 100){ // if more than 100 results already loaded, then stop pagination (only for testing)
$('#nomoreresults').fadeIn();
$('#content').stopScrollPagination();
}
}
});
// code for fade in element by element
$.fn.fadeInWithDelay = function(){
var delay = 0;
return this.each(function(){
$(this).delay(delay).animate({opacity:1}, 200);
delay += 100;
});
};
});

 

2、 jQuery Screw

Screw (scroll + view) 是一个 jQuery 插件当用户滚动页面的时候加载内容,是一个无限滚动翻页的插件。

官方地址: https://github.com/jasonlau/jQuery-Screw

 

3. AutoBrowse jQuery Plugin

Autobrowse jQuery Plugin 插件在用户滚动页面的时候自动通过 Ajax 加载更多内容,使用浏览器内置缓存。

官方地址: https://github.com/msjolund/jquery-esn-autobrowse

 源自: http://www.makeyuan.com/2014/02/21/1080.html





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


ITeye推荐



Viewing all 15843 articles
Browse latest View live


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