qileilove

blog已经转移至github,大家请访问 http://qaseven.github.io/

任意Android设备上运行测试

 图:打开数据源“对话框...
  
  图:添加一个简单数据表...
  
  图:添加设备名称到简单数据表
  这样做之后,切换到“数据绑定”选项卡,并绑定数据源中的模块变量。
  
  图:数据源绑定变量
  如果你想了解更多有关测试数据驱动的方法,参考第3课:数据驱动的测试。
  现在,测试套件准备好在不同的设备上运行了。 成功运行测试后,测试报告看起来应该像下面这样。
  
  图:两个设备上成功执行的测试
  我们会向你证明,在设备上运行您的Andr??oid测试是多么容易。添加其他设备,调制并部署测试的App,如本章前面所述。
  注意:在不同的设备上运行测试时,请一定要加一个'Close Application'的action,因为如果前一个设备上的 App不被关闭,那么接着执行时,这个设备上的App仍然会被自动化。
  图:添加“Close Application”action,以确保录制的脚本在正确的设备上执行
  这样做之后,对'Run Mobile App' 的'Device Display Name'列进行参数化,改成模块变量。
  
  图:把设备名称作为变量
  把设备名称参数化后,打开包含该模块用例的“数据源”对话框,添加一个简单数据表,在表中添加你想运行设备的名称。
 
并行执行测试
  它也可以在多个设备上同时运行一个测试。
  因为没有必要使用数据源,所以在测试用例属性对话框中禁用先前创建的数据源。
  
  图:禁用数据源
  添加一个全局参数,并把它绑定到变量'varMobileDevice'。
  
  图:添加全局参数
  
  图:把变量绑定到全局参数
  全局参数和数据绑定的进一步详情请参考“ 第3课:数据驱动测试。
  在对象库中,使用Ranorex Xpy 的path编辑器打开移动App的RanoreXPath,。
  
  图:打开高级RanoreXPath编辑器
  添加设备名称到RanoreXPath中,并选择变量'varMobileDevice'作为值。
  
  图:把设备名称变量添加到RanoreXPath
  执行这些步骤之后,你就可以编译测试套件,通过命令行,把移动设备名称作为命令行参数来执行测试用例,参考“ 第4课:Ranorex测试套件-无RanorexStudio运行测试 “:
  start MobileTest.exe /pa:globalMobileDevice="Galaxy Nexus"
  start MobileTest.exe /pa:globalMobileDevice="GT-P7500"

posted @ 2014-07-07 21:33 顺其自然EVO 阅读(228) | 评论 (0)编辑 收藏

lr检查点

 前言
  很久很久没有更新博客了。久到我都不记得上一次更新博客是什么时候,久到我们博客主机都过期了,一度我还想停掉这个博客。好在有simon的坚持才决定博客继续整下去。2013年对我来说是一个比较折腾的一年。一年之类换了两份工作。找工作的时候才发现理想与现实之间的差距是如此的巨大。期间经历了落差、失望、彷徨……
  最近一段时间给我们组成员培训LoadRunner,我自己也有所收获,也就有了这篇文章
  一、为什么要使用检查点
  为什么要使用检查点,那就要说明一下LR如何判断脚本是否执行成功。
  LR判断脚本是否执行成功是根据服务器返回的状态来确定的,如果服务器返回的HTTP状态为 200 OK ,那么VuGen 就认为脚本正确地运行了,并且是运行通过的。在绝大多数系统出错时会返回错误页面码? 不会一般系统都会返回一个消息提示框,来提升用户感受。例如,“网站繁忙,请稍后”。其实这个时候网站已经无法正确响应用户请求了,但是VuGen 脚本无法识别,会错误地认为网站还能正确访问,导致分析错误。所以这时需要一种检查点函数帮助验证请求发送出去后,服务器的返回是不是期望的内容,如果不是,那么就说明服务器返回无法提供正常的服务了。
  另外,需要特别说明的是,检查点一般跟事务结合起来使用。
  二、事务结束的四种状态
  前面说到检查点一般跟事务结合使用。这样需要说明一下事务(transaction)。我认为事务是LR中非常非常重要的一个概念。因为完成一个事务所需要的时间是响应时间(Trans Response Time),一秒钟可以完成多少事务是TPS(Trans/Sec)。响应时间和TPS是性能测试中非常重要的两个指标。可以通过这两个指标来分析系统是否出现瓶颈。
  LR中事务结束的时候需要带上一个状态码(Transaction Status)。LR中Transaction Status有四个, 分别为LR_PASS, LR_FAIL, LR_AUTO , LR_STOP。
  LR_AUTO:事物的状态被自动设置,如果事务执行成功,状态设置为PASS,如果执行失败,状态设置为FAIL,如果由于异常中断,状态被设置成STOP.
  LR_PASS:事务如果执行成功,代码的返回状态就是PASS。
  LR_FAIL:事务如果执行失败,代码的返回状态就是FAIL。
  一般情况下会选择LR_AUTO,让LR自动判断事务的状态。可是如上面所说LR判断脚本是否执行成功是根据服务器返回的状态来确定的,也就是只要服务器返回的HTTP状态为 200 OK ,事务执行后状态总是被置为LR_PASS。这样不科学的地方在于,LR提示成功的事务你不知道实际上它到底是成功的还是失败的。所以,这就需要检查点了。使用只有事务执行成功才会出现的文本或者图片(PS:虽然图片检查点我从来没用过)来作为事务是否执行成功的标准。
  三、如何添加检查点
  使用文本检查点(下面简称检查点)需要使用web_reg_find函数。函数的使用详见LR帮助手册,如果不会用可以下面的实战部分。
  另外说明一下如果web_reg_find查找中文失败,完全可以查找英文,只要能实现检查点功能就可以了,如果执意要查找英文,请将Record-Options 中勾选support charset中的UTF-8后重新录制。
  四、如何选择检查点
  选择什么作为检查点,这是困扰了很久了一个问题。就拿登陆来说,并不是所有的系统登陆完成后系统跳转到登陆成功的页面。这里这需要借助运行时查看器(run-time viewer)来帮助我们查找合适的检查点。运行时查看器在选择工具(tools)-常规选项(general Options)-显示(Display) ,选择 打开运行时查看器和自动排列窗口。
  运行时查看器的使用我还得感谢我们组成员文武同学。我还老吐槽他老开着这没用的玩意干嘛,我承认我错了。
 五、实战
  以网站www.huhoo.com(一不小心透露了经纬度)登陆举例,录制登陆脚本后回放,回放的时候打开运行时查看器。可以看到登陆成功后发回这样的信息。
  
图1 登陆成功后返回信息
  然后修改脚本,故意将用户名的密码弄错,重新回放
  
图2 登陆错误后返回信息
  结合两张图可以看出,用”code”:0作为检查点比较合适。因为这样的文本在登陆失败时没有出现。但是如果用“msg”来作为检查点就不合适,因为不管登陆成功和失败都出现了这也的文本,不能作为检查登陆成功的标准。
  检查点示例代码如下:
web_reg_find("Text=\"code\":0","SaveCount=Code_Count", LAST );
lr_start_transaction("login");
web_submit_data("login.quick",
"Action=http://www.huhoo.com/p/login.quick/",
……
"Name=account", "Value=XXXXXX", ENDITEM,
"Name=password", "Value=XXXXX", ENDITEM,
LAST);
if (atoi(lr_eval_string("{Code_Count}")) > 0){
//lr_output_message("Log on successful.");
lr_end_transaction("login", LR_PASS);
}
else{
lr_error_message("Log on failed");
lr_end_transaction("login", LR_FAIL);
return -1;
}
  完整脚本下载:传送门
  说明:
  脚本中用户名,密码已经被我用XXX替换,如果想用此脚本做实验,请到虎虎官网www.huhoo.com注册用户,并将用户名写入脚本中。

posted @ 2014-07-07 21:31 顺其自然EVO 阅读(667) | 评论 (0)编辑 收藏

Ant之build.xml详解

Ant的概念
  可能有些读者并不连接什么是Ant以及入可使用它,但只要使用通过Linux系统得读者,应该知道make这个命令。当编译Linux内核及一些软件的源程序时,经常要用这个命令。Make命令其实就是一个项目管理工具,而Ant所实现功能与此类似。像make,gnumake和nmake这些编译工具都有一定的缺陷,但是Ant却克服了这些工具的缺陷。最初Ant开发者在开发跨平台的应用时,用样也是基于这些缺陷对Ant做了更好的设计。
  Ant 与 makefile
  Makefile有一些不足之处,比如很多人都会碰到的烦人的Tab问题。最初的Ant开发者多次强调”只是我在Tab前面加了一个空格,所以我的命令就不能执行”。有一些工具在一定程度上解决了这个问题,但还是有很多其他的问题。Ant则与一般基于命令的工具有所不同,它是Java类的扩展。Ant运行需要的XML格式的文件不是Shell命令文件。它是由一个Project组成的,而一个Project又可分成可多target,target再细分又分成很多task,每一个task都是通过一个实现特定接口的java类来完成的。
  Ant的优点
  Ant是Apache软件基金会JAKARTA目录中的一个子项目,它有以下的优点。跨平台性。Ant是存Java语言编写的,所示具有很好的跨平台性。操作简单。Ant是由一个内置任务和可选任务组成的。Ant运行时需要一个XML文件(构建文件)。Ant通过调用target树,就可以执行各种task。每个task实现了特定接口对象。由于Ant构建文件时XML格式的文件,所以和容易维护和书写,而且结构很清晰。Ant可以集成到开发环境中。由于Ant的跨平台性和操作简单的特点,它很容易集成到一些开发环境中去。
  Ant 开发Ant的构建文件当开始一个新的项目时,首先应该编写Ant构建文件。构建文件定义了构建过程,并被团队开发中每个人使用。Ant构建文件默认命名为build.xml,也可以取其他的名字。只不过在运行的时候把这个命名当作参数传给Ant。构建文件可以放在任何的位置。一般做法是放在项目顶层目录中,这样可以保持项目的简洁和清晰。下面是一个典型的项目层次结构。
  (1) src存放文件。
  (2) class存放编译后的文件。
  (3) lib存放第三方JAR包。
  (4) dist存放打包,发布以后的代码。
  Ant构建文件是XML文件。每个构建文件定义一个唯一的项目(Project元素)。每个项目下可以定义很多目标(target元素),这些目标之间可以有依赖关系。当执行这类目标时,需要执行他们所依赖的目标。每个目标中可以定义多个任务,目标中还定义了所要执行的任务序列。Ant在构建目标时必须调用所定义的任务。任务定义了Ant实际执行的命令。Ant中的任务可以为3类。
  (1) 核心任务。核心任务是Ant自带的任务。
  (2) 可选任务。可选任务实来自第三方的任务,因此需要一个附加的JAR文件。
  (3) 用户自定义的任务。用户自定义的任务实用户自己开发的任务。
  1.<project>标签
  每个构建文件对应一个项目。<project>标签时构建文件的根标签。它可以有多个内在属性,就如代码中所示,其各个属性的含义分别如下。
  (1) default表示默认的运行目标,这个属性是必须的。
  (2) basedir表示项目的基准目录。
  (3) name表示项目名。
  (4) description表示项目的描述。
  每个构建文件都对应于一个项目,但是大型项目经常包含大量的子项目,每一个子项目都可以有自己的构建文件。
  2.<target>标签
  一个项目标签下可以有一个或多个target标签。一个target标签可以依赖其他的target标签。例如,有一个target用于编译程序,另一个target用于声称可执行文件。在生成可执行文件之前必须先编译该文件,因策可执行文件的target依赖于编译程序的target。Target的所有属性如下。
  (1) name表示标明,这个属性是必须的。
  (2) depends表示依赖的目标。
  (3) if表示仅当属性设置时才执行。
  (4) unless表示当属性没有设置时才执行。
  (5) description表示项目的描述。
  Ant的depends属性指定了target的执行顺序。Ant会依照depends属性中target出现顺序依次执行每个target。在执行之前,首先需要执行它所依赖的target。程序中的名为run的target的depends属性compile,而名为compile的target的depends属性是prepare,所以这几个target执行的顺序是prepare->compile->run。一个target只能被执行一次,即使有多个target依赖于它。如果没有if或unless属性,target总会被执行。3.<mkdir>标签
  该标签用于创建一个目录,它有一个属性dir用来指定所创建的目录名,其代码如下:<mkdir dir=”${class.root}”/>通过以上代码就创建了一个目录,这个目录已经被前面的property标签所指定。
  4.<jar>标签
  该标签用来生成一个JAR文件,其属性如下。
  (1) destfile表示JAR文件名。
  (2) basedir表示被归档的文件名。
  (3) includes表示别归档的文件模式。
  (4) exchudes表示被排除的文件模式。
  5.<javac>标签
  该标签用于编译一个或一组java文件,其属性如下:
  (1).srcdir表示源程序的目录。
  (2).destdir表示class文件的输出目录。
  (3).include表示被编译的文件的模式。
  (4).excludes表示被排除的文件的模式。
  (5).classpath表示所使用的类路径。
  (6).debug表示包含的调试信息。
  (7).optimize表示是否使用优化。
  (8).verbose 表示提供详细的输出信息。
  (9).fileonerror表示当碰到错误就自动停止。
  6.<java>标签
  该标签用来执行编译生成的.class文件,其属性如下。
  (1).classname 表示将执行的类名。
  (2).jar表示包含该类的JAR文件名。
  (3).classpath所表示用到的类路径。
  (4).fork表示在一个新的虚拟机中运行该类。
  (5).failonerror表示当出现错误时自动停止。
  (6).output 表示输出文件。
  (7).append表示追加或者覆盖默认文件。
  7.<delete>标签
  该标签用于删除一个文件或一组文件,去属性如下:
  (1).file表示要删除的文件。
  (2).dir表示要删除的目录。
  (3).includeEmptyDirs 表示指定是否要删除空目录,默认值是删除。
  (4).failonerror 表示指定当碰到错误是否停止,默认值是自动停止。
  (5).verbose表示指定是否列出所删除的文件,默认值为不列出。
  8.<copy>标签
  该标签用于文件或文件集的拷贝,其属性如下。
  (1).file 表示源文件。
  (2).tofile 表示目标文件。
  (3).todir 表示目标目录。
  (4).overwrite 表示指定是否覆盖目标文件,默认值是不覆盖。
  (5).includeEmptyDirs 表示制定是否拷贝空目录,默认值为拷贝。
  (6).failonerror 表示指定如目标没有发现是否自动停止,默认值是停止。
  (7).verbose 表示制定是否显示详细信息,默认值不显示。
  Ant的数据类型
  在构建文件中为了标识文件或文件组,经常需要使用数据类型。数据类型包含在
  org.apache.tool.ant.types包中。下面简单介绍构建文件中一些常用的数据类型。
  1. argument 类型
  由Ant构建文件调用的程序,可以通过<arg>元素向其传递命令行参数,如apply,exec和java任务均可接受嵌套<arg>元素,可以为各自的过程调用指定参数。以下是<arg>的所有属性。
  (1).values 是一个命令参数。如果参数种有空格,但又想将它作为单独一个值,则使用此属性。
  (2).file表示一个参数的文件名。在构建文件中,此文件名相对于当前的工作目录。
  (3).line表示用空格分隔的多个参数列表。
  (4).path表示路径。
  2.ervironment 类型
  由Ant构建文件调用的外部命令或程序,<env>元素制定了哪些环境变量要传递给正在执行的系统命令,<env>元素可以接受以下属性。
  (1).file表示环境变量值得文件名。此文件名要被转换位一个绝对路径。
  (2).path表示环境变量的路径。Ant会将它转换为一个本地约定。
  (3).value 表示环境变量的一个直接变量。
  (4).key 表示环境变量名。
  注意  file path 或 value只能取一个。
  3.filelist类型,Filelist 是一个支持命名的文件列表的数据类型,包含在一个filelist类型中的文件不一定是存在的文件。以下是其所有的属性。
  (1).dir是用于计算绝对文件名的目录。
  (2).files 是用逗号分隔的文件名列表。
  (3).refid 是对某处定义的一个<filelist>的引用。
  注意  dir 和 files 都是必要的,除非指定了refid(这种情况下,dir和files都不允许使用)。
  4.fileset类型
  Fileset 数据类型定义了一组文件,并通常表示为<fileset>元素。不过,许多ant任务构建成了隐式的fileset,这说明他们支持所有的fileset属性和嵌套元素。以下为fileset 的属性列表。
  (1).dir表示fileset 的基目录。
  (2).casesensitive的值如果为false,那么匹配文件名时,fileset不是区分大小写的,其默认值为true。
  (3).defaultexcludes 用来确定是否使用默认的排除模式,默认为true。
  (4).excludes 是用逗号分隔的需要派出的文件模式列表。
  (5).excludesfile 表示每行包含一个排除模式的文件的文件名。
  (6).includes 是用逗号分隔的,需要包含的文件模式列表。
  (7).includesfile 表示每行包括一个包含模式的文件名。
  5.patternset 类型
  Fileset 是对文件的分组,而patternset是对模式的分组,他们是紧密相关的概念。<patternset>支持4个属性:includes excludex includexfile 和 excludesfile,与fileset相同。Patternset 还允许以下嵌套元素:include,exclude,includefile 和 excludesfile。
 6.filterset 类型
  Filterset定义了一组过滤器,这些过滤器将在文件移动或复制时完成文件的文本替换。
  主要属性如下:
  (1).begintoken 表示嵌套过滤器所搜索的记号,这是标识其开始的字符串。
  (2).endtoken表示嵌套过滤器所搜索的记号这是标识其结束的字符串。
  (3).id是过滤器的唯一标志符。
  (4).refid是对构建文件中某处定义一个过滤器的引用。
  7.Path类型
  Path元素用来表示一个类路径,不过它还可以用于表示其他的路径。在用作揖个属性时,路经中的各项用分号或冒号隔开。在构建的时候,此分隔符将代替当前平台中所有的路径分隔符,其拥有的属性如下。
  (1).location 表示一个文件或目录。Ant在内部将此扩展为一个绝对路径。
  (2).refid 是对当前构建文件中某处定义的一个path的引用。
  (3).path表示一个文件或路径名列表。
  8.mapper类型
  Mapper类型定义了一组输入文件和一组输出文件间的关系,其属性如下。
  (1).classname 表示实现mapper类的类名。当内置mapper不满足要求时,用于创建定制mapper。
  (2).classpath表示查找一个定制mapper时所用的类型路径。
  (3).classpathref是对某处定义的一个类路径的引用。
  (4).from属性的含义取决于所用的mapper。
  (5).to属性的含义取决于所用的mapper。
  (6).type属性的取值为identity,flatten glob merge  regexp  其中之一,它定义了要是用的内置mapper的类型。
  Ant 的运行
  安装好Ant并且配置好路径之后,在命令行中切换到构建文件的目录,输入Ant命令就可以运行Ant.若没有指定任何参数,Ant会在当前目录下查询build.xml文件。如果找到了就用该文件作为构建文件。如果使用了 –find 选项,Ant 就会在上级目录中找构建文件,直至到达文件系统得跟目录。如果构建文件的名字不是build.xml ,则Ant运行的时候就可以使用 –buildfile file,这里file 指定了要使用的构建文件的名称,示例如下:
  Ant如下说明了表示当前目录的构建文件为build.xml 运行 ant 执行默认的目标。
  Ant –buildfile  test.xml使用当前目录下的test.xml 文件运行Ant ,执行默认的目标

posted @ 2014-07-07 21:29 顺其自然EVO 阅读(183) | 评论 (0)编辑 收藏

Ant编译时遇到的问题记录

 1. 需要使用svnant,从SVN中获取源码
  需要使用的扩展包:svnant-1.3.1.zip里所有的jar
  下载地址:http://subclipse.tigris.org/files/documents/906/49042/svnant-1.3.1.zip
  build.xml中的写法
<!--定义SVN地址-->
<property name="svnurl" value="http://xx/svn/projectName"/>
<!-- -->
<typedef resource="org/tigris/subversion/svnant/svnantlib.xml" />
<!--定义访问SVN的账号和密码-->
<svnSetting id="svn.setting" svnkit="true" username="username" password="password"  javahl="false" />
<!--检出代码到${project.dir}变量定义的目录下-->
<target name="export">
<delete dir="${project.dir}" />
<mkdir dir="${project.dir}" />
<svn refid="svn.setting">
<export srcUrl="${svnurl}" destPath="${project.dir}" force="true"/>
</svn>
</target>
  2.foreach循环需要使用ant-contrib-1.0b3.jar
  下载地址请百度
  build.xml中的写法
  <target name="loop" >
  <foreach list="src" target="all" param="src_loop" delimiter=","></foreach>
  </target>
  3. yguard代码混淆
  具体介绍参见:http://blog.csdn.net/vrix/article/details/7604636
  官网下载地址:http://www.yworks.com/en/downloads.html
  build.xml中的写法
<taskdef name="yguard" classname="com.yworks.yguard.YGuardTask"/>
<yguard>
<inoutpair in="${输入.jar}" out="${输出.jar}"/>
<shrink logfile="${build.dir}/shrink.xml">
<keep>
<class classes="friendly" methods="private" fields="friendly"/>
<field name="serialVersionUID"/>
</keep>
</shrink>
</yguard>
  4.执行脚本操作
  启动tomcat在build.xml中的写法
linux
<target name="start" >
<echo>start tomcat</echo>
<exec executable = "${tomcat.dir}/bin/startup.sh" />
</target>
windows
<target name="stop" >
<echo>stop tomcat</echo>
<exec executable="cmd" dir="${tomcat.dir}/bin" failonerror="false"  append="true">
<env key="CATALINA_HOME" path="${tomcat.dir}"/>
<arg value="/c startup.bat" />
</exec>
</target>

posted @ 2014-07-07 21:28 顺其自然EVO 阅读(215) | 评论 (0)编辑 收藏

XSS前端防火墙—天衣无缝的防护

  讲解了钩子程序的攻防实战,并实现了一套对框架页的监控方案,将防护作用到所有子页面。
  到目前为止,我们防护的深度已经差不多,但广度还有所欠缺。
  例如,我们的属性钩子只考虑了 setAttribute,却忽视还有类似的 setAttributeNode。尽管从来不用这方法,但并不意味人家不能使用。
  例如,创建元素通常都是 createElement,事实上 createElementNS 同样也可以。甚至还可以利用现成的元素 cloneNode,也能达到目的。因此,这些都是边缘方法都是值得考虑的。
  下面我们对之前讨论过的监控点,进行逐一审核。
  内联事件执行 eval
  在第一篇文章结尾谈到,在执行回调的时候,最好能监控 eval,setTimeout('...') 这些能够解析代码的函数,以防止执行储存在其他地方的 XSS 代码。
  先来列举下这类函数:
  eval
  setTimeout(String) / setInterval(String)
  Function
  execScript / setImmediate(String)
  事实上,利用上一篇的钩子技术,完全可以把它们都监控起来。但现实并没有我们想象的那样简单。
  eval 重写有问题吗
  eval 不就是个函数,为什么不可以重写?
  var raw_fn = window.eval;
  window.eval = function(exp) {
  alert('执行eval: ' + exp);
  return raw_fn.apply(this, arguments);
  };
  console.log(eval('1+1'));
  完全没问题啊。那是因为代码太简单了,下面这个 Demo 就可以看出山寨版 eval 的缺陷:
  (function() {
  eval('var a=1');
  })();
  alert(typeof a);
  Run
  按理说应该 undefined 才对,结果却是 number。局部变量都跑到全局上来了。这是什么情况?事实上,eval 并不是真正意义的函数,而是一个关键字!想了解详情请戳这里。
  Function 重写有意义吗
  Function 是一个全局变量,重写 window.Function 理论上完全可行吧。
  var raw_fn = window.Function;
  window.Function = function() {
  alert('调用Function');
  return raw_fn.apply(this, arguments);
  };
  var add = Function('a', 'b', 'return a+b');
  console.log( add(1, 2) );
  重写确实可行。但现实却是不堪一击的:因为所有函数都是 Function 类的实例,所以访问任何一个函数的 constructor 即可得到原始的 Function。
 例如 alert.constructor,就可以绕过我们的钩子。甚至可以用匿名函数:
  (function(){}).constructor
  所以,Function 是永远钩不住的。
  额外的执行方法
  就算不用这类函数,仍有相当多的办法执行字符串,例如:
  创建脚本,innerHTML = 代码
  创建脚本,路径 = data:代码
  创建框架,路径 = javascript:代码
  ......
  看来,想完全把类似 eval 的行为监控起来,是不现实的。不过作为预警,我们只监控 eval,setTimeout/Interval 也就足够了。
  可疑模块拦截
  第二篇谈了站外模块的拦截。之所以称之『模块』而不是『脚本』,并非只有脚本元素才具备执行能力。框架页、插件都是可以运行代码的。
  可执行元素
  我们列举下,能执行远程模块的元素:
  脚本
  <script src="..." />
  框架
  <iframe src="...">
  <frame src="...">
  插件(Flash)
  <embed src="...">
  <object data="...">
  <object><param name="moive|src" value="..."></object>
  插件(其他)
  <applet codebase="...">
  这些元素的路径属性,都应该作为排查的对象。
  不过,有这么个元素的存在,可能导致我们的路径检测失效,它就是:
  <base href="...">
  它能重定义页面的相对路径,显然是不容忽视的。
  事实上,除了使用元素来执行站外模块,还可以使用网络通信,获得站外的脚本代码,然后再调用 eval 执行:
  AJAX
  目前主流浏览器都支持跨域请求,只要服务端允许就可以。因此,我们需监控 XMLHttpRequest::open 方法。如果请求的是站外地址,就得做策略匹配。不通过则放弃向上调用,或者抛出一个异常,或者给 XHR 产生一个 400 状态。
  WebSocket
  WebSocket 和 XHR 类似,也能通过钩子的方法进行监控。
  不过,值得注意的是,WebSocket 并非是个函数,而是一个类。因此,在返回实例的时候,别忘了将 constructor 改成自己的钩子,否则就会泄露原始接口:
  var raw_class = window.WebSocket;
  window.WebSocket = function WebSocket(url, arg) {
  alert('WebSocket 请求:' + url);
  var ins = new raw_class(url, arg);
  // 切记
  ins.constructor = WebSocket;
  return ins;
  };
  var ws = new WebSocket('ws://127.0.0.1:1000');
  另外,因为它是一个类,所以不要忽略了静态方法或属性:
  WebSocket.CONNECTING
  WebSocket.OPEN
  ...
  因此,还需将它们拷贝到钩子上。
  框架页消息
  HTML5 赋予了框架页跨域通信的能力。如果没有为框架元素建立白名单的话,攻击者可以嵌入自己的框架页面,然后将 XSS 代码 postMessage 给主页面,通过 eval 执行。
  不过为了安全考虑,HTML5 在消息事件里保存了来源地址,以识别消息是哪个页面发出的。
  因为是个事件,我们可以使用第一篇文章里提到的方法,对其进行捕获。每当有消息收到时,可以根据策略,决定是否阻止该事件的传递。
// 我们的防御系统
(function() {
window.addEventListener('message', function(e) {
if (confirm('发现来自[' + e.origin + ']的消息:\n\n' + e.data + '\n\n是否拦截?')) {
e.stopImmediatePropagation();
}
}, true);
})();
window.addEventListener('message', function(e) {
alert('收到:' + e.data)
})
postMessage('hello', '*');
Run


  昨天尝试了一系列的可疑模块拦截试验,尽管最终的方案还存在着一些兼容性问题,但大体思路已经明确了:
  静态模块:使用 MutationObserver 扫描。
  动态模块:通过 API 钩子来拦截路径属性。
  提到钩子程序,大家会联想到传统应用程序里的 API Hook,以及各种外挂木马。当然,未必是系统函数,任何 CPU 指令都能被改写成跳转指令,以实现先运行自己的程序。
  无论是在哪个层面,钩子程序的核心理念都是一样的:无需修改已有的程序,即可先执行我们的程序。
  这是一种链式调用的模式。调用者无需关心上一级的细节,直管用就是了,即使有额外的操作对其也是不可见的。从最底层的指令拦截,到语言层面的虚函数继承,以及更高层次的面向切面,都带有这类思想。
  对于 JavaScript 这样灵活的语言,任何模式都可以实现。之前做过一个网页版的变速齿轮,用的就是这类原理。
  JavaScript 钩子小试
  要实现一个最基本的钩子程序非常简单,昨天已演示过了。现在我们再来给 setAttribute 接口实现一个钩子:
// 保存上级接口
var raw_fn = Element.prototype.setAttribute;
// 勾住当前接口
Element.prototype.setAttribute = function(name, value) {
// 额外细节实现
if (this.tagName == 'SCRIPT' && /^src$/i.test(name)) {
if (/xss/.test(value)) {
if (confirm('试图加载可疑模块:\n\n' + url + '\n\n是否拦截?')) {
return;
}
}
}
raw_fn.apply(this, arguments);
};
// 创建脚本
var el = document.createElement('script');
el.setAttribute('SRC', 'http://www.etherdream.com/xss/alert.js');
document.body.appendChild(el);
Run
  类似昨天的访问器拦截,现在我们对 setAttribute 也进行类似的监控。因为它是个函数,所有主流浏览器都兼容。
  钩子泄露
  看起来似乎毫无难度,而且也没什么不对的地方,这不就可以了吗?
  如果最终就用这代码,那也太挫了。我们把原始接口都暴露在全局变量里了,攻击者只要拿了这个变量,即可绕过我们的检测代码:
  var el = document.createElement('script');
  // 直接调用原始接口
  raw_fn.call(el, 'SRC', 'http://www.etherdream.com/xss/alert.js');
  document.body.appendChild(el);
  Run

posted @ 2014-07-07 21:27 顺其自然EVO 阅读(178) | 评论 (0)编辑 收藏

如何对所发现的缺陷进行严密的等级划分?

 提问:如何对所发现的缺陷进行严密的等级划分?
  回答:测试过程中发现的缺陷一般分为如下几类
  功能问题(FunctionError):对产品、项目质量有影响,但尚难以确定是否是错误,暂时无法解决
  功能缺陷(FunctionDefect):不满足用户需求等bug的总称
  页面缺陷(UIDefect):页面美观性、协调性、错别字等
  建议类(Suggestion):对产品、项目的建议性意见,不强制要求修改
  硬件性能:进行性能测试时使用,暂定:网络延时、内存问题、CPU占用、硬盘问题
  安全性问题:进行系统安全测试时使用,暂不订具体标准
  业务流程问题:进行业务流程测试时进行
  数据库性能:暂不执行
  模块间接口问题:涉及有模块间数据传递时使用
  其他(Other):其它
  根据各类缺陷的严重程度将缺陷分为5个等级,具体如下:
  1)低(Low)
  建议类错误,对软件的改进意见或者建议。如:
  a)功能建议
  b)操作建议
  c)校验建议
  d)说明建议
  e)UI建议
  2)中(Medium)
  使操作者不合理或者不方便或操作遇到麻烦,但它不影响执行工作功能或重要功能,次要功能,对产品使用影响不大。如:
  界面错误
  a)使操作者不方便或者遇到麻烦,但不影响执行工作功能的实现
  b)界面、控件的摆布、图标、输入输出不规范
  提示类错误
  a)删除操作未给出提示
  b)长时间操作未给出提示
  c)提示窗口文字未采用行业术语
  d)出错没有提示
  其他错误
  a)不符合编码标准
  b)辅助说明描述不清楚、不规范
  c)快捷键无效,快捷键错误操作
  d)打印内容、格式错误
  3)高(High)
  影响系统正常运行的缺陷,主要功能出现错误,影响到产品的使用。如:
  数据库缺陷:数据库设计未达到第三范式的要求或需求规格说明的格式水平
  操作错误:因错误操作迫使程序中断
  功能错误:
  a)程序功能无法实现
  b)程序功能实现错误
  其他错误:
  a)脚本错误
  b)软件产品的编译,打包,安装,卸载错误
  4)非常高(Very High)
  规定的功能没有实现或不完整或产生错误结果;设计不合理造成性能低下,影响系统的运营;使系统不稳定、或破坏数据;而且是常规操作中经常发生或非常规操作中不可避免的主要问题,且没有办法更正(重新安装或重新启动软件不属更正办法),须尽快修正,如:
  数据缺陷
  a)数据计算错误
  b)数据约束错误
  c)数据输入、输出错误
  数据库缺陷
  a)数据库发生死锁
  b)数据库的表、业务规则、缺省值未加完整性等约束条件
  c)数据库连接错误
  d)数据通讯错误
  接口缺陷
  a)程序接口错误
  b)硬件接口、通讯错误
  功能错误:
  a)程序功能无法实现
  b)程序功能实现错误
  5)紧急(Critical)
  不能执行正常工作或重要功能,使系统崩溃或资源严重不足,数据丢失(金币,包子)非常死机等导致系统不能继续运行须马上修正,如:
  a)由于程序所引起的死机,非法退出
  b)程序死循环
  c)性能与需求不一致(压力测试)
  d)存在安全性与保密性问题
  e)文件打开与保存错误
  总结:
  1级-建议问题的软件缺陷(Enhancemental):由问题提出人对测试对象的改进意见或测试人员提出的建议、质疑。
  2级—较小错误的软件缺陷(Minor),使操作者不方便或遇到麻烦,但它不影响功能过的操作和执行,如错别字、界面不规范(字体大小不统一,文字排列不整齐,可输入区域和只读区域没有明显的区分标志),辅助说明描述不清楚。
  3级—一般错误的软件缺陷(major):次要功能没有完全实现但不影响使用。如提示信息不太准确,或用户界面差,操作时间长,模块功能部分失效等,打印内容、格式错误,删除操作未给出提示,数据库表中有过多的空字段等。
  4级—严重错误的软件缺陷(critical):系统的主要功能部分丧失、数据不能保存,系统的次要功能完全丧失。问题局限在本模块,导致模块功能失效或异常退出。如致命的错误声明,程序接口错误,数据库的表、业务规则、缺省值未加完整性等约束条件
  5级—致命的软件缺陷(Fatal):造成系统或应用程序崩溃、死机、系统挂起,或造成数据丢失,主要功能完全丧失,导致本模块以及相关模块异常等问题。如代码错误,死循环,数据库发生死锁、与数据库连接错误或数据通讯错误,未考虑异常操作,功能错误等。
原帖地址:http://bbs.51testing.com/thread-1000328-1-1.html

posted @ 2014-07-07 21:25 顺其自然EVO 阅读(271) | 评论 (0)编辑 收藏

JAVA Reflection(反射机制)

 Java 反射机制
  反射机制简介
  反射机制应用示例
  简单的Ioc实现
  代理模式
  Java动态代理
  简单的Aop实现
  “程序运行时,允许改变程序结构或变量类型,这种语言称为动态语言”。从这个观点看,Perl,PythonRuby是动态语言,C++,Java,C#不是动态语言。
  尽管在这样得定义与分类下Java不是动态语言,它却有着一个非常突出的动态相关的机制:反射机制 (Reflection)。
  什么是反射?
  反射的概念是由Smith在1982年首次提出的,主要是指程序可以访问、检测和修改它本身状态或者行为的一种能力。
  JAVA反射机制都是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法;这种动态获取的信息以及动态调用对象的方法的功能称为Java语言的反射机制。
  JAVA反射机制(Reflection)
  动态获取类的信息,以及动态调用对象的方法的功能。
  主要提供了以下功能:
  在运行时判断任意一个对象所属的类;
  在运行时构造任意一个类的对象;
  在运行时判断任意一个类所具有的成员变量和方法;
  在运行时调用任意一个对象的方法;
  生成动态代理。
  JAVA反射机制包
  在 JDK 中,主要由以下类来实现 Java  反射机制,这些类都位于 java.lang.reflect包中。
  Class 类:代表一个类。
  Field 类:代表类的成员变量(成员变量也称为类的属性)。
  Method 类:代表类的方法。
  Constructor 类:代表类的构造方法。
  Array 类:提供了动态创建数组,以及访问数组元素的静态方法。
  java.lang.Class
  static Class forName(String className)
  返回描述类名为className的Class对象
  Object newInstance()
  返回一个类的一个新实例
  Field[] getFields()
  返回包含Field对象的数组,这些对象记录了这个类或者其超类的公共域
  Field[] getDeclaredField()
  返回包含Field对象的数组,这些对象记录了这个类的全部域
  Method[] getMethods()                             返回这个类或者其超类所有的公有方法
  Method[] getDeclareMethods()                 返回这个类或者接口的所有方法,不包括超类继承的方法
  Constructor[] getConstructors()                返回所有包含了Class对象所描述类的公有构造器
  Constructor[] getDeclaredConstructors()  返回包含了Class对象所描述的类的所有构造器
 Java.lang.reflect.Constructor
  Class[] getParameterTypes()
  返回一个用于描述参数类型的Class对象数组
  getReturnType()
  返回一个用于描述返回类型的Class对象
  int getModifiers()
  返回一个用于描述方法抛出的异常类型的Class对象数组
  Class getDeclaringClass()
  返回一个用于描述类中定义的构造器、方法或域的Class对象
  通过反射实例化参数
  平常实例化对象通常使用new关键字。但是使用new关键字实例化的对象具有强耦合性。New对象无法胜任未知对象的实例化,这时候只能通过反射动态生成。例如Spring的DI。
  实例化无参构造函数的对象
  Class.newInstance()
  Class.getConstructor(new Class[]{}).newInstance(new Object[]{})
  实例化带参构造函数的对象
  Clazz.getConstructor(Class<?> ...ParameterType).newInstance(Object ...initargs)
  反射机制举例
import java.lang.reflect.*;
public class DumpMethods {
public static void main(String args[]) throws Exception{
//加载并初始化命令行参数指定的类
Class classType = Class.forName(args[0]);
//获得类的所有方法
Method methods[] = classType.getDeclaredMethods();
for(int i = 0; i < methods.length; i++)
System.out.println(methods[i].toString());
}
}
输入:java DumpMethods java.util.Stack
public synchronized java.lang.Object java.util.Stack.pop()
public java.lang.Object java.util.Stack.push(java.lang.Object)
public boolean java.util.Stack.empty()
public synchronized java.lang.Object java.util.Stack.peek()
public synchronized int java.util.Stack.search(java.lang.Object)
  运用反射机制调用方法
  getMethod和invoke方法的时序图


 获取反射对象
import java.lang.reflect.*;
public class ReflectTester {
public Object  copy(Object object) throws Exception{
//获得对象的类型
Class classType=object.getClass();
System.out.println("Class:"+classType.getName());
//通过默认构造方法创建一个新的对象
Object  objectCopy=classType.getConstructor(new Class[]{}).
newInstance(new Object[]{});
//获得对象的所有属性
Field fields[]=classType.getDeclaredFields();
for(int i=0; i<fields.length;i++){
Field field=fields[i];
String fieldName=field.getName();
String firstLetter=fieldName.substring(0,1).toUpperCase();
//获得和属性对应的 getXXX()方法的名字
String getMethodName="get"+firstLetter+fieldName.substring(1);
//获得和属性对应的 setXXX()方法的名字
String setMethodName="set"+firstLetter+fieldName.substring(1);
//获得和属性对应的 getXXX()方法
Method getMethod=classType.getMethod(getMethodName,new Class[]{});
//获得和属性对应的 setXXX()方法
Method setMethod=classType.getMethod(setMethodName,new Class[]{field.getType()});
//调用原对象的 getXXX()方法
Object value=getMethod.invoke(object,new Object[]{});
System.out.println(fieldName+":"+value);
//调用复制对象的 setXXX()方法
setMethod.invoke(objectCopy,new Object[]{value});
}
return objectCopy;
}
public static void main(String[] args) throws Exception{
Customer customer=new Customer("Tom",21);
customer.setId(new Long(1));
Customer customerCopy=(Customer)new ReflectTester().copy(customer);
System.out.println("Copy information:"+customerCopy.getName()+
“ "+  customerCopy.getAge());
}
}
  运用反射机制调用方法
class Customer{
//Customer 类是一个 JavaBean
private Long id;
private String name;
private int age;
public Customer(){}
public Customer(String name,int age){
this.name=name;
this.age=age;
}
public Long getId(){return id;}
public void setId(Long id){this.id=id;}
public String getName(){return name;}
public void setName(String name){this.name=name;}
public int getAge(){return age;}
public void setAge(int age){this.age=age;}
}
import java.lang.reflect.*;
public class InvokeTester {
public int add(int param1,int param2){  return param1+param2;   }
public String echo(String msg){   return "echo:"+msg; }
public static void main(String[] args) throws Exception{
Class classType=InvokeTester.class;
Object invokeTester=classType.newInstance();
//调用 InvokeTester 对象的 add()方法
Method addMethod=classType.getMethod("add",new Class[]{int.class,int.class});
Object result=addMethod.invoke(invokeTester,
new Object[]{new Integer(100),new Integer(200)});
System.out.println((Integer)result);
//调用 InvokeTester 对象的 echo()方法
Method echoMethod=classType.getMethod("echo",new Class[]{String.class});
result=echoMethod.invoke(invokeTester,new Object[]{"Hello"});
System.out.println((String)result);
}
}

posted @ 2014-07-07 20:53 顺其自然EVO 阅读(126) | 评论 (0)编辑 收藏

Java高速、多线程虚拟内存的实现

 本文作者Alex已经从事Java开发15年了,最近帮助开发了COBOL和Magik语言的JVM 。当前,他正致力于Micro Focus的Java性能测试工具。在本文中,他阐述了在标准硬件中实现高速、多线程虚拟内存的可能性及方案。原文内容如下。
  你想在标准硬件上运行TB级甚至PB级内存的JVM吗?你想与内存交互一样读写文件,且无需关心文件的打开、关闭、读、写吗?
  JVM的64位地址空间使这些成为可能。
  首先,不要在观念上将内存和磁盘进行区分,而是统一处理为内存映射文件。在32位地址空间时,内存映射文件只是为了高速访问磁盘;因为受限于虚拟机的有限地址空间,并不支持大规模的虚拟内存或大文件。如今JVM已经发展为64位,而且可以在64位操作系统上运行。在一个进程的地址空间中,内存映射文件大小就可以达到TB甚至PB。
  进程无需关心内存是在RAM或是磁盘上。操作系统会负责处理,而且处理得非常高效。
  我们可以使用Java的MappedByteBuffer类访问内存映射文件。该类的实例对象与普通的ByteBuffer一样,但包含的内存是虚拟的——可能是在磁盘上,也可能是在RAM中。但无论哪种方式,都是由操作系统负责处理。因为的ByteBuffer的大小上限是Intger.MAX_VALUE,我们需要若干个ByteBuffer来映射大量内存。在这个示例中,我映射了40GB。
  这是因为我的Mac只有16GB内存,下面代码证明了这一点!
public MapperCore(String prefix, long size) throws IOException {
coreFile = new File(prefix + getUniqueId() + ".mem");
// This is a for testing - to avoid the disk filling up
coreFile.deleteOnExit();
// Now create the actual file
coreFileAccessor = new RandomAccessFile(coreFile, "rw");
FileChannel channelMapper = coreFileAccessor.getChannel();
long nChunks = size / TWOGIG;
if (nChunks > Integer.MAX_VALUE)
throw new ArithmeticException("Requested File Size Too Large");
length = size;
long countDown = size;
long from = 0;
while (countDown > 0) {
long len = Math.min(TWOGIG, countDown);
ByteBuffer chunk = channelMapper.map(MapMode.READ_WRITE, from, len);
chunks.add(chunk);
from += len;
countDown -= len;
}
}
  上面的代码在虚拟内存创建了40GB MappedByteBuffer对象列表。读取和写入时只需要注意处理两个内存模块的跨越访问。完整代码的可以在这里找到。
线程
  一个极其强大且简单易用的方法就是线程。但是普通的Java IO简直就是线程的噩梦。两个线程无法在不引起冲突的情况下同时访问相同的数据流或RandomAccessFile 。虽然可以使用非阻塞IO,但是这样做会增加代码的复杂性并对原有的代码造成侵入。
  与其他的内存线程一样,内存映射文件也是由操作系统来处理。可以根据读写需要,在同一时刻尽可能多的使用线程。我的测试代码有128个线程,而且工作得很好(虽然机器发热比较大)。唯一重要的技巧是复用MappedByteBuffer对象,避免自身位置状态引发问题。
  现在可以执行下面的测试:
@Test
public void readWriteCycleThreaded() throws IOException {
final MapperCore mapper = new MapperCore("/tmp/MemoryMap", BIG_SIZE);
final AtomicInteger fails = new AtomicInteger();
final AtomicInteger done = new AtomicInteger();
Runnable r = new Runnable() {
public void run() {
try {
// Set to 0 for sequential test
long off = (long) ((BIG_SIZE - 1024) * Math.random());
System.out.println("Running new thread");
byte[] bOut = new byte[1024];
double counts = 10000000;
for (long i = 0; i < counts; ++i) {
ByteBuffer buf = ByteBuffer.wrap(bOut);
long pos = (long) (((BIG_SIZE - 1024) * (i / counts)) + off)
% (BIG_SIZE - 1024);
// Align with 8 byte boundary
pos = pos / 8;
pos = pos * 8;
for (int j = 0; j < 128; ++j) {
buf.putLong(pos + j * 8);
}
mapper.put(pos, bOut);
byte[] bIn = mapper.get(pos, 1024);
buf = ByteBuffer.wrap(bIn);
for (int j = 0; j < 128; ++j) {
long val = buf.getLong();
if (val != pos + j * 8) {
throw new RuntimeException("Error at " + (pos + j * 8) + " was " + val);
}
}
}
System.out.println("Thread Complete");
} catch (Throwable e) {
e.printStackTrace();
fails.incrementAndGet();
} finally {
done.incrementAndGet();
}
}
};
int nThreads = 128;
for (int i = 0; i < nThreads; ++i) {
new Thread(r).start();
}
while (done.intValue() != nThreads) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// ignore
}
}
if (fails.intValue() != 0) {
throw new RuntimeException("It failed " + fails.intValue());
}
}
  我曾尝试进行其他形式的IO,但是只要像上面那样运行128个线程,性能都不如上面的方法。我在四核、超线程I7 Retina MacBook Pro上尝试过。代码运行时会启动128个线程,超出CPU的最大负载(800%),直到操作系统检测到该进程的内存不足。在这个时候,系统开始对内存映射文件的读写进行分页。为实现这一目标,内核会占用一定的CPU,Java进程的性能会下降到650~750%。Java无需关心读取、写入、同步或类似的东西——操作系统会负责处理。
  结果会有所不同
  如果读取和写入点不是连续而是随机的,性能下降有所区别(带有交换时会达到750%,否则会达到250%)。我相信这种方式可能更适合处理少量的大数据对象,而不适用于大量的小数据对象。对于后者,可能的处理办法是预先将大量小数据对象加载到缓存中,再将其映射到虚拟内存。
  应用程序
  到目前为止,我使用的技术都是虚拟内存系统。在示例中,一旦与虚拟内存交互完成,就会删除底层文件。但是,这种方法可以很容易地进行数据持久化。
  例如,视频编辑是一个非常具有挑战性的工程问题。一般来说,有两个有效的方法:无损耗存储整个视频,并编辑存储的信息;或根据需要重新生成视频。因为RAM的制约,后一种方法越来越普遍。然而,视频是线性的——这是一种理想的数据类型,可用来存储非常大的映射虚拟内存。由于在视频算法上取得的进步,可以将它作为原始字节数组访问。操作系统会根据需要将磁盘到虚拟内存的缓冲区进行分页处理。
  另一个同样有效的应用场景是替代文档服务中过度设计的RAM缓存解决方案。想想看,我们有一个几TB的中等规模的文档库。它可能包含图片、短片和PDF文件。有一种常见的快速访问磁盘的方法,使用文件的RAM缓存弱引用或软引用。但是,这会对JVM垃圾收集器产生重大影响,并且增加操作难度。如果将整个文档映射到虚拟内存,可以更加简单地完成同样的工作。操作系统会根据需要将数据读入内存。更重要的是,操作系统将尽量保持RAM中最近被访问的内存页。这意味着内存映射文件就像RAM缓存一样,不会对Java或JVM垃圾收集器产生任何影响。
  最后,内存映射文件在科学计算和建模等应用中非常有效。在用来处理代表真实世界系统的计算模型时,经常需要大量的数据才能正常工作。在我的音频处理系统Sonic Field中,通过混合和处理单一声波,可以模拟真实世界中的音频效果。例如,创建原始音频副本是为模拟从硬表面反射的声波,并将反射回来的声波与原声波混合。这种方法需要大量的存储空间,这时就可以把音频信号放在虚拟内存中(也是这项工作的最初动机)。

posted @ 2014-07-07 20:47 顺其自然EVO 阅读(189) | 评论 (0)编辑 收藏

NoSQL数据库:数据的一致性

读取一致性
  · 强一致性
  在任何时间访问集群中任一结点,得到的数据结果一致;
  · 用户一致性
  对同一用户,访问集群期间得到的数据一致;
  解决用户一致性:使用粘性会话,将会话绑定到特定结点来处理;
  这样会降低负载均衡器的性能;
  · 最终一致性
  集群中各结点间由于数据同步不及时造成暂时的数据不一致,但数据同步完成后,最终具有一致性;
  更新一致性
  · 悲观方式
  使用写锁
  大幅降低系统响应能力
  可能导致死锁
  · 乐观方式
  先让冲突发生,再检测顺序
  自动合并的处理方式极具“领域特定”问题
  放宽“一致性约束”
  · CAP定理
  一致性(Consistency)、可用性(Availability)和分区耐受性(Partition tolerance),3个属性只可能同时满足2个;
  分区耐受性的解释:集群因通信故障而划分为多个时仍然可用
  · CA系统
  单服务器
  集群中出现”分区“,就不可用
  · PA/PC
  集群出现”分区“时,需要在”一致性“ 和“可用性”间权衡
  一般会牺牲部分一致性(eg:使用最终一致性),保证可用性
 放宽“持久性”约束
  更严格的持久性,意味着更多的性能损失;
  · 牺牲“持久性”换取更好的性能
  · 复制“持久性”故障
  主节点故障,未同步到从节点的数据丢失
  主节点恢复,故障期间更新的数据冲突
  解决方案:针对单个请求指定其所需的持久性
  附思维导图

posted @ 2014-07-07 20:45 顺其自然EVO 阅读(157) | 评论 (0)编辑 收藏

开发者应了解的一些SQL优化准则

  下面介绍一些开发者在数据库操作中要注意的SQL编码准则。虽然本文不能覆盖所有的准则,但还是希望能给开发者带来些许帮助。下面就来看看在编码实践中哪些应该做,哪些不应该做。
  1.  在长时间运行的查询和短查询中使用事务
  如果预期有一个长时间运行的查询,并且有大量的数据输出时,开发者就应该在BEGIN TRAN 和END TRAN之间使用事务。
  这样事务会在缓冲区缓存为独立事务,并会被分配特定内存,以此来提高处理速度。
  2.  不要使用SELECT *
  如果使用SELECT * 来选择表中的所有记录,那么一些不必要的记录也被读取、缓存,增加了磁盘的I/O和内存消耗。
  3.  避免在WHERE子句中使用显式或隐式函数,比如Convert ()
  4.  避免在触发器中执行长时间的操作
  5.  适当使用临时表和表变量
  当结果集较小的时候,请尽量使用表变量;当结果集相当大时,使用临时表。
  6.  使用连接(JOIN)代替子查询(Sub-Queries)
  子查询通常作为内联代码来使用,而连接(JOIN)则作为表来使用,这样速度会更快。所以,应尽量避免在连接中使用子查询。
  7.  连接条件中表的顺序
  在连接条件中,应尽量首先使用较小的表,然后逐步使用较大的表。
  8.  循环优化
  如果操作在循环内部没有任何影响,那么应尽量将操作放到循环外面,这样可以减少不必要的重复工作。因为,SQL Server优化器不会自动识别这种低效率的代码,更不会自动优化(其他一些语言的编译器可以)。
  9.  参数探测
  不要在正执行的SP(存储过程)中使用SP参数,这样会导致参数探测(Parameter Sniffing)。应该在声明和设置后再使用SP参数。由于这个原因,SP的行为在每次运行期间都不相同。
  10.  当使用条件语句时,可以使用Index(索引)Hint(提示)
  比如在SQL Server 2008中,可以使用Index hint,也可以使用fixed plan hint强制在查询中使用hint,以提高运行速度。
  11.  在声明中明确指定存储过程中数据类型的大小
  开发者随机声明数据类型的大小是不可取的,如:Varchar (500)。这在执行时会在缓冲区中增加不必要的预留空间。
  12.  在查询中有效利用MAXDOP(最大并行度)设置
  询问数据库管理员关于四核CPU可用性的设置,包括内存的设置,然后适当使用hint,可以有效改善查询速度。
  13.  SQL Server 2008中的GROUPING SETS
  如果数据库服务器为SQL Server 2008,那么可以在所有的Unions中使用Grouping Set来代替Group By。这样在Union中重新进行group by排序时,优化器不会每次都制定一个计划。
  14.  当发生死锁时,总是使用With (nolock) 和With (rowlock)

posted @ 2014-07-07 20:44 顺其自然EVO 阅读(175) | 评论 (0)编辑 收藏

仅列出标题
共394页: First 上一页 88 89 90 91 92 93 94 95 96 下一页 Last 
<2024年11月>
272829303112
3456789
10111213141516
17181920212223
24252627282930
1234567

导航

统计

常用链接

留言簿(55)

随笔分类

随笔档案

文章分类

文章档案

搜索

最新评论

阅读排行榜

评论排行榜