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

Nginx并发访问优化

$
0
0

    Nginx反向代理并发能力的强弱,直接影响到系统的稳定性。安装Nginx过程,默认配置并不涉及到过多的并发参数,作为产品运行,不得不考虑这些因素。Nginx作为产品运行,官方建议部署到Linux64位系统,基于该建议,本文中从系统线之上考虑Nginx的并发优化。

    1、打开Linux系统epoll支持

         epoll支持,能够大大提高系统网络IO的并发数。

     2、Linux文件句柄数限制

         Nginx代理过程,将业务服务器请求数据缓存到本地文件,再将文件数据转发给请求客户端。高并发的客户端请求,必然要求服务器文件句柄的并发打开限制。

         使用ulimit命令,查看linux系统文件句柄并发限制。

         $ ulimit -n

          1024

     linux系统默认设为1024,我们需要将该值设为65535。

         修改系统文件/etc/security/limits.conf,添加如下信息,并重新启动系统生效。

         *               soft    nofile            65535
         *               hard    nofile            65535

        $ sudo vi /etc/security/limits.conf

      3、Nginx配置文件中,添加文件限制及连接数信息

    worker_rlimit_nofile 65535;
    events {
        use epoll;
        worker_connections  65535;
    }

    Nginx并发数受限,通常引起502错误,完成上述操作,通常情况都能解决。


作者:AttaGain 发表于2014-9-3 11:45:25 原文链接
阅读:0 评论:0 查看评论

内存泄漏

$
0
0

内存泄漏:

程序申请了堆空间,但是“忘记”释放,导致该块区域在程序结束前无法被再次使用导致的。泄漏时间长了,就会导致用户空间内存不足,严重的导致死机。

如果泄漏比较严重,很容易察觉;但是有些泄漏很缓慢,不容易察觉,但是软件会运行很长时间后,会慢慢导致严重问题,而且当发现症状的时候,基本上已经是比较晚的时候了,想要识别泄漏,还是可以实现的,本篇文章来聊聊内存操作的原理。

C++中申请内存使用的是new,C语言中使用的malloc(还有其他比如alloc原理类似),一般情况下new调用的是C语言使用的malloc。而由于C++/C可以在多个操作系统使用,所以可以想到malloc肯定是封装了不同操作系统提供的API,比如Windows上边调用的有这几个:VirtualAlloc、VirtualAllocEx、VirtualFree、VirtualProtect、VirtualQuery、VirtualLock、VirtualUnLock,不过它们分配的都是内存页的整数倍的虚拟内存空间RAM,然而我们想要使用内存的时候,几乎很少需要整数倍,那么就需要封装它们改变灵活一些,API替我们封装了:HeapAlloc、GlobalAlloc,它们全都是内核级别,存在于kernel32.dll里边。

很容易看出,我们调用new,实际调用的是HeapAlloc,不过不需要在检测内存泄漏的时候走到这么底层,回归正传,还是回到new/malloc。

在申请内存的时候new调用malloc,释放delete调用free,那么怎么能够让每一次申请和每一次释放都能够记录,最终找到可能的哪怕1字节的泄漏呢?容易想到,在new调用malloc的时候,记录下申请空间的地址,在delete调用free的时候,将记录里边对应地址的数据删除,这样最后如果记录中还有剩余记录,则表示有泄漏。这样还不够,即使知道泄漏,可是不知道在哪有有什么用呢?显然在记录的时候,除了记录地址,还应记录申请的文件名字、行数,这样最后有泄漏的时候,可以立刻知道在哪里泄漏,原理就是这些,看下例子、解决的基础代码。


#include

#include

using namespace std;

#include




void* operator new(size_t size, const char* file, int line)

{

void *p = (void*)malloc(size);

printf("【%d】%s : (%d) 申请%d字节内存\n", p,file,line,size);

return p;

}

void* operator new[](size_t size, const char* file, int line)

{

return operator new(size, file, line);

}

#define new DEBUG_NEW

#define DEBUG_NEW new(__FILE__, __LINE__)


void operator delete(void* pointer)

{

printf("【%d】释放内存\n",pointer);

free(pointer);

}


void operator delete[](void* pointer)

{

operator delete(pointer);

}


void operator delete(void* pointer, const char* file, int line)

{

operator delete(pointer);

}


void operator delete[](void* pointer, const char* file, int line)

{

operator delete(pointer, file, line);

}



int main()

{

int *pos1 = new int[10];

int *pos2 = new int(0x70000001);

delete []pos1;

delete pos2;;

return 0;

}
这里边没有记录申请堆的文件名字、行号,不过增加很容易,用个HASH保存就行了,就不修改了。运行结果:


容易发现申请和释放是成对的,释放内存地方本来也可以知道释放的大小的,不过有点忘记具体保存的方式了,C++编译器一般都会在new返回的只针的前边几字节记录申请的长度等信息,可以在上边代码这么修改:


就会出现崩溃,因为将编译器的数据修改了,它无法正常释放内存了。

有个比较不错的开源内存泄漏检测项目:Visual Leak Detector,用它非常方便,仅仅需要将它的头文件、静态链接库添加到我们的项目中即可,用上边的例子做例子:


而当去掉一个delete 的时候,是这样的:


直接找到泄漏大小、地点。



Visual Leak Detector下载地址:

http://www.codeproject.com/script/articles/download.aspx?file=/KB/applications/visualleakdetector/vld-10.zip&rp=http://www.codeproject.com/Articles/9815/Visual-Leak-Detector-Enhanced-Memory-Leak-Detectio



参考:

http://www.ibm.com/developerworks/cn/linux/l-mleak2/

http://blog.csdn.net/yapingxin/article/details/6751940

http://bbs.csdn.net/topics/20329607

http://blog.csdn.net/g5dsk/article/details/6077601

http://babybandf.blog.163.com/blog/static/6199353201128101029894/

http://www.codeproject.com/KB/applications/visualleakdetector/vld-10.zip

http://blog.csdn.net/sunmenggmail/article/details/8316734
























作者:duhaomin 发表于2014-9-3 9:42:11 原文链接
阅读:75 评论:0 查看评论

Hibernate的缓存机制

$
0
0
缓存是数据库数据在内存中的临时容器,它包含了库表数据在内存中的临时拷贝,位于数据库与应用程序之间,其作用是为了降低应用程序对物理数据源访问的频次,从而提高应用的运行性能。

Hibernate的缓存机制

1.1持久化层的缓存的范围
     持久层设计中,往往需要考虑几个不同层次中的数据缓存策略。这些层次的划分标准针对不同情况有所差异,一般而言,ORM的数据缓存应包含如下几个层次:
事务级缓存(Transaction Layer Cache)
   缓存只能被当前事务访问。缓存的生命周期依赖于事务的生命周期,当事务结束时,缓存也就结束生命周期。在此范围下,缓存的介质是内存。事务可以是数据库事务或者应用事务,每个事务都有独自的缓存,缓存内的数据通常采用相互关联的对象形式。
应用级/进程级缓存(Application/Process Layer Cache)
    缓存被进程内的所有事务共享。这些事务有可能是并发访问缓存,因此必须对缓存采取必要的事务隔离机制。缓存的生命周期依赖于进程的生命周期,进程结束时,缓存也就结束了生命周期。进程范围的缓存可能会存放大量的数据,所以存放的介质可以是内存或硬盘。缓存内的数据既可以是相互关联的对象形式也可以是对象的松散数据形式。对象的松散数据形式有点类似于对象的序列化数据,但是对象分解为松散的算法比对象序列化的算法要求更快。
集群级缓存(Cluster Layer Cache)
   在集群环境中,缓存被一个机器或者多个机器的进程共享。缓存中的数据被复制到集群环境中的每个进程节点,进程间通过远程通信来保证缓存中的数据的一致性,缓存中的数据通常采用对象的松散数据形式。对大多数应用来说,应该慎重地考虑是否需要使用集群范围的缓存,因为访问的速度不一定会比直接访问数据库数据的速度快多少。
    持久层提供以上多种层次的缓存。如果在事务级缓存中没有查到相应的数据,还可以到进程级或集群级缓存内查询,如果还是没有查到,那么只有到数据库中查询。事务级缓存是持久化层的第一级缓存,通常它是必需的;进程级或集群级缓存是持久化层的第二级缓存,通常是可选的。
1.2 hibernate缓存机制
    Hibernate提供了两种缓存,第一种是Session的缓存,又称为一级缓存。由于Session对象的生命周期通常对应一个数据库事务或者一个应用事务,因此它的缓存是事务范围的缓存。第一级缓存是必需的,不允许而且事实上也无法卸除。在第一级缓存中,持久化类的每个实例都具有唯一的OID。

Hibernate第一级缓存(session的缓存)
Hibernate第二级缓存(SessionFactory的外置缓存)
            缓存并发访问策略        查询缓存
缓存适配器
缓存的实现
    第二种缓存是SessionFactory的缓存,又可以分为两类:内置缓存和外置缓存。sessionFactory的内置缓存和Session的缓存在实现方式上比较相似,前者是SessionFactory对象的一些集合属性包含的数据,后者是指Session的一些集合属性包含的数据。SessionFactory的内置缓存中存放了映射元数据和预定义SQL语句,映射元数据是映射文件中数据的拷贝,而预定义SQL语句是在Hibernate初始化阶段根据映射元数据推导出来,SessionFactory的内置缓存是只读的,应用程序不能修改缓存中的映射元数据和预
定义SQL语句,因此SessionFactory不需要进行内置缓存与映射文件的同步。
SessionFactory的外置缓存是一个可配置的插件。在默认情况下,SessionFactory不会启用这个插件。外置缓存的数据是数据库数据的拷贝,外置缓存的介质可以是内存或者硬盘。SessionFactory的外置缓存也被称为Hibernate的第二级缓存。由于SessionFactory对象的生命周期和应用程序的整个过程对应,因此第二级缓存是进程范围或者集群范围的缓存。二级缓存将由从属于本SessionFactroy的所有Session实例共享,因此有时成为SessionFactory Level Cache。这个缓存中存放的对象的松散数据。第二级对象有可能出现并发问题,因此需要采用适当的并发访问策略,该策略为被缓存的数据提供了事务隔离级别。缓存适配器(Cache Provider)用于把具体的缓存实现软件与Hibernate集成。第二级缓存是可选的,可以在每个类或每个集合的粒度上配置第二级缓存。Hibernate还为查询结果提供了一个查询缓存,它依赖于第二级缓存。
1.4二级缓存应用策略。
   二级缓存在一个SessionFactory中有效,是优化的重中之重,因此,各类策略也考虑的较多,但是并非所有的情况都适合于使用二级缓存,需要根据具体情况来决定。同时可以针对某一个持久化对象配置其具体的缓存策略。适合于使用二级缓存的情况:
(1)数据不会被第三方修改;
   一般情况下,会被hibernate以外修改的数据最好不要配置二级缓存,以免引起数据不一致问题。但是如果此数据因为性能的原因需要被缓存,同时又有可能被第三方比如SQL修改,也可以为其配置二级缓存。只是需要在sql执行修改后手动清除cache,以保证数据的一致性。
(2)数据大小在可接收范围之内;
    如果数据表数据量特别巨大,不适合配置二级缓存。原因是缓存的数据量过大可能会引起内存资源紧张,反而降低性能。如果数据表数据量特别巨大,但是经常使用的只是较新部分
的数据,也可以为其配置二级缓存。但是必须单独配置其持久化类的缓存策略,比如最大缓存数、缓存过期时间等,将这些参数降低至一个合理的范围(太高会引起内存资源紧张,太低了缓存的意义不大)。
(3)数据更新频率低;
    对于数据更新频率过高的数据,频繁同步缓存中数据的代价可能和从查询缓存中的数据获得的好处相当,坏处益处相抵消。此时缓存的意义也不大。
(4)非关键数据(不是财务数据等)
    财务数据等是非常重要的数据,绝对不允许出现或使用无效的数据,所以此时为了安全起见最好不要使用二级缓存。
2基于缓存的优化策略

   查询性能往往是一个系统性能表现的重要方面。相对数据库的更新、删除操作而言,查询机制的优劣很大程度决定了系统的整体性能。
2.1查询缓存的应用
对于经常使用的查询语句,如果启用了查询缓存(QueryCache),当第一次执行查询语句时,hibernate会把查询结果存放在第二级缓存中。以后再执行该查询语句时,只需从缓存中获得查询结果,从而提高性能。
查询缓存策略的一般过程如下:
(1)Query Cache保存了之前查询执行过的Select SQL以及结果集等信息,组成一个Query Key。Query Key包括条件查询的请求一般信息:SQL,SQL需要的参数,记录范围(起始位置rowStart,最大记录个数maxRows)等。
(2)当再次遇到查询请求的时候,就会根据Query Key从Query Cache找,如果存在就返回这个结果列表;如果不存在,查询数据库获取结果列表,把整个结果列表根据Query Key放入到
Query缓存中。
(3)但是两次查询之间,数据表发生数据变动的话,Hibernate就会自动清除Query Cache中对应的Query Key。为了启用Query Cache,我们需要在hibernate.cfg.xml中进行
配置,参考配置如下(只列出核心配置项):
…………
true
…………
应用程序中必须在查询执行之前,将Query.Cacheable设置为true,而且每次都应该这样。比如:
………
Query query=session.createQuery(hql).setInteger(0.15);
query.setCacheable(true);
………
但是,Query Cache只在特定的条件下才会发挥作用,而且要求相当严格:
(1)完全相同的Select SQL重复执行。
(2)重复执行期间,Query Key对应的数据表不能有数据变动(比如添、删、改操作)。
并且,查询缓存在一个交易系统(数据变更频繁,查询条件相同的机率并不大)中可能会起反作用:它会白白耗费大量的系统资源但却很难发挥优势。
2.2数据查询方法的选用
   完成同样的查询,Hibernate提供了可供选择的一些方式,但具体使用什么方式,可能对性能和代码都会有影响。
(1)Session.load/get方法均可以根据指定的实体类和id从数据
库读取记录,并返回与之对应的实体对象。
(a)Session.load
在执行session.load时,Hibernate首先从当前session的一级缓存中获取id对应的值,在获取不到的情况下,将根据该对象是否配置了二级缓存来做相应的处理,如配置了二级缓存,则从二级缓存中获取id对应的值,如仍然获取不到则还需要根据是否配置了延迟加载来决定如何执行,如未配置延迟加载则从数据库中直接获取,在从数据库获取到数据的情况下,Hibernate会相应的填充一级缓存和二级缓存,如配置了延迟加载则直接返回一个代理类,只有在触发代理类的调用时才进行数据库查询的操作。如果未能发现符合条件的记录,load方法会抛出一个ObjectNotFoundException。
(b)Session.get
在执行Session.get时,和Session.load不同的就是get方法则仅仅在内部缓存中进行数据查找,如没有发现对应数据,将越过二级缓存,直接调用SQL完成数据读取。直接从数据库中获取id
对应的值。如果未能发现符合条件的记录返回null,而且get方法永远直接返回实体类.
(2)Query.list/Query.iterate方法均可根据指定条件查询并返回符合条件的实体对象集。
(c)Query.list
在执行Query.list时,Hibernate的做法是首先检查是否配置了查询缓存,如配置了则从查询缓存中通过一条sql语句获取所有符合条件的记录,并构造相应的实体对象,然后将其纳入缓存。如获取不到则从数据库中进行获取,从数据库获取到后Hibernate将会相应的填充一级、二级和查询缓存,如获取到的为直接的结果集,则直接返回,如获取到的为一堆id的值,则再根据id获取相应的值(Session.load),最后形成结果集返回。
(d)Query.iterate
在执行Query.iterate时,和Query.list的不同的在于从数据库获取的处理,Query.iterate向数据库发起的是select id from这样的语句,也就是它是先获取符合查询条件的id,之后在进行iterate.next调用时才再次发起session.load的调用获取实际的数据。iterate方法首先在本地缓存中根据id查找对应的实体对象是否存在(类似Session.load方法),如果缓存中已经存在对应的数据,则直接以此数据对象为查询结果,如果没有找到,再执行相应的Select语句获得对应的库表记录。(iterate方法如果执行了数据库读取操
作并构建了完整的数据对象,也会将其查询结果纳入缓存)。而且,通过iterate,配合缓存管理API,在海量数据查询中可以很好的解决内存问题,如:
while(it.hasNext()){
YouObject object=(YouObject)it.next();
session.evict(youObject);
sessionFactory.evice(YouObject.class,youObject.getId());}
如果用list方法,很可能就出OutofMemory错误了。
可见,在拥有二级缓存并且查询参数多变的情况下,Query.iterate、Session.load会比Query.list及Session.get更为高效。

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


ITeye推荐



Remind这个APP正在引发教育革命

$
0
0

这个 APP 正在引发教育革命

9 月 3 日,一个名为 Remind 的移动应用最近迅速成为苹果和谷歌应用商店中最流行的应用之一,并有可能引发一场教育革命。

Remind 不是游戏,也不是社交网络,而是一个适用于学校师生及学生家长的通讯应用。已经有约 100 万名教师和 1700 万家长及学生下载了 Remind。在美国的许多地方,Remind 被教师、学生和家长用来建立强大的通讯网络。

Remind 公司是美国旧金山的一个创业企业。该公司表示,在得克萨斯州、阿拉巴马州和佐治亚州等地区,40% 到 50% 的教师正在使用这个免费应用。教育工作者可以使用 Remind 来布置家庭作业、为校外参观考察征求志愿者,也可以使用 Remind 在教室里发送照片。有了 Remind,教师可以减少对纸质材料的依靠,学生家长也可以不必频繁查收来自学校的电子邮件。

Remind 还在 8 月 28 日推出了一种新功能,教师可以用它来发布短小的调查问卷(例如:“今天的功课太难了吗?”),并录制语音消息。“如果我们能找到一种方法,让学生家长每周两三次(而不是每年一两次)参与学校的教学工作,如果我们可以提高教师的工作效率,那么我们就可以产生巨大的影响。”Remind 公司年仅 27 岁的首席执行官布雷特·科普夫(Brett Kopf)说。

Remind 公司成立于 2009 年,当时科普夫刚刚在美国密歇根州立大学(Michigan State University)获得农业经济学的学士学位。最初几年,Remind 是不成功的。科普夫从小患有失读症(dyslexia),还有其他学习障碍。他设计 Remind 的初衷是帮助具有类似学习障碍的学生。学生如果在 Remind 中上传了自己的作业清单,它会提醒他们在最后期限内完成测验和其他作业。

最初几年,下载 Remind 的学生很少。科普夫和另一位公司创始人——他的哥哥大卫(David)——很快欠下了 1 万美元的债务。

2011 年,Remind 公司搬到了旧金山湾区(Bay Area),并加入了教育创业公司孵化器 Imagine K12。他们决定更专注于通信服务,并在 200 名教师中进行了需求调查。这些教师一致表示,他们需要让家长更多参与教学。

现在,Remind 获得了大多数硅谷初创企业梦寐以求的投资者。First Round Capital、 Kleiner Perkins Caufield & Byers(KPCB)和 Social+Capital Partnership 等风险投资公司已经对 Remind 投资了 2000 万美元。KPCB 公司的约翰·杜尔(John Doerr)现在是 Remind 董事会成员。约翰表示,教育技术创业具有很大的挑战性,Remind 的成功证明了智能手机定制服务的价值。“几十年来,我们努力开发实用的教育技术,”约翰说,“虽然 Remind 不太引人关注,但它已经走进了课堂。”

如何保护学生的隐私和安全,这是 Remind 和它的竞争对手面临的最大挑战。Remind 隐藏了用户的电话号码,家长在与教师联系时只需要输入一个特定的教室代码。为了保护学生,Remind 只允许老师向全体学生而非单个学生发送消息,而且会保存每一条信息。科普夫说,他不打算出售基于用户数据的广告,而希望开发收费的附加服务(移动支付功能),以此来实现盈利。

美国路易斯安那州杰一位名叫杰西卡·迪翁的老师表示,她的许多学生来自贫困家庭,家里没有可靠的互联网,但他们都有手机。杰卡西使用 Remind 来与家长进行各种提醒和沟通。她说,Remind 使更多的学生按时完成家庭作业。“它改变了我的课堂和学生。我认为 Remind 让我成了一个更好的老师。”她说。

本文链接

Hadoop中的分块与分片

$
0
0

        HDFS存储系统中,引入了文件系统的分块概念(block),块是存储的最小单位,HDFS定义其大小为64MB。与单磁盘文件系统相似,存储在HDFS上的文件均存储为多个块,不同的是,如果某文件大小没有到达64MB,该文件也不会占据整个块空间。 在分布式的HDFS集群上,Hadoop系统保证一个块存储在一个datanode上,不跨越存储。

  当我们执行hadoop fs -put aa.txt /bb.txt,则aa.txt会被复制为集群的/bb.txt。查看系统的log日志hadoop-$username-namenode-*.log,可以看到类似于

  2011-09-07 08:39:12,506 INFO org.apache.hadoop.hdfs.StateChange: BLOCK* NameSystem.addStoredBlock: blockMap updated: 127.

  0.0.1:50010 is added to blk_5715489406767973176_1455 size 32

  这样的信息,里面记录有分配block的元数据信息和block号(blk_5715489406767973176)。

  在另一个日志中hadoop-$username-datanode-*.log可以看到对应的datanode打印出相应的log:

  2011-09-07 08:39:12,495 INFO org.apache.hadoop.hdfs.server.datanode.DataNode: Receiving block blk_5715489406767973176_145

  5 src: /127.0.0.1:48492 dest: /127.0.0.1:50010

   HDFS的namenode只存储整个文件系统的元数据镜像,这个镜像由配置dfs.name.dir指定,datanode则存有文件的metainfo和具体的分块,存储路径由dfs.data.dir指定。

  分析完毕分块,下面讨论一下分片:

   hadoop的作业在提交过程中,需要把具体的输入进行分片。具体的分片细节由InputSplitFormat指定。分片的规则为  FileInputFormat.class中的getSplits()方法指定:

  long splitSize = computeSplitSize(goalSize, minSize, blockSize);

  computeSplitSize:    Math.max(minSize, Math.min(goalSize, blockSize));

   其中goalSize为“InputFile大小”/“我们在配置文件中定义的mapred.map.tasks(默认为2)”值,minsize为mapred.min.split.size(分片下限),blockSize为64M(分片上限),所以,这个算式为取分片大小不大于blockSize,并且不小于在mapred.min.split.size配置中定义的最小Size。

  当某个分块分成均等的若干分片时,会有最后一个分片大小小于定义的分片大小,则该分片独立成为一个分片。



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


ITeye推荐



HBase vs Cassandra: 我们迁移系统的原因

$
0
0

原文:  http://ria101.wordpress.com/2010/02/24/hbase-vs-cassandra-why-we-moved/ 
原作者:Dominic Williams 
原文发布日期:February 24, 2010 at 7:27 pm 
译者:王旭( http://wangxu.me/blog/ , @gnawux) 
翻译时间:2010年3月21-25日

我的团队近来正在忙于一个全新的产品——即将发布的网络游戏  www.FightMyMonster.com。这让我们得以奢侈地去构建一个全新的 NOSQL 数据库,也就是说,我们可以把恐怖的 MySQL sharding 和昂贵的可伸缩性抛在脑后了。最近有很多人一直在问,为什么我们要把注意力从 HBase 上转移到 Cassandra 上去。我确认,确实有这样的变化,实际上我们基本上已经把代码移植到了 Cassandra 上了,这里我将给出解释。

为了那些不熟悉 NOSQL 的读者,后面的其他文章中,我会介绍为什么我们将会在未来几年中看到地震式的从 SQL 到 NOSQL 的迁移,这正和向云计算的迁移一样重要。后面的文章还会尝试解释为什么我认为 NOSQL 可能会是贵公司的正确选择。不过本文我只是解释我们选择 Cassandra 作为我们的 NOSQL 解决方案的选择。

免责声明——如果你正在寻找一个捷径来决定你的系统选择,你必须要明白,这可不是一个详尽而严格的比较,它只是概述了另一个初创团队在有限时间和资源的情况下的逻辑。

Cassandra 的血统是否预言了它的未来

我最喜欢的一个工程师们用来找 bug 的谒语是“广度优先而非深度优先”。这可以可能对那些解决技术细节的人来说很恼人,因为它暗示着如果他们只是看看的话,解决方法就会简单很多(忠告:只对那些能够原谅你的同事说这个)。我造出这个谒语的原因在于,我发现,软件问题中,如果我们强迫我们自己在进入某行代码的细节层面之前,先去看看那些高层次的考虑的话,可以节省大量时间。

所以,在谈论技术之前,我在做 HBase 和 Cassandra 之间的选择问题上先应用一下我的箴言。我们选择切换的技术结论可能已经可以预测了:Hbase和Cassandra有着迥异的血统和基因,而我认为这会影响到他们对我们的业务的适用性。

严格的说,Hbase 和它的支持系统源于著名的 Google BigTable 和 Google 文件系统设计(GFS 的论文发于 2003 年,BigTable 的论文发于 2006 年)。而 Cassandra 则是最近 Facebook 的数据库系统的开源分支,她在实现了 BigTable 的数据模型的同时,使用了基于 Amazon 的 Dynamo 的系统架构来存储数据(实际上,Cassandra 的最初开发工作就是由两位从 Amazon 跳槽到 Facebook 的 Dynamo 工程师完成的)。

在我看来,这些不同的历史也导致Hbase更加适合于数据仓库、大型数据的处理和分析(如进行Web页面的索引等),而 Cassandra 则更适合于实时事务处理和提供交互型数据。要进行系统研究来证明这个观点超出了本文的范畴,但我相信你在考虑数据库的时候总能发现这个差异的存在。

注意:如果你在寻找一个简单的证明,你可以通过主要 committer 的关注点来进行验证:大部分 HBase 的 committer 都为 Bing 工作(M$ 去年收购了他们的搜索公司,并允许他们在数月之后继续提交开源代码)。与之对应,Cassandra 的主要 committer 来自 Rackspace,用来可以自由获得的支持先进的通用的 NOSQL 的解决方案,用来和 Google, Yahoo, Amazon EC2 等提供的那些锁定在专有的 NOSQL 系统的方案相抗衡。

Malcolm Gladwell 会说只是根据这些背景的不同就可以简单地选择了 Cassandra。不过这是小马过河的问题。但当然,闭着眼睛就进行一个商业选择是相当困难的……

哪个 NOSQL数据库风头更劲?

另一个说服我们转向 Cassandra 的原因是我们社区中的大风向。如你所知,软件平台行业里,大者恒大——那些被普遍看好的平台,会有更多人聚集在这个平台周围,于是,从长远看,你可以得到更好的生态系统的支持(也就是说,大部分支持的软件可以从社区中获得,也有更多的开发者可以雇佣)。

如果从 HBase 开始时,我的印象就是它后面有巨大的社区力量,但我现在相信,Cassandra 更加强大。最初的印象部分来源于 StumpleUpon 和 Streamy 的两位 CTO 的两个非常有说服力的出色的讲演,他们是 Web 行业中两个在 Cassandra 成为一个可选系统之前的 HBase 的两个重要的贡献者,同时也部分来源于快速阅读了一篇名为“HBase vs Cassandra: NoSQL 战役!”的文章(大部分内容都被广泛证实了)。

势头是很难确证的,你不得不自己进行研究,不过我可以找到的一个重要的标志是 IRC 上的开发者动向。如果你在 freenode.org 上比较 #hbase 和 #cassandra 的开发这频道,你会发现 Cassandra 差不多在任何时候都有两倍的开发者在线。

如果你用考虑 HBase 一般的时间来考察 Cassandra,你就能发现 Cassandra 的背后确实有非常明显的加速势头。你可能还会发现那些逐渐出现的鼎鼎大名,如 Twitter,他们也计划广泛使用 Cassandra( 这里)。

注:Cassandra 的网站看起来比 HBase 的好看多了,但认真的说,这可能不仅是市场的趋势。继续吧。

深入到技术部分: CAP 和 CA 与 AP 的神话

对于分布式系统,有个非常重要的理论(这里我们在讨论分布式数据库,我相信你注意到了)。这个理论被称为 CAP 理论,由 Inktomi 的 联合创始人兼首席科学家 Eric Brewer 博士提出。

这个理论说明,分布式(或共享数据)系统的设计中,至多只能够提供三个重要特性中的两个——一致性、可用性和容忍网络分区。简单的说,一致性指如果一个人向数据库写了一个值,那么其他用户能够立刻读取这个值,可用性意味着如果一些节点失效了,集群中的分布式系统仍然能继续工作,而容忍分区意味着,如果节点被分割成两组无法互相通信的节点,系统仍然能够继续工作。

Brewer教授是一个杰出的人物,许多开发者,包括 HBase 社区的很多人,都把此理论牢记在心,并用于他们的设计当中。事实上,如果你搜索线上的关于 HBase 和 Cassandra 比较的文章,你通常会发现,HBase 社区解释他们选择了 CP,而 Cassandra 选择了 AP ——毫无疑问,大多数开发者需要某种程度的一致性 (C)。

不过,我需要请你注意,事实上这些生命基于一个不完全的推论。CAP 理论仅仅适用于一个分布式算法(我希望 Brewer 教授可以统一)。但没有说明你不能设计一个系统,在其中的各种操作的底层算法选择上进行这种。所以,在一个系统中,确实一个操作职能提供这些特性中的两个,但被忽视的问题是在系统设计中,实际是可以允许调用者来选择他们的某个操作时需要哪些特性的。不仅如此,现实世界并不简单的划分为黑白两色,所有这些特性都可以以某种程度来提供。这就是 Cassandra。

这点非常重要,我重申:Cassandra 的优点在于你可以根据具体情况来选择一个最佳的折衷,来满足特定操作的需求。Cassandra 证明,你可以超越通常的 CAP 理论的解读,而世界仍然在转动。

我们来看看两种不同的极端。比如我必须从数据库中读取一个要求具有很高一致性的值,也就是说,我必须 100%保证能够读取到先前写入的最新的内容。在这种情况下,我可以通过指定一致性水平为“ALL”来从 Cassandra 读取数据,这时要求所有节点都有数据的一致的副本。这里我们不具有对任何节点失效和网络分裂的容错性。在另一个极端的方面,如果我不特别关心一致性,或仅仅就是希望最佳性能,我可以使用一致性级别“ONE”来访问数据。在这种情况下,从任意一个保存有这个副本的节点获取数据都可以——即使数据有三个副本,也并不在意其他两个有副本的节点是否失效或是否有不同,当然,这种情况下我们读到的数据可能不是最新的。

不仅如此,你不必被迫生活在黑白世界中。比如,在我们的一个特定的应用中,重要的读写操作通常使用“QUORUM”一致性级别,这意味着大部分存有此数据的节点上的副本是一致的——我这里是个简要描述,具体写你的 Cassandra 程序之前最好还是仔细研究一下。从我们的视角看,这这提供了一个合理的节点失效与网络分裂的耐受性,同时也提供了很高的一致性。而在一般情况下,我们使用前面提到的“ONE”一致性级别,者可以提供最高的性能。就是这样。

对我们来说,这是 Cassandra 的一个巨大的加分项目。我们不仅能轻易地调整我们的系统,也可以设计它。比如,当一定数量的节点失效或出现网络连接故障时,我们的大部分服务仍然可以继续工作,只有那些需要数据一致性的服务会失效。HBase并没有这么灵活,它单纯地追求系统的一个方面(CP),这让我再次看到了 SQL 开发者和查询优化人员们之间的那道隔阂——有些事情最好能够超越它,HBase!

In our project then, Cassandra has proven by far the most flexible system, although you may find your brain at first loses consistency when considering your QUORUMs.在我们的项目之后,卡桑德拉已被证明是迄今为止最灵活的系统,虽然你可能发现一致性第一失去你的大脑在考虑您的法定人数。

在我们的项目中,Cassandra 已经证明了它是有史以来最灵活的系统,虽然你可能在对这个问题进行投票(QUORUM)的时候发现的大脑失去了一致性。

什么时候单体会比模块化强?

Cassandra 和 HBase 的一个重要区别是, Cassandra 在每个节点是是一个单 Java 进程,而完整的 HBase 解决方案却由不同部分组成:有数据库进程本身,它可能会运行在多个模式;一个配置好的 hadoop HDFS 分布式文件系统,以及一个 Zookeeper 系统来协调不同的 HBase 进程。那么,这是否意味着 HBase 有更好的模块化结构呢?

虽然 HBase 的这种架构可能确实可以平衡不同开发团队的利益,在系统管理方面,模块化的 HBase 却无法视为一个加分项目。事实上,特别是对于一些小的初创公司,模块化倒是一个很大的负面因素。

HBase的下层相当复杂,任何对此有疑惑的人应该读读 Google 的 GFS 和 BigTable 的论文。即使是在一个单一节点的伪分布式模式下来架设 HBase 也很困难——事实上,我曾经费力写过一篇快速入门的教程(如果你要试试HBase的话 看看这里)。在这个指南里你可以看到,设置好 HBase 并启动它实际包含了两个不同系统的手工设置:首先是 hadoop HDFS,然后才是 HBase 本身。

然后,HBase 的配置文件本身就是个怪兽,而你的设置可能和缺省的网络配置有极大的不同(在文章里我写了两个不同的Ubuntu的缺省网络设置,以及 EC2 里易变的 Elastic IP 和内部分配的域名)。当系统工作不正常的时候,你需要查看大量的日志。所有的需要修复的东西的信息都在日志里,而如果你是一个经验丰富的管理员的话,就能发现并处理问题。

但是,如果是在生产过程中出现问题,而你又没有时间耐心查找问题呢?如果你和我们一样,只有一个小的开发团队却有远大的目标,没有经历去 7*24 的进行系统监控管理会怎么样呢?

严肃地说,如果你是一个希望学习 NoSQL 系统的高级 DB 管理员的话,那么选择 HBase。这个系统超级复杂,有灵巧双手的管理员肯定能拿到高薪。

但是如果你们是一个向我们一样尽力去发现隧道尽头的小团队的话,还是等着听听别的闲话吧

胜在 Gossip

Cassandra 是一个完全对称的系统。也就是说,没有主节点或像 HBase 里的 region server 这样的东西——每个节点的角色是完全一样的。不会有任何特定的节点或其他实体来充当协调者的角色,集群中的节点使用称为 “Cossip” 的纯 P2P 通信协议来协调他们的行为。

对 Gossip 的详细描述和使用 Gossip 的模型超过了本文的内容,但 Cassandra 所采用的 P2P 通信模型都是论证过的,比如发现节点失效的消息传播到整个系统的时间,或是一个客户应用的请求被路由到保存数据的节点的时间,所有这些过程所消耗的时间都毫无疑问的非常的短。我个人相信,Cassandra 代表了当今最振奋的一种 P2P 技术,当然,这和你的 NOSQL 数据库的选择无关。

那么,这个基于 Gossip 的架构究竟给 Cassandra 用户带来什么显示的好处呢。首先,继续我们的系统管理主体,系统管理变得简单多了。比如,增加一个新节点到系统中就是启动一个 Cassandra 进程并告诉它一个种子节点(一个已知的在集群中的节点)这么简单。试想当你的分布式集群可能运行在上百个节点的规模上的时候,如此轻易地增加新节点简直是难以置信。更进一步,当有什么出错的时候,你不需要考虑是哪种节点出了问题——所有节点都是一样的,这让调试成为了一个更加易于进行且可重复的过程。

第二,我可以得出结论,Cassandra 的 P2P 架构给了它更好的性能和可用性。这样的系统中,负载可以被均衡地三步倒各个节点上,来最大化潜在的并行性,这个能力让系统面临网络分裂和节点失效的时候都能更加的无缝,并且节点的对称性防止了 HBase 中发现的那种在节点加入和删除时的暂时性的性能都懂(Cassandra 启动非常迅速,并且性能可以随着节点的加入而平滑扩展)。

如果你想寻找更多更多的证据,你会对一个原来一直关注 hadoop 的小组(应该对 HBase 更加偏爱)的报告很感兴趣……

一份报告胜过千言万语。我是指图表

Yahoo!进行的第一个 NOSQL 系统的完整评测。研究似乎证实了 Cassandra 所享有的性能优势,从图表上看,非常倾向于 Cassandra。

目前这些论文还是草稿,你可以从这里找到这些论文: 
http://www.brianfrankcooper.net/pubs/ycsb-v4.pdf 
http://www.brianfrankcooper.net/pubs/ycsb.pdf

注意:这份报告中 HBase 仅在对一个范围的记录进行扫描这一项上优于 Cassandra。虽然 Cassandra 团队相信他们可以很快达到 HBase 的时间,但还是值得指出,在通常的 Cassandra 配置中,区间扫描几乎是不可能的。我建议你可以无视这一点,因为实际上你应该在 Cassandra 上面来实现你自己的索引,而非使用区间扫描。如果你对区间扫描和在 Cassandra 中存储索引相关问题有兴趣,可以看我的 这篇文章

最后一点: 这篇文章背后的 Yahoo!研究团队正尝试让它们的评测应用通过法律部门的评估,并将它发布给社区。如果他们成功的话,我当然希望他们成功,我们将能够看到一个持续的竞争场面,不论 HBase 还是 Cassandra 无疑都会进一步提高他们的性能。

锁和有用的模块性

毫无疑问,你会从 HBase 阵营听到这样的声音:HBase 的复杂结构让它可以提供 Cassandra 的 P2P 架构无法提供的东西。其中一个例子可能就是 Hbase 提供给开发者行锁机制,而 Cassandra 则没有(在 HBase 中,因为数据副本发生在 hadoop 底层,行锁可以由 region server 控制,而在 Cassandra 的 P2P 架构中,所有节点都是平等的,所以也就没有节点可以像一个网管囊样负责锁定有副本的数据)。

不够,我还是把这个问题返回到关于模块化的争论中,这实际是对 Cassandra 有理的。Cassandra 通过在对称节点上分布式存储数据来实现了 BigTable 的数据模型。它完整地实现了这些功能,而且是以最灵活和高性能的方式实现的。但如果你需要锁、事务和其它功能的话,这些可以以模块的方式添加到你的系统之中——比如,我们发现我们可以使用 Zookeeper 和相关的工具来很简单地为我们的应用提供可扩展的锁功能(对于这个功能,Hazelcast 等系统可能也可以实现这个功能,虽然我们没有进行研究)。

通过为一个窄领域目的来最小化它的功能,对我来说,Cassandra 的设计达到了它的目的——比如前面指出可配置的 CAP 的折衷。这种模块性意味着你可以依据你的需求来构建一个系统——需要锁,那么拿来 Zookeeper,需要存储全文索引,拿来  Lucandra ,等等。对于我们这样的开发者来说,这意味着我们不必部署复杂度超出我们实际需要的系统,给我们提供了更加灵活的构建我们需要的应用的终极道路。

MapReduce,别提 MapReduce!

Cassandra 做的还不够好的一件事情就是 MapReduce!对于不精通此项技术同学简单的解释一句,这是一个用于并行处理大量数据的系统,比如从上百万从网络上抓取的页面提取统计信息。MapReduce 和相关系统,比如 Pig 和 Hive 可以和 HBase 一起良好协作,因为它使用 HDFS 来存储数据,这些系统也是设计用来使用 HDFS 的。如果你需要进行这样的数据处理和分析的话,HBase 可能是你目前的最佳选择。

记住,这就像小马过河!

因此,我停止了对 Cassandra  的优点的赞美,实际上,HBase 和 Cassandra 并不一定是一对完全的竞争对手。虽然它们常常可以用于同样的用途,和 MySQL 和 PostgreSQL 类似,我相信在将来它们将会成为不同应用的首选解决方案。比如,据我所知 StumbleUpon 使用了 HBase 和 hadoop MapReduce 技术,来处理其业务的大量数据。Twitter 现在使用 Cassandra 来存储实时交互的社区发言,可能你已经在某种程度上使用它了。

作为一个有争议的临别赠言,下面我们进入下一个话题。

注意:在继续下一个小节之前,我要指出,Cassandra 在 0.6 版本会有 hadoop 支持,所以 MapReduce 整合能获得更好的支持。

兄弟,我不能失去数据…

作为先前 CAP 理论争议的一个可能结果,可能有这样的印象,HBase 的数据似乎比 Cassandra 中的数据更安全。这是我希望揭露的最后一个关于 Cassandra 的秘密,当你写入新数据的时候,它实际上立刻将它写入一个将要存储副本的仲裁节点的 commit log 当中了,也被复制到了节点们的内存中。这意味着如果你完全让你的集群掉电,只可能会损失极少数据。更进一步,在系统中,通过使用 Merkle tree 来组织数据的过分不一致(数据熵),更加增加了数据的安全性 :)

事实上,我对 HBase 的情况并不是非常确切——如果能有更细节的情况,我回尽快更新这里的内容的——但现在我的理解是,因为 hadoop 还不支持 append,HBase 不能有效地将修改的块信息刷入 HDFS (新的对数据变化会被复制为多个副本并永久化保存)。这意味着会有一个更大的缺口,你最新的更改是不可见的(如果我错了,可能是这样,请告诉我,我回修正本文)。

所以,尽管希腊神话中的 Cassandra 非常不幸(译注:Cassandra 是希腊神话里,特洛伊的那个可怜的女先知的名字,如果你不知道详情的话,可以参考wiki),但你的 Cassandra 中的数据不会有危险。

注意:Wade Amold 指出, hadoop .21 很快就会发布,其中将会解决 HBase 的这个问题。

未经特殊声明,本站作品均为原创,同时会通过 ifttt 转发至  本人 wordpress.com 博客,原则上不反对转载,但建议保留本文链接。

Post Footer automatically generated by  wp-posturl plugin for wordpress.

This entry was posted in  translation and tagged  cassandracloudhadoophbasenosqltranslation on  March 25, 2010.

- See more at: http://wangxu.me/blog/p/371#sthash.iJXIHh2J.dpuf



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


ITeye推荐



基于Item的时序协同过滤算法

$
0
0

基于Item的时序协同过滤算法技术方案包括两个步骤:

(1)提取用户商品点击日志、搜索点击日志和商品基本信息等基本数据。然后,去除噪音数据(譬如每天点击商品数达到数以万计的用户)和缺失值数据,构建时序点击流数据,即记录用户每天按照点击时间先后顺序排序的商品行为数据。从而得到如下数据结构:<用户id,商品id,点击时间,点击日期>;

(2)时序协同过滤算法构建模块,根据数据预处理阶段的得到的商品点击时序数据集,在ODPS平台上实现该算法算法,计算商品之间的相关性。

时序协同过滤算法

步骤1:计算商品之间相关性

Map阶段

输入:key(行记录标识), value(用户id,商品id,点击时间,点击日期)

输出:key(用户id,点击日期,点击时间), value(商品id,点击时间)

Reduce阶段:

输入:key(用户id,点击日期,点击时间), value(商品id,点击时间)

输出:ODPS Record(点击日期,商品1, 商品2, 相关性分数)

计算相关性分数算法:

  1. 计算每个用户每天的点击时间序列对,按照升序排列,即<商品1,点击时间1>,<商品2,点击时间2>,…,<商品n,点击时间n>;
  2. 在每个用户的商品点击序列中,如果两两商品时间序列对的点击时间差小于等于两个小时,则表示这两个商品具备相关性;计算出有效时序商品序列<商品1,商品2,商品3,…,商品n>;
  3. 计算商品之间的相关性,公式如下:   

    ,其中score表示相关性分值,delta表示任意两个商品之间的时间排序位置之差

步骤2:计算每天商品之间相关性均值,减少噪声数据,譬如用户无意图的商品点击序列

Map阶段

输入:key(行记录标识), value(点击日期,商品1, 商品2, 相关性分数)

输出:key(点击日期,商品1, 商品2), value(相关性分数)

Reduce阶段

输入:key(点击日期,商品1, 商品2), value(相关性分数)

输出:ODPS Record(商品1, 商品2, 相关性分数均值)

步骤3:计算每月商品之间的相关性,减少噪声数据,去除异常的相关性数据

Map阶段

输入:key(行记录标识), value(商品1, 商品2, 相关性分数)

输出:key(商品1, 商品2), value(相关性分数)

Reduce阶段

输入:key(商品1, 商品2), value(相关性分数)

输出:ODPS Record(商品1, 商品2, 相关性分数均值)

参考:

http://blog.sina.com.cn/s/blog_61c463090102uwqu.html

http://www.aliyun.com/ odps 


  青春就应该这样绽放   游戏测试:三国时期谁是你最好的兄弟!!   你不得不信的星座秘密

Node.js连接数据库

$
0
0

Node.js连接数据库前,需要安装相应的包,如果安装sql server 需要先装包node-sqlserver。我们以mysql为案例来说明node.js查询mysql数据。

1、安装 node-mysql

npm install node-mysql

2、通过express框架实现数据库连接

var express = require('express');
var mysql = require('mysql');
var app = express();
app.use(function(req, res, next){
  console.log('%s %s', req.method, req.url);
  next();
});
var conn = mysql.createConnection({
    host:'localhost',
    user:'root',
    database:'ceshi',
    password:'123456',
    port:3306
});
conn.connect();
app.get('/', function(req, res){
   conn.query('SELECT * from ceshibiao', function(err, rows, fields) {
        if(err) throw err;
        var data = '';
        foreach(rows,function(key,value){
            data += '<p>' + 'contents:' + value.contents + '</p>';
            data += '<hr />';
        }
        res.send(data);
    });
});
app.listen(81);
console.log('Listening on port 81');
作者:Zhao1234567890123456 发表于2014-9-3 22:31:21 原文链接
阅读:0 评论:0 查看评论

Android中的11种传感器

$
0
0

在Android2.3 gingerbread系统中,google提供了11种传感器供应用层使用。 

1
2
3
4
5
6
7
8
9
10
11
#define SENSOR_TYPE_ACCELEROMETER       1 //加速度
#define SENSOR_TYPE_MAGNETIC_FIELD      2 //磁力
#define SENSOR_TYPE_ORIENTATION         3 //方向
#define SENSOR_TYPE_GYROSCOPE           4 //陀螺仪
#define SENSOR_TYPE_LIGHT               5 //光线感应
#define SENSOR_TYPE_PRESSURE            6 //压力
#define SENSOR_TYPE_TEMPERATURE         7 //温度
#define SENSOR_TYPE_PROXIMITY           8 //接近
#define SENSOR_TYPE_GRAVITY             9 //重力
#define SENSOR_TYPE_LINEAR_ACCELERATION 10//线性加速度
#define SENSOR_TYPE_ROTATION_VECTOR     11//旋转矢量

我们依次看看这十一种传感器

 

1 加速度传感器

加速度传感器又叫G-sensor,返回x、y、z三轴的加速度数值。

该数值包含地心引力的影响,单位是m/s^2。

将手机平放在桌面上,x轴默认为0,y轴默认0,z轴默认9.81。

将手机朝下放在桌面上,z轴为-9.81。

将手机向左倾斜,x轴为正值。

将手机向右倾斜,x轴为负值。

将手机向上倾斜,y轴为负值。

将手机向下倾斜,y轴为正值。

 

加速度传感器可能是最为成熟的一种mems产品,市场上的加速度传感器种类很多。

手机中常用的加速度传感器有BOSCH(博世)的BMA系列,AMK的897X系列,ST的LIS3X系列等。

这些传感器一般提供±2G至±16G的加速度测量范围,采用I2C或SPI接口和MCU相连,数据精度小于16bit。

 

2 磁力传感器

磁力传感器简称为M-sensor,返回x、y、z三轴的环境磁场数据。

该数值的单位是微特斯拉(micro-Tesla),用uT表示。

单位也可以是高斯(Gauss),1Tesla=10000Gauss。

硬件上一般没有独立的磁力传感器,磁力数据由电子罗盘传感器提供(E-compass)。

电子罗盘传感器同时提供下文的方向传感器数据。

 

3 方向传感器

方向传感器简称为O-sensor,返回三轴的角度数据,方向数据的单位是角度。

为了得到精确的角度数据,E-compass需要获取G-sensor的数据,

经过计算生产O-sensor数据,否则只能获取水平方向的角度。

方向传感器提供三个数据,分别为azimuth、pitch和roll。

azimuth:方位,返回水平时磁北极和Y轴的夹角,范围为0°至360°。

0°=北,90°=东,180°=南,270°=西。

pitch:x轴和水平面的夹角,范围为-180°至180°。

当z轴向y轴转动时,角度为正值。

roll:y轴和水平面的夹角,由于历史原因,范围为-90°至90°。

当x轴向z轴移动时,角度为正值。

 

电子罗盘在获取正确的数据前需要进行校准,通常可用8字校准法。

8字校准法要求用户使用需要校准的设备在空中做8字晃动,

原则上尽量多的让设备法线方向指向空间的所有8个象限。

 

手机中使用的电子罗盘芯片有AKM公司的897X系列,ST公司的LSM系列以及雅马哈公司等等。

由于需要读取G-sensor数据并计算出M-sensor和O-sensor数据,

因此厂商一般会提供一个后台daemon来完成工作,电子罗盘算法一般是公司私有产权。

 

4 陀螺仪传感器

陀螺仪传感器叫做Gyro-sensor,返回x、y、z三轴的角加速度数据。

角加速度的单位是radians/second。

根据Nexus S手机实测:

水平逆时针旋转,Z轴为正。

水平逆时针旋转,z轴为负。

向左旋转,y轴为负。

向右旋转,y轴为正。

向上旋转,x轴为负。

向下旋转,x轴为正。

 

ST的L3G系列的陀螺仪传感器比较流行,iphone4和google的nexus s中使用该种传感器。

 

5 光线感应传感器

光线感应传感器检测实时的光线强度,光强单位是lux,其物理意义是照射到单位面积上的光通量。

光线感应传感器主要用于Android系统的LCD自动亮度功能。

可以根据采样到的光强数值实时调整LCD的亮度。

 

6 压力传感器

压力传感器返回当前的压强,单位是百帕斯卡hectopascal(hPa)。

 

7 温度传感器

温度传感器返回当前的温度。

 

8 接近传感器

接近传感器检测物体与手机的距离,单位是厘米。

一些接近传感器只能返回远和近两个状态,

因此,接近传感器将最大距离返回远状态,小于最大距离返回近状态。

接近传感器可用于接听电话时自动关闭LCD屏幕以节省电量。

一些芯片集成了接近传感器和光线传感器两者功能。

 

 

下面三个传感器是Android2新提出的传感器类型,目前还不太清楚有哪些应用程序使用。

9 重力传感器

重力传感器简称GV-sensor,输出重力数据。

在地球上,重力数值为9.8,单位是m/s^2。

坐标系统与加速度传感器相同。

当设备复位时,重力传感器的输出与加速度传感器相同。

 

10 线性加速度传感器

线性加速度传感器简称LA-sensor。

线性加速度传感器是加速度传感器减去重力影响获取的数据。

单位是m/s^2,坐标系统与加速度传感器相同。

加速度传感器、重力传感器和线性加速度传感器的计算公式如下:

加速度 = 重力 + 线性加速度

 

11 旋转矢量传感器

旋转矢量传感器简称RV-sensor。

旋转矢量代表设备的方向,是一个将坐标轴和角度混合计算得到的数据。

RV-sensor输出三个数据:

x*sin(theta/2)

y*sin(theta/2)

z*sin(theta/2)

sin(theta/2)是RV的数量级。

RV的方向与轴旋转的方向相同。

RV的三个数值,与cos(theta/2)组成一个四元组。

RV的数据没有单位,使用的坐标系与加速度相同。

举例:

1
2
3
4
sensors_event_t.data[0] = x*sin(theta/2)
sensors_event_t.data[1] = y*sin(theta/2)
sensors_event_t.data[2] = z*sin(theta/2)
sensors_event_t.data[3] =   cos(theta/2)

GV、LA和RV的数值没有物理传感器可以直接给出,

需要G-sensor、O-sensor和Gyro-sensor经过算法计算后得出。

算法一般是传感器公司的私有产权。

作者:wemisa 发表于2014-9-4 0:26:10 原文链接
阅读:0 评论:0 查看评论

【Android 开发技巧】布局优化利器和ViewStub

$
0
0

『原创作品,转载请注明出处。 --- 孙国威』

〔文章原始地址  http://blog.csdn.net/manoel/article/details/39036507


当创建复杂的布局的时候,有时候会发现添加了很多的ViewGroup和View。随之而来的问题是View树的层次越来越深,应用也变的越来越慢,因为UI渲染是非常耗时的。

这时候就应该进行布局优化了。这里介绍两种方式,分别为<include>标签和ViewStub类。


<include/>

使用<include/>是为了避免代码的重复。设想一种情况,我们需要为app中的每个视图都添加一个footer,这个footer是一个显示app名字的TextView。通常多个Activity对应多个XML布局文件,难道要把这个TextView复制到每个XML中吗?如果TextView需要做修改,那么每个XML布局文件都要进行修改,那简直是噩梦。

面向对象编程的其中一个思想就是代码的复用,那么怎么进行布局的复用呢?这时,<include/>就起作用了。

如果学过C语言,那么对#include应该不陌生,它是一个预编译指令,在程序编译成二进制文件之前,会把#include的内容拷贝到#include的位置。

Android中的<include/>也可以这么理解,就是把某些通用的xml代码拷贝到<include/>所在的地方。以一个Activity为例。

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent"
    android:layout_height="fill_parent" ><TextView
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:gravity="center_horizontal"
        android:text="@string/hello" /><include layout="@layout/footer_with_layout_properties"/></RelativeLayout>
footer_with_layout_properties.xml中就是一个简单的TextView,代码如下:

<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:layout_alignParentBottom="true"
    android:layout_marginBottom="30dp"
    android:gravity="center_horizontal"
    android:text="@string/footer_text" />
上述的代码中,我们使用了<include/>标签,达到了代码复用的目的。

但是,仍然存在一些疑惑。

footer_with_layout_properties.xml中使用了android:layout_alignParentBottom属性,这个属性之所以可行,是因为外层布局是RelativeLayout。

那么,如果外层布局换做LinearLayout又会怎样呢?答案显而易见,这肯定是行不通的。那么怎么办呢?我们可以把具体的属性写在<include/>标签里面,看下面的代码。

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent"
    android:layout_height="fill_parent"><TextView
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:gravity="center_horizontal"
        android:text="@string/hello"/><include
        layout="@layout/footer"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_marginBottom="30dp"/></RelativeLayout>
我们直接在<include/>标签里面使用了android:layout_*属性。

注意:如果想要在<include/>标签中覆盖被包含布局所指定的任何android:layout_*属性,必须在<include/>标签中同时指定layout_width和layout_height属性,这可能是一个Android系统的一个bug吧。


ViewStub
在开发过程中,难免会遇到各种交互问题,例如显示或隐藏某个视图。如果想要一个视图只在需要的时候显示,可以尝试使用ViewStub这个类。

先看一下ViewStub的官方介绍:

“ViewStub是一个不可视并且大小为0的视图,可以延迟到运行时填充布局资源。当ViewStub设置为Visible或调用inflate()之后,就会填充布局资源,ViewStub便会被填充的视图替代”。

现在已经清楚ViewStub能干什么了,那么看一个例子。一个布局中,存在一个MapView,只有需要它的时候,才让它显示出来。

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent" ><Button
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="center_vertical"
        android:onClick="onShowMap"
        android:text="@string/show_map" /><ViewStub
        android:id="@+id/map_stub"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:inflatedId="@+id/map_view"
        android:layout="@layout/map" /></RelativeLayout>

map.xml文件中包含一个MapView,只有在必要的时候,才会让它显示出来。

<com.google.android.maps.MapView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/map_view"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:apiKey="my_api_key"
    android:clickable="true" />

另外,inflatedId是ViewStub被设置成Visible或调用inflate()方法后返回的id,这个id就是被填充的View的id。在这个例子中,就是MapView的id。

接下来看看ViewStub是怎么使用的。

public class MainActivity extends MapActivity {

  private View mViewStub;

  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    mViewStub = findViewById(R.id.map_stub);
  }

  public void onShowMap(View v) {
    mViewStub.setVisibility(View.VISIBLE);
  }

  @Override
  protected boolean isRouteDisplayed() {
    return false;
  }
}


题外话

有的同学肯定会问,使用ViewStub和单纯地把View设置为View.GONE或View.VISIBLE有什么区别呢?不都是显示和隐藏吗,使用ViewStub反而更麻烦了。

确实是有区别的,会涉及到View树的渲染,内存消耗等。

至于有什么具体的差别,就请大家自己去Google吧。俗话说,自己动手,丰衣足食嘛!


参考资料

http://code.google.com/p/android/issues/detail?id=2863

http://android-developers.blogspot.com.ar/2009/03/android-layout-tricks-3-optimize-with.html

http://developer.android.com/reference/android/view/ViewStub.html


作者:manoel 发表于2014-9-4 0:24:49 原文链接
阅读:225 评论:0 查看评论

最全解释:百度直达号到底是什么?

$
0
0

百度的移动搜索功能终于迈出了新的一步。这一次,百度要从连线用户和信息,转向连接用户和服务。

最新的连接渠道,就是百度副总裁李明远在今天百度世界大会上推出的新平台:直达号。

直达号到底是一个什么样的平台?百度借助这个平台想要实现什么样的价值?李明远在今天的演讲中介绍道,移动端的搜索流量不应该被浪费,百度将利用直达号为企业提供移动化解决方案,让用户在移动端直达商家服务。

直达号是什么?

直达号是商家在百度移动平台的官方服务账号。

商家的直达号展示在用户面前,其实类似于商家的移动端网站。

在直达号的移动页面上,可以实现各种功能,比如餐饮企业的座位预订、订餐、服务评论、查看菜单等功能。

目前已经开通的账号包括峨眉山、海底捞、良子健身、一亩田、平安保险等.

最全解释:百度直达号到底是什么?

百度搜索海底捞,展现海底捞直达号

用户如何发现直达号?

直达号基于移动搜索、 @账号、地图、个性化推荐等多种方式,让顾客直达商家服务。

以目前开通直达号的海底捞为例,它就会在以下情景中出现在用户面前:

移动搜索:用户打开百度移动网页,或百度搜索应用,在输入框中输入“海底捞”,现在得到搜索结果的第一条就是海底捞的直达号。

@账号:用户在搜索框中输入“@海底捞”会跳过搜索结果页面,直接打开海底捞的直达号页面。

地图:目前还不适用于海底捞。官方解释是,在地图上搜索某商家,点击进去后可能会进入相应的直达号页面,

个性化推荐:基于场景和兴趣对用户推荐,让用户在百度移动端上直接看到海底捞的直达号。

最全解释:百度直达号到底是什么?

百度搜索中输入@良子健身,直接跳转到商家直达号

商家如何建立自己的直达号?

百度针对不同行业推出适配于细分行业需求的模板。商家登录之后,选择自己所处的行业,编辑文字,上传图片,就能开通一个直达号。如果行业模板不能满足个性化需求,商家还可以使用组件工厂,通过选择一些模块,进行拖拽编辑,建立一个直达号。

百度为什么要推直达号?

1.帮助传统企业移动化。

大量线下企业想要移动化,但没有配套的移动互联网解决方案。用户在移动端不能方便地直接触达企业服务。所以百度希望利用直达号,为餐饮、旅游、娱乐、生活服务等各行各业商家直接提供移动化方案。

2.移动端的搜索流量不应该被浪费。

百度副总裁李明远以“良子健身”为例,用户在上午10点到下午6点期间,从手机百度以及百度地图寻找良子相关服务的需求,达到近千人次。如果把这些顾客需求都连接到良子健身直达号,可能为企业带来近100个潜在客单。

3.利用直达号为企业提供CRM系统。

百度利用已有的用户账号体系,帮助商家进行用户画像。通过数据分析,将用户标签化。让商家为用户提供个性化的服务。

百度大会:坚定不移地走向技术流

$
0
0

A man walks past the logo of Baidu at it

今天,百度世界大会召开,从大会传达的信息和李彦宏演讲来看,未来百度将坚定不移地走技术流,既然是技术流,那么我们挑一个细节,分析一下百度是如何坚定地走技术流的。

我们所讲的细节就是这次在百度世界大会发布的两款硬件产品其中之一的百度筷搜。

无论百度将百度筷搜描绘成多么牛逼的产品,但当我们拆分一下会发现,虽然百度筷搜无论从需求或者是工艺上,它都能在如今参差不齐的智能硬件里面脱颖而出,它的核心技术依旧是百度的优势——大数据。

为什么这么说呢,因为在硬件方面,百度筷搜底端集成了四颗传感器,它们分别是,油脂快速分析引擎、钠离子分析装置、PH 值感应装置、高灵敏温度感应模块、这对应的测量对象就是油脂、盐分、PH 值和温度。

虽然把它们集成在筷子大小的硬件设备上的确十分考验工艺,但是想必我们日常生活中也会接触到便携式 PH 检测笔和高灵敏温度计等,因此百度筷搜在工艺上虽然很优秀,但是并不足以令人吃惊。

最令人吃惊的也是这个筷子最核心的价值就是其背后百度强大的数据库。

首先我们看看数据能值多少钱,此前基于癌症大数据分析的医疗初创公司 Flatiron Health 获得了 1.3 亿美元的 B 轮融资,而领投的正是 Google Venture。

当然,你可以认为医疗数据值钱多了,这完全是两码子事,但是从百度筷搜提供的信息包括营养成分、保质期、搭配禁忌、卡路里等关于食品的一系列信息,我们也可以看出这并不是一个小的数据量。

因此这也拉开了百度筷搜与其他硬件产品的距离,哪怕将 Flatiron Health 获得的融资除以 10 或者 100,它都不是一般的硬件厂商所能负担的。

为什么我要强调百度筷搜以及它背后的数据库?因为一直以来百度商业模式单一,过于依赖网络搜索入口的优势,但在移动互联网的当下,这一优势正面临动摇,百度急需下一个引爆点。这也是李彦宏喊出“狼性”口号的原因。

因此这一次百度开始认真的寻找一个新的方向,它不再只是想当一个单纯的入口,相反它想将自己已经积累的大数据以及技术转换成下一个赢利点。

这一次与硬件结合是一个很好的尝试,不能说是重新起航,但是正如李彦宏所说,人们表达需求的方式不再只是文字了,而将大数据与硬件结合,正是以另外一种方式解决人们的需求,或者说是将搜索信息以另外一种形式表达出来。

题图来自 blouinnews

安心修道,才是王道。

#欢迎关注爱范儿认证微信公众号:AppSolution(微信号:appsolution),发现新酷精华应用。



爱范儿 · Beats of Bits |原文链接· 查看评论· 新浪微博· 微信订阅· 加入爱范社区!


关于代码审查的几点建议

$
0
0

Code Review即代码审查是软件开发中常用的手段,它和QA测试相比,更容易发现架构以及时序相关等较难发现的问题,还可以帮助团队成员统一编程风格,提高编程技能等。代码审查被公认为是一个提高代码质量的有效手段。目前很多开发团队虽然进行了代码审查,但是他们可能没有有效、合理的进行代码审查,以致没有很好达到代码审查的目的。近日,BIDS 贸易科技有限公司的CTO Jim Bird总结了关于代码审查的一些建议。现对这些建议进行了一个全面的梳理,具体内容如下:

1、代码审查不要太正式

目前,有很多研究表明正式代码的评审会议会延误开发进度和增加开发成本。尽管可能只需要几周的时间进行代码评审,但是只有4%的缺陷是在会议期间发现的,其余所有的权限是靠代码审查者自己发现和处理的。只有采用简短、轻量的代码审查才是有效的发现问题在代码检查,这样的代码审查更适合迭代、增量开发,为开发者提供更快的反馈。

2、代码审查人员要尽可能少

并不是代码审查人员越多就能发现越多Bug,只有合理数量的审查人员才能够更加有效的地审查代码。研究表明,平均来说,一个代码审查人员能够发现Bug的一半, 第二审稿人会发现剩余新问题的一半。多个人同2个人发现问题的数量没有太大差异,故两个人进行代码审查是比较合适的。另外,还由于社会惰性的存在,更多代码审查人员意味着多人在寻找同样的问题,使得审查人员积极性、主动性不高,更加不利于代码审查工作的有效进行。

3、需要有经验的开发者进行代码审查

研究充分表明,代码审查的有效性依赖于审查人的技能和对问题领域以及代码的熟悉程度。如果让新加入团队的成员进行代码审查的话,并不利于他们的成长,且对于代码审查来说也是一种非常糟糕的方式。只有擅长阅读代码、程序调试、非常熟悉语言、框架、对应的问题的人才最适合代码审查,才能够高效发现问题、提供更多有价值的反馈。新的、没有经验的开发者只适合检查代码的变化和使用静态分析工具并和另一位评论人员共同代码审查。

4、实质重于方式

完全按照编码规格标准进行的代码审查是一个浪费开发人员宝贵时间的方式。代码审查的实质是确认代码能够正确的运行,发现安全漏洞、功能错误、代码错误、设计失误、安全验证和防范、恶意代码等。而不是单单按照编码规范完全保证代码格式一致,而丢失了代码审查的实质。

5、合理安排Bug 和可维护性问题代码的审查时间分配

发现代码中的Bug是很难的,在别人的代码找到的Bug更难。研究表明,代码审查人员找到Bug和可维护性、可读性问题的比例是25:75,故消耗在了代码可读性、可维护性等问题上和Bug上的代码审查时间应该合理分配。

6、尽量使用静态代码分析工具以提高审查效率

工欲善其事,必先利其器。静态代码分析工具可以帮助程序开发人员自动执行静态代码分析,快速定位代码隐藏错误和缺陷;帮助代码设计人员更专注于分析和解决代码设计缺陷;显著减少在代码逐行检查上花费的时间,提高了软件可靠性并节省软件开发和测试成本。

7二八定律处理高风险代码

审查所有的代码并没有太大的意义,应该把审查的重点放在高风险的代码和容易引起高风险的修改或者重构的代码上。旧而复杂、处理敏感数据、处理重要业务逻辑和流程、大规模重构以及刚加入团队的开发者实现的代码都是审查的重点。

8、从代码审查中尽量获得最大的收益

虽然代码审查是发现Bug、提高开发人员代码编写质量的重要方式,但是它也增加了代码开发成本。如果没有合理、有效的进行代码审查,将有可能影响项目进度和破坏团队文化。故我们要紧抓代码审查的实质性问题,尽早和经常性的进行非正式的代码审查;选择精而少的人员并运用二八定律审查高风险的代码,同时,还需要合理分配Bug以及可维护性问题的代码审查时间,才可以从代码审查中获得最大的收益。

数据库调优

$
0
0

1、1、调整数据结构的设计。这一部分在开发信息系统之前完成,程序员需要考虑是否使用ORACLE数据库的分区功能,对于经常访问的数据库表是否需要建立索引等。 
2、2、调整应用程序结构设计。这一部分也是在开发信息系统之前完成,程序员在这一步需要考虑应用程序使用什么样的体系结构,是使用传统的Client/Server两层体系结构,还是使用Browser/Web/Database的三层体系结构。不同的应用程序体系结构要求的数据库资源是不同的。 
3、3、调整数据库SQL语句。应用程序的执行最终将归结为数据库中的SQL语句执行,因此SQL语句的执行效率最终决定了ORACLE数据库的性能。ORACLE公司推荐使用ORACLE语句优化器(Oracle Optimizer)和行锁管理器(row-level manager)来调整优化SQL语句。 
4、4、调整服务器内存分配。内存分配是在信息系统运行过程中优化配置的,数据库管理员可以根据数据库运行状况调整数据库系统全局区(SGA区)的数据缓冲区、日志缓冲区和共享池的大小;还可以调整程序全局区(PGA区)的大小。需要注意的是,SGA区不是越大越好,SGA区过大会占用操作系统使用的内存而引起虚拟内存的页面交换,这样反而会降低系统。 
5、5、调整硬盘I/O,这一步是在信息系统开发之前完成的。数据库管理员可以将组成同一个表空间的数据文件放在不同的硬盘上,做到硬盘之间I/O负载均衡。 
6、6、调整操作系统参数,例如:运行在UNIX操作系统上的ORACLE数据库,可以调整UNIX数据缓冲池的大小,每个进程所能使用的内存大小等参数。 
实际上,上述数据库优化措施之间是相互联系的。ORACLE数据库性能恶化表现基本上都是用户响应时间比较长,需要用户长时间的等待。但性能恶化的原因却是多种多样的,有时是多个因素共同造成了性能恶化的结果,这就需要数据库管理员有比较全面的计算机知识,能够敏感地察觉到影响数据库性能的主要原因所在。另外,良好的数据库管理工具对于优化数据库性能也是很重要的。 

ORACLE数据库性能优化工具 
常用的数据库性能优化工具有: 
1、1、ORACLE数据库在线数据字典,ORACLE在线数据字典能够反映出ORACLE动态运行情况,对于调整数据库性能是很有帮助的。 
2、2、操作系统工具,例如UNIX操作系统的vmstat,iostat等命令可以查看到系统系统级内存和硬盘I/O的使用情况,这些工具对于管理员弄清出系统瓶颈出现在什么地方有时候很有用。 
3、3、SQL语言跟踪工具(SQL TRACE FACILITY),SQL语言跟踪工具可以记录SQL语句的执行情况,管理员可以使用虚拟表来调整实例,使用SQL语句跟踪文件调整应用程序性能。SQL语言跟踪工具将结果输出成一个操作系统的文件,管理员可以使用TKPROF工具查看这些文件。 
4、4、ORACLE Enterprise Manager(OEM),这是一个图形的用户管理界面,用户可以使用它方便地进行数据库管理而不必记住复杂的ORACLE数据库管理的命令。 
5、5、EXPLAIN PLAN——SQL语言优化命令,使用这个命令可以帮助程序员写出高效的SQL语言。 

ORACLE数据库的系统性能评估 
信息系统的类型不同,需要关注的数据库参数也是不同的。数据库管理员需要根据自己的信息系统的类型着重考虑不同的数据库参数。 
1、1、在线事务处理信息系统(OLTP),这种类型的信息系统一般需要有大量的Insert、Update操作,典型的系统包括民航机票发售系统、银行储蓄系统等。OLTP系统需要保证数据库的并发性、可靠性和最终用户的速度,这类系统使用的ORACLE数据库需要主要考虑下述参数: 
l     l     数据库回滚段是否足够? 
l     l     是否需要建立ORACLE数据库索引、聚集、散列? 
l     l     系统全局区(SGA)大小是否足够? 
l     l     SQL语句是否高效?

2、2、数据仓库系统(Data Warehousing),这种信息系统的主要任务是从ORACLE的海量数据中进行查询,得到数据之间的某些规律。数据库管理员需要为这种类型的ORACLE数据库着重考虑下述参数: 
l     l     是否采用B*-索引或者bitmap索引? 
l     l     是否采用并行SQL查询以提高查询效率? 
l     l     是否采用PL/SQL函数编写存储过程? 
l     l     有必要的话,需要建立并行数据库提高数据库的查询效率 

SQL语句的调整原则 
SQL语言是一种灵活的语言,相同的功能可以使用不同的语句来实现,但是语句的执行效率是很不相同的。程序员可以使用EXPLAIN PLAN语句来比较各种实现方案,并选出最优的实现方案。总得来讲,程序员写SQL语句需要满足考虑如下规则: 
1、1、尽量使用索引。试比较下面两条SQL语句: 
语句A:SELECT dname, deptno FROM dept WHERE deptno NOT IN  
(SELECT deptno FROM emp); 
语句B:SELECT dname, deptno FROM dept WHERE NOT EXISTS 
(SELECT deptno FROM emp WHERE dept.deptno = emp.deptno); 
这两条查询语句实现的结果是相同的,但是执行语句A的时候,ORACLE会对整个emp表进行扫描,没有使用建立在emp表上的deptno索引,执行语句B的时候,由于在子查询中使用了联合查询,ORACLE只是对emp表进行的部分数据扫描,并利用了deptno列的索引,所以语句B的效率要比语句A的效率高一些。 

2、2、选择联合查询的联合次序。考虑下面的例子: 
SELECT stuff FROM taba a, tabb b, tabc c 
WHERE a.acol between :alow and :ahigh 
AND b.bcol between :blow and :bhigh 
AND c.ccol between :clow and :chigh 
AND a.key1 = b.key1 
AMD a.key2 = c.key2; 

这个SQL例子中,程序员首先需要选择要查询的主表,因为主表要进行整个表数据的扫描,所以主表应该数据量最小,所以例子中表A的acol列的范围应该比表B和表C相应列的范围小。 

3、3、在子查询中慎重使用IN或者NOT IN语句,使用where (NOT) exists的效果要好的多。 
4、4、慎重使用视图的联合查询,尤其是比较复杂的视图之间的联合查询。一般对视图的查询最好都分解为对数据表的直接查询效果要好一些。 
5、5、可以在参数文件中设置SHARED_POOL_RESERVED_SIZE参数,这个参数在SGA共享池中保留一个连续的内存空间,连续的内存空间有益于存放大的SQL程序包。 
6、6、ORACLE公司提供的DBMS_SHARED_POOL程序可以帮助程序员将某些经常使用的存储过程“钉”在SQL区中而不被换出内存,程序员对于经常使用并且占用内存很多的存储过程“钉”到内存中有利于提高最终用户的响应时间。 

CPU参数的调整 
CPU是服务器的一项重要资源,服务器良好的工作状态是在工作高峰时CPU的使用率在90%以上。如果空闲时间CPU使用率就在90%以上,说明服务器缺乏CPU资源,如果工作高峰时CPU使用率仍然很低,说明服务器CPU资源还比较富余。 
使用操作相同命令可以看到CPU的使用情况,一般UNIX操作系统的服务器,可以使用sar –u命令查看CPU的使用率,NT操作系统的服务器,可以使用NT的性能管理器来查看CPU的使用率。 

数据库管理员可以通过查看v$sysstat数据字典中“CPU used by this session”统计项得知ORACLE数据库使用的CPU时间,查看“OS User level CPU time”统计项得知操作系统用户态下的CPU时间,查看“OS System call CPU time”统计项得知操作系统系统态下的CPU时间,操作系统总的CPU时间就是用户态和系统态时间之和,如果ORACLE数据库使用的CPU时间占操作系统总的CPU时间90%以上,说明服务器CPU基本上被ORACLE数据库使用着,这是合理,反之,说明服务器CPU被其它程序占用过多,ORACLE数据库无法得到更多的CPU时间。 

数据库管理员还可以通过查看v$sesstat数据字典来获得当前连接ORACLE数据库各个会话占用的CPU时间,从而得知什么会话耗用服务器CPU比较多。 
出现CPU资源不足的情况是很多的:SQL语句的重解析、低效率的SQL语句、锁冲突都会引起CPU资源不足。 
1、数据库管理员可以执行下述语句来查看SQL语句的解析情况: 
SELECT * FROM V$SYSSTAT WHERE NAME IN 
('parse time cpu', 'parse time elapsed', 'parse count (hard)'); 

这里parse time cpu是系统服务时间,parse time elapsed是响应时间,用户等待时间 
waite time = parse time elapsed – parse time cpu 
由此可以得到用户SQL语句平均解析等待时间=waite time / parse count。这个平均等待时间应该接近于0,如果平均解析等待时间过长,数据库管理员可以通过下述语句 
SELECT SQL_TEXT, PARSE_CALLS, EXECUTIONS FROM V$SQLAREA 
ORDER BY PARSE_CALLS; 
来发现是什么SQL语句解析效率比较低。程序员可以优化这些语句,或者增加ORACLE参数SESSION_CACHED_CURSORS的值。 

2、数据库管理员还可以通过下述语句: 
SELECT BUFFER_GETS, EXECUTIONS, SQL_TEXT FROM V$SQLAREA; 
查看低效率的SQL语句,优化这些语句也有助于提高CPU的利用率。 

3、3、数据库管理员可以通过v$system_event数据字典中的“latch free”统计项查看ORACLE数据库的冲突情况,如果没有冲突的话,latch free查询出来没有结果。如果冲突太大的话,数据库管理员可以降低spin_count参数值,来消除高的CPU使用率。

内存参数的调整 
内存参数的调整主要是指ORACLE数据库的系统全局区(SGA)的调整。SGA主要由三部分构成:共享池、数据缓冲区、日志缓冲区。 
1、  1、   共享池由两部分构成:共享SQL区和数据字典缓冲区,共享SQL区是存放用户SQL命令的区域,数据字典缓冲区存放数据库运行的动态信息。数据库管理员通过执行下述语句: 
select (sum(pins - reloads)) / sum(pins) "Lib Cache"  from v$librarycache; 
来查看共享SQL区的使用率。这个使用率应该在90%以上,否则需要增加共享池的大小。数据库管理员还可以执行下述语句: 
select (sum(gets - getmisses - usage - fixed)) / sum(gets) "Row Cache" from v$rowcache; 
查看数据字典缓冲区的使用率,这个使用率也应该在90%以上,否则需要增加共享池的大小。 

2、  2、   数据缓冲区。数据库管理员可以通过下述语句: 
SELECT name, value  FROM v$sysstat  WHERE name IN ('db block gets', 'consistent gets','physical reads'); 
来查看数据库数据缓冲区的使用情况。查询出来的结果可以计算出来数据缓冲区的使用命中率=1 - ( physical reads / (db block gets + consistent gets) )。 
这个命中率应该在90%以上,否则需要增加数据缓冲区的大小。

3、  3、   日志缓冲区。数据库管理员可以通过执行下述语句: 
select name,value from v$sysstat where name in ('redo entries','redo log space requests');查看日志缓冲区的使用情况。查询出的结果可以计算出日志缓冲区的申请失败率: 

申请失败率=requests/entries,申请失败率应该接近于0,否则说明日志缓冲区开设太小,需要增加ORACLE数据库的日志缓冲区。

 

=====

数据库查询调优

      1.对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引。 

  2.应尽量避免在 where 子句中对字段进行 null 值判断,否则将导致引擎放弃使用索引而进行全表扫描,如: 

  select id from t where num is null 

  可以在num上设置默认值0,确保表中num列没有null值,然后这样查询: 

  select id from t where num=0 

  3.应尽量避免在 where 子句中使用!=或<>操作符,否则将引擎放弃使用索引而进行全表扫描。 

  4.应尽量避免在 where 子句中使用 or 来连接条件,否则将导致引擎放弃使用索引而进行全表扫描,如: 

  select id from t where num=10 or num=20 

  可以这样查询: 

  select id from t where num=10 

  union all 

  select id from t where num=20 

  5.in 和 not in 也要慎用,否则会导致全表扫描,如: 

  select id from t where num in(1,2,3) 

  对于连续的数值,能用 between 就不要用 in 了: 

  select id from t where num between 1 and 3 

  6.下面的查询也将导致全表扫描: 

  select id from t where name like '%abc%' 

  若要提高效率,可以考虑全文检索。 

  7.如果在 where 子句中使用参数,也会导致全表扫描。因为SQL只有在运行时才会解析局部变量,但优化程序不能将访问计划的选择推迟到运行时;它必须在编译时进行选择。然而,如果在编译时建立访问计划,变量的值还是未知的,因而无法作为索引选择的输入项。如下面语句将进行全表扫描: 

  select id from t where num=@num 

  可以改为强制查询使用索引: 

  select id from t with(index(索引名)) where num=@num 

  8.应尽量避免在 where 子句中对字段进行表达式操作,这将导致引擎放弃使用索引而进行全表扫描。如: 

  select id from t where num/2=100 

  应改为: 

  select id from t where num=100*2 

  9.应尽量避免在where子句中对字段进行函数操作,这将导致引擎放弃使用索引而进行全表扫描。如: 

  select id from t where substring(name,1,3)='abc'--name以abc开头的id 

  select id from t where datediff(day,createdate,'2005-11-30')=0--‘2005-11-30’生成的id 

  应改为: 

  select id from t where name like 'abc%' 

  select id from t where createdate>='2005-11-30' and createdate<'2005-12-1'

10.不要在 where 子句中的“=”左边进行函数、算术运算或其他表达式运算,否则系统将可能无法正确使用索引。 

  11.在使用索引字段作为条件时,如果该索引是复合索引,那么必须使用到该索引中的第一个字段作为条件时才能保证系统使用该索引,否则该索引将不会被使用,并且应尽可能的让字段顺序与索引顺序相一致。 

  12.不要写一些没有意义的查询,如需要生成一个空表结构: 

  select col1,col2 into #t from t where 1=0 

  这类代码不会返回任何结果集,但是会消耗系统资源的,应改成这样: 

  create table #t(...) 

  13.很多时候用 exists 代替 in 是一个好的选择: 

  select num from a where num in(select num from b) 

  用下面的语句替换: 

  select num from a where exists(select 1 from b where num=a.num) 

  14.并不是所有索引对查询都有效,SQL是根据表中数据来进行查询优化的,当索引列有大量数据重复时,SQL查询可能不会去利用索引,如一表中有字段sex,male、female几乎各一半,那么即使在sex上建了索引也对查询效率起不了作用。 

  15.索引并不是越多越好,索引固然可以提高相应的 select 的效率,但同时也降低了 insert 及 update 的效率,因为 insert 或 update 时有可能会重建索引,所以怎样建索引需要慎重考虑,视具体情况而定。一个表的索引数最好不要超过6个,若太多则应考虑一些不常使用到的列上建的索引是否有必要。 

  16.应尽可能的避免更新 clustered 索引数据列,因为 clustered 索引数据列的顺序就是表记录的物理存储顺序,一旦该列值改变将导致整个表记录的顺序的调整,会耗费相当大的资源。若应用系统需要频繁更新 clustered 索引数据列,那么需要考虑是否应将该索引建为 clustered 索引。 

  17.尽量使用数字型字段,若只含数值信息的字段尽量不要设计为字符型,这会降低查询和连接的性能,并会增加存储开销。这是因为引擎在处理查询和连接时会逐个比较字符串中每一个字符,而对于数字型而言只需要比较一次就够了。 

  18.尽可能的使用 varchar/nvarchar 代替 char/nchar ,因为首先变长字段存储空间小,可以节省存储空间,其次对于查询来说,在一个相对较小的字段内搜索效率显然要高些。 

  19.任何地方都不要使用 select * from t ,用具体的字段列表代替“*”,不要返回用不到的任何字段。 

  20.尽量使用表变量来代替临时表。如果表变量包含大量数据,请注意索引非常有限(只有主键索引)。 

  21.避免频繁创建和删除临时表,以减少系统表资源的消耗。 

  22.临时表并不是不可使用,适当地使用它们可以使某些例程更有效,例如,当需要重复引用大型表或常用表中的某个数据集时。但是,对于一次性事件,最好使用导出表。 

  23.在新建临时表时,如果一次性插入数据量很大,那么可以使用 select into 代替 create table,避免造成大量 log ,以提高速度;如果数据量不大,为了缓和系统表的资源,应先create table,然后insert。 

  24.如果使用到了临时表,在存储过程的最后务必将所有的临时表显式删除,先 truncate table ,然后 drop table ,这样可以避免系统表的较长时间锁定。 

  25.尽量避免使用游标,因为游标的效率较差,如果游标操作的数据超过1万行,那么就应该考虑改写。 

  26.使用基于游标的方法或临时表方法之前,应先寻找基于集的解决方案来解决问题,基于集的方法通常更有效。 

  27.与临时表一样,游标并不是不可使用。对小型数据集使用 FAST_FORWARD 游标通常要优于其他逐行处理方法,尤其是在必须引用几个表才能获得所需的数据时。在结果集中包括“合计”的例程通常要比使用游标执行的速度快。如果开发时间允许,基于游标的方法和基于集的方法都可以尝试一下,看哪一种方法的效果更好。 

  28.在所有的存储过程和触发器的开始处设置 SET NOCOUNT ON ,在结束时设置 SET NOCOUNT OFF 。无需在执行存储过程和触发器的每个语句后向客户端发送 DONE_IN_PROC 消息。 

  29.尽量避免大事务操作,提高系统并发能力。 

  30.尽量避免向客户端返回大数据量,若数据量过大,应该考虑相应需求是否合理

 



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


ITeye推荐



如何开发无法维护的软件

$
0
0

我靠解决技术债务养家糊口。在我的工作中我看到许多难以维护的代码,并且一次又一次地看到很多相同的原本可以避免的问题。

我专长于调试,修复,维护和扩展旧的软件系统。我的典型的客户拥有一个尚可运行的网站或内部应用,但是开发者已经不知所踪。业务需求已经改变了但是软件没有跟上。抑或我的客户有了些“快要完成”的东西但是由于预算和日程安排的关系失去了开发者。通常那包括一系列尚未完成的功能和bug。

我的客户通常被别的开发者告知需要丢弃所有的东西从头来过。大多数程序员不喜欢维护代码,尤其是维护别人的代码。当程序员写代码的时候他们总是在可维护性上问错误的问题——关于这个话题详见Matt DuVall的文章: The myth of maintainability

我在这里为你的开发项目提供了一些建议以使我有活可以干。

 

不要用版本控制

我总是能惊奇地发现在过去几年写的大项目不使用版本控制。如果你不使用版本控制,下一任开发者就要找出哪些文件是现有系统的一部分以及哪些仅仅是备份。他没有任何提交信息和改动日志来知悉代码的历史。我在我的文章Introduction to Abject-Oriented Programming中讲述了如何不使用版本控制。

 

自定义你的开发环境——越多越好

不要让下一任开发者可以轻松地上手。要求特定的开发语言版本和工具,并且确保他们和操作系统自带的版本有冲突。疯狂自定义你的Eclipse或VisualStudio或vim,然后写一些只能在那个配置下运行的宏和脚本。不要创建一个磁盘映像或者脚本来重现你的开发环境,并且不要写任何文档——那给了太多提示。

 

创建一个详细的构建和展开环境

把一个网站投入到正式服务器应该以下面的形式进行:

svn up
git pull
hg pull

程序员可以讨论代码是否简洁和优雅,然后他们转过身去建立最为详尽和复杂的展开系统。这是他们悄悄干的,不经过产品经理和客户的审查,也无法被理解的行为之一,所以它会轻易地失控。当你用不同的脚本语言把八个工具连接起来时,记得留下文档。

 

不要建立测试/登录平台

改变一个产品系统让人激动。不用麻烦去搭建测试或登录平台了。取而代之的,用秘密的登录方法或者用些后门URL来测试新特性。把测试数据和真实数据混合在你的数据库里。因为你没有使用版本控制,保存几份原先版本的拷贝以防万一。不要在代码里加入登录。不要在测试中关闭邮件发送,信用卡验证,等等。

 

将所有的东西从头写过

千万别用一个像Django, Rails, 或者CakePHP那样大家都能理解的框架。你可以写一个更好的引擎,ORM,排序或者哈希算法。当我看到一些例如“比原有字典更快的方法”或者“改变了PHP的库函数因为参数顺序烂透了”的注释时,我就要重置我的大脑。

 

为特殊的库和资源加上从属关系

尽可能多的加入第三方代码。连接你需要连接的库。我见过用了大量的外接库只为调用某个方法的代码。改变第三方库的源代码这样它们就无法自动更新,但是千万不要用版本控制。这样我就能发现不同的地方从而还原出原来的版本。

 

但是千万不要保护这些关系或者为此写文档

我接到最多的紧急电话和更新出错有关。一个看上去无害的wordpress升级,Linux更新包,或者新的jQuery版本会造成一系列实效。不要把你的代码放到特殊的或者不用的第三方库版本下检测。甚至不要加上注释。

 

用不同的编程语言并且紧跟潮流

每一天HackerNews和Reddit上涌现出新的酷的语言。在你的客户的东西上试试它们。任何合格的程序员可以在瞬间学会一种新语言,所以你的代码的继任者对其毫不了解也不是你的错。语言的边界,不兼容的API和数据格式,不同的服务器配置都是有趣的挑战并且值得在StackOverFlow上贴出来。我真的见过有人把Ruby嵌入PHP网站因为所有人都知道PHP很烂而Ruby更好。半吊子的caching, 流产的Rails和Node.js项目,特别是那些NoSQL方案都是我的好生意。

 

编程建议在哪里?

你的代码是否完美地面向对象,光鲜亮丽都无关紧要——程序员在面对旧的系统时总是一团浆糊。我擅长用diff,grep和Ctag, 追踪代码,重构和调试。我会搞清楚所有的东西。最美丽,优雅的代码如果缺少了版本控制,加上太多从属关系和自定义,并且没有测试系统的话仍然是很难维护的。这就像在一群强迫性囤积症患者中找到一间干净整洁的屋子。

如何开发无法维护的软件,首发于 博客 - 伯乐在线


使用ThreadPoolExecutor并行执行独立的单线程任务

$
0
0

Java SE 5.0中引入了任务执行框架,这是简化多线程程序设计开发的一大进步。使用这个框架可以方便地管理任务:管理任务的生命周期以及执行策略。

在这篇文章中,我们通过一个简单的例子来展现这个框架所带来的灵活与简单。

基础

执行框架引入了Executor接口来管理任务的执行。Executor是一个用来提交Runnable任务的接口。这个接口将任务提交与任务执行隔离起来:拥有不同执行策略的executor都实现了同一个提交接口。改变执行策略不会影响任务的提交逻辑。

如果你要提交一个Runnable对象来执行,很简单:

Executor exec = …;
exec.execute(runnable);

线程池

如前所述,executor如何去执行提交的runnable任务并没有在Executor接口中规定,这取决于你所用的executor的具体类型。这个框架提供了几种不同的executor,执行策略针对不同的场景而不同。

你可能会用到的最常见的executor类型就是线程池executor,也就是ThreadPoolExecutor类(及其子类)的实例。ThreadPoolExecutor管理着一个线程池和一个工作队列,线程池存放着用于执行任务的工作线程。

你肯定在其他技术中也了解过“池”的概念。使用“池”的一个最大的好处就是减少资源创建的开销,用过并释放后,还可以重用。另一个间接的好处是你可以控制使用资源的多少。比如,你可以调整线程池的大小达到你想要的负载,而不损害系统的资源。

这个框架提供了一个工厂类,叫Executors,来创建线程池。使用这个工程类你可以创建不同特性的线程池。尽管底层的实现常常是一样的(ThreadPoolExecutor),但工厂类可以使你不必使用复杂的构造函数就可以快速地设置一个线程池。工程类的工厂方法有:

  • newFixedThreadPool:该方法返回一个最大容量固定的线程池。它会按需创建新线程,线程数量不大于配置的数量大小。当线程数达到最大以后,线程池会一直维持这么多不变。
  • newCachedThreadPool:该方法返回一个无界的线程池,也就是没有最大数量限制。但当工作量减小时,这类线程池会销毁没用的线程。
  • newSingleThreadedExecutor:该方法返回一个executor,它可以保证所有的任务都在一个单线程中执行。
  • newScheduledThreadPool:该方法返回一个固定大小的线程池,它支持延时和定时任务的执行。

这仅仅是一个开端。Executor还有一些其他用法已超出了这篇文章的范围,我强烈推荐你研究以下内容:

  • 生命周期管理的方法,这些方法由ExecutorService接口声明(比如shutdown()和awaitTermination())。
  • 使用CompletionService来查询任务状态、获取返回值,如果有返回值的话。

ExecutorService接口特别重要,因为它提供了关闭线程池的方法,并确保清理了不再使用的资源。令人欣慰的是,ExecutorService接口相当简单、一目了然,我建议全面地学习下它的文档。

大致来说,当你向ExecutorService发送了一个shutdown()消息后,它就不会接收新提交的任务,但是仍在队列中的任务会被继续处理完。你可以使用isTerminated()来查询ExecutorService终止状态,或使用awaitTermination(…)方法来等待ExecutorService终止。如果传入一个最大超时时间作为参数,awaitTermination方法就不会永远等待。

警告:对JVM进程永远不会退出的理解上,存在着一些错误和迷惑。如果你不关闭executorService,只是销毁了底层的线程,JVM就不会退出。当最后一个普通线程(非守护线程)退出后,JVM也会退出。

配置ThreadPoolExecutor

如果你决定不使用Executor的工厂类,而是手动创建一个 ThreadPoolExecutor,你需要使用构造函数来创建并配置。下面是这个类使用最广泛的一个构造函数:

public ThreadPoolExecutor(
    int corePoolSize,
    int maxPoolSize,
    long keepAlive,
    TimeUnit unit,
    BlockingQueue<Runnable> workQueue,
    RejectedExecutionHandler handler);

如你所见,你可以配置以下内容:

  • 核心池的大小(线程池将会使用的大小)
  • 最大池大小
  • 存活时间,空闲线程在这个时间后被销毁
  • 存放任务的工作队列
  • 任务提交拒绝后要执行的策略

限制队列中任务数

限制执行任务的并发数、限制线程池大小对应用程序以及程序执行结果的可预期性与稳定性有很大的好处。无尽地创建线程,最终会耗尽运行时资源。你的应用程序因此会产生严重的性能问题,甚至导致程序不稳定。

这只解决了部分问题:限制了并发任务数,但并没有限制提交到等待队列的任务数。如果任务提交的速率一直高于任务执行的速率,那么应用程序最终会出现资源短缺的状况。

解决方法是:

  • 为Executor提供一个存放待执行任务的阻塞队列。如果队列填满,以后提交的任务会被“拒绝”。
  • 当任务提交被拒绝时会触发RejectedExecutionHandler,这也是为什么这个类名中引用动词“rejected”。你可以实现自己的拒绝策略,或者使用框架内置的策略。

默认的拒绝策略可以让executor抛出一个RejectedExecutionException异常。然而,还有其他的内建策略:

  • 悄悄地丢弃一个任务
  • 丢弃最旧的任务,重新提交最新的
  • 在调用者的线程中执行被拒绝的任务

什么时候以及为什么我们才会这样配置线程池?让我们看一个例子。

示例:并行执行独立的单线程任务

最近,我被叫去解决一个很久以前的任务的问题,我的客户之前就运行过这个任务。大致来说,这个任务包含一个组件,这个组件监听目录树所产生的文件系统事件。每当一个事件被触发,必须处理一个文件。一个专门的单线程执行文件处理。说真的,根据任务的特点,即使我能把它并行化,我也不想那么做。一天的某些时候,事件到达率才很高,文件也没必要实时处理,在第二天之前处理完即可。

当前的实现采用了一些混合且匹配的技术,包括使用UNIX SHELL脚本扫描目录结构,并检测是否发生改变。实现完成后,我们采用了双核的执行环境。同样,事件的到达率相当低:目前为止,事件数以百万计,总共要处理1~2T字节的原始数据。

运行处理程序的主机是12核的机器:很好机会去并行化这些旧的单线程任务。基本上,我们有了食谱的所有原料,我们需要做的仅仅是把程序建立起来并调节。在写代码前,我们必须了解下程序的负载。我列一下我检测到的内容:

  • 有非常多的文件需要被周期性地扫描:每个目录包含1~2百万个文件
  • 扫描算法很快,可以并行化
  • 处理一个文件至少需要1s,甚至上升到2s或3s
  • 处理文件时,性能瓶颈主要是CPU
  • CPU利用率必须可调,根据一天时间的不同而使用不同的负载配置。

我需要这样一个线程池,它的大小在程序运行的时候通过负载配置来设置。我倾向于根据负载策略创建一个固定大小的线程池。由于线程的性能瓶颈在CPU,它的核心使用率是100%,不会等待其他资源,那么负载策略就很好计算了:用执行环境的CPU核心数乘以一个负载因子(保证计算的结果在峰值时至少有一个核心):

int cpus = Runtime.getRuntime().availableProcessors();
int maxThreads = cpus * scaleFactor;
maxThreads = (maxThreads > 0 ? maxThreads : 1);

然后我需要使用阻塞队列创建一个ThreadPoolExecutor,可以限制提交的任务数。为什么?是这样,扫描算法执行很快,很快就产生庞大数量需要处理的文件。数量有多庞大呢?很难预测,因为变动太大了。我不想让executor内部的队列不加选择地填满了要执行的任务实例(这些实例包含了庞大的文件描述符)。我宁愿在队列填满时,拒绝这些文件。

而且,我将使用ThreadPoolExecutor.CallerRunsPolicy作为拒绝策略。为什么?因为当队列已满时,线程池的线程忙于处理文件,我让提交任务的线程去执行它(被拒绝的任务)。这样,扫面会停止,转而去处理一个文件,处理结束后马上又会扫描目录。

下面是创建executor的代码:

ExecutorService executorService =
    new ThreadPoolExecutor(
        maxThreads, // core thread pool size
        maxThreads, // maximum thread pool size
        1, // time to wait before resizing pool
        TimeUnit.MINUTES, 
        new ArrayBlockingQueue<Runnable>(maxThreads, true),
        new ThreadPoolExecutor.CallerRunsPolicy());

下面是程序的框架(极其简化版):

// scanning loop: fake scanning
while (!dirsToProcess.isEmpty()) {
    File currentDir = dirsToProcess.pop();

    // listing children
    File[] children = currentDir.listFiles();

    // processing children
    for (final File currentFile : children) {
        // if it's a directory, defer processing
        if (currentFile.isDirectory()) {
            dirsToProcess.add(currentFile);
            continue;
        }

        executorService.submit(new Runnable() {
            @Override
            public void run() {
                try {
                    // if it's a file, process it
                    new ConvertTask(currentFile).perform();
                } catch (Exception ex) {
                    // error management logic
                }
            }
        });
    }
}

// ...
// wait for all of the executor threads to finish
executorService.shutdown();
try {
    if (!executorService.awaitTermination(60, TimeUnit.SECONDS)) {
        // pool didn't terminate after the first try
        executorService.shutdownNow();
    }

    if (!executorService.awaitTermination(60, TimeUnit.SECONDS)) {
        // pool didn't terminate after the second try
    }
} catch (InterruptedException ex) {
    executorService.shutdownNow();
    Thread.currentThread().interrupt();
}

总结

看到了吧,Java并发API非常简单易用,十分灵活,也很强大。真希望我多年前可以多花点功夫写一个这样简单的程序。这样我就可以在几小时内解决由传统单线程组件所引发的扩展性问题。

相关文章

前台页面优化全攻略(一)

$
0
0

   英文原文:http://www.sitepoint.com/complete-guide-reducing-page-weight/

  据调查,网页大小在2013年平均增长了32%,平均达到了1.7M,单独的HTTP请求达到96个。这是令人震惊的数字,而且这只是个平均值,有一半的网站会大于这个值。网站也得了肥胖症,而我们这些开发者就是罪魁祸首。

  一个超重的网站会对你产生如下影响:

  1. 网站代码越多,用户下载的就越多,加载速度就会越慢。在这个地球上,并不是每个人都能享受20M的宽带,每一个开发者心里都很清楚,用户不愿意等。

  2. 众所周知,移动互联网发展迅速,对于2G网络来说,加载1.7M的页面甚至需要一分钟时间。

  3. 影响搜索引擎抓取速度将会对网站排名造成很大影响。

  4. 对于开发者来说,代码量越大,就越不容易更新和维护。

  我猜测今年页面平均代码量会减小,希望事实如我所愿。如今已经有很多人开始关注这个问题,并出现了很多优化的工具,而且这些技术都非常容易上手,不需要花太多时间,也不需要重新开发。

  在本文中,我会给大家一些建议。前三个建议实际上不能给网页减肥,但它们仍能有效的加快网页加载速度。

  1. 用GZIP格式压缩

  gzip是GNUzip的缩写,它是一个GNU自由软件的文件压缩程序。它是Jean-loupGailly和MarkAdler一起开发的。第一次公开发布版本是1992年10月31日发布的版本0.1,1993年2月发布了版本1.0。

我们在Linux中经常会用到后缀为.gz的文件,它们就是GZIP格式的。现今已经成为Internet 上使用非常普遍的一种数据压缩格式,或者说一种文件格式。

  HTTP协议上的GZIP编码是一种用来改进WEB应用程序性能的技术。大流量的WEB站点常常使用GZIP压缩技术来让用户感受更快的速度。这一般是指WWW服务器中安装的一个功能,当有人来访问这个服务器中的网站时,服务器中的这个功能就将网页内容压缩后传输到来访的电脑浏览器中显示出来.一般对纯文本内容可压缩到原大小的40%.这样传输就快了,效果就是你点击网址后会很快的显示出来.当然这也会增加服务器的负载. 一般服务器中都安装有这个功能模块的。

  根据W3C组织调查,大部分的网站都没有启用压缩功能。 

  2. 支持浏览器缓存

  如果浏览器支持缓存,我们就不用重复下载网页资源。最简单的设置缓存方法是在响应头中添加相应的内容,包括:Expires header,Last-Modified等。

  你可以可以通过配置服务器来自动添加这些属性。比如你在Apache服务器中配置缓存所有的照片一个月:

<IfModule mod_expires.c>
ExpiresActive On

<FilesMatch "\.(jpg|jpeg|png|gif|svg)$">
ExpiresDefault "access plus 1 month"
</FilesMatch>

</IfModule>

  3. 使用内容分发网络 (CDN)

  CDN的全称是Content Delivery Network,即内容分发网络。其目的是通过在现有的Internet中增加一层新的网络架构,将网站的内容发布到最接近用户的网络“边缘”,使用户可以就近取得所需的内容,提高用户访问网站的响应速度。CDN有别于镜像,因为它比镜像更智能,或者可以做这样一个比 喻:CDN=更智能的镜像+缓存+流量导流。因而,CDN可以明显提高Internet网络中信息流动的效率。从技术上全面解决由于网络带宽小、用户访问量大、网点分布不均等问题,提高用户访问网站的响应速度。 

  为更好地理解CDN,让我们看一下CDN的工作流程。当用户访问已经加入CDN服务的网站时,首先通过DNS重定向技术确定最接近用户的最佳CDN节点,同时将用户的请求指向该节点。当用户的请求到达指定节点时,CDN的服务器(节点上的高速缓存)负责将用户请求的内容提供给用户。具体流程为: 用户在自己的浏览器中输入要访问的网站的域名,浏览器向本地DNS请求对该域名的解析,本地DNS将请求发到网站的主DNS,主DNS根据一系列的策略确定当时最适当的CDN节点,并将解析的结果(IP地址)发给用户,用户向给定的CDN节点请求相——应网站的内容。

  以上三个方法可以有效地加快页面的访问速度,现在我们将对你的代码进行诊断,帮助我们给页面减肥。

  4. 删除不需要的资源

  当你不再需要一个组件的时候,你应该删掉它的CSS和JavaScript代码,如果这些代码都单独放在一个文件中,那删掉它们也不是难事,但如果已经没有用的代码和其它代码在一个文件中,那你肯定要费不少精力去删掉它们。这个时候你就需要使用第三方的工具来帮你一键解决,比如 JSLintDust-Me SelectorsCSS Usageunused-css.com 或是像 grunt-uncss一样的构建工具。

  5. 通用和最小化CSS

  理想情况下,需要一个单独的CSS文件,让每个页面都调用这一个布局,当然,如果你想要支持老版本的IE,你就得多弄一个CSS文件。当你把它们构建到服务器上之前,你应该把代码间所有不必要的格式都删掉。

  有很多预处理工具都可以帮你解决这件麻烦事,比如 SassLESS 和 Stylus

  有一些方法可以帮助你直接合并多个CSS文件,在Windows上:

copy file1.css+file2.css file.css

  在 Mac或Linux上:

cat file1.css file2.css > file.css

  你可以把得到的CSS文件再经过在线的CSS压缩工具删除格式化, cssminifier.comCSS Compressor & Minifier 和 CSS Compressor都是很不错的工具。

  最后,在head标签中加载所有的CSS,这样浏览器就知道你的页面样式不用多次重绘了。

  6. 通用和最小化的JavaScript

  平均每个页面加载了18个javascript文件,虽然把像jQuery这样的库文件单独分开非常实用,但是你自己的JavaScript代码应该保持通用和最小化。同样很多第三方的工具可以帮你解决这样事情,比如  YUI CompressorClosure Compiler 和我最喜欢用的  The JavaScript CompressorRater。简化的JavaScript代码会加快网页的访问速度,减少HTTP请求次数。

  最后,最好在HTML的body标签后放置JavaScript引用代码,这样能保证JavaScript代码不影响到其它内容的加载。

  7. 使用正确的图片路径

  加载错误的图片格式会对你的网页造成很大影响,一般来说选取图片我们应用遵循如下原则:

  1.照片使用JPG格式。

  2.其它所有的图片都使用PNG格式。

  8. 调整大图的大小

  目前智能机所拍出的照片越来越大,你不可能把原照片直接展示在页面中。普通的编辑器都会直接上传原图,这样会让页面的加载速度慢到另一个级别。在正常的照片处理中,一般都没有必要给用户高质量的图片展示。所以你需要一个自动调整图片大小的工具。

  需要注意的是,图片的尺寸是不能超过容量的大小的,这样一来页面加载了全图,却无法展示出来。现在照片的尺寸基本上都超过电脑显示屏的尺寸了。

  图片的大小在网页总大小中占很大的比重,图片减小50%会导致整体页面大小减少75%,所以你应该认真解决一下图片的加载。

  9. 进一步压缩图片

  仅仅调优图片的大小是不够的,你应该通过第三方工具对图片进行分析,进一步压缩图片。比较好用的工具有 OptiPNGPNGOUTjpegtran 和 jpegoptim。这些工具大都能安装成独立的工具或是整合到开发过程中,另外像 Smush这样的工具,还可以直接在云端处理。

  10. 删除不必要的字体

  Web fonts已经彻底改变了字体的设计,它减少了很多不必要的文本。然而,目前的字体仍然会给你的网页带来多余的字节。如果你使用超过两种字体,这就已经开始对性能造成影响了。

  结论

  我相信大部分网站都可以通过以上的优化减小大概30%-50%的重量,但是身为一个完美主义的开发者这是远远不够的,我们在接下来的系列文章中会继续对网站瘦身进行深入研究,感兴趣的可以关注一下极客头条的微博和微信,我们会将接下来的文章在各个社交平台上进行推送。

ActiveMq NON_PERSISTENT与PERSISTENT以及 durable subscription(持久订阅)的理解

$
0
0

 

http://quentinXXZ.iteye.com/blog/2113458

 

实验一:

public class Producer {
	public static void main(String[] args) {
	    String user = ActiveMQConnection.DEFAULT_USER;
	    String password = ActiveMQConnection.DEFAULT_PASSWORD;
	    String url = ActiveMQConnection.DEFAULT_BROKER_URL;
	    String subject = "TOOL.DEFAULT";
	    System.out.println(user +" "+ password+" "+url+" "+subject+" ");
		ConnectionFactory contectionFactory = new ActiveMQConnectionFactory(user,password,url);
		try {
			Connection connection = contectionFactory.createConnection();
			connection.start();
			Session session = connection.createSession(Boolean.TRUE, Session.AUTO_ACKNOWLEDGE);
			Destination destination = session.createQueue(subject);
			MessageProducer producer = session.createProducer(destination);
			for(int i = 0;i<=20;i++){
				MapMessage message = session.createMapMessage();
				message.setLong("date", new Date().getTime());
				Thread.sleep(5000);
				producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
				producer.send(message);
				System.out.println("—SendMessge:"+new Date());
			}
			session.commit();
			session.close();
			connection.close();
		} catch (JMSException e) {
			e.printStackTrace();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
}

 注意:producer.setDeliveryMode(DeliveryMode. NON_PERSISTENT);

 此处显式指明DeliveryMode为NON_PERSISENT

 

public class Consumer {

	public static void main(String[] args) {
		String user = ActiveMQConnection.DEFAULT_USER;
	    String password = ActiveMQConnection.DEFAULT_PASSWORD;
	    String url = ActiveMQConnection.DEFAULT_BROKER_URL;
	    String subject = "TOOL.DEFAULT";
		ConnectionFactory connectionFactory = new ActiveMQConnectionFactory(user,password,url);
		Connection connection;
		try {
			connection = connectionFactory.createConnection();
			connection.start();
			final Session session = connection.createSession(Boolean.TRUE, Session.AUTO_ACKNOWLEDGE);
			Destination destination = session.createQueue(subject);
			MessageConsumer message = session.createConsumer(destination);
			message.setMessageListener(new MessageListener(){

				public void onMessage(Message msg) {
					MapMessage message = (MapMessage)msg;
					try {
						System.out.println("--Receive:"+new Date(message.getLong("date")));
						session.commit();
					} catch (JMSException e) {
						e.printStackTrace();
					}
				}
			});
			Thread.sleep(30000);
			session.close();
			connection.close();
		} catch (JMSException e) {
			e.printStackTrace();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}

}

 ActiveMq Broker的配置都为默认。

先启动Broker,再启动Producer,等待Producer的20条Message发送完毕,Prducer程序运行结束,之后再启动Consumer,20条Message正常接收。

可见PERSISTENT与NON_PERSISTENT,并不是指Broker会不会在Consumer未连接的情况为其存储Message

 

实验二:

先启动Broker,再启动Producer,等待Producer的20条Message发送完毕,Prducer程序运行结束。关闭ActiveMq  Broker服务,然后重启。之后再启动Consumer。

Consumer没有接收到任何消息。

 

实验三:

producer.setDeliveryMode(DeliveryMode. PERSISTENT);

在Producer中显式指明DeliveryMode为PERSISENT

实验步骤与实验二相同,但是此次Consumer收到了来自Producer的消息。

 

 

总结:

Persistent 用来指定JMS Provider对消息进行持久化操作,以免Provider fail的时候,丢失Message.

NON_Persistent 方式下的JMS Provider不会对消进宪持久化,但上述实验一可知,Consumer还是会收到Message,可见JMS Provider会将相应的消息存在内存中,当Consumer连接上时,再发送过去,但在Provider fail的时候,Message会丢失。

事实上ActiveMq提供了多种消息持久化方式,包括AMQ、KahaDB、JDBC、LevelDB。从5.4版本之后KahaDB做为默认的持久化方式。

 

 

以下网上摘的:

 

消息订阅分为非持久订阅(non-durable subscription)和持久订阅(durablesubscription),非持久订阅只有当客户端处于激活状态,也就是和JMS Provider保持连接状态才能收到发送到某个主题的消息,而当客户端处于离线状态,这个时间段发到主题的消息将会丢失,永远不会收到。持久订阅时,客户端向JMS注册一个识别自己身份的ID,当这个客户端处于离线时,JMS Provider 会为这个ID 保存所有发送到主题的消息,当客户再次连接到JMS Provider时,会根据自己的ID得到所有当自己处于离线时发送到主题的消息。

Topic 主题由JMS Provider 管理,主题由主题名识别,客户端可以通过JNDI接口用主题名得到一个主题对象。

 

 

消息发送端

消息接收端

可靠性及因素

PERSISTENT

queue receiver/durable subscriber

消费一次且仅消费一次。可靠性最好,但是占用服务器资源比较多。

PERSISTENT

non-durable subscriber

最多消费一次。这是由于non-durable subscriber决定的,如果消费端宕机或其他问题导致与JMS服务器断开连接,等下次再联上JMS服务器时的一系列消息,不为之保留。

NON_PERSISTENT

queue receiver/durable subscriber

最多消费一次。这是由于服务器的宕机会造成消息丢失

NON_PERSISTENT

non-durable subscriber

最多消费一次。这是由于服务器的宕机造成消息丢失,也可能是由于non-durable subscriber的性质所决定

 

 



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


ITeye推荐



Twitter下一步攻破方向:搜索和群聊

$
0
0

Twitter 下一步攻破方向:搜索和群聊

9 月 4 日,Twitter 财务官安东尼·诺托(Anthony Noto)透露,Twitter 将优先改进搜索服务,同时还将开发群聊功能。

在花旗全球技术大会上,诺托称,Twitter 新任产品主管丹尼尔·格拉夫(Daniel Graf)把提升搜索功能作为 2015 年工作的首要目标之一。

诺托说:“说起搜索功能,我们拥有一个关于主题 Twitter 消息的信息数据集。搜索的结构层次必须适用于这种分类方法。”他还表示,Twitter 因此需要一种算法,这种算法要展示特定主题内容的深度和广度,并要让内容与用户相关联。

这就与 Twitter 更大的战略目标联系在一起——Twitter 希望更好地组织自己的内容,帮助用户从信息噪音中分离出有趣、及时的 Twitter 信息。Twitter 已经着手改进时间轴功能。时间轴可以展示陌生用户发布的信息,这是它最显著的特点,也是颇具争议的特点。

Twitter 时间轴以相反的时间顺序展示信息,自从八年前上线以来,这项功能就没有变化。一些早期 Twitter 用户甚至将时间轴奉为核心 Twitter 体验。

但诺托表示:“对于用户,它(时间轴)并不是最相关的体验。”举例来说,如果用户没有打开 Twitter 应用,一些及时的 Twitter 信息可能被其他信息淹没,埋藏在时间轴底部。

“如果要更好地组织 Twitter 内容,Twitter 就要把信息及时放到用户眼前。”诺托补充道。

上周六,Twitter 首席执行官迪克·科斯特罗(Dick Costolo)尝试在 Twitter 上解释时间轴信息推送服务的优点。针对用户抱怨的“不速之客类信息”,科斯特罗称用户两次刷新时间轴,时间轴就会展示其他用户喜爱的信息,Twitter 无法连续两次展示新的内容。

“否则,用户的第二次内容请求就会返回空值。我认为,满足用户的请求是一个值得我们努力的目标。”科斯特罗这样解释。

诺托表示,改进将是渐进式的。“我们将有条不紊地加以改进。我们会测试,确保自己了解各种可能性。我们不会妄想用户在某一天早晨醒来,突然发现自己时间轴完全以一种算法推送信息。”他说道。

诺托还暗示,Twitter 可能正在开发群聊功能。Twitter 私信功能历来居于次要地位。公开是 Twitter 服务的本质特性,Twitter 内部一直争论私信功能所扮演的角色。过去一年,随着消息应用的兴起,Twitter 已经让私信功能扮演一个更加突出的角色。诺托认为私信功能可能会更加社交化。

现在,Twitter 用户只能每次向一个帐号发送一条私信。诺托表示:“假如我用 Twitter 发布了一条球赛信息,同学可能会回复这条信息。但是,我不想当着老板和其他用户的面与同学讨论球赛。那么我就会选择私密的交流方式,我可能会选择私信功能。目前,私信功能只支持一对一会话,还不支持一对多会话。因此,这就是一个围绕分享或表达的创新样本。”

本文链接

WordPress主题后门严重威胁网站安全

$
0
0

作者:田民 赤莺

 

WordPress是国内站长非常喜欢采用的一款建站应用软件,由于其具有非常丰富的模版和插件,具有良好的可扩展性。特别对于博客类网站,WordPress几乎成为建站首选。

在阿里云安全团队的日常运营中,我们发现,WordPress一直是黑客攻击的主要目标。下图是阿里云云盾安全运营团队对第三方应用遭受攻击的统计(Source:第27期阿里云云盾安全运营报告,http://security.aliyun.com/doc/view/13762631.html):

  1

图1 WordPress是攻击者最主要的攻击目标之一

 

从上图来看,WordPress是攻击者最主要的攻击目标应用之一。这很大程度上在于WordPress应用在建站中的大量采用,以及不断暴露出来的安全隐患。

WordPress存在安全隐患的原因主要在于两个方面:一方面由于应用功能的丰富,程序越来越复杂,WordPress屡暴漏洞在所难免;另一方面提供WordPress主题和插件下载的网站五花八门、鱼龙混杂。很多黑客恰恰利用了这个现状,通过各种提供WordPress建站资源下载的网站散布带有恶意脚本的插件。事实上,上述两方面原因中后者的安全隐患更大。对于一个渴望找到建站资源的网站站长,在下载插件程序时,往往疏于防护,对提供下载资源的来源网站不加选择。

云盾安全技术团队在不久前截获了一个带有后门的WordPress程序。这个后门程序存在于WordPress一个叫做“KnowHow”的主题插件中。在这个插件里,我们发现如下代码:

  2

图2: WordPress主题程序中的后门

 

红圈内的代码,很显然,就是后门。攻击者利用这个后门可以进一步获得网站的控制权。

经过云盾安全技术人员进一步调查,KnowHow是一款非常流行的WordPress主题。KowHow主题是收费的,价格为48美金。为了明确问题的根源,技术人员决定从确定被植入后门的程序来源入手。

我们联系了用户。和用户沟通后证实,该用户并非购买的正版主题,而是从国内某偏僻站点下载。与此同时,我们从官方渠道下载了一份同版本的主题程序,两者进行了比较。结果证实官方版本中并没有相对应的后门代码。因此,用户下载的程序显然是被人恶意修改后发布的版本。

我们并没有到此止步。云盾安全技术人员接下来经过搜索和对比, 发现大量国内此主题的下载文件中被人嵌入了类似的后门。

在明确了后门问题的原因后,云盾安全运营团队立刻对阿里云全网用户进行了扫描,并在第一时间通知了存在类似安全隐患的阿里云用户。

 

最后,对于WordPress KnowHow主题后门,阿里云云盾安全运营团队提出如下建议:

第一,请已下载并安装Knowhow主题的站长尽快检查自己的网站服务器,找到 /wp-content/themes/knowhow/functions.php文件,对比上文检查是否存在恶意代码。后门特征一般含有eval字符;

第二,从官方或具有良好信誉的网站下载插件,不要随意下载/添加不明站点的代码;

第三,请购买正版软件。

Viewing all 15843 articles
Browse latest View live


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