<?xml version="1.0" encoding="utf-8"?><?xml-stylesheet href='http://feed.feedsky.com/styles/feedsky2.xsl' type='text/xsl' ?><!--这是一个由Feedsy提供技术支持的Feed，为了提高读者阅读的体验，以及满足用户美化自己Feed的需要，我们设计了多种精美的Feed模板，提供给大家选择，所有最终呈现出来的样式，皆由用户自愿选择使用，未经许可，任何团体和个人，请不要擅自修改样式或者盗用，这是对于用户选择权的尊重。--><rss xmlns:atom="http://www.w3.org/2005/Atom" xmlns:fs="http://www.feedsky.com/namespace/feed" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:dc="http://purl.org/dc/elements/1.1/" version="2.0"><channel><atom:link href="http://feed.feedsky.com/javaBloger" type="application/rss+xml" rel="self"></atom:link><fs:self_link href="http://feed.feedsky.com/javaBloger" type="application/rss+xml"></fs:self_link><lastBuildDate>Tue, 06 Dec 2011 04:31:48 GMT</lastBuildDate><title>H.E. 's Blog</title><description>javaBloger</description><image><url>http://www.feedsky.com/feed/javaBloger/sc/gif</url><title>H.E. 's Blog</title><link>http://www.javabloger.com</link></image><link>http://www.javabloger.com</link><sy:updatePeriod>hourly</sy:updatePeriod><sy:updateFrequency>1</sy:updateFrequency><language>en</language><pubDate>Tue, 06 Dec 2011 04:31:48 GMT</pubDate><item><title>大型互联网站解决海量数据的常见策略</title><link>http://item.feedsky.com/~feedsky/javaBloger/~8046889/584563588/6154110/1/item.html</link><content:encoded>&lt;p&gt;&amp;nbsp; &amp;nbsp;大型互联网站的数据存储与传统存储环境相比不仅是一个服务器、一个数据库那么简单，而是由网络设备、存储设备、应用服务器、公用访问接口、应用程序 等多个部分组成的复杂系统。分为 业务数据层、计算层、数据仓储、数据备份，通过应用服务器软件提供数据存储服务，并且通过监控工具对存储单元监控。&lt;/p&gt;
&lt;p&gt;&amp;nbsp; &amp;nbsp; 随着系统中用户数据量的线性增长，数据量将会越来越多。在这样一个数据不断膨胀的环境中，数据已经如洪水般汹涌泛滥。数据查找和调用困难，在海量数据中一些用户提交的请求往往要等到第二天才能得知结果，直接影响到了用户满意度的提升和新业务的布局。在技术上而言，这一特点使得RDBMS在大型应用场景被大幅限制，唯一的可选方案是Scale Out,通过增加多个逻辑单元的资源,并使它们如同一个集中的资源那样提供服务来实现系统的扩展性。&lt;/p&gt;
&lt;p&gt;	&amp;nbsp; &amp;nbsp;系统中的数据就好比我们家里的物品，衣服放在衣柜里，碟子放在碗橱里，数据库、存储系统就好比你的衣柜和碗橱是一个存放的容器，衣服和碟子就好比不同的数据，将不同类型的东西放入合适的存储空间里面，这样系统的效率和利用率将会更高，所以我们将会做出如下设计，如图所示：&lt;br /&gt;
	&lt;a href=&quot;http://ww3.sinaimg.cn/large/6579bcb1gw1dnrt44y0esj.jpg&quot;&gt;&lt;img alt=&quot;&quot; height=&quot;351&quot; src=&quot;http://ww3.sinaimg.cn/mw600/6579bcb1gw1dnrt44y0esj.jpg&quot; width=&quot;600&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://ww3.sinaimg.cn/large/6579bcb1gw1dnrt44y0esj.jpg&quot; target=&quot;_blank&quot;&gt;查看大图请点击这里&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;对于大型系统存储单元的结构模型我们分为6个部分组成，清单如下：&lt;/p&gt;
&lt;p&gt;1.&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space:pre&quot;&gt; &lt;/span&gt;业务数据层&lt;br /&gt;
	各类业务所产生的各种文件类型的数据，其中包含 用户信息、用户操作记录、实时业务数据、手机客户端升级应用程序、图片，等。&lt;/p&gt;
&lt;p&gt;2.&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space:pre&quot;&gt; &lt;/span&gt;计算层&lt;br /&gt;
	针对不同的数据格式、不同类型的数据文件，通过不同的工具、计算方法进行操作，针对大量的数据计算采用一些分布式、并行计算的算法，例如：MapReduce，BSP。并且对一部分的数据进行缓存，缓解对存储应用服务器的压力。&lt;/p&gt;
&lt;p&gt;3.&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space:pre&quot;&gt; &lt;/span&gt;数据存储层&lt;br /&gt;
	对于海量数据的查询与存储，特别是针对用户行为日志操作，需要使用到一些列式数据库服务器，对于处理业务和一些业务规则的数据依然存放在关系型数据库中，将采用MySQL来存储。&lt;/p&gt;
&lt;p&gt;4.&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space:pre&quot;&gt; &lt;/span&gt;数据仓储&lt;br /&gt;
	数据存储主要是针对于用户行为日志和用户行为分析，也是系统中数据量产生较大的一个环节，将会采用Apache Hive、Pig、Mathout 对数据仓储进行构建。&lt;/p&gt;
&lt;p&gt;5.&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space:pre&quot;&gt; &lt;/span&gt;数据备份&lt;br /&gt;
	分为在线数据备份和离线数据备份，数据备份环节需要经过运维经验的积累，根据业务和用户访问量进行定制合理的备份规律。&lt;/p&gt;
&lt;p&gt;6.&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space:pre&quot;&gt; &lt;/span&gt;硬件&lt;br /&gt;
	硬件环境是存储单元最基础的部分，分为磁盘、内存、网络设备存储，将不同的业务数据、文件存储在不同的硬件设备上。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;技术实现&lt;/strong&gt;&lt;br /&gt;
	对于系统不同的业务数据和应用服务器的架构需要采用不同的读写方式，以及数据存储类型存放，数据仓储构建，数据冷热分离、数据索引多个部分组成。例如：业务应用程序、日志采集代理、用户空间文件系统（Filesystem in Userspace）。Data Access Proxy Layer(DDAL/Cache Handler)、OLAP、日志服务器、Oracle(暂定)、MySQL、Redis、Hive、HDFS、Moosefs。&lt;/p&gt;
&lt;p&gt;如图所示：&lt;br /&gt;
	&lt;a href=&quot;http://ww4.sinaimg.cn/large/6579bcb1gw1dnrtomacd5j.jpg&quot; target=&quot;_blank&quot;&gt;&lt;img alt=&quot;&quot; height=&quot;808&quot; src=&quot;http://ww4.sinaimg.cn/mw600/6579bcb1gw1dnrtomacd5j.jpg&quot; width=&quot;600&quot; /&gt;&lt;br /&gt;
	&lt;/a&gt;&lt;a href=&quot;http://ww4.sinaimg.cn/large/6579bcb1gw1dnrtomacd5j.jpg&quot; target=&quot;_blank&quot;&gt;查看大图请点击这里&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;针对以上设计架构，描述清单如下：&lt;/p&gt;
&lt;p&gt;1.&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space:pre&quot;&gt; &lt;/span&gt;Data Access Proxy Layer&lt;br /&gt;
	统称数据访问代理层(简称 DAPL)，封装了DDAL和Cache Handler层，抽象的对编写的应用程序进行了划分，便于扩展和维护，例如：需要对HDFS或者图形数据库操作，上层不需要知道HDFS具体操作，只需要关注提供的接口。DAPL封装了很多访问各种数据源的读写策略。因此，可以保证对不同数据库、数据源操作的事务完整性。&lt;/p&gt;
&lt;p&gt;2.&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space:pre&quot;&gt; &lt;/span&gt;DDAL&lt;br /&gt;
	统称分布式数据访问层(简称 DDAL)主要针对关系数据库的读写分离操作，需要做到读写分离，首先需要对传入的SQL语句进行解析，并且采用Round-Robin算法负载分载对数据大量读取的操作，在代码实现中将使用MySQL-JDBC中的参数配置实现对MySQL-Slave的读取压力分载。&lt;/p&gt;
&lt;p&gt;3.&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space:pre&quot;&gt; &lt;/span&gt;Cache Handler&lt;br /&gt;
	与DDAL的相似，具体区别在于自己实现了Round-Robin算法负载分载对数据大量读取的操作，并且能在Redis Master当机的状态下重新指派新的Master进行写的操作。&lt;/p&gt;
&lt;p&gt;4.&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space:pre&quot;&gt; &lt;/span&gt;Redis一主多从&lt;br /&gt;
	对缓存数据进行读写分离，减少单台机器的I/O瓶颈，值得一提的是Cache不是可靠的存储，所以在设计时，需要容许Cache的数据丢失，因此，Cache的数据全部失效时，会从数据库里重新装载。&lt;/p&gt;
&lt;p&gt;5.&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space:pre&quot;&gt; &lt;/span&gt;MySQL双主多从&lt;br /&gt;
	这种方式是MySQL架构设计中最折中的方案，对数据的访问压力分载和数据的可靠性都有了相应的保障。前端2台Master MySQL相互进行数据备份，后端大量的Slave MySQL对Master写入的数据进行同步，所以每台机器节点上的MySQL数据库中的数据都是一致的，并且DDAL应用程序将数据轮询写入Master MySQL数据库中。&lt;/p&gt;
&lt;p&gt;6.&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space:pre&quot;&gt; &lt;/span&gt;数据库读写分离&lt;br /&gt;
	主要采用mysql的策略，学习MySQL-Prxoy的策略，自己开发对MySQL书籍节点进行读写分离的方法，MySQL驱动支持读写分离的数据完整性，当数据量超大规模的时候将会采用Sharding策略。&lt;/p&gt;
&lt;p&gt;7.&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space:pre&quot;&gt; &lt;/span&gt;缓存读写分离&lt;br /&gt;
	缓存Redis的策略，采用自己开发的应用程序需要实现Round Robin算法，对Redis Master和Slave缓存集群进行读写分离操作。&lt;/p&gt;
&lt;p&gt;8.&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space:pre&quot;&gt; &lt;/span&gt;ETL Tools&lt;br /&gt;
	采用Apache Hadoop项目中的Pig对海量的行为数据进行清洗，Pig可以针对有规律的半结构化数据执行类似SQL的脚本，并且可以将计算压力分载到每台服务器上进行分布式、并行处理。&lt;/p&gt;
&lt;p&gt;9.&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space:pre&quot;&gt; &lt;/span&gt;Hive集群&lt;br /&gt;
	针对数据仓库的建设由Apache Hive进行构建，是一个建立在Hadoop上的数据仓库框架，它提供了一个方便的数据集成方法和类似SQL的Hive QL查询语言，实现了Map/Reduce算法支持在Hadoop框架上进行大规模数据分析。&lt;/p&gt;
&lt;p&gt;10.&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space:pre&quot;&gt; &lt;/span&gt;HDFS分布式文件系统&lt;br /&gt;
	Hive中的数据全部存储在Hadoop分布式文件系统中，所有被存储的数据都会有数据的存储副本，这样对数据的可靠性有了保障。&lt;/p&gt;
&lt;p&gt;11.&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space:pre&quot;&gt; &lt;/span&gt;Moosefs分布式文件系统&lt;br /&gt;
	与上面提到的HDFS一个文件系统是有区别的，Moosefs不需要任何客户端程序对分布式文件进行操作的服务器，可以直接与任何运行环境进行对接，而且服务端也有副本复制的功能。&lt;/p&gt;
&lt;p&gt;12.&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space:pre&quot;&gt; &lt;/span&gt;冷热数据分离&lt;br /&gt;
	将系统中产生的进行归类存放，将用户更多关心、热门话题等内容 抽象为&amp;ldquo;最近几天&amp;rdquo;的&amp;ldquo;热数据&amp;rdquo;，而越早的数据我们在设计中抽象的分为&amp;ldquo;冷数据&amp;rdquo;。由此可见，&amp;ldquo;热节点&amp;rdquo;存放最新的、被访问频率较高的数据。对于这部分数据，我们希望能给用户提供尽可能快的查询速度，因此无论在硬件还是软件的选择上都会有了明显的区分，例如：最近常访问频率高的数据将会存储在系统缓存中，需要经常性被的业务数据将会存储在MySQL或者Oracle数据库系统中，&lt;/p&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;&lt;strong&gt;相关文章&lt;/strong&gt;&lt;br /&gt;
	&lt;a href=&quot;http://www.javabloger.com/article/high-concurrent-common-coping-strategies.html?source=rss&quot;&gt;大型互联网站解决高并发的常见策略&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;&amp;#8211;end&amp;#8211;&lt;/div&gt;&lt;img src=&quot;http://www1.feedsky.com/t1/584563588/javaBloger/feedsky/s.gif?r=http://item.feedsky.com/~feedsky/javaBloger/~8046889/584563588/6154110/1/item.html&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</content:encoded><wfw:commentRss>http://www.javabloger.com/article/big-data-architecture.html/feed</wfw:commentRss><slash:comments>0</slash:comments><description>&amp;#160; &amp;#160;大型互联网站的数据存储与传统存储环境相比不仅是一个服务器、一个数据库那么简单，而是由网络设备、存储设备、应用服务器、公用访问接口、应用程序 等多个部分组成的复杂系统。分为 业务数据层、计算层、数据仓储、数据备份，通过应用服务器软件提供数据存储服务，并且通过监控工具对存储单元监控。
&amp;#160; &amp;#160; 随着系统中用户数据量的线性增长，数据量将会越来越多。在这样一个数据不断膨胀的环境中，数据已经如洪水般汹涌泛滥。数据查找和调用困难，在海量数据中一些用户提交的请求往往要等到第二天才能得知结果，直接影响到了用户满意度的提升和新业务的布局。在技术上而言，这一特点使得RDBMS在大型应用场景被大幅限制，唯一的可选方案是Scale Out,通过增加多个逻辑单元的资源,并使它们如同一个集中的资源那样提供服务来实现系统的扩展性。
	&amp;#160; &amp;#160;系统中的数据就好比我们家里的物品，衣服放在衣柜里，碟子放在碗橱里，数据库、存储系统就好比你的衣柜和碗橱是一个存放的容器，衣服和碟子就好比不同的数据，将不同类型的东西放入合适的存储空间里面，这样系统的效率和利用率将会更高，所以我们将会做出如下设计，如图所示：
	
查看大图请点击这里
对于大型系统存储单元的结构模型我们分为6个部分组成，清单如下：
1. 业务数据层
	各类业务所产生的各种文件类型的数据，其中包含 用户信息、用户操作记录、实时业务数据、手机客户端升级应用程序、图片，等。
2. 计算层
	针对不同的数据格式、不同类型的数据文件，通过不同的工具、计算方法进行操作，针对大量的数据计算采用一些分布式、并行计算的算法，例如：MapReduce，BSP。并且对一部分的数据进行缓存，缓解对存储应用服务器的压力。
3. 数据存储层
	对于海量数据的查询与存储，特别是针对用户行为日志操作，需要使用到一些列式数据库服务器，对于处理业务和一些业务规则的数据依然存放在关系型数据库中，将采用MySQL来存储。
4. 数据仓储
	数据存储主要是针对于用户行为日志和用户行为分析，也是系统中数据量产生较大的一个环节，将会采用Apache Hive、Pig、Mathout 对数据仓储进行构建。
5. 数据备份
	分为在线数据备份和离线数据备份，数据备份环节需要经过运维经验的积累，根据业务和用户访问量进行定制合理的备份规律。
6. 硬件
	硬件环境是存储单元最基础的部分，分为磁盘、内存、网络设备存储，将不同的业务数据、文件存储在不同的硬件设备上。
技术实现
	对于系统不同的业务数据和应用服务器的架构需要采用不同的读写方式，以及数据存储类型存放，数据仓储构建，数据冷热分离、数据索引多个部分组成。例如：业务应用程序、日志采集代理、用户空间文件系统（Filesystem in Userspace）。Data Access Proxy Layer(DDAL/Cache Handler)、OLAP、日志服务器、Oracle(暂定)、MySQL、Redis、Hive、HDFS、Moosefs。
如图所示：
	
	查看大图请点击这里
针对以上设计架构，描述清单如下：
1. Data Access Proxy Layer
	统称数据访问代理层(简称 DAPL)，封装了DDAL和Cache Handler层，抽象的对编写的应用程序进行了划分，便于扩展和维护，例如：需要对HDFS或者图形数据库操作，上层不需要知道HDFS具体操作，只需要关注提供的接口。DAPL封装了很多访问各种数据源的读写策略。因此，可以保证对不同数据库、数据源操作的事务完整性。
2. DDAL
	统称分布式数据访问层(简称 DDAL)主要针对关系数据库的读写分离操作，需要做到读写分离，首先需要对传入的SQL语句进行解析，并且采用Round-Robin算法负载分载对数据大量读取的操作，在代码实现中将使用MySQL-JDBC中的参数配置实现对MySQL-Slave的读取压力分载。
3. Cache Handler
	与DDAL的相似，具体区别在于自己实现了Round-Robin算法负载分载对数据大量读取的操作，并且能在Redis Master当机的状态下重新指派新的Master进行写的操作。
4. Redis一主多从
	对缓存数据进行读写分离，减少单台机器的I/O瓶颈，值得一提的是Cache不是可靠的存储，所以在设计时，需要容许Cache的数据丢失，因此，Cache的数据全部失效时，会从数据库里重新装载。
5. MySQL双主多从
	这种方式是MySQL架构设计中最折中的方案，对数据的访问压力分载和数据的可靠性都有了相应的保障。前端2台Master MySQL相互进行数据备份，后端大量的Slave MySQL对Master写入的数据进行同步，所以每台机器节点上的MySQL数据库中的数据都是一致的，并且DDAL应用程序将数据轮询写入Master MySQL数据库中。
6. 数据库读写分离
	主要采用mysql的策略，学习MySQL-Prxoy的策略，自己开发对MySQL书籍节点进行读写分离的方法，MySQL驱动支持读写分离的数据完整性，当数据量超大规模的时候将会采用Sharding策略。
7. 缓存读写分离
	缓存Redis的策略，采用自己开发的应用程序需要实现Round Robin算法，对Redis Master和Slave缓存集群进行读写分离操作。
8. ETL Tools
	采用Apache Hadoop项目中的Pig对海量的行为数据进行清洗，Pig可以针对有规律的半结构化数据执行类似SQL的脚本，并且可以将计算压力分载到每台服务器上进行分布式、并行处理。
9. Hive集群
	针对数据仓库的建设由Apache Hive进行构建，是一个建立在Hadoop上的数据仓库框架，它提供了一个方便的数据集成方法和类似SQL的Hive QL查询语言，实现了Map/Reduce算法支持在Hadoop框架上进行大规模数据分析。
10. HDFS分布式文件系统
	Hive中的数据全部存储在Hadoop分布式文件系统中，所有被存储的数据都会有数据的存储副本，这样对数据的可靠性有了保障。
11. Moosefs分布式文件系统
	与上面提到的HDFS一个文件系统是有区别的，Moosefs不需要任何客户端程序对分布式文件进行操作的服务器，可以直接与任何运行环境进行对接，而且服务端也有副本复制的功能。
12. 冷热数据分离
	将系统中产生的进行归类存放，将用户更多关心、热门话题等内容 抽象为&amp;#8220;最近几天&amp;#8221;的&amp;#8220;热数据&amp;#8221;，而越早的数据我们在设计中抽象的分为&amp;#8220;冷数据&amp;#8221;。由此可见，&amp;#8220;热节点&amp;#8221;存放最新的、被访问频率较高的数据。对于这部分数据，我们希望能给用户提供尽可能快的查询速度，因此无论在硬件还是软件的选择上都会有了明显的区分，例如：最近常访问频率高的数据将会存储在系统缓存中，需要经常性被的业务数据将会存储在MySQL或者Oracle数据库系统中，
&amp;#160;
相关文章
	大型互联网站解决高并发的常见策略
&amp;#160;
&amp;#8211;end&amp;#8211;&lt;img src=&quot;http://www1.feedsky.com/t1/584563588/javaBloger/feedsky/s.gif?r=http://item.feedsky.com/~feedsky/javaBloger/~8046889/584563588/6154110/1/item.html&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</description><category>架构设计</category><category>JMS</category><category>J2EE服务器</category><category>Hive</category><category>云计算</category><category>Hadoop</category><category>存储</category><category>数据库</category><category>分布式</category><category>海量数据</category><pubDate>Tue, 06 Dec 2011 12:31:48 +0800</pubDate><author>H.E.</author><comments>http://www.javabloger.com/article/big-data-architecture.html#comments</comments><guid isPermaLink="false">http://www.javabloger.com/?p=1637</guid><dc:creator>H.E.</dc:creator><fs:srclink>http://www.javabloger.com/article/big-data-architecture.html?source=rss</fs:srclink><fs:srcfeed>http://www.javabloger.com/index.php/feed/</fs:srcfeed><fs:itemid>feedsky/javaBloger/~8046889/584563588/6154110</fs:itemid></item><item><title>大型互联网站解决高并发的常见策略</title><link>http://item.feedsky.com/~feedsky/javaBloger/~8046889/584467532/6154110/1/item.html</link><content:encoded>&lt;p&gt;一个运营的系统在正式上线后将会遇到各种层级的高并发请求，因此我们必须对此做出相应的策略和技术解决方案，首先我们需要认清系统的高并发由3个层面导致：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1.&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre; &quot;&gt; &lt;/span&gt;传输层&lt;/strong&gt;&lt;br /&gt;
	大量用户对系统请求后，将会造成网络带宽和Web服务器的I/O瓶颈。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2.&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space:pre&quot;&gt; &lt;/span&gt;计算层&lt;/strong&gt;&lt;br /&gt;
	接收大量用户请求进行计算，将会造成业务服务器和业务支撑服务器的瓶颈。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3.&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space:pre&quot;&gt; &lt;/span&gt;存储层&lt;/strong&gt;&lt;br /&gt;
	传输层和计算层将会产生大量的数据，数据量暴增，将会导致数据库和储存上的瓶颈。&lt;/p&gt;
&lt;p&gt;针对以上将会造成的系统高并发瓶颈，我们需要采用不同的技术手段解决。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;从总体上来看&lt;/strong&gt;&lt;br /&gt;
	1.首先需要解决网络带宽和Web请求的高并发，需要合理的加大服务器和带宽的投入，并且需要充分的利用系统中软件、硬件的缓存机制，将能缓存的内容都进行缓存存储，减少计算层和存储层的压力。&lt;/p&gt;
&lt;p&gt;2.其次需要对业务服务器和业务支撑服务器进行合理的分层，并且采用并行计算和分布式算法对大量计算进行处理，并且在开发的过程中需要采用Java SDK中并发包(Concurrency)进行编码实现。&lt;/p&gt;
&lt;p&gt;3.存储层需要采用分布式文件服务器和列式的存储服务器进行构建，支撑海量数据的存放和读取，并且还要对关系型数据进行深层次的配置参数优化。&lt;/p&gt;
&lt;p&gt;4.我们还需要清楚的认识到，将来根据系统运行的状态以及平台中不同的业务场景循序渐进的进行调整和优化。&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp; &amp;nbsp;对于大型系统来说，采用的技术是涉及面非常广，从硬件到软件、编程语言、数据库、WebServer、防火墙等各个领域都有了很高的要求。在面对大量用户访问、高并发请求方面，基本的解决方案集中在这样几个环节：将会使用高性能的服务器、高性能的数据库、高效率的编程语言、还有高性能的Web容器。&lt;/div&gt;
&lt;div&gt;&amp;nbsp; &amp;nbsp;但是除了这几个方面，还没法根本解决面临的高负载和高并发问题，所以需要将计算和负载的压力分载到每个计算机上，使用不同的服务器集群机组进行分布式和并行计算，面对所产生的压力，下面这张图清晰的描述了，我们对系统中不同的计算瓶颈采用的不同解决手段，如图所示：&lt;/div&gt;
&lt;div&gt;&lt;a href=&quot;http://ww3.sinaimg.cn/large/6579bcb1gw1dnrquf431tj.jpg&quot;&gt;&lt;img alt=&quot;&quot; height=&quot;354&quot; src=&quot;http://ww3.sinaimg.cn/mw600/6579bcb1gw1dnrquf431tj.jpg&quot; width=&quot;600&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;&lt;a href=&quot;http://ww3.sinaimg.cn/large/6579bcb1gw1dnrquf431tj.jpg&quot;&gt;&lt;br /&gt;
		查看大图请点击这里&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;以下描述是针对不同层面产生的计算压力所采用的计算策略，清单如下：&lt;/div&gt;
&lt;div&gt;&lt;strong&gt;传输层&lt;/strong&gt;&lt;/div&gt;
&lt;div&gt;1.&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space:pre&quot;&gt; &lt;/span&gt;CDN&lt;/div&gt;
&lt;div&gt;&amp;nbsp; &amp;nbsp; 网络链路出口进行压力分载，通过CDN让用户访问最近的数据缓存。&lt;/div&gt;
&lt;div&gt;2.&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space:pre&quot;&gt; &lt;/span&gt;智能双路&lt;/div&gt;
&lt;div&gt;&amp;nbsp; &amp;nbsp; 针对电信、网通 不同的访问用户访问请求，对应用户访问请求进行服务器带宽的智能切换。&lt;/div&gt;
&lt;div&gt;3.&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space:pre&quot;&gt; &lt;/span&gt;LVS&lt;/div&gt;
&lt;div&gt;&amp;nbsp; &amp;nbsp; 对用户的请求进行压力分载，并且实现多种负载均衡的策略，也可以选择使用HA-Proxy实现。&lt;/div&gt;
&lt;div&gt;4.&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space:pre&quot;&gt; &lt;/span&gt;HA-Proxy&lt;/div&gt;
&lt;div&gt;&amp;nbsp; &amp;nbsp;针对Web服务器进行方向代理，通过HA-Proxy将用户的请求分发到不同的Web服务器上。&lt;/div&gt;
&lt;div&gt;5.&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space:pre&quot;&gt; &lt;/span&gt;Long-Polling&lt;/div&gt;
&lt;div&gt;&amp;nbsp; &amp;nbsp; 在Web服务器上采用的一种策略，专门针对某个用户需要不断频繁的轮询访问。&lt;/div&gt;
&lt;div&gt;6.&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space:pre&quot;&gt; &lt;/span&gt;Session2Cache&lt;/div&gt;
&lt;div&gt;&amp;nbsp; &amp;nbsp; 将用户的会话进行集中处理，存放在中央式的缓存服务器当中，减少服务器之间的会话通信&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;&lt;strong&gt;计算层&lt;/strong&gt;&lt;/div&gt;
&lt;div&gt;1.&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space:pre&quot;&gt; &lt;/span&gt;MapReduce&lt;/div&gt;
&lt;div&gt;&amp;nbsp; &amp;nbsp;采用最经典的分布式算法对海量数据进行处理，将计算进行分载。&lt;/div&gt;
&lt;div&gt;2.&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space:pre&quot;&gt; &lt;/span&gt;BSP&lt;/div&gt;
&lt;div&gt;&amp;nbsp; &amp;nbsp; BSP(Bulk Synchronous Parallel-大型同步模型)算法是基于MPI算法的基础进行演化，运用在系统中并行计算的部分。&lt;/div&gt;
&lt;div&gt;3.&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space:pre&quot;&gt; &lt;/span&gt;Result Cache&lt;/div&gt;
&lt;div&gt;&amp;nbsp; &amp;nbsp; 将计算的一部分结果进行缓存，缓解对存储层读取的请求。&lt;/div&gt;
&lt;div&gt;4.&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space:pre&quot;&gt; &lt;/span&gt;Scatter/Gather&lt;/div&gt;
&lt;div&gt;&amp;nbsp; &amp;nbsp; 中间通过一个服务器进行中转，将大量的请求分发给内部的服务器进行计算，类似前端的web反向代理。&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;&lt;strong&gt;存储层&lt;/strong&gt;&lt;/div&gt;
&lt;div&gt;1.&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space:pre&quot;&gt; &lt;/span&gt;读写分离&lt;/div&gt;
&lt;div&gt;&amp;nbsp; &amp;nbsp; 由于系统的读大于写的频率，数据库架构采用了1主/多从，双主多从的策略，所以我们将会将读和写进行分离，并且将大量的读请求分散给多台不同的(Slave)服务器。&lt;/div&gt;
&lt;div&gt;2.&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space:pre&quot;&gt; &lt;/span&gt;分区策略&lt;/div&gt;
&lt;div&gt;&amp;nbsp; &amp;nbsp; 系统采用不同的时间段作为分区的主要策略，提高对数据的读写性能。&lt;/div&gt;
&lt;div&gt;3.&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space:pre&quot;&gt; &lt;/span&gt;Sharding&lt;/div&gt;
&lt;div&gt;&amp;nbsp; &amp;nbsp; 一台数据库将很快无法满足大量并发，需要使用库表散列，将数据库中的数据进行分散存储。&lt;/div&gt;
&lt;div&gt;4.&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space:pre&quot;&gt; &lt;/span&gt;Column-Based&lt;/div&gt;
&lt;div&gt;&amp;nbsp; &amp;nbsp;使用在海量数据中的查询功能，采用列模式的存储方式将可以有效的提高系统查询效率。&lt;/div&gt;
&lt;/p&gt;&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;&amp;#8211;end&amp;#8211;&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;&lt;img src=&quot;http://www1.feedsky.com/t1/584467532/javaBloger/feedsky/s.gif?r=http://item.feedsky.com/~feedsky/javaBloger/~8046889/584467532/6154110/1/item.html&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</content:encoded><wfw:commentRss>http://www.javabloger.com/article/high-concurrent-common-coping-strategies.html/feed</wfw:commentRss><slash:comments>0</slash:comments><description>一个运营的系统在正式上线后将会遇到各种层级的高并发请求，因此我们必须对此做出相应的策略和技术解决方案，首先我们需要认清系统的高并发由3个层面导致：
1. 传输层
	大量用户对系统请求后，将会造成网络带宽和Web服务器的I/O瓶颈。
2. 计算层
	接收大量用户请求进行计算，将会造成业务服务器和业务支撑服务器的瓶颈。
3. 存储层
	传输层和计算层将会产生大量的数据，数据量暴增，将会导致数据库和储存上的瓶颈。
针对以上将会造成的系统高并发瓶颈，我们需要采用不同的技术手段解决。
从总体上来看
	1.首先需要解决网络带宽和Web请求的高并发，需要合理的加大服务器和带宽的投入，并且需要充分的利用系统中软件、硬件的缓存机制，将能缓存的内容都进行缓存存储，减少计算层和存储层的压力。
2.其次需要对业务服务器和业务支撑服务器进行合理的分层，并且采用并行计算和分布式算法对大量计算进行处理，并且在开发的过程中需要采用Java SDK中并发包(Concurrency)进行编码实现。
3.存储层需要采用分布式文件服务器和列式的存储服务器进行构建，支撑海量数据的存放和读取，并且还要对关系型数据进行深层次的配置参数优化。
4.我们还需要清楚的认识到，将来根据系统运行的状态以及平台中不同的业务场景循序渐进的进行调整和优化。

&amp;#160; &amp;#160;对于大型系统来说，采用的技术是涉及面非常广，从硬件到软件、编程语言、数据库、WebServer、防火墙等各个领域都有了很高的要求。在面对大量用户访问、高并发请求方面，基本的解决方案集中在这样几个环节：将会使用高性能的服务器、高性能的数据库、高效率的编程语言、还有高性能的Web容器。
&amp;#160; &amp;#160;但是除了这几个方面，还没法根本解决面临的高负载和高并发问题，所以需要将计算和负载的压力分载到每个计算机上，使用不同的服务器集群机组进行分布式和并行计算，面对所产生的压力，下面这张图清晰的描述了，我们对系统中不同的计算瓶颈采用的不同解决手段，如图所示：


		查看大图请点击这里

&amp;#160;
以下描述是针对不同层面产生的计算压力所采用的计算策略，清单如下：
传输层
1. CDN
&amp;#160; &amp;#160; 网络链路出口进行压力分载，通过CDN让用户访问最近的数据缓存。
2. 智能双路
&amp;#160; &amp;#160; 针对电信、网通 不同的访问用户访问请求，对应用户访问请求进行服务器带宽的智能切换。
3. LVS
&amp;#160; &amp;#160; 对用户的请求进行压力分载，并且实现多种负载均衡的策略，也可以选择使用HA-Proxy实现。
4. HA-Proxy
&amp;#160; &amp;#160;针对Web服务器进行方向代理，通过HA-Proxy将用户的请求分发到不同的Web服务器上。
5. Long-Polling
&amp;#160; &amp;#160; 在Web服务器上采用的一种策略，专门针对某个用户需要不断频繁的轮询访问。
6. Session2Cache
&amp;#160; &amp;#160; 将用户的会话进行集中处理，存放在中央式的缓存服务器当中，减少服务器之间的会话通信
&amp;#160;
计算层
1. MapReduce
&amp;#160; &amp;#160;采用最经典的分布式算法对海量数据进行处理，将计算进行分载。
2. BSP
&amp;#160; &amp;#160; BSP(Bulk Synchronous Parallel-大型同步模型)算法是基于MPI算法的基础进行演化，运用在系统中并行计算的部分。
3. Result Cache
&amp;#160; &amp;#160; 将计算的一部分结果进行缓存，缓解对存储层读取的请求。
4. Scatter/Gather
&amp;#160; &amp;#160; 中间通过一个服务器进行中转，将大量的请求分发给内部的服务器进行计算，类似前端的web反向代理。
&amp;#160;
存储层
1. 读写分离
&amp;#160; &amp;#160; 由于系统的读大于写的频率，数据库架构采用了1主/多从，双主多从的策略，所以我们将会将读和写进行分离，并且将大量的读请求分散给多台不同的(Slave)服务器。
2. 分区策略
&amp;#160; &amp;#160; 系统采用不同的时间段作为分区的主要策略，提高对数据的读写性能。
3. Sharding
&amp;#160; &amp;#160; 一台数据库将很快无法满足大量并发，需要使用库表散列，将数据库中的数据进行分散存储。
4. Column-Based
&amp;#160; &amp;#160;使用在海量数据中的查询功能，采用列模式的存储方式将可以有效的提高系统查询效率。

&amp;#160;
&amp;#160;
&amp;#8211;end&amp;#8211;
&amp;#160;
&amp;#160;
&amp;#160;&lt;img src=&quot;http://www1.feedsky.com/t1/584467532/javaBloger/feedsky/s.gif?r=http://item.feedsky.com/~feedsky/javaBloger/~8046889/584467532/6154110/1/item.html&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</description><category>架构设计</category><category>云计算</category><category>MapReduce</category><category>web</category><category>NoSQL</category><category>Linux/Unix</category><category>J2ee企业顾问</category><category>Hadoop</category><category>互联网站高并发</category><category>性能</category><category>存储</category><category>分布式</category><pubDate>Mon, 05 Dec 2011 15:31:50 +0800</pubDate><author>H.E.</author><comments>http://www.javabloger.com/article/high-concurrent-common-coping-strategies.html#comments</comments><guid isPermaLink="false">http://www.javabloger.com/?p=1626</guid><dc:creator>H.E.</dc:creator><fs:srclink>http://www.javabloger.com/article/high-concurrent-common-coping-strategies.html?source=rss</fs:srclink><fs:srcfeed>http://www.javabloger.com/index.php/feed/</fs:srcfeed><fs:itemid>feedsky/javaBloger/~8046889/584467532/6154110</fs:itemid></item><item><title>Keep Looking Don’t Settle</title><link>http://item.feedsky.com/~feedsky/javaBloger/~8046889/584467533/6154110/1/item.html</link><content:encoded>&lt;p&gt;&lt;strong&gt;&lt;span style=&quot;color:#(color);&quot;&gt;无论是战争中的最后胜利，还是最终战死在沙场上，都是我生命中的骄傲。因此，我很喜欢乔布斯说的下面这段话，特别是其中这句&amp;ldquo;keep looking don&amp;#39;t settle&amp;rdquo;。&lt;/span&gt; &lt;br /&gt;
	&lt;/strong&gt;&lt;br /&gt;
	&amp;nbsp; &amp;nbsp;Sometimes life hits you in the head with a brick. Don&amp;#39;t lose faith. I&amp;#39;m convinced that the only thing that kept me going was that I loved what I did. You&amp;#39;ve got to find what you love. And that is as true for your work as it is for your lovers. Your work is going to fill a large part of your life, and the only way to be truly satisfied is to do what you believe is great work. And the only way to do great work is to love what you do. If you haven&amp;#39;t found it yet, keep looking. Don&amp;#39;t settle. As with all matters of the heart, you&amp;#39;ll know when you find it. And, like any great relationship, it just gets better and better as the years roll on. So keep looking until you find it. Don&amp;#39;t settle. &lt;/p&gt;
&lt;p&gt;	&amp;nbsp; &amp;nbsp;有些时候, 生活会拿起一块砖头向你的脑袋上猛拍一下。不要失去信心。我很清楚唯一使我一直走下去的，就是我做的事情令我无比钟爱。你需要去找到你所爱的东西。对于工作是如此, 对于你的爱人也是如此。你的工作将会占据生活中很大的一部分。你只有相信自己所做的是伟大的工作, 你才能怡然自得。如果你现在还没有找到, 那么继续找、不要停下来、全心全意的去找, 当你找到的时候你就会知道的。就像任何真诚的关系, 随着岁月的流逝只会越来越紧密。所以继续找，直到你找到它，不要停下来！ &lt;/p&gt;
&lt;p&gt;	&lt;img alt=&quot;&quot; height=&quot;227&quot; src=&quot;http://www.javabloger.com/wp-content/uploads/steve_jobs_stanford_commencement-300x227.jpg&quot; width=&quot;300&quot; /&gt;&lt;/p&gt;
&lt;p style=&quot;margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; &quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; &quot;&gt;&amp;#8211;end&amp;#8212;&lt;/p&gt;&lt;img src=&quot;http://www1.feedsky.com/t1/584467533/javaBloger/feedsky/s.gif?r=http://item.feedsky.com/~feedsky/javaBloger/~8046889/584467533/6154110/1/item.html&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</content:encoded><wfw:commentRss>http://www.javabloger.com/article/keep-looking-dont-settle.html/feed</wfw:commentRss><slash:comments>1</slash:comments><description>keep looking don't settle&lt;img src=&quot;http://www1.feedsky.com/t1/584467533/javaBloger/feedsky/s.gif?r=http://item.feedsky.com/~feedsky/javaBloger/~8046889/584467533/6154110/1/item.html&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</description><category>keep-looking-dont-settle</category><category>Life</category><pubDate>Tue, 01 Nov 2011 16:11:52 +0800</pubDate><author>H.E.</author><comments>http://www.javabloger.com/article/keep-looking-dont-settle.html#comments</comments><guid isPermaLink="false">http://www.javabloger.com/?p=1613</guid><dc:creator>H.E.</dc:creator><fs:srclink>http://www.javabloger.com/article/keep-looking-dont-settle.html?source=rss</fs:srclink><fs:srcfeed>http://www.javabloger.com/index.php/feed/</fs:srcfeed><fs:itemid>feedsky/javaBloger/~8046889/584467533/6154110</fs:itemid></item><item><title>视频网站的推荐搜索引擎介绍</title><link>http://item.feedsky.com/~feedsky/javaBloger/~8046889/584467534/6154110/1/item.html</link><content:encoded>&lt;p&gt;&lt;strong&gt;开场白&lt;br /&gt;
	&lt;/strong&gt;很久没有更新blog了 ，从5月份到现在中间发生了太多的事情，公司对我职位上的调整，让我每天需要处理的事情越来越多，近几个月来基本上很多时候难以静下心来去写一些东西，可是仍然想把一些在技术上心得给记录下来，不会因为写博客而且写，更不会直接转载网上的内容。最近在推荐搜索引擎和海量数据存储方面看了不少资料，正在准备项目中的实践，以下是一些总结和见解。&lt;/p&gt;
&lt;p&gt;&amp;nbsp; &amp;nbsp; 在一个推荐系统中可以分析用户的行为，在后台对用户行为数据建模，经过分析去预测用户的喜好、向用户推荐。这里讲的动态，是因为用户的行为是跟时间有关系的，系统中包含了大量和时间有关的数据集合。现实社会是处于变化之中的，用户的喜好也在不断的变化着。&lt;br /&gt;
	&amp;nbsp; &amp;nbsp;系统中每天都会有大量的新用户，新的商品加入，按照时间段划分，一个用户在不同的时间段、不同的季节喜好的商品也会有所不同，一个好的智能推荐系统要满足以下两点：1.向用户推荐他们喜欢的内容；2.能够为内容服务提供商提升节目访问量。&lt;/p&gt;
&lt;div&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;一个完整的推荐系统应该包括几大方面：用户界面、日志系统、推荐引擎。用户界面有两个作用，一方面给用户展示推荐结果，另一方面收集用户对推荐结果的反馈。收集到的用户反馈将通过日志系统写入用户行为数据库中，最后推荐引擎通过分析用户行为数据库中的用户行为，给用户生成推荐结果并展示在用户界面上。&lt;br /&gt;
	&amp;nbsp;从这个循环可以看到，推荐系统是一个不断收集用户行为，不断更新用户兴趣模型，从而不断改善用户推荐结果的闭环反馈系统。如下图：&lt;/div&gt;
&lt;p&gt;&lt;a href=&quot;http://public.bay.livefilestore.com/y1pAtPnNPNwCZtFW7BXlDNeai_d0lL1iHBUEC1sYlwUe4FDf5FIH3uQup1dg14JHIigi5KBKqkwDtEteN2PQGuXfw/CF-1.png&quot;&gt;&lt;img alt=&quot;&quot; height=&quot;294&quot; src=&quot;http://public.bay.livefilestore.com/y1pAtPnNPNwCZtFW7BXlDNeai_d0lL1iHBUEC1sYlwUe4FDf5FIH3uQup1dg14JHIigi5KBKqkwDtEteN2PQGuXfw/CF-1.png&quot; width=&quot;352&quot; /&gt;&lt;br /&gt;
	&lt;/a&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;推荐系统的用户界面设计在推荐系统中占有非常重要的作用，好的用户界面设计能够收集到更多，更明确的用户反馈，这对提高后面推荐引擎的准确性有至关重要的作用。日志系统在推荐系统中也有很重要的作用，在很多大流量的网站中，日志系统需要同时满足两方面的需求，一方面需要能够实时的将用户最新的行为写入到数据库中，另一方面需要能够快速的处理大量的数据存储。&lt;/p&gt;
&lt;p&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;完整的推荐引擎包括离线系统和在线系统两部分。在线系统负责实时响应用户的请求，在线提取和分析用户行为并生成最终推荐结果。离线系统主要负责生成各种用户兴趣模型，视频相关度矩阵，存储在数据库中，供在线系统实时查询和调用。如下图：&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; height=&quot;509&quot; src=&quot; http://public.bay.livefilestore.com/y1pNX7H5xm0HinPPTGI2sD5XOVSxsSIJIbWsoMbFRo1AC394DTFLQQt2hMrQIJUiJOuCIZt1_1jGn_MiolrvgSGUw/CF-2.png&quot; width=&quot;564&quot; /&gt;&lt;/p&gt;
&lt;p&gt;协同过滤推荐算法(Collaborative filtering&amp;mdash;CF)在推荐系统中是一个非常的组件，其中包含2种 &amp;nbsp;:&lt;br /&gt;
	&amp;nbsp; &amp;nbsp;a.基于用户的(User-based-CF):此种算法假定用户更倾向于那些和他具有相同爱好的人喜欢的节目，&lt;br /&gt;
	&amp;nbsp; &amp;nbsp;b.基于内容的(Item-based-CF):此种算法假定用户更倾向于以前对他有用的节目类别。此种算法被广泛应用，如Amazon、Netflix。&lt;br /&gt;
	这种算法有两个优势：1.适用于用户数远多于节目数；2.能够很容易的根据用户行为历史数据推荐当前节目。&lt;/p&gt;
&lt;p&gt;五个主要的组成部分&lt;br /&gt;
	1.建立用户信息：用户第一次进入推荐系统，系统会为他们建立个人用户信息。包括用户的历史行为、主题（分类）以及从那些来自以前行为的信息。例如，他们可以选择观看录像，添加节目到我的最爱，搜索录像，投票给录像和节目。所有这些行为都会被系统纳入考虑范围，将这些行为提炼，然后用成熟的主题模型离线生成用户对主题的喜好表。&lt;/p&gt;
&lt;p&gt;2.推荐的核心：在生成关于主题和节目的用户喜好列表以后，将那些相似的节目放在源推荐当中。&lt;/p&gt;
&lt;p&gt;3.过滤：由于一些显而易见的原因，源推荐不能直接推荐给用户。对于那些用户已经看过或者正在浏览的视频，从源推荐当中去除，从而使源推荐更准确。&lt;/p&gt;
&lt;p&gt;4.排序模块：排序模块重新排列源推荐的顺序来使它们更好的符合用户的喜好。首先，让源推荐更多变化，然后增加源推荐的新鲜度，让用户发现他们喜欢但以前没看过的节目。&lt;/p&gt;
&lt;p&gt;5.推荐解释模块：此模块是每一个推荐系统最重要的组件，解释模块对利用用户历史行为而产生的推荐结果给出解答。&lt;/p&gt;
&lt;p&gt;这里要特别对推荐解释模块说明一下：推荐解释有很多优点，它可以增加用户对推荐系统的信任。当用户看到一个不靠谱的推荐结果时，根据推荐解释他会知道这个推荐是怎么产生的（由他以前的什么行为产生的），这样用户就会知道，如果需要好的推荐，他应该怎样反馈给系统，整体结构如图所示：&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; height=&quot;389&quot; src=&quot;http://public.bay.livefilestore.com/y1pJZ1t9_LEc2WGukLWFwMjw0vhGcaQhISuGW_C-WOjCS32qmgnUaw3UIVzwbFkHCO94y1Z5c53N_OOOrgEO4Rb8A/Architecture-for-Hulu.png&quot; width=&quot;600&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;推荐系统离线组件&amp;nbsp;&lt;br /&gt;
	&lt;/strong&gt;上面的在线组件有些模块是基于离线组件的。如主题模型、关系模型，反馈模型等。离线系统也是整个智能推荐系统中一个重要的部分。&lt;/p&gt;
&lt;p&gt;1.数据中心：数据中心存储所有用户行为数据。一部分存在Handoop集群中，另一部分存在RMDBS中。&lt;/p&gt;
&lt;p&gt;2.关系表生成器：关系表对于在线推荐组件来说是份重要的资源。主要用到两种类型的关系表：一种基于协同过滤（CF），另一种基于内容。在CF如果用户喜欢视频A也喜欢视频B，视频A和视频B会有着高相似度；内容过滤，使用一些基本信息如标题、描述、频道、公司、演员和标签等。&lt;/p&gt;
&lt;p&gt;3.主题模型：一组具有相似内容的节目称为一个主题（类别）。他的范围比节目大，但是比频道范围小。也就是说是在一个频道下面的一组相似节目的集合。这里使用的是线性判别分析算法（LDA）。&lt;/p&gt;
&lt;p&gt;4.反馈分析器：反馈特指用户对于推荐结果的反馈。利用用户反馈可以很好的提升推荐质量，比如一个节目推荐给了很多用户，却很少有用户点击，那么就要降低这个节目的排序，用户有各种各样的喜好，可以根据这些反馈制定更合理的推荐排序。然而，有些用户会更喜欢那些来自之前观看历史的推荐，一些用户更喜欢来自投票结果的推荐。所有这些影响可以通过分析用户在推荐上的反馈而离线生成模型。&lt;/p&gt;
&lt;p&gt;5.报告生成模块：度量（评估）是推荐系统最重要的一部分。它每天对系统推荐质量评估并形成一个多维的报告。如点击率、转换率&lt;br /&gt;
	&lt;img alt=&quot;&quot; height=&quot;330&quot; src=&quot;http://public.bay.livefilestore.com/y1pZX4N8w21SPTYdsUmiK7sDwImlmHCTUsQu10elI41hbEyqIhvAnU5ZRNcGn57yNVIwrnvWN_qgGiFbN_c8Sb_3A/Architecture-for-Hulu-2.png&quot; width=&quot;600&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp; &amp;nbsp; 基于内容的协同过滤算法(ItemCF)使我们所有算法的基础。在CF中,定义N(u)是用户u以前较喜欢的节目的集合，那么用户对于节目i的偏好可以用以下公式衡量：&lt;br /&gt;
	&lt;img alt=&quot;&quot; height=&quot;78&quot; src=&quot;http://public.bay.livefilestore.com/y1pAtPnNPNwCZvBdXYkqlTyjKsFH7ud-KjFo7M42_PrCiQ7MjkcEj3Hgimr3qdmKh2MrCvwkipqHZwI2EOUjVRjPg/CF-5.png&quot; width=&quot;364&quot; /&gt;&lt;br /&gt;
	&amp;nbsp;其中r(u,j)表示用户u对节目j喜爱的度，s(i,j)是节目i和节目j之间的相似度。在CF中，两个节目之间的相似度是根据两个节目的用户行为数据计算出来的，定义N(i)是观看过i节目的用户集合,N(j)是观看过j节目的用户集合，这样节目i和节目j之间的相似度s(i,j)可以用下列公式计算：&lt;br /&gt;
	&lt;img alt=&quot;&quot; height=&quot;71&quot; src=&quot;http://public.bay.livefilestore.com/y1prVefk92Q0U5n6JagfzhwSlaKNa8tdzPwVNbh9BzAfejvux6FdXeWDffqCY19a_V5NIlkjGzHcuD7mNWBW4dICQ/CF-6.png&quot; width=&quot;271&quot; /&gt;&lt;br /&gt;
	&amp;nbsp; &amp;nbsp; 在这个定义中，如果多数用户看过节目i，同时也看过了节目j，那么节目i和节目j就会高度相关。但是，这个定义会出现哈利波特问题(Harry Potter Problem),即每一个节目都会和那些受欢迎的节目高度相关，原因是由于Harry Potter这本书很火，买了任何书的人都会买这本书，那么所有的书和这本书都会很相关，从而使得相似度的结果不够合理，缺乏说服力。&lt;/p&gt;
&lt;p&gt;还有一些问题也是值得我们去考虑的，例如：&lt;br /&gt;
	1.最近行为：&lt;br /&gt;
	&amp;nbsp; &amp;nbsp; 我们从分桶测试中了解到，用户最近行为比以前的历史行为在系统推荐的分析上更重要。分析的时候要放更多的权重在上面。&lt;br /&gt;
	&amp;nbsp; &amp;nbsp;&amp;nbsp;&lt;img alt=&quot;&quot; height=&quot;226&quot; src=&quot;http://public.bay.livefilestore.com/y1pB7HXG3JkWUpxnqRhnc34AlwM8gUO_zraRWBMZS-C4w7FRBnzhowoIyus6NFoz9s6LDnCZoJca6sKZSukIglkdw/CF-7.png&quot; width=&quot;263&quot; /&gt;&lt;br /&gt;
	2.最新鲜的：&amp;nbsp; &amp;nbsp; 一个推荐系统能够准确的预知用户的行为，并不代表它只是单纯的将一个节目推荐给在线用户。比如一部家喻户晓的电影并不需要系统去推荐，完全可以由用户去决定看或者不看。因此，新鲜度也是评价一个推荐系统的重要指标。提高新鲜度的一个方法是修改基于节目的协同过滤算法。首先，对于那些观众已经观赏过的热门的节目，要减少其比重。其次，不仅要增加那些和活跃观众以前观赏过的类似的节目的比例，还要增加热度不及活跃用户以前观赏过的节目。&lt;/p&gt;
&lt;p&gt;3.基于解释的多样性：大多数的用户有着多种喜好，推荐系统应该去迎合他们不同的兴趣。在系统中，可以用解释器去多样化推荐系统。可以通过分桶测试（A/B test）展示多样化的有效性。实验结果表明，对于看过十部节目以上的活跃用户，多样化能够显著的增加推荐视频的点击率。&lt;/p&gt;
&lt;p&gt;4.时空多样性：&amp;nbsp;一个好的推荐系统不应该只生成一些静态的推荐推荐。用户希望在每次登陆的时候看到一些新的推荐。比如一位用户有了新的行为（新爱好、新类型），他应该发现对他的推荐有了一些改变，就像前面所说，要把比较多的比重放在用户最近的行为上。但是如果用户最近没有新的动态，那么我们的推荐也应该有所更新和改变。可以用一下几个方法保持推荐系统的时空多样性，例如：将每天最新的节目推荐给用户，这样用户每天能够看到最新的东西，总有部分用户会喜欢。随机的将节目推荐给用户，这是保持推荐更新的最简单的方法。最后，降低那些被用户点击或观赏了很多次的推荐的排名，我们称这为隐式反馈，数据表明，此方法使点击率上升了10%。&lt;/p&gt;
&lt;p&gt;在Hulu.com中有一个Recommendation Hub的东东，其实就是系统给每个用户的个人推荐页面。系统认为的用户最喜欢的节目。最顶端的下面有三中不同类型的推荐，这些推荐是分析用户历史行为获得的。用户之前标注过以后希望观看（类似于收藏夹），最后一条传送带是用户已经评分过的视频，这条传送带是用来显式的收集用户的反馈。下面的图是Hulu.com进行的分桶测试结果，经验表明推荐系统使用的算法的点击率远远高于常见的普通推荐算法：观看最多的和评分最高的。&lt;br /&gt;
	&lt;img alt=&quot;&quot; height=&quot;318&quot; src=&quot;http://public.bay.livefilestore.com/y1p1okEq90pvHoLJVC7K51sq7yav6ZsuNMSdIKuyrtRFKkLLFgwK1jTdWt29Eoobf2-G_rfawL17gRRAyJD6muxvw/CF-8.png&quot; width=&quot;472&quot; /&gt;&lt;br /&gt;
	下图是对于不同类型行为推荐的点击率。&lt;br /&gt;
	&lt;img alt=&quot;&quot; height=&quot;325&quot; src=&quot;http://public.bay.livefilestore.com/y1ptyhxQlVEjhYp0EoApzS8muYkiPfU6Q2YKlm31Rik4Ca0fLdbgVTpc0Pr99aZwPmyjjgPar2WnR4Ua0XME65TRw/CF-9.png&quot; width=&quot;600&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp; &amp;nbsp; 每一个用户的行为能够反映其喜好。我们用大量的用户行为生成我们的推荐，上图中每一种行为反馈的点击率都可以生成用户可能会点击的推荐来。(我们看到最近观看的点击率比较高，系统就可以根据最近观看的类型、标签推荐最有可能被用户点击的节目)。&lt;/p&gt;
&lt;p&gt;由此看来，显式反馈的显式数据比隐式数据更重要。如上图，从用户行为历史上看，来自钟爱和喜欢的推荐点击率高于对用户以往订阅/观看/搜索的推荐点击率。虽然显式反馈的数据量要小于隐式反馈，但是实际上它却是重要的多。用户最近的行为比以前的行为重要。新鲜度、多样性和离线精度都是重要的因素。大多数的研究人员聚焦在离线精度，如均方根误差、精度/检索。然而，能够准确预测用户某一单独行为的推荐系统可能不足以满足实际应用，一个优秀的推荐系统应该将多种因素结合在一起考虑。Hulu系统结合了新鲜度和多样性后，点击率提高了超过10%。&lt;/p&gt;
&lt;p&gt;总结&lt;/p&gt;
&lt;p&gt;1.直观的数据库排序：&lt;br /&gt;
	&amp;nbsp; &amp;nbsp;根据用户评价、或者点击率，这也是上面所说的两种最传统的方式。&lt;/p&gt;
&lt;p&gt;2.浏览了该商品的用户浏览的其他商品&lt;br /&gt;
	&amp;nbsp; &amp;nbsp;延伸&amp;mdash;&amp;mdash;浏览此商品的用户最终购买了商品的比例和购买本商品的比例，记录用户的行为，加入多样性的考虑&lt;/p&gt;
&lt;p&gt;3.用推荐算法&lt;br /&gt;
	&amp;nbsp; &amp;nbsp; a.协同过滤：找到一个用户最感兴趣商品，方法是分析和此用户具有相同喜好的用户对什么最感兴趣。&lt;br /&gt;
	&amp;nbsp; &amp;nbsp; b.关联过滤：购买商品集X的用户有多少购买了商品集Y。&lt;/p&gt;
&lt;p&gt;4.基于内容推荐：&lt;br /&gt;
	&amp;nbsp; &amp;nbsp;用到了决策树算法，比较各子树的权重，实现有难度！&lt;/p&gt;
&lt;p&gt;一个好的推荐系统，有简洁而重要的内容，有推荐理由，而且推荐理由还具有多样性。同时还给出了用户反馈的方式方法，节目产品的推荐可以和广告结合在一起。不光要满足用户的需要，还要满足节目发布者、广告投放商的需要，同时推荐反馈的数据能够对系统有利，推动系统良性的发展。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;#8211;end&amp;#8211;&lt;/p&gt;&lt;img src=&quot;http://www1.feedsky.com/t1/584467534/javaBloger/feedsky/s.gif?r=http://item.feedsky.com/~feedsky/javaBloger/~8046889/584467534/6154110/1/item.html&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</content:encoded><wfw:commentRss>http://www.javabloger.com/article/hadoop-dynamic-intelligent-recommendation-system.html/feed</wfw:commentRss><slash:comments>1</slash:comments><description>在一个推荐系统中可以分析用户的行为，在后台对用户行为数据建模，经过分析去预测用户的喜好、向用户推荐。这里讲的动态，是因为用户的行为是跟时间有关系的，系统中包含了大量和时间有关的数据集合。现实社会是处于变化之中的，用户的喜好也在不断的变化着。系统中每天都会有大量的新用户，新的商品加入，按照时间段划分，一个用户在不同的时间段、不同的季节喜好的商品也会有所不同，一个好的智能推荐系统要满足以下两点：1.向用户推荐他们喜欢的内容；2.能够为内容服务提供商提升节目访问量。

     一个完整的推荐系统应该包括几大方面：用户界面、日志系统、推荐引擎。用户界面有两个作用，一方面给用户展示推荐结果，另一方面收集用户对推荐结果的反馈。收集到的用户反馈将通过日志系统写入用户行为数据库中，最后推荐引擎通过分析用户行为数据库中的用户行为，给用户生成推荐结果并展示在用户界面上。从这个循环可以看到，推荐系统是一个不断收集用户行为，不断更新用户兴趣模型，从而不断改善用户推荐结果的闭环反馈系统。&lt;img src=&quot;http://www1.feedsky.com/t1/584467534/javaBloger/feedsky/s.gif?r=http://item.feedsky.com/~feedsky/javaBloger/~8046889/584467534/6154110/1/item.html&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</description><category>OpenSource</category><category>视频网站</category><category>架构设计</category><category>智能推荐</category><category>云计算</category><category>推荐引擎</category><category>J2ee企业顾问</category><category>分布式</category><category>智能推荐系统</category><pubDate>Fri, 28 Oct 2011 13:24:58 +0800</pubDate><author>H.E.</author><comments>http://www.javabloger.com/article/hadoop-dynamic-intelligent-recommendation-system.html#comments</comments><guid isPermaLink="false">http://www.javabloger.com/?p=1600</guid><dc:creator>H.E.</dc:creator><fs:srclink>http://www.javabloger.com/article/hadoop-dynamic-intelligent-recommendation-system.html?source=rss</fs:srclink><fs:srcfeed>http://www.javabloger.com/index.php/feed/</fs:srcfeed><fs:itemid>feedsky/javaBloger/~8046889/584467534/6154110</fs:itemid></item><item><title>MySQL空间数据库–查询点到多点间的最短路径</title><link>http://item.feedsky.com/~feedsky/javaBloger/~8046889/584467535/6154110/1/item.html</link><content:encoded>&lt;p&gt;当SNS产品加入LBS的技术将会让移动互联网领域更加丰富多彩，例如：大众点评，街旁，盛大切客 这些运行在智能手机端的应用，当用户拿出手机就可以根据你当前的所在地向你推荐一些有用的信息，例如：附近的美食，商铺，周边生活信息，等。&lt;/p&gt;
&lt;p&gt;	攻城师们，你有没有想过这些应用背后的技术实现呢？手机端获得当前的坐标后是怎么进行计算和查询返回附件的结果呢？&lt;/p&gt;
&lt;p&gt;	用Java程序可以实现Dijkstra算法获得点与多点之间最短路径的计算结果，但是我个人认为是一种暴力的方法，开发的简化程度和计算的执行效率不会非常高。&lt;br /&gt;
	参考资料：&lt;a href=&quot;http://baike.baidu.com/view/7839.htm&quot;&gt;http://baike.baidu.com/view/7839.htm&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;	接着再往下想，用到数据库技术是必然，但不会把节点的坐标信息存储到数据库普通的字段中进行查询，如果和Dijkstra算法相比不会简化工作量也不会提高性能，但使用到MySQL中空间数据库的概念就会简化很多也会得到性能的提升，开源的MySQL Spatial空间索引机制就可以对点到多点之间的距离计算，类似的Spatial Database还有，PostGIS，SpatiaLite。&lt;/p&gt;
&lt;p&gt;	&lt;strong&gt;我的废话：&lt;/strong&gt;&lt;br /&gt;
	在android手机上获得当前坐标后，将数据整好录入android中的SQLite数据库也可以获得当前点对多点的最短路径，也就是说在地理数据不会更新的场景下完全可以采用android手机上的数据库完成这项工作，没有必要非要利用服务器端的Spatial Database完成最短路径的计算。&lt;/p&gt;
&lt;p&gt;	MySQL空间数据几种主要类型:&lt;br /&gt;
	&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;ndash; GEOMETRY&amp;nbsp; Geometry是层次结构的根类。它是一种非实例化类，但具有很多属性，这些属性对由任何Geometry子类创建的所有几何值来说是共同的。&lt;br /&gt;
	&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;ndash; POINT&amp;nbsp;&amp;nbsp; 代表坐标空间中单个位置的几何类，他的属性包含 X-坐标值，Y-坐标值。&lt;br /&gt;
	&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;ndash; LINESTRING&amp;nbsp; 具有线段的坐标，由每个连续的点对(两点)定义。如果仅包含两点，LineString为Line。 如果它既是简单的也是封闭的，LineString为LinearRing。&lt;br /&gt;
	&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;ndash; POLYGON&amp;nbsp; 它由单个外部边界以及0或多个内部边界定义，其中，每个内部边界定义为Polygon中的1个孔。例如:在地区地图上，Polygon对象可表示森林。&lt;br /&gt;
	&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;ndash; MULTIPOINT&amp;nbsp; MultiPoint是一种由Point元素构成的几何对象集合。这些点未以任何方式连接或排序。&lt;br /&gt;
	&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;ndash; MULTILINESTRING&amp;nbsp; MultiLineString是一种由 LineString元素构成的MultiCurve几何对象集合，例如：河流体系或高速路系统。&lt;br /&gt;
	&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;ndash; MULTIPOLYGON&amp;nbsp; MultiPolygon是一种由Polygon元素构成的几何对象集合。在地区地图上，MultiPolygon可表示湖泊系统。&lt;br /&gt;
	&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;ndash; GEOMETRYCOLLECTION&amp;nbsp;&amp;nbsp; 他是由1个或多个任意类几何对象构成的几何对象。GeometryCollection中的所有元素必须具有相同的空间参考系(即相同的坐标系).&lt;br /&gt;
	以上几种的类型依赖关系，如图所示：&lt;br /&gt;
	&lt;img alt=&quot;xyz&quot; height=&quot;346&quot; src=&quot;http://b4szfq.bay.livefilestore.com/y1pRybtrBLB4QjvTyYqMukYhiWDt23cZY0l9O8XQsqfCmBJ3lw-HPgpnKyEM-XphIk-o2lC-q44gN2CfLFWo0mAyuHd4qHHcPXm/x_y_z_3.png?psid=1&quot; width=&quot;661&quot; /&gt;&lt;/p&gt;
&lt;p&gt;	了解过上述一些基本知识，下面来创建一张商户表，并且包含定义的空间数据库的POINT字段：&lt;br /&gt;
	&amp;nbsp; Create table shop (&lt;br /&gt;
	&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; shop_id int(3) primary key,&lt;br /&gt;
	&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Location POINT,&lt;br /&gt;
	&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Shop_na vachar(100),&lt;br /&gt;
	&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Shop_info vachar(300)&lt;br /&gt;
	&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; );&lt;/p&gt;
&lt;p&gt;	插入几条商家的门店信息，其中采用GeomFromText方法将坐标的数据库插入POINT字段中，例如：&lt;br /&gt;
	insert into shop values (&amp;lsquo;XXX&amp;rsquo;,&amp;rsquo;,GeomFromText(&amp;lsquo;POINT(1 1)&amp;rsquo;),&amp;rsquo;XX店&amp;rsquo;,&amp;rsquo; &amp;#39;其他信息&amp;#39;);&lt;br /&gt;
	下面将根据客户当前所在位置在MySQL中查询，搜索出在当前位置附近的一定范围内的门店，并且可以做到按距离由近到远排列显示出来，从让用户而找到离他最近的门店。&lt;br /&gt;
	把客户当前所在位置可设成变量 ，例如:set @center=GeomFromText(&amp;lsquo;POINT(10 10)&amp;rsquo;)；&lt;/p&gt;
&lt;p&gt;	再把要找到最近门店可以缩小搜索范围 设半径，添加搜索条件&lt;br /&gt;
	例：set @radius=30;&lt;br /&gt;
	WHERE SQRT(POW( ABS( X(location) &amp;#8211; X(@center)), 2) + POW( ABS(Y(location) &amp;#8211; Y(@center)), 2 )) &amp;lt; @radius&lt;/p&gt;
&lt;p&gt;	最近门店搜索，完整的SQL示例：&lt;br /&gt;
	SELECT shop_id,shop_na, SQRT(POW( ABS( X(Location) &amp;#8211; X(@center)), 2) + POW(ABS(Y(Location) &amp;#8211; Y(@center)), 2 )) AS distance&lt;br /&gt;
	FROM shop WHERE SQRT(POW( ABS( X(location) &amp;#8211; X(@center)), 2) + POW( ABS(Y(location) &amp;#8211; Y(@center)), 2 )) &amp;lt; @radius&lt;br /&gt;
	order by distance;&lt;/p&gt;
&lt;p&gt;	其中涉及的数学函数SQRT(x)：表示求一个数x的平方根。POW(x,y):包含两个参数表示求x的y次幂。ABS(x)：表示求数X的绝对值。整个SQRT(POW( ABS( X(Location) &amp;#8211; X(@center)), 2) + POW(ABS(Y(Location) &amp;#8211; Y(@center)), 2 ))这个SQL语句实现的是一个算术表达式&lt;br /&gt;
	&lt;img alt=&quot;http://public.bay.livefilestore.com/y1po7ENYXgBlsmmLKp2_WlYd_iiXZhsAAIyqniUqqAkWrJYinExgS5_YBDIcI_vwVg8AEe5Fjh0NLwvbWlAapZpIA/x_y_z_1.png?psid=1&quot; src=&quot;http://public.bay.livefilestore.com/y1po7ENYXgBlsmmLKp2_WlYd_iiXZhsAAIyqniUqqAkWrJYinExgS5_YBDIcI_vwVg8AEe5Fjh0NLwvbWlAapZpIA/x_y_z_1.png?psid=1&quot; style=&quot;width: 205px; height: 45px;&quot; /&gt;&lt;br /&gt;
	即两点间的直线距离。&lt;br /&gt;
	比如说现在有两个点坐标A(x1,y1)，B(x2,y2) 要求线段AB长度 就是用&lt;img alt=&quot;http://public.bay.livefilestore.com/y1po7ENYXgBlsmmLKp2_WlYd_iiXZhsAAIyqniUqqAkWrJYinExgS5_YBDIcI_vwVg8AEe5Fjh0NLwvbWlAapZpIA/x_y_z_1.png?psid=1&quot; src=&quot;http://public.bay.livefilestore.com/y1po7ENYXgBlsmmLKp2_WlYd_iiXZhsAAIyqniUqqAkWrJYinExgS5_YBDIcI_vwVg8AEe5Fjh0NLwvbWlAapZpIA/x_y_z_1.png?psid=1&quot; style=&quot;width: 186px; height: 40px;&quot; /&gt;这个公式去计算。把A看成当前位置B看成一个门店，不就是相当于计算当前位置到门店这两个点的距离吗。坐标点有了带进去就行，等于现在只要能用函数把这个公式表示出来就可以了。&lt;br /&gt;
	所以用到这三个函数：&lt;br /&gt;
	SQRT(x)：表示求一个数x的平方根。就相当于那个根号。&amp;radic;x&lt;br /&gt;
	POW(x,y):包含两个参数表示求x的y次幂&lt;br /&gt;
	例如pow(2,3)就表示23，那么POW((X1-X2),2)就相当于〖（x1-x2）〗^2&lt;br /&gt;
	ABS(x)：表示求数X的绝对值。|x|&amp;nbsp; ABS(x1-x2)就等于|x1-x2|.&lt;/p&gt;
&lt;p&gt;	根据那个公式组合起来就行了&lt;br /&gt;
	整个SQRT(POW( ABS( X(Location) &amp;#8211; X(@center)), 2) + POW(ABS(Y(Location) &amp;#8211; Y(@center)), 2))这句话就是用来表示这个公式的&lt;br /&gt;
	&lt;img alt=&quot;http://public.bay.livefilestore.com/y1pM_5Xtwtl4QeSaP8qXtHUJyDToYypy1K3UmyZVxM_6_E64Xad_C0AlmQDWWE_ncb8ap6FRZfjQX2jWD4eGJMe8w/x_y_z_2.png?psid=1&quot; src=&quot;http://public.bay.livefilestore.com/y1pM_5Xtwtl4QeSaP8qXtHUJyDToYypy1K3UmyZVxM_6_E64Xad_C0AlmQDWWE_ncb8ap6FRZfjQX2jWD4eGJMe8w/x_y_z_2.png?psid=1&quot; style=&quot;width: 497px; height: 50px;&quot; /&gt;,&lt;br /&gt;
	这个公式计算得出来的值就是两点间的直线距离。&lt;/p&gt;
&lt;p&gt;	参考资料：&lt;br /&gt;
	&lt;a href=&quot;http://dev.mysql.com/doc/refman/5.1/zh/spatial-extensions-in-mysql.html&quot;&gt;http://dev.mysql.com/doc/refman/5.1/zh/spatial-extensions-in-mysql.html&lt;/a&gt;&lt;br /&gt;
	&lt;a href=&quot;http://en.wikipedia.org/wiki/Spatial_database&quot;&gt;http://en.wikipedia.org/wiki/Spatial_database&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;	&lt;strong&gt;口水：&lt;/strong&gt;&lt;br /&gt;
	&amp;nbsp;以上部分内容来自 NJ-AMT 实习生余珊的分析报告。&lt;/p&gt;
&lt;p&gt;&amp;#8211;end&amp;#8211;&lt;/p&gt;&lt;img src=&quot;http://www1.feedsky.com/t1/584467535/javaBloger/feedsky/s.gif?r=http://item.feedsky.com/~feedsky/javaBloger/~8046889/584467535/6154110/1/item.html&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</content:encoded><wfw:commentRss>http://www.javabloger.com/article/mysql-spatial-database.html/feed</wfw:commentRss><slash:comments>10</slash:comments><description>当SNS产品加入LBS的技术将会让移动互联网领域更加丰富多彩，例如：大众点评，街旁，盛大切客 这些运行在智能手机端的应用，当用户拿出手机就可以根据你当前的所在地向你推荐一些有用的信息，例如：附近的美食，商铺，周边生活信息，等。
	攻城师们，你有没有想过这些应用背后的技术实现呢？手机端获得当前的坐标后是怎么进行计算和查询返回附件的结果呢？
	用Java程序可以实现Dijkstra算法获得点与多点之间最短路径的计算结果，但是我个人认为是一种暴力的方法，开发的简化程度和计算的执行效率不会非常高。
	参考资料：http://baike.baidu.com/view/7839.htm
	接着再往下想，用到数据库技术是必然，但不会把节点的坐标信息存储到数据库普通的字段中进行查询，如果和Dijkstra算法相比不会简化工作量也不会提高性能，但使用到MySQL中空间数据库的概念就会简化很多也会得到性能的提升，开源的MySQL Spatial空间索引机制就可以对点到多点之间的距离计算，类似的Spatial Database还有，PostGIS，SpatiaLite。
	我的废话：
	在android手机上获得当前坐标后，将数据整好录入android中的SQLite数据库也可以获得当前点对多点的最短路径，也就是说在地理数据不会更新的场景下完全可以采用android手机上的数据库完成这项工作，没有必要非要利用服务器端的Spatial Database完成最短路径的计算。
	MySQL空间数据几种主要类型:
	&amp;#160;&amp;#160;&amp;#160;&amp;#160; &amp;#8211; GEOMETRY&amp;#160; Geometry是层次结构的根类。它是一种非实例化类，但具有很多属性，这些属性对由任何Geometry子类创建的所有几何值来说是共同的。
	&amp;#160;&amp;#160;&amp;#160;&amp;#160; &amp;#8211; POINT&amp;#160;&amp;#160; 代表坐标空间中单个位置的几何类，他的属性包含 X-坐标值，Y-坐标值。
	&amp;#160;&amp;#160;&amp;#160;&amp;#160; &amp;#8211; LINESTRING&amp;#160; 具有线段的坐标，由每个连续的点对(两点)定义。如果仅包含两点，LineString为Line。 如果它既是简单的也是封闭的，LineString为LinearRing。
	&amp;#160;&amp;#160;&amp;#160;&amp;#160; &amp;#8211; POLYGON&amp;#160; 它由单个外部边界以及0或多个内部边界定义，其中，每个内部边界定义为Polygon中的1个孔。例如:在地区地图上，Polygon对象可表示森林。
	&amp;#160;&amp;#160;&amp;#160;&amp;#160; &amp;#8211; MULTIPOINT&amp;#160; MultiPoint是一种由Point元素构成的几何对象集合。这些点未以任何方式连接或排序。
	&amp;#160;&amp;#160;&amp;#160;&amp;#160; &amp;#8211; MULTILINESTRING&amp;#160; MultiLineString是一种由 LineString元素构成的MultiCurve几何对象集合，例如：河流体系或高速路系统。
	&amp;#160;&amp;#160;&amp;#160;&amp;#160; &amp;#8211; MULTIPOLYGON&amp;#160; MultiPolygon是一种由Polygon元素构成的几何对象集合。在地区地图上，MultiPolygon可表示湖泊系统。
	&amp;#160;&amp;#160;&amp;#160;&amp;#160; &amp;#8211; GEOMETRYCOLLECTION&amp;#160;&amp;#160; 他是由1个或多个任意类几何对象构成的几何对象。GeometryCollection中的所有元素必须具有相同的空间参考系(即相同的坐标系).
	以上几种的类型依赖关系，如图所示：
	
	了解过上述一些基本知识，下面来创建一张商户表，并且包含定义的空间数据库的POINT字段：
	&amp;#160; Create table shop (
	&amp;#160;&amp;#160;&amp;#160;&amp;#160; shop_id int(3) primary key,
	&amp;#160;&amp;#160;&amp;#160;&amp;#160; Location POINT,
	&amp;#160;&amp;#160;&amp;#160;&amp;#160; Shop_na vachar(100),
	&amp;#160;&amp;#160;&amp;#160;&amp;#160; Shop_info vachar(300)
	&amp;#160;&amp;#160;&amp;#160;&amp;#160; );
	插入几条商家的门店信息，其中采用GeomFromText方法将坐标的数据库插入POINT字段中，例如：
	insert into shop values (&amp;#8216;XXX&amp;#8217;,&amp;#8217;,GeomFromText(&amp;#8216;POINT(1 1)&amp;#8217;),&amp;#8217;XX店&amp;#8217;,&amp;#8217; &amp;#39;其他信息&amp;#39;);
	下面将根据客户当前所在位置在MySQL中查询，搜索出在当前位置附近的一定范围内的门店，并且可以做到按距离由近到远排列显示出来，从让用户而找到离他最近的门店。
	把客户当前所在位置可设成变量 ，例如:set @center=GeomFromText(&amp;#8216;POINT(10 [...]&lt;img src=&quot;http://www1.feedsky.com/t1/584467535/javaBloger/feedsky/s.gif?r=http://item.feedsky.com/~feedsky/javaBloger/~8046889/584467535/6154110/1/item.html&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</description><category>性能</category><category>存储</category><category>Spatial Database</category><category>数据库</category><pubDate>Fri, 20 May 2011 10:05:49 +0800</pubDate><author>H.E.</author><comments>http://www.javabloger.com/article/mysql-spatial-database.html#comments</comments><guid isPermaLink="false">http://www.javabloger.com/?p=1598</guid><dc:creator>H.E.</dc:creator><fs:srclink>http://www.javabloger.com/article/mysql-spatial-database.html?source=rss</fs:srclink><fs:srcfeed>http://www.javabloger.com/index.php/feed/</fs:srcfeed><fs:itemid>feedsky/javaBloger/~8046889/584467535/6154110</fs:itemid></item><item><title>使用Java开发需要关注的那些事儿</title><link>http://item.feedsky.com/~feedsky/javaBloger/~8046889/584467536/6154110/1/item.html</link><content:encoded>&lt;p&gt;近期各家IT媒体举办的业内技术大会让很多网站都在披露自己的技术内幕与同行们分享，大到facebook，百度，小到刚起步的网站。facebook，百度之类的大型网站采用的技术和超凡的处理能力的确给人耳目一新的感觉，但并不是每个网站都是像facebook，百度 有上亿的用户访问流量，有海量的数据需要存储，需要使用到mapreduce/并行计算，HBase/列存储这些技术不可。技术手段始终是运营的支撑，对于当前的运营环境适用就好，没有必要非要赶个时髦，一定要和某项流行的技术产生点关系才善罢甘休。&lt;/p&gt;
&lt;p&gt;	在最近的技术大会中我们更多的目光都聚焦在这些大型网站，其实中小型门户网站的技术体系也是值得去探讨和关注。全天下的攻城师们并不是都在为这些大型门户网站服务，更多的攻城师们正在默默无闻的为一些刚刚起步的中小型网站服务，而且占据了攻城师队伍中的60%以上的人群。在关注大型门户网站的时候，中小型门户网站的技术发展和实战经验更值得去分享。&lt;/p&gt;
&lt;p&gt;	无论大型门户网站还是中小型垂直类型网站都会对稳定性、性能和可伸缩性有所追求。大型网站的技术经验分享值得我们去学习和借用，但落实到更具体的实践上并不是对所有网站可以适用,其他语言开发的网站我还不敢多说，但Java开发的系统，我还是能您给插上几句话：&lt;/p&gt;
&lt;p&gt;	&lt;strong&gt;JVM&lt;/strong&gt;&lt;br /&gt;
	JEE容器中运行的JVM参数配置参数的正确使用直接关系到整个系统的性能和处理能力，JVM的调优主要是对内存管理方面的调优，优化的方向分为以下4点：&lt;br /&gt;
	1.HeapSize&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 堆的大小，也可以说Java虚拟机使用内存的策略，这点是非常关键的。&lt;br /&gt;
	2.GarbageCollector&amp;nbsp; 通过配置相关的参数进行Java中的垃圾收集器的4个算法(策略)进行使用。&lt;br /&gt;
	3.StackSize&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 栈是JVM的内存指令区,每个线程都有他自己的Stack，Stack的大小限制着线程的数量。&lt;br /&gt;
	4.DeBug/Log&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 在JVM中还可以设置对JVM运行时的日志和JVM挂掉后的日志输出，这点非常的关键，根据各类JVM的日志输出才能配置合适的参数。&lt;br /&gt;
	网上随处可见JVM的配置技巧，但是我还是推荐阅读Sun官方的2篇文章，可以对配置参数的其所依然有一个了解&lt;br /&gt;
	1.Java HotSpot VM Options http://www.oracle.com/technetwork/java/javase/tech/vmoptions-jsp-140102.html&lt;br /&gt;
	2.Troubleshooting Guide for Java SE 6 with HotSpot VM http://www.oracle.com/technetwork/java/javase/index-137495.html&lt;br /&gt;
	另外，我相信不是每个人攻城师都是天天对着这些JVM参数的，如果你忘记了那些关键的参数你可以输入Java -X(大写X)进行提示。&lt;/p&gt;
&lt;p&gt;	&lt;strong&gt;JDBC&lt;/strong&gt;&lt;br /&gt;
	针对MySQL的JDBC的参数在之前的文章中也有介绍过，在单台机器或者集群的环境下合理的使用JDBC中的配置参数对操作数据库也有很大的影响。&lt;br /&gt;
	一些所谓高性能的 Java ORM开源框架也就是打开了很多JDBC中的默认参数：&lt;br /&gt;
	&amp;nbsp;1.例如：autoReconnect、prepStmtCacheSize、cachePrepStmts、useNewIO、blobSendChunkSize 等，&lt;br /&gt;
	&amp;nbsp;2.例如集群环境下：roundRobinLoadBalance、failOverReadOnly、autoReconnectForPools、secondsBeforeRetryMaster。&lt;br /&gt;
	具体内容可以参阅MySQL的JDBC官方使用手册：&lt;br /&gt;
	&lt;a href=&quot;http://dev.mysql.com/doc/refman/5.1/zh/connectors.html#cj-jdbc-reference&quot;&gt;http://dev.mysql.com/doc/refman/5.1/zh/connectors.html#cj-jdbc-reference&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;	&lt;strong&gt;数据库连接池(DataSource)&lt;/strong&gt;&lt;br /&gt;
	应用程序与数据库连接频繁的交互会给系统带来瓶颈和大量的开销会影响到系统的性能，JDBC连接池负责分配、管理和释放数据库连接，它允许应用程序重复使用一个现有的数据库连接，而再不是重新建立一个连接，因此应用程序不需要频繁的与数据库开关连接，并且可以释放空闲时间超过最大空闲时间的数据库连接来避免因为没有释放数据库连接而引起的数据库连接遗漏。这项技术能明显提高对数据库操作的性能。&lt;br /&gt;
	在此我认为有一点需要说明：&lt;br /&gt;
	连接池的使用也是需要关闭，因为在数据库连接池启动的时候就预先和数据库获得了相应的连接，之后不再需要应用程序直接的和数据库打交道，因为应用程序使用数据库连接池是一个&amp;ldquo;借&amp;rdquo;的概念，应用程序从数据库连接池中获得资源是&amp;ldquo;借出&amp;rdquo;，还需要还回去，就好比有20个水桶放在这里，需要拿水的人都可以使用这些木桶从水池里面拿水，如果20个人都拿完水，不将水桶还回原地，那么后面来的人再需要拿水，只能在旁边等待有人将木桶还回去，之前的人用完后需要放回去，不然后面的人就会一直等待，造成资源堵塞，同理，应用程序获取数据库连接的时候Connection连接对象的时候是从&amp;ldquo;池&amp;rdquo;中分配一个数据库连接出去，在使用完毕后，归还这个数据库连接，这样才能保持数据库的连接&amp;ldquo;有借有还&amp;rdquo;准则。 &lt;br /&gt;
	参考资料：&lt;br /&gt;
	&lt;a href=&quot;http://dev.mysql.com/doc/refman/5.1/zh/connectors.html#cj-connection-pooling&quot;&gt;http://dev.mysql.com/doc/refman/5.1/zh/connectors.html#cj-connection-pooling&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;	&lt;strong&gt;数据存取&lt;/strong&gt;&lt;br /&gt;
	数据库服务器的优化和数据的存取，什么类型的数据放在什么地方更好是值得去思考的问题，将来的存储很可能是混用的，Cache，NOSQL，DFS，DataBase 在一个系统中都会有，生活的餐具和平日里穿衣服需要摆放在家里，但是不会用同一种类型的家具存放，貌似没有那个人家把餐具和衣服放在同一个柜子里面的。这就像是系统中不同类型的数据一样，对不同类型的数据需要使用合适的存储环境。文件和图片的存储，首先按照访问的热度分类，或者按照文件的大小。强关系类型并且需要事务支持的采用传统的数据库，弱关系型不需要事务支持的可以考虑NOSQL，海量文件存储可以考虑一下支持网络存储的DFS，至于缓存要看你单个数据存储的大小和读写的比例。&lt;br /&gt;
	还有一点值得注意就是数据读写分离，无论在DataBase还是NOSQL的环境中大部分都是读大于写，因此在设计时还需考虑 不仅仅需要让数据的读分散在多台机器上，还需要考虑多台机器之间的数据一致性，MySQL的一主多从，在加上MySQL-Proxy或者借用JDBC中的一些参数(roundRobinLoadBalance、failOverReadOnly、autoReconnectForPools、secondsBeforeRetryMaster)对后续应用程序开发，可以将读和写分离，将大量读的压力分散在多台机器上，并且还保证了数据的一致性。&lt;/p&gt;
&lt;p&gt;	&lt;strong&gt;缓存&lt;/strong&gt;&lt;br /&gt;
	在宏观上看缓存一般分为2种：本地缓存和分布式缓存&lt;br /&gt;
	1.本地缓存，对于Java的本地缓存而言就是讲数据放入静态(static)的数据结合中，然后需要用的时候就从静态数据结合中拿出来,对于高并发的环境建议使用 ConcurrentHashMap或者CopyOnWriteArrayList作为本地缓存。缓存的使用更具体点说就是对系统内存的使用，使用多少内存的资源需要有一个适当比例，如果超过适当的使用存储访问，将会适得其反，导致整个系统的运行效率低下。&lt;br /&gt;
	2. 分布式缓存，一般用于分布式的环境，将每台机器上的缓存进行集中化的存储，并且不仅仅用于缓存的使用范畴，还可以作为分布式系统数据同步/传输的一种手段，一般被使用最多的就是Memcached和Redis。&lt;br /&gt;
	数据存储在不同的介质上读/写得到的效率是不同的，在系统中如何善用缓存，让你的数据更靠近cpu，下面有一张图你需要永远牢记在心里，来自Google的技术大牛Jeff Dean(&lt;a href=&quot;http://research.google.com/people/jeff/index.html &quot;&gt;Ref&lt;/a&gt;)的杰作，如图所示：&lt;br /&gt;
	&lt;img alt=&quot;cache-speed.png&quot; src=&quot;http://b4szfq.bay.livefilestore.com/y1pbwBs6C0gM7C0cdpstcF0UUtYn32TKJAJLTP42peNdauJmMA74MefxuRWOnhyvmNRjNR_l9WCE200_NyyQK4oVFS1RoUhMHb1/cache-speed.png?psid=1&quot; /&gt;&lt;br /&gt;
	&lt;strong&gt;并发/多线程&lt;/strong&gt;&lt;br /&gt;
	在高并发环境下建议开发者使用JDK中自带的并发包(java.util.concurrent)，在JDK1.5以后使用java.util.concurrent下的工具类可以简化多线程开发，在java.util.concurrent的工具中主要分为以下几个主要部分：&lt;br /&gt;
	1.线程池，线程池的接口(Executor、ExecutorService)与实现类(ThreadPoolExecutor、 ScheduledThreadPoolExecutor），利用jdk自带的线程池框架可以管理任务的排队和安排，并允许受控制的关闭。因为运行一个线程需要消耗系统CPU资源，而创建、结束一个线程也对系统CPU资源有开销，使用线程池不仅仅可以有效的管理多线程的使用，还是可以提高线程的运行效率。&lt;br /&gt;
	2.本地队列，提供了高效的、可伸缩的、线程安全的非阻塞 FIFO 队列。java.util.concurrent 中的五个实现都支持扩展的 BlockingQueue 接口，该接口定义了 put 和 take 的阻塞版本：LinkedBlockingQueue、ArrayBlockingQueue、SynchronousQueue、PriorityBlockingQueue 和 DelayQueue。这些不同的类覆盖了生产者-使用者、消息传递、并行任务执行和相关并发设计的大多数常见使用的上下文。&lt;br /&gt;
	3.同步器，四个类可协助实现常见的专用同步语句。Semaphore 是一个经典的并发工具。CountDownLatch 是一个极其简单但又极其常用的实用工具，用于在保持给定数目的信号、事件或条件前阻塞执行。CyclicBarrier 是一个可重置的多路同步点，在某些并行编程风格中很有用。Exchanger 允许两个线程在 collection 点交换对象，它在多流水线设计中是有用的。&lt;br /&gt;
	4.并发包 Collection，此包还提供了设计用于多线程上下文中的 Collection 实现：ConcurrentHashMap、ConcurrentSkipListMap、ConcurrentSkipListSet、CopyOnWriteArrayList 和 CopyOnWriteArraySet。当期望许多线程访问一个给定 collection 时，ConcurrentHashMap 通常优于同步的 HashMap，ConcurrentSkipListMap 通常优于同步的 TreeMap。当期望的读数和遍历远远大于列表的更新数时，CopyOnWriteArrayList 优于同步的 ArrayList。&lt;/p&gt;
&lt;p&gt;	&lt;strong&gt;队列&lt;/strong&gt;&lt;br /&gt;
	关于队列可以分为：本地的队列 和 分布式队列 2类&lt;br /&gt;
	本地队列：一般常见的用于非及时性的数据批量写入，可以将获取的数据缓存在一个数组中等达到一定数量的时候在进行批量的一次写入，可以使用BlockingQueue或者List/Map来实现。&lt;br /&gt;
	相关资料：&lt;a href=&quot;http://  http://www.gznc.edu.cn/yxsz/jjglxy/book/Java_api/java/util/concurrent/BlockingQueue.html&quot;&gt;Sun Java API&lt;/a&gt;.&lt;br /&gt;
	分布式队列：一般作为消息中间件，构建分布式环境下子系统与子系统之间通信的桥梁，JEE环境中使用最多的就是Apache的AvtiveMQ和Sun公司的OpenMQ。&lt;br /&gt;
	轻量级的MQ中间件之前也向大家介绍过一些例如：Kestrel和Redis(Ref http://www.javabloger.com/article/mq-kestrel-redis-for-java.html)，最近又听说LinkedIn的搜索技术团队推出了一个MQ产品-kaukaf(Ref http://sna-projects.com/kafka )，对此保持关注。&lt;br /&gt;
	相关资料：&lt;br /&gt;
	1.ActiveMQ &lt;a href=&quot;http://activemq.apache.org/getting-started.html&quot;&gt;http://activemq.apache.org/getting-started.html&lt;/a&gt;&lt;br /&gt;
	2.OpenMQ&amp;nbsp; &lt;a href=&quot;http://mq.java.net/about.html&quot;&gt;http://mq.java.net/about.html&lt;/a&gt;&lt;br /&gt;
	3.Kafka&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;a href=&quot;http://sna-projects.com/kafka      &quot;&gt;http://sna-projects.com/kafka&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/a&gt;&lt;br /&gt;
	4.JMS文章&amp;nbsp; &lt;a href=&quot;http://www.javabloger.com/article/category/jms ?source=rss&quot;&gt;http://www.javabloger.com/article/category/jms &lt;/a&gt;&lt;/p&gt;
&lt;p&gt;	&lt;strong&gt;NIO&lt;/strong&gt;&lt;br /&gt;
	NIO是在JDK1.4后的版本中出现的，在Java 1.4之前，Jdk提供的都是面向流的I/O系统，例如读/写文件则是一次一个字节地处理数据，一个输入流产生一个字节的数据，一个输出流消费一个字节的数据， 面向流的I/O速度非常慢，并且一个数据包要么整个数据报已经收到，要么还没有。Java NIO非堵塞技术实际是采取Reactor模式，有内容进来会自动通知,不必死等、死循环，大大的提升了系统性能。在现实场景中NIO技术多数运用两个方面，1是文件的读写操作，2是网络上数据流的操作。在NIO中有几个核心对象需要掌握：1选择器(Selector)、2通道(Channel)、3缓冲区(Buffer)。&lt;br /&gt;
	&lt;em&gt;&lt;strong&gt;我的废话：&lt;/strong&gt;&lt;/em&gt;&lt;br /&gt;
	1.在Java NIO的技术范畴中内存映射文件是一种高效的做法，可以用于缓存中存储的冷/热数据分离，将缓存中的一部分冷数据进行这样的处理，这种做法上比常规的基于流或者基于通道的I/O快的多，通过使文件中的数据出现为内存数组的内容来完成的，将文件中实际读取或者写入的部分才会映射到内存中，并不是将整个文件读到内存中。&lt;br /&gt;
	2.在Mysql的jdbc驱动中也可以使用NIO技术对数据库进行操作来提升系统的性能。&lt;/p&gt;
&lt;p&gt;	&lt;strong&gt;长连接/Servlet3.0&lt;/strong&gt;&lt;br /&gt;
	这里说的长连接就是长轮询，以前浏览器(客户端)需要关注服务器端发生的数据变化需要不断的访问服务器，这样客户端的数量一多必然会给服务器端造成很大的压力，例如：论坛中的站内消息。现在Servlet3.0规范中提供了一个新的特性：异步IO通信；该特性会保持一个长连接。利用Servlet3异步请求的这项技术可以大大的缓解服务器端的压力。&lt;br /&gt;
	Servlet3.0的原理就是将request的请求开启一个线程挂起，中间设置等待超时的时间，如果后台事件触发request请求，得到的结果返回给客户端的request请求，如果在设置等待超时的时间内没有任何事件发生也将请求返回给客户端，客户端将再次发起request请求，客户端与服务器端的交互可以与此往复。&lt;br /&gt;
	就好比，你先过来跟我说如果有人找你，我就立马通知你你来见他，原先你需要不断的问我有没有要找你，而不管有没有人找你，你都需要不断的问我有没有人找你，这样的话不论问的人还是被问的人都会累死。&lt;/p&gt;
&lt;p&gt;	&lt;strong&gt;日志&lt;/strong&gt;&lt;br /&gt;
	Log4J是通常被人们使用的工具，系统在刚刚上线的时候日志一般都设置在INFO的级，真正上线后一般设置在ERROR级，但无论在任何时候，日志的输入内容都是需要关注的，开发人员一般可以依靠输出的日志查找出现的问题或者依靠输出的日志对系统的性能进行优化，日志也是系统运行状态的报告和排错的依据。&lt;br /&gt;
	简单来说日志按照定义的不同策略和等级输出到不同的环境，那样便于我们分析和管理。相反你没有策略的输出，那么机器一多，时间一长，会有一大推乱糟糟的日志，会让你排错的时候无从下手，所以日志的输出策略是使用日志的关键点。&lt;br /&gt;
	参考资料：&lt;a href=&quot;http://logging.apache.org/log4j/1.2/manual.html&quot;&gt;http://logging.apache.org/log4j/1.2/manual.html&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;	&lt;strong&gt;打包/部署&lt;/strong&gt;&lt;br /&gt;
	在代码设计的时候最好能将不同类型的功能模块在IDE环境中粗粒度的分为不同的工程，便于打成不同jar包部署在不同的环境中。有这样的一个应用场景：需要每天定时远程从SP那边获得当天100条新闻和部分城市的天气预报，虽然每天的数据量不多，但是前端访问的并发量很大，显然需要在系统架构上做到读写分离。&lt;br /&gt;
	如果把web工程和定时抓取的功能模块完全集中在一个工程里打包，将导致需要扩展的时候每台机器上既有web应用也有定时器，因为功能模块没有分开，每台机器上都有定时器工作将会造成数据库里面的数据重复。&lt;br /&gt;
	如果开发的时候就将web和定时器分为2个工程，打包的时候就可以分开部署，10台web对应一台定期器，分解了前端请求的压力，数据的写入也不会重复。&lt;br /&gt;
	这样做的另一个好处就是可以共用，在上述的场景中web和定时器都需要对数据库进行读取，那么web和定时器的工程里都有操作数据库的代码，在代码的逻辑上还是感觉乱乱的。如果再抽出一个DAL层的jar，web和定时器的应用模块开发者只需要引用DAL层的jar，开发相关的业务逻辑，面向接口编程，无需考虑具体的数据库操作，具体的对数据库操作由其他开发者完成，可以在开发任务分工上很明确，并且互不干涉。&lt;/p&gt;
&lt;p&gt;	&lt;strong&gt;框架&lt;/strong&gt;&lt;br /&gt;
	所谓流行的SSH(Struts/Spring/Hiberanet)轻量级框架,对于很多中小型项目而言一点都不轻量级，开发者不仅需要维护代码，还需要维护繁琐的xml配置文件，而且说不定某个配置文件写的不对就让整个都工程无法运行。无配置文件可以取代SSH(struts/Spring/Hiberanet)框架的产品真的太多了，我之前就向大家介绍过一些个产品(&lt;a href=&quot;http://www.javabloger.com/article/spring3-dbutils-mrpersister-dbcp-oscache.html?source=rss&quot;&gt;Ref&lt;/a&gt;)。&lt;br /&gt;
	这个我并不是一味的反对使用SSH(Struts/Spring/Hiberanet)框架，在我眼里SSH框架真的作用是做到了规范开发，而并不使用了SSH(Struts/Spring/Hiberanet)框架能提高多少性能。&lt;br /&gt;
	SSH框架只是对于非常大的项目人数上百人的团队，还需要、继续增加团队规模的公司而言，是需要选择一些市面上大家都认可，并且熟悉的技术，SSH(Struts/Spring/Hiberanet)框架比较成熟所以是首先产品。&lt;br /&gt;
	但是对于一些小团队中间有个把技术高人的团队而言完全可以选择更加简洁的框架，真正的做到提速你的开发效率，早日抛弃SSH框架选择更简洁的技术在小团队开发中是一种比较明知的选择。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;#8211;end&amp;#8211;&lt;/p&gt;&lt;img src=&quot;http://www1.feedsky.com/t1/584467536/javaBloger/feedsky/s.gif?r=http://item.feedsky.com/~feedsky/javaBloger/~8046889/584467536/6154110/1/item.html&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</content:encoded><wfw:commentRss>http://www.javabloger.com/article/java-development-concern-those-things.html/feed</wfw:commentRss><slash:comments>6</slash:comments><description>近期各家IT媒体举办的业内技术大会让很多网站都在披露自己的技术内幕与同行们分享，大到facebook，百度，小到刚起步的网站。facebook，百度之类的大型网站采用的技术和超凡的处理能力的确给人耳目一新的感觉，但并不是每个网站都是像facebook，百度 有上亿的用户访问流量，有海量的数据需要存储，需要使用到mapreduce/并行计算，HBase/列存储这些技术不可。技术手段始终是运营的支撑，对于当前的运营环境适用就好，没有必要非要赶个时髦，一定要和某项流行的技术产生点关系才善罢甘休。
	在最近的技术大会中我们更多的目光都聚焦在这些大型网站，其实中小型门户网站的技术体系也是值得去探讨和关注。全天下的攻城师们并不是都在为这些大型门户网站服务，更多的攻城师们正在默默无闻的为一些刚刚起步的中小型网站服务，而且占据了攻城师队伍中的60%以上的人群。在关注大型门户网站的时候，中小型门户网站的技术发展和实战经验更值得去分享。
	无论大型门户网站还是中小型垂直类型网站都会对稳定性、性能和可伸缩性有所追求。大型网站的技术经验分享值得我们去学习和借用，但落实到更具体的实践上并不是对所有网站可以适用,其他语言开发的网站我还不敢多说，但Java开发的系统，我还是能您给插上几句话：
	JVM
	JEE容器中运行的JVM参数配置参数的正确使用直接关系到整个系统的性能和处理能力，JVM的调优主要是对内存管理方面的调优，优化的方向分为以下4点：
	1.HeapSize&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; 堆的大小，也可以说Java虚拟机使用内存的策略，这点是非常关键的。
	2.GarbageCollector&amp;#160; 通过配置相关的参数进行Java中的垃圾收集器的4个算法(策略)进行使用。
	3.StackSize&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; 栈是JVM的内存指令区,每个线程都有他自己的Stack，Stack的大小限制着线程的数量。
	4.DeBug/Log&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; 在JVM中还可以设置对JVM运行时的日志和JVM挂掉后的日志输出，这点非常的关键，根据各类JVM的日志输出才能配置合适的参数。
	网上随处可见JVM的配置技巧，但是我还是推荐阅读Sun官方的2篇文章，可以对配置参数的其所依然有一个了解
	1.Java HotSpot VM Options http://www.oracle.com/technetwork/java/javase/tech/vmoptions-jsp-140102.html
	2.Troubleshooting Guide for Java SE 6 with HotSpot VM http://www.oracle.com/technetwork/java/javase/index-137495.html
	另外，我相信不是每个人攻城师都是天天对着这些JVM参数的，如果你忘记了那些关键的参数你可以输入Java -X(大写X)进行提示。
	JDBC
	针对MySQL的JDBC的参数在之前的文章中也有介绍过，在单台机器或者集群的环境下合理的使用JDBC中的配置参数对操作数据库也有很大的影响。
	一些所谓高性能的 Java ORM开源框架也就是打开了很多JDBC中的默认参数：
	&amp;#160;1.例如：autoReconnect、prepStmtCacheSize、cachePrepStmts、useNewIO、blobSendChunkSize 等，
	&amp;#160;2.例如集群环境下：roundRobinLoadBalance、failOverReadOnly、autoReconnectForPools、secondsBeforeRetryMaster。
	具体内容可以参阅MySQL的JDBC官方使用手册：
	http://dev.mysql.com/doc/refman/5.1/zh/connectors.html#cj-jdbc-reference
	数据库连接池(DataSource)
	应用程序与数据库连接频繁的交互会给系统带来瓶颈和大量的开销会影响到系统的性能，JDBC连接池负责分配、管理和释放数据库连接，它允许应用程序重复使用一个现有的数据库连接，而再不是重新建立一个连接，因此应用程序不需要频繁的与数据库开关连接，并且可以释放空闲时间超过最大空闲时间的数据库连接来避免因为没有释放数据库连接而引起的数据库连接遗漏。这项技术能明显提高对数据库操作的性能。
	在此我认为有一点需要说明：
	连接池的使用也是需要关闭，因为在数据库连接池启动的时候就预先和数据库获得了相应的连接，之后不再需要应用程序直接的和数据库打交道，因为应用程序使用数据库连接池是一个&amp;#8220;借&amp;#8221;的概念，应用程序从数据库连接池中获得资源是&amp;#8220;借出&amp;#8221;，还需要还回去，就好比有20个水桶放在这里，需要拿水的人都可以使用这些木桶从水池里面拿水，如果20个人都拿完水，不将水桶还回原地，那么后面来的人再需要拿水，只能在旁边等待有人将木桶还回去，之前的人用完后需要放回去，不然后面的人就会一直等待，造成资源堵塞，同理，应用程序获取数据库连接的时候Connection连接对象的时候是从&amp;#8220;池&amp;#8221;中分配一个数据库连接出去，在使用完毕后，归还这个数据库连接，这样才能保持数据库的连接&amp;#8220;有借有还&amp;#8221;准则。 
	参考资料：
	http://dev.mysql.com/doc/refman/5.1/zh/connectors.html#cj-connection-pooling
	数据存取
	数据库服务器的优化和数据的存取，什么类型的数据放在什么地方更好是值得去思考的问题，将来的存储很可能是混用的，Cache，NOSQL，DFS，DataBase 在一个系统中都会有，生活的餐具和平日里穿衣服需要摆放在家里，但是不会用同一种类型的家具存放，貌似没有那个人家把餐具和衣服放在同一个柜子里面的。这就像是系统中不同类型的数据一样，对不同类型的数据需要使用合适的存储环境。文件和图片的存储，首先按照访问的热度分类，或者按照文件的大小。强关系类型并且需要事务支持的采用传统的数据库，弱关系型不需要事务支持的可以考虑NOSQL，海量文件存储可以考虑一下支持网络存储的DFS，至于缓存要看你单个数据存储的大小和读写的比例。
	还有一点值得注意就是数据读写分离，无论在DataBase还是NOSQL的环境中大部分都是读大于写，因此在设计时还需考虑 不仅仅需要让数据的读分散在多台机器上，还需要考虑多台机器之间的数据一致性，MySQL的一主多从，在加上MySQL-Proxy或者借用JDBC中的一些参数(roundRobinLoadBalance、failOverReadOnly、autoReconnectForPools、secondsBeforeRetryMaster)对后续应用程序开发，可以将读和写分离，将大量读的压力分散在多台机器上，并且还保证了数据的一致性。
	缓存
	在宏观上看缓存一般分为2种：本地缓存和分布式缓存
	1.本地缓存，对于Java的本地缓存而言就是讲数据放入静态(static)的数据结合中，然后需要用的时候就从静态数据结合中拿出来,对于高并发的环境建议使用 ConcurrentHashMap或者CopyOnWriteArrayList作为本地缓存。缓存的使用更具体点说就是对系统内存的使用，使用多少内存的资源需要有一个适当比例，如果超过适当的使用存储访问，将会适得其反，导致整个系统的运行效率低下。
	2. 分布式缓存，一般用于分布式的环境，将每台机器上的缓存进行集中化的存储，并且不仅仅用于缓存的使用范畴，还可以作为分布式系统数据同步/传输的一种手段，一般被使用最多的就是Memcached和Redis。
	数据存储在不同的介质上读/写得到的效率是不同的，在系统中如何善用缓存，让你的数据更靠近cpu，下面有一张图你需要永远牢记在心里，来自Google的技术大牛Jeff Dean(Ref)的杰作，如图所示：
	
	并发/多线程
	在高并发环境下建议开发者使用JDK中自带的并发包(java.util.concurrent)，在JDK1.5以后使用java.util.concurrent下的工具类可以简化多线程开发，在java.util.concurrent的工具中主要分为以下几个主要部分：
	1.线程池，线程池的接口(Executor、ExecutorService)与实现类(ThreadPoolExecutor、 ScheduledThreadPoolExecutor），利用jdk自带的线程池框架可以管理任务的排队和安排，并允许受控制的关闭。因为运行一个线程需要消耗系统CPU资源，而创建、结束一个线程也对系统CPU资源有开销，使用线程池不仅仅可以有效的管理多线程的使用，还是可以提高线程的运行效率。
	2.本地队列，提供了高效的、可伸缩的、线程安全的非阻塞 FIFO 队列。java.util.concurrent 中的五个实现都支持扩展的 BlockingQueue 接口，该接口定义了 put 和 take 的阻塞版本：LinkedBlockingQueue、ArrayBlockingQueue、SynchronousQueue、PriorityBlockingQueue 和 DelayQueue。这些不同的类覆盖了生产者-使用者、消息传递、并行任务执行和相关并发设计的大多数常见使用的上下文。
	3.同步器，四个类可协助实现常见的专用同步语句。Semaphore 是一个经典的并发工具。CountDownLatch 是一个极其简单但又极其常用的实用工具，用于在保持给定数目的信号、事件或条件前阻塞执行。CyclicBarrier 是一个可重置的多路同步点，在某些并行编程风格中很有用。Exchanger 允许两个线程在 collection 点交换对象，它在多流水线设计中是有用的。
	4.并发包 Collection，此包还提供了设计用于多线程上下文中的 Collection 实现：ConcurrentHashMap、ConcurrentSkipListMap、ConcurrentSkipListSet、CopyOnWriteArrayList 和 CopyOnWriteArraySet。当期望许多线程访问一个给定 collection 时，ConcurrentHashMap 通常优于同步的 [...]&lt;img src=&quot;http://www1.feedsky.com/t1/584467536/javaBloger/feedsky/s.gif?r=http://item.feedsky.com/~feedsky/javaBloger/~8046889/584467536/6154110/1/item.html&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</description><category>NIO</category><category>架构设计</category><category>NoSQL</category><category>openmq</category><category>性能</category><category>MQ</category><category>J2EE框架</category><category>Java消息中间件</category><category>数据库</category><category>Thread-Pool</category><category>JVM</category><pubDate>Sun, 15 May 2011 20:11:26 +0800</pubDate><author>H.E.</author><comments>http://www.javabloger.com/article/java-development-concern-those-things.html#comments</comments><guid isPermaLink="false">http://www.javabloger.com/?p=1590</guid><dc:creator>H.E.</dc:creator><fs:srclink>http://www.javabloger.com/article/java-development-concern-those-things.html?source=rss</fs:srclink><fs:srcfeed>http://www.javabloger.com/index.php/feed/</fs:srcfeed><fs:itemid>feedsky/javaBloger/~8046889/584467536/6154110</fs:itemid></item><item><title>巧用zookeeper实现分布式并行计算</title><link>http://item.feedsky.com/~feedsky/javaBloger/~8046889/584467537/6154110/1/item.html</link><content:encoded>&lt;p&gt;云计算的技术话题中少不了&amp;ldquo;分布式&amp;rdquo;，&amp;ldquo;并行计算&amp;rdquo; 这些个关键词，我们知道硬件扩展的条件(​Scale-up)始终是有限制的，将计算分散到网络中更多机器的CPU上提供更高的计算性能(Scale-out)，并在这基础上能将计算同时进行，那么总体计算瓶颈会减小，计算的性能会显著提高，也就是说将串行计算变为并行计算，将大量的计算在同一时间发生，，将任务分配到每一个处理器上。这里面需要一个重要的角色，分布式计算资源中的协调者。&lt;/p&gt;
&lt;p&gt;	&lt;strong&gt;有这样一个场景：&lt;/strong&gt;系统中有大约100w的用户，每个用户平均有3个邮箱账号，每隔5分钟，每个邮箱账需要收取100封邮件，最多3亿份邮件需要下载到服务器中(不含附件和正文)。用20台机器划分计算的压力，从多个不同的网路出口进行访问外网，计算的压力得到缓解，那么每台机器的计算压力也不会很大了。&lt;/p&gt;
&lt;p&gt;	通过我们的讨论和以往的经验判断在这场景中可以实现并行计算，但我们还期望能对并行计算的节点进行动态的添加/删除，做到在线更新并行计算的数目并且不会影响计算单元中的其他计算节点，但是有4个问题需要解决，否则会出现一些严重的问题：&lt;br /&gt;
	1.20台机器同时工作时，有一台机器down掉了，其他机器怎么进行接管计算任务，否则有些用户的业务不会被处理，造成用户服务终断。&lt;br /&gt;
	2.随着用户数量增加，添加机器是可以解决计算的瓶颈，但需要重启所有计算节点，如果需要，那么将会造成整个系统的不可用。&lt;br /&gt;
	3.用户数量增加或者减少，计算节点中的机器会出现有的机器资源使用率繁忙，有的却空闲，因为计算节点不知道彼此的运行负载状态。&lt;br /&gt;
	4.怎么去通知每个节点彼此的负载状态，怎么保证通知每个计算节点方式的可靠性和实时性。&lt;/p&gt;
&lt;p&gt;	先不说那么多专业名词，白话来说我们需要的是：1记录状态，2事件通知 ，3可靠稳定的中央调度器，4易上手、管理简单。&lt;br /&gt;
	采用Zookeeper完全可以解决我们的问题，分布式计算中的协调员，观察者，分布式锁&amp;nbsp; 都可以作为zookeeper的关键词，在系统中利用Zookeeper来处理事件通知,队列,优先队列,锁,共享锁等功能，利用这些特色在分布式计算中发挥重要的作用。&lt;/p&gt;
&lt;p&gt;	zookeeper的服务器端是采用Java编写，而zookeeper的客户端不仅可以支持java还可以支持C语言的客户端，在zookeeper服务端可以创建一个树状的Key/Vaule 存在着父子节点之间的关系。&lt;/p&gt;
&lt;p&gt;	Zookeeper允许多个Client对一个或多个ZNode数据进行监控，当ZNode有变化时能够通知到监控这个ZNode的各个Client，所有监听这个节点的成员都会知道了，Zookeeper使用Watcher察觉事件信息,当客户端接收到事件信息,比如连接超时,节点数据改变,子节点改变,可以调用相应的行为来处理业务逻辑。&lt;u&gt;相反，如果zookeeper客户端对服务端的znode不关注，不Watcher，那么发生任何变化zookeeper的客户端都不会收到事件通知。&lt;/u&gt;&lt;/p&gt;
&lt;p&gt;	zookeeper中znode的数据模型&lt;br /&gt;
	&lt;img alt=&quot;data model&quot; src=&quot;http://hadoop.apache.org/zookeeper/docs/r3.1.1/images/zknamespace.jpg&quot; /&gt;&lt;/p&gt;
&lt;p&gt;	每次zookeeper客户端与服务器端连接后都会创建一个session ID 给客户端，客户端将会定期心跳协议到服务器端验证这个连接的有效性。如果由于某种原因，客户端无法发送心跳到服务器，将导致服务器验证过期的会话，会话ID将变为无效。客户持有的连接/对象将不可用，因此应用程序必须创建一个新的客户对象。如果zookeeper客户端连接到服务器没有任何响应，首先客户端会作抛出的异常并且被捕获，清除当前与Server相关的网络资源和连接会话，然后客户端逐个尝试配置列表中Server的连接地址，选择可用的服务器继续进行工作。&lt;/p&gt;
&lt;p&gt;	上述Zookeeper客户端和服务器端的关系又是一个典型的&amp;ldquo;观察者&amp;rdquo;模式，客户端关注自己关心的对象(znode)，一旦发送变化就立刻通知。在《Head First设计模式》中有这样的一张图来表达 观察者模式的。&lt;br /&gt;
	&lt;img alt=&quot;“观察者”模式&quot; height=&quot;360&quot; src=&quot;http://l99eaa.bay.livefilestore.com/y1pWX-wdyRGXiRQxy5ER2pFnfPicAHFEi3_ydLEAUSrKQmN-z0-72kIdNGdVC2FKyeTMl8wLvQU7xhf7r8pn9-S6US7N_85hQrz/DesignPattern-observer-1.jpg&quot; width=&quot;600&quot; /&gt;&lt;br /&gt;
	如图所示，此系统中的三个部分是气象站(获取实际气象数据的物理装置)、WeatherData对象(追踪来自气象站的数据，并更新布告板)和布告板,再来看看百度百科对&amp;ldquo;观察者&amp;rdquo;模式的解释：&lt;u&gt;http://baike.baidu.com/view/1854779.htm&lt;/u&gt;&lt;/p&gt;
&lt;p&gt;	通过对Zookeeper的了解，实现我们系统中需要的Failure detection和Load detection 功能，只需要在每个计算的节点中实现zookeeper客户端程序，计算节点关注zookeeper服务器上znode节点变化。可以在zookeeper服务器的znode上创建一个根节点/clusterA,下面根据计算节点机器名创建对应的子节点，子节点中的value就是这台计算节点的ip地址。&lt;br /&gt;
	如：/clusterA/node1,/clusterA/node2,/clusterA/nodeN,这些节点都是临时节点(EPHEMERAL)，一旦连接断开，创建的节点自动会被删除，关注/clusterA这个根节点/clusterA的机器都会知道现在哪台机器离开计算单元了，并且获知现在有多少个计算节点在这个计算单元中。&lt;br /&gt;
	如果有新的计算节点添加，在程序运行的第一步将会到zookeeper服务器上的/clusterA 的znode上创建一个子节点/clusterA/nodeZ，这样关注 /clusterA这个znode的机器都会知道现在多了一个计算节点。&lt;br /&gt;
	通过zookeeper客户端API中的getChildren()方法对应的数据类型是java.util.List,其返回/clusterA下面的机器列表，这样还能判断出自己在这个列表中排行位置，通过列表中排行位置可以对应用户列表中的数目，这样就知道自己去获得需要计算总数中的几分之分。&lt;br /&gt;
	例如：有100w用户，20个节点时，每个节点处理5w用户进行同时计算，node3计算节点承载用户总数中10w-15w用户之间的计算压力，有200w用户，20个节点时，每个节点处理10w个用户的业务进行同时计算，node3计算节点承载用户总数中30w-40w用户的计算压力，以此类推。&lt;br /&gt;
	这样一来无论计算节点的数目发生变化还是，需要计算的数目发生变化，都可以保证计算压力的平均分载。 &lt;/p&gt;
&lt;p&gt;	&lt;strong&gt;我的废话：&lt;/strong&gt;&lt;br /&gt;
	&lt;strong&gt;1.&lt;/strong&gt;根据节点数对应用户数算出百分比之后进行计算分载，貌似我们通常的分页查询，只不过将每页的分页结果同时显示在N多个显示器上输出，希望这样比喻能让您更好的理解。&lt;br /&gt;
	&lt;strong&gt;2.&lt;/strong&gt;在计算的中间有新的用户数量增加，将会通知每个计算节点 下次轮询时需要重新统计用户数量，因为用户所有用户的数据分块拿走以后放入本地的静态hashmap(缓存)，没有发生变化就从本地加载，操作数据库发生变化后，通知zookeeper的znode节点 每个计算节点重新从数据库中加载一次。&lt;br /&gt;
	&lt;strong&gt;3.&lt;/strong&gt;在并行计算中时间同步也是一个需要注意的地方，如果每台机器上的时间不一致会导致潜在的隐患，可以找些工具通过时间服务器同步每台机器上的当前时间和时区。&lt;br /&gt;
	&lt;strong&gt;4.&lt;/strong&gt;使用zookeeper对计算节点的状态管理只是zookeeper实现的一部分，zookeeper还可以对外提供分组，配置管理，命名空间等服务等，这里只是做了一个抛砖引玉的作用。&lt;/p&gt;
&lt;p&gt;
	对于zookeeper的可靠性和性能而言，有足够的机器那么稳定性就会越高，但是性能会降低，因为ZooKeeper在运行时全部的数据都会加载到内存中，集群中每一台服务器都包含全量的数据，每个节点实时保持数据的同步。因此整个集群中Follower数量越多，整个集群写入的性能越差。后来zookeeper Server为了避免这个问题，可以将ZooKeeper集群中部分服务器指定为Observer。&lt;/p&gt;
&lt;p&gt;	&lt;strong&gt;相关文章：&lt;/strong&gt;&lt;br /&gt;
	&lt;a href=&quot;../article/apache-zookeeper-hbase-hadoop-3.html&quot;&gt;Apache ZooKeeper入门3 &lt;/a&gt; &lt;br /&gt;
	&lt;a href=&quot;../article/zookeeper-hapood-apache.html&quot;&gt;Apache ZooKeeper入门2 &lt;/a&gt; &lt;br /&gt;
	&lt;a href=&quot;../article/apache-zookeeper-hadoop.html&quot;&gt;Apache Zookeeper入门1 &lt;/a&gt; &lt;/p&gt;
&lt;p&gt;
	&amp;#8211;end&amp;#8211;&lt;/p&gt;&lt;img src=&quot;http://www1.feedsky.com/t1/584467537/javaBloger/feedsky/s.gif?r=http://item.feedsky.com/~feedsky/javaBloger/~8046889/584467537/6154110/1/item.html&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</content:encoded><wfw:commentRss>http://www.javabloger.com/article/zookeeper-parallel-computing.html/feed</wfw:commentRss><slash:comments>0</slash:comments><description>云计算的技术话题中少不了&amp;#8220;分布式&amp;#8221;，&amp;#8220;并行计算&amp;#8221; 这些个关键词，我们知道硬件扩展的条件(​Scale-up)始终是有限制的，将计算分散到网络中更多机器的CPU上提供更高的计算性能(Scale-out)，并在这基础上能将计算同时进行，那么总体计算瓶颈会减小，计算的性能会显著提高，也就是说将串行计算变为并行计算，将大量的计算在同一时间发生，，将任务分配到每一个处理器上。这里面需要一个重要的角色，分布式计算资源中的协调者。
	有这样一个场景：系统中有大约100w的用户，每个用户平均有3个邮箱账号，每隔5分钟，每个邮箱账需要收取100封邮件，最多3亿份邮件需要下载到服务器中(不含附件和正文)。用20台机器划分计算的压力，从多个不同的网路出口进行访问外网，计算的压力得到缓解，那么每台机器的计算压力也不会很大了。
	通过我们的讨论和以往的经验判断在这场景中可以实现并行计算，但我们还期望能对并行计算的节点进行动态的添加/删除，做到在线更新并行计算的数目并且不会影响计算单元中的其他计算节点，但是有4个问题需要解决，否则会出现一些严重的问题：
	1.20台机器同时工作时，有一台机器down掉了，其他机器怎么进行接管计算任务，否则有些用户的业务不会被处理，造成用户服务终断。
	2.随着用户数量增加，添加机器是可以解决计算的瓶颈，但需要重启所有计算节点，如果需要，那么将会造成整个系统的不可用。
	3.用户数量增加或者减少，计算节点中的机器会出现有的机器资源使用率繁忙，有的却空闲，因为计算节点不知道彼此的运行负载状态。
	4.怎么去通知每个节点彼此的负载状态，怎么保证通知每个计算节点方式的可靠性和实时性。
	先不说那么多专业名词，白话来说我们需要的是：1记录状态，2事件通知 ，3可靠稳定的中央调度器，4易上手、管理简单。
	采用Zookeeper完全可以解决我们的问题，分布式计算中的协调员，观察者，分布式锁&amp;#160; 都可以作为zookeeper的关键词，在系统中利用Zookeeper来处理事件通知,队列,优先队列,锁,共享锁等功能，利用这些特色在分布式计算中发挥重要的作用。
	zookeeper的服务器端是采用Java编写，而zookeeper的客户端不仅可以支持java还可以支持C语言的客户端，在zookeeper服务端可以创建一个树状的Key/Vaule 存在着父子节点之间的关系。
	Zookeeper允许多个Client对一个或多个ZNode数据进行监控，当ZNode有变化时能够通知到监控这个ZNode的各个Client，所有监听这个节点的成员都会知道了，Zookeeper使用Watcher察觉事件信息,当客户端接收到事件信息,比如连接超时,节点数据改变,子节点改变,可以调用相应的行为来处理业务逻辑。相反，如果zookeeper客户端对服务端的znode不关注，不Watcher，那么发生任何变化zookeeper的客户端都不会收到事件通知。
	zookeeper中znode的数据模型
	
	每次zookeeper客户端与服务器端连接后都会创建一个session ID 给客户端，客户端将会定期心跳协议到服务器端验证这个连接的有效性。如果由于某种原因，客户端无法发送心跳到服务器，将导致服务器验证过期的会话，会话ID将变为无效。客户持有的连接/对象将不可用，因此应用程序必须创建一个新的客户对象。如果zookeeper客户端连接到服务器没有任何响应，首先客户端会作抛出的异常并且被捕获，清除当前与Server相关的网络资源和连接会话，然后客户端逐个尝试配置列表中Server的连接地址，选择可用的服务器继续进行工作。
	上述Zookeeper客户端和服务器端的关系又是一个典型的&amp;#8220;观察者&amp;#8221;模式，客户端关注自己关心的对象(znode)，一旦发送变化就立刻通知。在《Head First设计模式》中有这样的一张图来表达 观察者模式的。
	
	如图所示，此系统中的三个部分是气象站(获取实际气象数据的物理装置)、WeatherData对象(追踪来自气象站的数据，并更新布告板)和布告板,再来看看百度百科对&amp;#8220;观察者&amp;#8221;模式的解释：http://baike.baidu.com/view/1854779.htm
	通过对Zookeeper的了解，实现我们系统中需要的Failure detection和Load detection 功能，只需要在每个计算的节点中实现zookeeper客户端程序，计算节点关注zookeeper服务器上znode节点变化。可以在zookeeper服务器的znode上创建一个根节点/clusterA,下面根据计算节点机器名创建对应的子节点，子节点中的value就是这台计算节点的ip地址。
	如：/clusterA/node1,/clusterA/node2,/clusterA/nodeN,这些节点都是临时节点(EPHEMERAL)，一旦连接断开，创建的节点自动会被删除，关注/clusterA这个根节点/clusterA的机器都会知道现在哪台机器离开计算单元了，并且获知现在有多少个计算节点在这个计算单元中。
	如果有新的计算节点添加，在程序运行的第一步将会到zookeeper服务器上的/clusterA 的znode上创建一个子节点/clusterA/nodeZ，这样关注 /clusterA这个znode的机器都会知道现在多了一个计算节点。
	通过zookeeper客户端API中的getChildren()方法对应的数据类型是java.util.List,其返回/clusterA下面的机器列表，这样还能判断出自己在这个列表中排行位置，通过列表中排行位置可以对应用户列表中的数目，这样就知道自己去获得需要计算总数中的几分之分。
	例如：有100w用户，20个节点时，每个节点处理5w用户进行同时计算，node3计算节点承载用户总数中10w-15w用户之间的计算压力，有200w用户，20个节点时，每个节点处理10w个用户的业务进行同时计算，node3计算节点承载用户总数中30w-40w用户的计算压力，以此类推。
	这样一来无论计算节点的数目发生变化还是，需要计算的数目发生变化，都可以保证计算压力的平均分载。 
	我的废话：
	1.根据节点数对应用户数算出百分比之后进行计算分载，貌似我们通常的分页查询，只不过将每页的分页结果同时显示在N多个显示器上输出，希望这样比喻能让您更好的理解。
	2.在计算的中间有新的用户数量增加，将会通知每个计算节点 下次轮询时需要重新统计用户数量，因为用户所有用户的数据分块拿走以后放入本地的静态hashmap(缓存)，没有发生变化就从本地加载，操作数据库发生变化后，通知zookeeper的znode节点 每个计算节点重新从数据库中加载一次。
	3.在并行计算中时间同步也是一个需要注意的地方，如果每台机器上的时间不一致会导致潜在的隐患，可以找些工具通过时间服务器同步每台机器上的当前时间和时区。
	4.使用zookeeper对计算节点的状态管理只是zookeeper实现的一部分，zookeeper还可以对外提供分组，配置管理，命名空间等服务等，这里只是做了一个抛砖引玉的作用。

	对于zookeeper的可靠性和性能而言，有足够的机器那么稳定性就会越高，但是性能会降低，因为ZooKeeper在运行时全部的数据都会加载到内存中，集群中每一台服务器都包含全量的数据，每个节点实时保持数据的同步。因此整个集群中Follower数量越多，整个集群写入的性能越差。后来zookeeper Server为了避免这个问题，可以将ZooKeeper集群中部分服务器指定为Observer。
	相关文章：
	Apache ZooKeeper入门3  
	Apache ZooKeeper入门2  
	Apache Zookeeper入门1  

	&amp;#8211;end&amp;#8211;&lt;img src=&quot;http://www1.feedsky.com/t1/584467537/javaBloger/feedsky/s.gif?r=http://item.feedsky.com/~feedsky/javaBloger/~8046889/584467537/6154110/1/item.html&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</description><category>架构设计</category><category>云计算</category><category>zookeeper-client</category><category>Scale-out</category><category>性能</category><category>分布式</category><category>zookeeper</category><pubDate>Mon, 25 Apr 2011 10:05:36 +0800</pubDate><author>H.E.</author><comments>http://www.javabloger.com/article/zookeeper-parallel-computing.html#comments</comments><guid isPermaLink="false">http://www.javabloger.com/?p=1572</guid><dc:creator>H.E.</dc:creator><fs:srclink>http://www.javabloger.com/article/zookeeper-parallel-computing.html?source=rss</fs:srclink><fs:srcfeed>http://www.javabloger.com/index.php/feed/</fs:srcfeed><fs:itemid>feedsky/javaBloger/~8046889/584467537/6154110</fs:itemid></item><item><title>JDBC操作MySQL产生的read-only连接异常</title><link>http://item.feedsky.com/~feedsky/javaBloger/~8046889/584467538/6154110/1/item.html</link><content:encoded>&lt;p&gt;对于Java(JEE)的攻城师来说，使用JDBC操作MySQL数据库是再平常不过的事儿了，但是你知道吗？在MySQL的JDBC驱动里还要很多配置参数，例如：autoReconnectForPools/failOverReadOnly/queriesBeforeRetryMaster/secondsBeforeRetryMaster 这些参数对双机或者集群环境是很有用的，昨天在就发生了一些MySQL运维的事儿，而这几个参数也引起了我们的关注。&lt;/p&gt;
&lt;p&gt;	我的废话：&lt;span style=&quot;color: rgb(255, 0, 0);&quot;&gt;&lt;u&gt;MySQL的JDBC参数加起来有百来个&lt;/u&gt;&lt;/span&gt;，分为6大类，更多详情请查阅，&lt;a href=&quot;http://javabloger-mini-books.googlecode.com/files/MySQL-JDBC%E4%BD%BF%E7%94%A8%E6%89%8B%E5%86%8C.pdf&quot;&gt;《MySQL-JDBC连接器使用手册》&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;	我们有一个生产环境的数据库是MySQL双主，12台JEE应用服务器对MySQL先读再写的轮训操作。昨天运维的人员需要对数据库机器添加内存，添加内存的事儿显然是需要对数据库服务器进行开关机，一拨人负责一台，两台服务器很快内存升级完毕，MySQL服务器也正常工作了。&lt;/p&gt;
&lt;p&gt;	但回头发现无法执行业务操作，12台应用服务器抛出全部Cause: java.sql.SQLException: Connection is read-only 异常。之前我们没有动应用服务器啊，只是重启数据库服务器按理说应该等数据库服务器重启完毕以后应用服务器会自动重连正常工作了。&lt;br /&gt;
	由于时间紧迫需要立即恢复，没有办法，我们对12台应用服务器重启了一下，天下太平，世界又恢复平静了。当时没时间去研究个究竟到底是什么原因导致，但我知道如果再次遇到这样的类似场景还是出现同样的问题，所以需要找出问题的根本原因，给自己一个解释。&lt;/p&gt;
&lt;p&gt;	在MySQL的官方网站上找了一些可能性的依据，原因是设置了autoReconnectForPools=true参数，导致failOverReadOnly参数默认生效。原来failOverReadOnly的默认值是true，导致失效重新连接后出现&amp;nbsp; Cause: java.sql.SQLException: Connection is read-only. Queries leading to data modification are not allowed 的错误。&lt;/p&gt;
&lt;p&gt;	&lt;a href=&quot;http://public.bay.livefilestore.com/y1pNy84T-HBEpNNLrQa3NuaHQvYPPcZtt9J-x26E-ymooAL9JTUh1c3oSlUocuNysjSvi4noqdImU_iAUi3OymOKQ/mysql-jdbc.png?psid=1&quot; target=&quot;_blank&quot;&gt;&lt;img alt=&quot;“Starting with Connector/J 3.1.7, we've made available a variant of the driver that will automatically send queries to a read/write master,or a failover or round-robin loadbalanced set of slaves based on the state of Connection.getReadOnly() .”&quot; src=&quot;http://public.bay.livefilestore.com/y1pNy84T-HBEpNNLrQa3NuaHQvYPPcZtt9J-x26E-ymooAL9JTUh1c3oSlUocuNysjSvi4noqdImU_iAUi3OymOKQ/mysql-jdbc.png?psid=1&quot; /&gt;&lt;/a&gt;&lt;br /&gt;
	看了官方文档中的上面这段话为何是ReadOnly的状态也很能理解是为什么了，其实MySQL官方倡导的是Master-To-Slave的数据库备份方案,而我们的运行环境是Master-To-Master，如果前一个Master挂掉的话 往Slave中去写，等到Master恢复再对Master操作的时候数据就沉于大海，那么数据就不一致了，恢复起来会非常的麻烦，当前一个挂掉的时候，MySQL驱动会认为你的Master挂了，如果继续写将会写入Slave，所以默认的状态是ReadOnly=true，失败后重连，但重连后对下一台操作的是只读(ReadOnly)。&lt;/p&gt;
&lt;p&gt;	后来我们在测试环境中也重现了这个错误，然后加上failOverReadOnly=false，并且加上了queriesBeforeRetryMaster 和secondsBeforeRetryMaster 配置参数缩短切换和重试之间的时间长度。这两个参数是表示如果出现故障切换(使用多主机故障切换)并返回主机之前发出的查询数。无论首先满足了哪个条件，&amp;ldquo;queriesBeforeRetryMaster&amp;rdquo;或&amp;ldquo;secondsBeforeRetryMaster&amp;rdquo;，均会再次与主机进行连接，secondsBeforeRetryMaster是表示 出现故障切换后，在尝试再次连接到主服务器。&lt;/p&gt;
&lt;p&gt;	在测试环境中无论怎么重试、重启或者重连，世界很平静，哥很淡定，才能现在有空写这个blog，将整个过程记录下来。等下次需要停机或者重启的时候将这个参数加上，现已经记录在下个版本的发布计划中了。另外，我整理了一份JDBC操作MySQL的文档，方面日后查阅，&lt;a href=&quot;http://javabloger-mini-books.googlecode.com/files/MySQL-JDBC%E4%BD%BF%E7%94%A8%E6%89%8B%E5%86%8C.pdf&quot; target=&quot;_blank&quot;&gt;下载地址&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;相关文章：&lt;/strong&gt;&lt;br /&gt;
	&lt;a href=&quot;../article/mysql-jdbc-autoreconnectforpools.html&quot;&gt;MySQL JDBC中autoReconnectForPools的用途 &lt;/a&gt; &lt;br /&gt;
	&lt;a href=&quot;../article/jdbc-mysql-loadbalance.html&quot;&gt;MySQL JDBC 集群 &lt;/a&gt; &lt;/p&gt;
&lt;p&gt;
	&amp;#8211;end&amp;#8211;&lt;/p&gt;&lt;img src=&quot;http://www1.feedsky.com/t1/584467538/javaBloger/feedsky/s.gif?r=http://item.feedsky.com/~feedsky/javaBloger/~8046889/584467538/6154110/1/item.html&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</content:encoded><wfw:commentRss>http://www.javabloger.com/article/mysql-read-only-ibatis-dbcp-hibernate.html/feed</wfw:commentRss><slash:comments>4</slash:comments><description>对于Java(JEE)的攻城师来说，使用JDBC操作MySQL数据库是再平常不过的事儿了，但是你知道吗？在MySQL的JDBC驱动里还要很多配置参数，例如：autoReconnectForPools/failOverReadOnly/queriesBeforeRetryMaster/secondsBeforeRetryMaster 这些参数对双机或者集群环境是很有用的，昨天在就发生了一些MySQL运维的事儿，而这几个参数也引起了我们的关注。
	我的废话：MySQL的JDBC参数加起来有百来个，分为6大类，更多详情请查阅，《MySQL-JDBC连接器使用手册》。
	我们有一个生产环境的数据库是MySQL双主，12台JEE应用服务器对MySQL先读再写的轮训操作。昨天运维的人员需要对数据库机器添加内存，添加内存的事儿显然是需要对数据库服务器进行开关机，一拨人负责一台，两台服务器很快内存升级完毕，MySQL服务器也正常工作了。
	但回头发现无法执行业务操作，12台应用服务器抛出全部Cause: java.sql.SQLException: Connection is read-only 异常。之前我们没有动应用服务器啊，只是重启数据库服务器按理说应该等数据库服务器重启完毕以后应用服务器会自动重连正常工作了。
	由于时间紧迫需要立即恢复，没有办法，我们对12台应用服务器重启了一下，天下太平，世界又恢复平静了。当时没时间去研究个究竟到底是什么原因导致，但我知道如果再次遇到这样的类似场景还是出现同样的问题，所以需要找出问题的根本原因，给自己一个解释。
	在MySQL的官方网站上找了一些可能性的依据，原因是设置了autoReconnectForPools=true参数，导致failOverReadOnly参数默认生效。原来failOverReadOnly的默认值是true，导致失效重新连接后出现&amp;#160; Cause: java.sql.SQLException: Connection is read-only. Queries leading to data modification are not allowed 的错误。
	
	看了官方文档中的上面这段话为何是ReadOnly的状态也很能理解是为什么了，其实MySQL官方倡导的是Master-To-Slave的数据库备份方案,而我们的运行环境是Master-To-Master，如果前一个Master挂掉的话 往Slave中去写，等到Master恢复再对Master操作的时候数据就沉于大海，那么数据就不一致了，恢复起来会非常的麻烦，当前一个挂掉的时候，MySQL驱动会认为你的Master挂了，如果继续写将会写入Slave，所以默认的状态是ReadOnly=true，失败后重连，但重连后对下一台操作的是只读(ReadOnly)。
	后来我们在测试环境中也重现了这个错误，然后加上failOverReadOnly=false，并且加上了queriesBeforeRetryMaster 和secondsBeforeRetryMaster 配置参数缩短切换和重试之间的时间长度。这两个参数是表示如果出现故障切换(使用多主机故障切换)并返回主机之前发出的查询数。无论首先满足了哪个条件，&amp;#8220;queriesBeforeRetryMaster&amp;#8221;或&amp;#8220;secondsBeforeRetryMaster&amp;#8221;，均会再次与主机进行连接，secondsBeforeRetryMaster是表示 出现故障切换后，在尝试再次连接到主服务器。
	在测试环境中无论怎么重试、重启或者重连，世界很平静，哥很淡定，才能现在有空写这个blog，将整个过程记录下来。等下次需要停机或者重启的时候将这个参数加上，现已经记录在下个版本的发布计划中了。另外，我整理了一份JDBC操作MySQL的文档，方面日后查阅，下载地址。
相关文章：
	MySQL JDBC中autoReconnectForPools的用途  
	MySQL JDBC 集群  

	&amp;#8211;end&amp;#8211;&lt;img src=&quot;http://www1.feedsky.com/t1/584467538/javaBloger/feedsky/s.gif?r=http://item.feedsky.com/~feedsky/javaBloger/~8046889/584467538/6154110/1/item.html&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</description><category>OpenSource</category><category>架构设计</category><category>J2EE服务器</category><category>J2ee企业顾问</category><category>性能</category><category>MiddleWare</category><category>存储</category><category>分布式</category><category>mysql-Connection-read-only</category><pubDate>Wed, 20 Apr 2011 17:06:14 +0800</pubDate><author>H.E.</author><comments>http://www.javabloger.com/article/mysql-read-only-ibatis-dbcp-hibernate.html#comments</comments><guid isPermaLink="false">http://www.javabloger.com/?p=1561</guid><dc:creator>H.E.</dc:creator><fs:srclink>http://www.javabloger.com/article/mysql-read-only-ibatis-dbcp-hibernate.html?source=rss</fs:srclink><fs:srcfeed>http://www.javabloger.com/index.php/feed/</fs:srcfeed><fs:itemid>feedsky/javaBloger/~8046889/584467538/6154110</fs:itemid></item><item><title>山寨技术下的网站图片服务器(NGINX)</title><link>http://item.feedsky.com/~feedsky/javaBloger/~8046889/584467539/6154110/1/item.html</link><content:encoded>&lt;p&gt;网站数据存储需要做好前期的规划，不然数据量上来以后无论是管理还是性能上都带来很多问题，对于需要存储大量文件、图片的网站来说是个重点的话题，通常网页文字内容和网页图片内容 所占用的存储空间相比较的话，显然是图片存储占用的空间要远远超过网站文字内容所需要存储的空间，从另外一个角度上来看访问图片所占用的网络带宽要远远超过文字内容所占用的带宽。&lt;br /&gt;
	在系统运行上的瓶颈对于互联网用户来说往往不是落在系统内部计算的I/O瓶颈上，而是落在网络带宽的瓶颈上。把存储图片的服务器和访问图片服务器的网络入口独立出来，在条件允许的情况下给予更的高网络带宽和独立的域名，有利于扩展性和整体性能的发挥，将计算、存储的扩展性和带宽的资源做到合理分配，互不影响，是我们&lt;u&gt;当前&lt;/u&gt;的目标。&lt;/p&gt;
&lt;p&gt;	&lt;strong&gt;除此之外，还需要能做到：&lt;/strong&gt;&lt;br /&gt;
	&amp;nbsp; 1.使用廉价机器(老机器)构建分布式网络存储环境，支持150TB以上的存储容量，&lt;br /&gt;
	&amp;nbsp; 2.数据在线同步，支持文件副本复制，无明显的单点问题，可快速恢复故障节点，&lt;br /&gt;
	&amp;nbsp; 3.通用文件系统，不需要修改上层应用就可以使用(支持fuse)，web服务器可以直接读取分布式存储空间，无中间转取。&lt;br /&gt;
	&amp;nbsp; 4.支持在线不停机的情况下扩展存储的空间，&lt;br /&gt;
	&amp;nbsp; 5.随机读写的高效，并且支持海量小文件(5kb)的高效读写，&lt;br /&gt;
	&amp;nbsp; 6.可监控运行时的存储使用状态，最好是web界面。&lt;/p&gt;
&lt;p&gt;	得到了一些个解决方案，但依然不满足，对存储本身还有&lt;strong&gt;更高的期望：&lt;/strong&gt;&lt;br /&gt;
	&amp;nbsp;&amp;nbsp;&amp;nbsp; 1.需要避免图片文件重复的写入，建立图片存储的索引，根据唯一的图片文件名的查询后，再判断是否写入，&lt;br /&gt;
	&amp;nbsp;&amp;nbsp;&amp;nbsp; 2.小图片，签名照，小头像，表情图片 放在缓存里读取，让数据更靠近cpu，设计的黄金原则，我们尽量把能放入Redis缓存中的数据就在Redis里读取。&lt;br /&gt;
	&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br /&gt;
	&lt;strong&gt;架构介绍&lt;/strong&gt;&lt;br /&gt;
	&amp;nbsp; 1.负载均衡：HAproxy采用RoundRobin负载均衡算法，分载前端用户请求的压力到每个web图片服务器上，&lt;br /&gt;
	&amp;nbsp; 2.web服务：采用Nginx-0.9.6 做图片的web服务器，对网站的大、中、小图片进行读取，加上&lt;a href=&quot;http://wiki.nginx.org/HttpRedis&quot; target=&quot;_blank&quot;&gt;Nginx的Redis模块&lt;/a&gt;对缓存中的微型(头像)图片进行读取，&lt;br /&gt;
	&amp;nbsp; 3. 缓存服务器：存储网站的 微型图片，签名照，小头像，表情图片，通过Nginx的Redis模块直接读取，通过调用Redis的java API程序对数据进行写入，&lt;br /&gt;
	&amp;nbsp; 4.存储单元：采用Moosefs 存储&amp;nbsp; 大、中、小图片，并且提供监控管理界面，查看存储空间运行状态，&lt;br /&gt;
	&amp;nbsp; 5.图片索引：将图片名和图片url路径作为键值对(Key/Value)，放入HBase 中存储，并且进行数据查询，避免图片重复存储，便于将来管理，&lt;br /&gt;
	&amp;nbsp; 6.应用服务器：对图片写入的操作全部由Java应用服务器完成。&lt;/p&gt;
&lt;p&gt;	我们目前图片存储的系统架构，如图所示：&lt;br /&gt;
	&lt;a href=&quot;http://public.bay.livefilestore.com/y1pQju3-Tm6JmLCvh4uZ8pWQI9_c7aMuR9iyZoa8xD22jTS2UP41I-FH4Hyt32IX_mg_kM3lNa2T-PuNIk8owW-jQ/图片服务器.jpg&quot; target=&quot;_blank&quot;&gt;&lt;img alt=&quot;网站图片服务器架构&quot; height=&quot;401&quot; src=&quot;http://l99eaa.bay.livefilestore.com/y1pd1XPwHuyEeIpiG_0cmSXnZ81RnexrZSKcEi5MFe6HeJsk0UOj--s3tu2yxFcLgYFL-Vb-lGtbx6w1D4pdBVgen03q-iU2Urh/图片服务器.jpg&quot; width=&quot;600&quot; /&gt;&lt;/a&gt;&lt;br /&gt;
	&lt;a href=&quot;http://l99eaa.bay.livefilestore.com/y1p0r3WPO_V0BU7OVXHNM8HKEFEIQSIGL-BLYXIfTX_vhr91zCbN4Khq_7aDu-VPmeI6XPD9omywPY_BK2VCGHbDQw7TBt-jEhR/图片服务器.jpg?psid=1&quot; target=&quot;_blank&quot;&gt;查看大图请点击这里&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;	关于HBase的话题在这里就不多说了，可以参考我&lt;a href=&quot;http://www.javabloger.com/article/category/hbase?source=rss&quot;&gt;之前写的几篇文件文章&lt;/a&gt;，主要想说说&lt;strong&gt;Moosefs的体系&lt;/strong&gt;：&lt;br /&gt;
	&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 1 Master 管理服务器:负责各个数据存储服务器的管理,文件读写调度,文件空间回收以及恢复.多节点拷贝 &lt;br /&gt;
	&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 2 Chunk 元数据日志服务器: 负责备份master服务器的变化日志文件，文件类型为changelog_ml.*.mfs，以便于在master server出问题的时候接替其进行工作&lt;br /&gt;
	&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 3 Metalogger&amp;nbsp; 数据存储服务器:负责连接管理服务器,听从管理服务器调度,提供存储空间，并为客户提供数据传输. &lt;br /&gt;
	&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 4 Client&amp;nbsp; 客户端: 通过fuse内核接口挂接远程管理服务器上所管理的数据存储服务器,看起来共享的文件系统和本地unix文件系统使用一样的效果.&lt;/p&gt;
&lt;p&gt;	&lt;strong&gt;最有代表性的成功案例&lt;/strong&gt;&lt;br /&gt;
	&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 豆瓣网(Douban Inc),155 TB的存储空间，&amp;nbsp;&amp;nbsp; &lt;br /&gt;
	&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Master server: Gentoo Linux / ReiserFS 3.6&lt;br /&gt;
	&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 24 chunk servers: Gentoo Linux / ReiserFS / XFS&lt;br /&gt;
	&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 3 metalogger(s): Gentoo Linux / ReiserFS 3.6&lt;br /&gt;
	&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 37 client machines: Gentoo Linux&lt;/p&gt;
&lt;p&gt;	其实，采用某种技术只是一种具体实现的手段，或许从外界的统计数据来看 mogileFS、ceph、FastDFS 等其他产品具有更高的读写性能，甚至可以到满足我上述的任何一项要求，但我们所关注的侧重点不一样，要需要简单，易上手，够用就行，所以在这里利用Moosefs做了一个抛砖引玉。&lt;br /&gt;
	&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;#8211;end&amp;#8211;&lt;/p&gt;&lt;img src=&quot;http://www1.feedsky.com/t1/584467539/javaBloger/feedsky/s.gif?r=http://item.feedsky.com/~feedsky/javaBloger/~8046889/584467539/6154110/1/item.html&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</content:encoded><wfw:commentRss>http://www.javabloger.com/article/nginx-moosefs-hbase-haproxy.html/feed</wfw:commentRss><slash:comments>6</slash:comments><description>网站数据存储需要做好前期的规划，不然数据量上来以后无论是管理还是性能上都带来很多问题，对于需要存储大量文件、图片的网站来说是个重点的话题，通常网页文字内容和网页图片内容 所占用的存储空间相比较的话，显然是图片存储占用的空间要远远超过网站文字内容所需要存储的空间，从另外一个角度上来看访问图片所占用的网络带宽要远远超过文字内容所占用的带宽。
	在系统运行上的瓶颈对于互联网用户来说往往不是落在系统内部计算的I/O瓶颈上，而是落在网络带宽的瓶颈上。把存储图片的服务器和访问图片服务器的网络入口独立出来，在条件允许的情况下给予更的高网络带宽和独立的域名，有利于扩展性和整体性能的发挥，将计算、存储的扩展性和带宽的资源做到合理分配，互不影响，是我们当前的目标。
	除此之外，还需要能做到：
	&amp;#160; 1.使用廉价机器(老机器)构建分布式网络存储环境，支持150TB以上的存储容量，
	&amp;#160; 2.数据在线同步，支持文件副本复制，无明显的单点问题，可快速恢复故障节点，
	&amp;#160; 3.通用文件系统，不需要修改上层应用就可以使用(支持fuse)，web服务器可以直接读取分布式存储空间，无中间转取。
	&amp;#160; 4.支持在线不停机的情况下扩展存储的空间，
	&amp;#160; 5.随机读写的高效，并且支持海量小文件(5kb)的高效读写，
	&amp;#160; 6.可监控运行时的存储使用状态，最好是web界面。
	得到了一些个解决方案，但依然不满足，对存储本身还有更高的期望：
	&amp;#160;&amp;#160;&amp;#160; 1.需要避免图片文件重复的写入，建立图片存储的索引，根据唯一的图片文件名的查询后，再判断是否写入，
	&amp;#160;&amp;#160;&amp;#160; 2.小图片，签名照，小头像，表情图片 放在缓存里读取，让数据更靠近cpu，设计的黄金原则，我们尽量把能放入Redis缓存中的数据就在Redis里读取。
	&amp;#160;&amp;#160;&amp;#160; 
	架构介绍
	&amp;#160; 1.负载均衡：HAproxy采用RoundRobin负载均衡算法，分载前端用户请求的压力到每个web图片服务器上，
	&amp;#160; 2.web服务：采用Nginx-0.9.6 做图片的web服务器，对网站的大、中、小图片进行读取，加上Nginx的Redis模块对缓存中的微型(头像)图片进行读取，
	&amp;#160; 3. 缓存服务器：存储网站的 微型图片，签名照，小头像，表情图片，通过Nginx的Redis模块直接读取，通过调用Redis的java API程序对数据进行写入，
	&amp;#160; 4.存储单元：采用Moosefs 存储&amp;#160; 大、中、小图片，并且提供监控管理界面，查看存储空间运行状态，
	&amp;#160; 5.图片索引：将图片名和图片url路径作为键值对(Key/Value)，放入HBase 中存储，并且进行数据查询，避免图片重复存储，便于将来管理，
	&amp;#160; 6.应用服务器：对图片写入的操作全部由Java应用服务器完成。
	我们目前图片存储的系统架构，如图所示：
	
	查看大图请点击这里
	关于HBase的话题在这里就不多说了，可以参考我之前写的几篇文件文章，主要想说说Moosefs的体系：
	&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; 1 Master 管理服务器:负责各个数据存储服务器的管理,文件读写调度,文件空间回收以及恢复.多节点拷贝 
	&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; 2 Chunk 元数据日志服务器: 负责备份master服务器的变化日志文件，文件类型为changelog_ml.*.mfs，以便于在master server出问题的时候接替其进行工作
	&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; 3 Metalogger&amp;#160; 数据存储服务器:负责连接管理服务器,听从管理服务器调度,提供存储空间，并为客户提供数据传输. 
	&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; 4 Client&amp;#160; 客户端: 通过fuse内核接口挂接远程管理服务器上所管理的数据存储服务器,看起来共享的文件系统和本地unix文件系统使用一样的效果.
	最有代表性的成功案例
	&amp;#160;&amp;#160;&amp;#160;&amp;#160; 豆瓣网(Douban Inc),155 TB的存储空间，&amp;#160;&amp;#160; 
	&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; Master server: Gentoo Linux / ReiserFS 3.6
	&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; 24 chunk [...]&lt;img src=&quot;http://www1.feedsky.com/t1/584467539/javaBloger/feedsky/s.gif?r=http://item.feedsky.com/~feedsky/javaBloger/~8046889/584467539/6154110/1/item.html&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</description><category>OpenSource</category><category>架构设计</category><category>图片服务器解决方案</category><category>云计算</category><category>NoSQL</category><category>Linux/Unix</category><category>存储</category><category>redis</category><category>nginx-moosefs-hbase-haproxy</category><category>分布式</category><pubDate>Sat, 09 Apr 2011 10:11:23 +0800</pubDate><author>H.E.</author><comments>http://www.javabloger.com/article/nginx-moosefs-hbase-haproxy.html#comments</comments><guid isPermaLink="false">http://www.javabloger.com/?p=1557</guid><dc:creator>H.E.</dc:creator><fs:srclink>http://www.javabloger.com/article/nginx-moosefs-hbase-haproxy.html?source=rss</fs:srclink><fs:srcfeed>http://www.javabloger.com/index.php/feed/</fs:srcfeed><fs:itemid>feedsky/javaBloger/~8046889/584467539/6154110</fs:itemid></item><item><title>轻量级消息(MQ)服务器Kestrel 和 Redis</title><link>http://item.feedsky.com/~feedsky/javaBloger/~8046889/584467540/6154110/1/item.html</link><content:encoded>&lt;p&gt;Kestrel是twitter的开发团队用scala语言写的开源消息中间件，可以将消息持久存储到磁盘上，也可以将消息存储于内存中，但是不论保存磁盘还是内存中都可以设置消息存储的超期时间长短。&lt;br /&gt;
	原先Kestrel是由Ruby写的Starling项目，但是后来 twitter的开发人员尝试用scala重新实现，并且可以支持Memcached的部分协议，例如：GET、SET、FLUSH_ALL、STATS。对于Kestrel 服务器端而言如果有N个接收端连接在Kestrel服务器上，那么每个接收端会平均或者随机的收到不同的消息，并且发送端发过了消息接收端就算不接收，等到接收端再上去接收的时候还能收到消息，因为Kestrel支持消息持久化。&lt;br /&gt;
	Kestrel 不存在主从 和 集群的概念，只存在分布式的说法，这有点类似memcached 通过客户端组成一个环状，对于Kestrel 服务器端而言，如果服务器端收到消息了，但是里面有消息没有收下来就挂了，再重启的时候接收端还能收到之前的消息。&lt;/p&gt;
&lt;p&gt;	Redis是一个key/value存储系统,大多数开发者把他当做类似Memcached的缓存系统使用，&lt;br /&gt;
	Redis和MemCached区别的是：&lt;br /&gt;
	&amp;nbsp;&amp;nbsp;&amp;nbsp; 1.会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件&lt;br /&gt;
	&amp;nbsp;&amp;nbsp;&amp;nbsp; 2.对于我来说更重要的是Redis还实现了master-slave(主从)数据同步的功能。&lt;br /&gt;
	&amp;nbsp;&amp;nbsp;&amp;nbsp; 3.Redis不仅支持传统的存储的value类型，还可以支持list(链表)、set(集合)和zset(有序集合)，&lt;br /&gt;
	&amp;nbsp;&amp;nbsp;&amp;nbsp; 4.Redis还支持多种方式的排序，并且可以按照数据存储的范围来访问，有点像查询(select)，&lt;br /&gt;
	&amp;nbsp;&amp;nbsp;&amp;nbsp; 5.支持消息发布和订阅功能。&lt;/p&gt;
&lt;p&gt;	Redis也有我们对他不满意之处，例如：&lt;br /&gt;
	&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 1.对于同一个队列或者通道来说，有N个接收端连接在Redis服务器上，每个接收端会收到相同的消息。&lt;br /&gt;
	&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp; 2.发过了 你不接收 等接收端再上去消息就没有了，默认的配置是写在内存中，重启后不保存。&lt;br /&gt;
	这2点上跟 Kestrel 是相反的，但通过一些奇巧淫技将Redis消息视为缓存进行持久化，保证redis服务器重启后数据还在，并且通过Redis客户端动态设置机器的主从备份，只要有两台或以上的Redis做集群可以对数据永远有保证，除非服务器集群环境全挂，这样的话Redis还算是对数据提供了可靠性。&lt;br /&gt;
	但动态指定主从关系的话此时又会面临一致性的话题，在客户端指定Master的时候，为避免相互竞争或者重复指定，我们通过Jgroups工具作为Redis for Java客户端之间的通讯工具，在通讯过程中采用了&lt;a href=&quot;http://en.wikipedia.org/wiki/Paxos_%28computer_science%29&quot;&gt;Paxos算法&lt;/a&gt;，由客户端先选出一个Leader，再由这个选出来的Leader进行动态指定Redis集群中的master机器，这样可以提高一致性，避免竞争和冲突。&lt;/p&gt;
&lt;p&gt;	回到一开始说的Kestrel， 经过一番测试比较使用 xmemcached、spymemcached 等客户端对Kestrel进行收发操作，发现效果都比较烂，很遗憾没有找到让人满意的Kestrel for Java的客户端，所以我们一致认为使用Kestrel 这货将来的杯具估计产生在客户端(java)，也许Twitter使用的是ruby，是不是对ruby反而支持的很好？对Java支持的不够给力？Kestrel 接收端 需要不断的循环服务器 才能及时的收到消息， 这样节点数一多的话网络开销会不会很大？&lt;br /&gt;
	在测试的过程中，我们使用xmemcached作为客户端，貌似不太靠谱，开10个线程，循环1000次，表示鸭梨很大，出现以下异常信息，producer和consumer都有，而且同时冒出来。&lt;br /&gt;
	发送端：&lt;br /&gt;
	Exception in thread &amp;quot;main&amp;quot; java.util.concurrent.TimeoutException: Timed out(1000) waiting for operation&lt;br /&gt;
	接收端：&lt;br /&gt;
	Exception in thread &amp;quot;main&amp;quot; java.util.concurrent.TimeoutException: Timed out waiting for operation&lt;br /&gt;
	随后google之，作者提供了解答：http://code.google.com/p/xmemcached/issues/detail?id=108&lt;br /&gt;
	作者给出的解释是：&amp;ldquo;这主要是因为xmc的操作都是异步的，同步等待有个超时时间，默认的1秒在高并发或者存取大数据的时候通常是不够的。&amp;rdquo;晕啊，表示不能接受这样的解释。&lt;/p&gt;
&lt;p&gt;	随后目光开始关注Redis，Redis采用长连接，事件监听，不需要轮询，接收端等待消息，只接收字符串类型的消息，对消息的数据没有保证，不接收就没有了服务器端不保存，也不支持Queue的消息模式，就像JMS中的Topic消息那样一个发送端对应N个接收端每个接收端收到同样的消息。&lt;br /&gt;
	但我们将publish/subscribe和rpush/rpop 4个协议混合使用就可以完全满足我们的要求，客户端不轮训可以保证及时性和消息持久化的问题，而且还是Queue的模式。思路上通了后，做了压力测试，收发100w个消息开1000个线程，8秒以内搞定收发，表示毫无压力，体积小，部署简单比JMS方便，而且无单点，支持可散列。&lt;/p&gt;
&lt;p&gt;	在压力测试的过程中发现使用Redis Java客户端需要注意的两个问题：1.接收端莫名其妙的异常退出，这是由于没有设置连接空闲的超时导致的，就和MySQL的8小时问题一样，在Redis客户端设置一下config.setMaxIdle(num) 就好了。2.发送端由于发送大量请求会崩溃，出现超时错误，例如：JedisConnectionException: java.net.SocketTimeoutException: Read timed out，后来使用JedisPool和JedisPoolConfig实例，进行池化，一切都ok了，否则难以支持大数据量的高并发。&lt;/p&gt;
&lt;p&gt;	在系统中采用MQ是为了进行解耦合，用在2个环节上：&lt;br /&gt;
	&amp;nbsp;&amp;nbsp;&amp;nbsp; 1.系统中有大量数据并发写入，并且可以容忍一定的延时，那么就可以先存储缓存中，然后再将数据批量写入，降低DAL和数据库层每次通讯的开销。&lt;br /&gt;
	&amp;nbsp;&amp;nbsp;&amp;nbsp; 2.我们自己开发的分布式并行计算的定时器称为&amp;ldquo;任务工厂&amp;rdquo;(支持失败转发)，任务工厂从数据库或者缓存中拿用户的信息，将用户信息和业务逻辑框架作为消息，发送给各个不同的处理业务逻辑的服务器进行处理，那样1000w个用户的需要定时批量操作的话，任务工厂集群越大处理的速度就越快，而且如果有一个任务工厂的节点坏掉了或者又添加了一台新节点，轮询完毕后 重新计算一次后，每台机器又将平摊被分载的计算。&lt;/p&gt;
&lt;p&gt;	这次在实施的项目中，我们还专门设计了一个&amp;ldquo;失败队列&amp;rdquo;，他的作用是 处理具体业务逻辑的服务器 收到消息后将处理失败的请求放入&amp;ldquo;失败队列&amp;rdquo;中，往往消息在发送过来后进行处理，但是由于种种原因处理失败，但是下次还会再进来处理，这样的情况如果量大而且每次都这样的话对系统显然很不利，所以从原有的队列中移除这个用户请求，转移到&amp;ldquo;失败队列&amp;rdquo;中由 专门处理&amp;ldquo;失败队列&amp;rdquo;的任务工厂会去定时处理，如果这个账号轮训处理5次再失败，移除失败队列，存入数据库，进行管理员人工干预。&lt;/p&gt;
&lt;p&gt;	如果你真正的理解了MQ的工作原理，可以采用一些网络通信工具例如：netty、mina、grizzly&amp;nbsp; ，加上一些基于Key/Value的内存存储产品，例如memcached、redis ，自己可以是建造一个符合自己要求高效的轻量级MQ系统，如果说你可以失去一部分性能而换取可靠性的系统而言JMS依旧是首选产品。&lt;/p&gt;
&lt;p&gt;感谢作者 庄晓丹 的回复，内容如下：&lt;br /&gt;
	&amp;#8212;&amp;#8212;&amp;#8212;&amp;#8212;&amp;#8212;&amp;#8212;&amp;#8212;&amp;#8212;&amp;#8212;&amp;#8212;&amp;#8212;&amp;#8212;&amp;#8212;&amp;#8212;&amp;#8212;&amp;#8212;&amp;#8212;&amp;#8212;&amp;#8212;&amp;#8212;&amp;#8212;&amp;#8212;&amp;#8212;&amp;#8212;&amp;#8212;&amp;#8212;&amp;#8212;&amp;#8212;&amp;#8212;&amp;#8212;&amp;#8212;&amp;#8212;&amp;#8212;&amp;#8212;&amp;#8212;&amp;#8212;&amp;#8212;&amp;#8212;&amp;#8212;-&lt;br /&gt;
	&lt;strong&gt;1、&lt;/strong&gt;需要轮询，kestrel就是一个简单的push/pull模型，消费者只能通过pull轮询来获取消息。这个轮询的代价我认为很低的，取决于队列名称的大小，一般也就十几个字节一次请求。&lt;br /&gt;
	&lt;strong&gt;2、&lt;/strong&gt;超时的原因很多，通常来说跟你传输的消息大小、网络状况、kestrel的服务器状况都有关系，数据越大，在网络传输上耗费的时间越多，相应的越容易出现超时的情况。kestrel是scala写的，启动的时候要注意下jvm参数，如堆大小、gc算法之类，减少gc暂停带来的影响。服务器如果gc暂停，或者磁盘做刷入，都有可能导致响应超时，简单的做法就是将操作的超时时间加大，请注意，这个超时加大，不代表每个操作都要用这么多时间（可以统计平均看看），而是代表可以容许的最大超时时间。&lt;/p&gt;
&lt;div id=&quot;:xc&quot;&gt;kestrel整体来讲，只能作为一个轻量级的mq方案，&lt;wbr&gt;用在一些相对简单的场景。&amp;#8212;&amp;#8212;&amp;#8212;&amp;#8212;&amp;#8212;&amp;#8212;&amp;#8212;&amp;#8212;&amp;#8212;&amp;#8212;&amp;#8212;&amp;#8212;&amp;#8212;&amp;#8212;&amp;#8212;&amp;#8212;&amp;#8212;&amp;#8212;&amp;#8212;&amp;#8212;&amp;#8212;&amp;#8212;&amp;#8212;&amp;#8212;&amp;#8212;&amp;#8212;&amp;#8212;&amp;#8212;&amp;#8212;&amp;#8212;&amp;#8212;&amp;#8212;&amp;#8212;&amp;#8212;&amp;#8212;&amp;#8212;&amp;#8212;&amp;#8212;&amp;#8212;- &lt;/wbr&gt;&lt;/div&gt;
&lt;p&gt;&lt;wbr&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;&amp;#8211;end&amp;#8211;&lt;/div&gt;
&lt;p&gt;	&lt;/wbr&gt;&lt;/p&gt;&lt;img src=&quot;http://www1.feedsky.com/t1/584467540/javaBloger/feedsky/s.gif?r=http://item.feedsky.com/~feedsky/javaBloger/~8046889/584467540/6154110/1/item.html&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</content:encoded><wfw:commentRss>http://www.javabloger.com/article/mq-kestrel-redis-for-java.html/feed</wfw:commentRss><slash:comments>1</slash:comments><description>Kestrel是twitter的开发团队用scala语言写的开源消息中间件，可以将消息持久存储到磁盘上，也可以将消息存储于内存中，但是不论保存磁盘还是内存中都可以设置消息存储的超期时间长短。
	原先Kestrel是由Ruby写的Starling项目，但是后来 twitter的开发人员尝试用scala重新实现，并且可以支持Memcached的部分协议，例如：GET、SET、FLUSH_ALL、STATS。对于Kestrel 服务器端而言如果有N个接收端连接在Kestrel服务器上，那么每个接收端会平均或者随机的收到不同的消息，并且发送端发过了消息接收端就算不接收，等到接收端再上去接收的时候还能收到消息，因为Kestrel支持消息持久化。
	Kestrel 不存在主从 和 集群的概念，只存在分布式的说法，这有点类似memcached 通过客户端组成一个环状，对于Kestrel 服务器端而言，如果服务器端收到消息了，但是里面有消息没有收下来就挂了，再重启的时候接收端还能收到之前的消息。
	Redis是一个key/value存储系统,大多数开发者把他当做类似Memcached的缓存系统使用，
	Redis和MemCached区别的是：
	&amp;#160;&amp;#160;&amp;#160; 1.会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件
	&amp;#160;&amp;#160;&amp;#160; 2.对于我来说更重要的是Redis还实现了master-slave(主从)数据同步的功能。
	&amp;#160;&amp;#160;&amp;#160; 3.Redis不仅支持传统的存储的value类型，还可以支持list(链表)、set(集合)和zset(有序集合)，
	&amp;#160;&amp;#160;&amp;#160; 4.Redis还支持多种方式的排序，并且可以按照数据存储的范围来访问，有点像查询(select)，
	&amp;#160;&amp;#160;&amp;#160; 5.支持消息发布和订阅功能。
	Redis也有我们对他不满意之处，例如：
	&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; 1.对于同一个队列或者通道来说，有N个接收端连接在Redis服务器上，每个接收端会收到相同的消息。
	&amp;#160;&amp;#160; &amp;#160; &amp;#160;&amp;#160; 2.发过了 你不接收 等接收端再上去消息就没有了，默认的配置是写在内存中，重启后不保存。
	这2点上跟 Kestrel 是相反的，但通过一些奇巧淫技将Redis消息视为缓存进行持久化，保证redis服务器重启后数据还在，并且通过Redis客户端动态设置机器的主从备份，只要有两台或以上的Redis做集群可以对数据永远有保证，除非服务器集群环境全挂，这样的话Redis还算是对数据提供了可靠性。
	但动态指定主从关系的话此时又会面临一致性的话题，在客户端指定Master的时候，为避免相互竞争或者重复指定，我们通过Jgroups工具作为Redis for Java客户端之间的通讯工具，在通讯过程中采用了Paxos算法，由客户端先选出一个Leader，再由这个选出来的Leader进行动态指定Redis集群中的master机器，这样可以提高一致性，避免竞争和冲突。
	回到一开始说的Kestrel， 经过一番测试比较使用 xmemcached、spymemcached 等客户端对Kestrel进行收发操作，发现效果都比较烂，很遗憾没有找到让人满意的Kestrel for Java的客户端，所以我们一致认为使用Kestrel 这货将来的杯具估计产生在客户端(java)，也许Twitter使用的是ruby，是不是对ruby反而支持的很好？对Java支持的不够给力？Kestrel 接收端 需要不断的循环服务器 才能及时的收到消息， 这样节点数一多的话网络开销会不会很大？
	在测试的过程中，我们使用xmemcached作为客户端，貌似不太靠谱，开10个线程，循环1000次，表示鸭梨很大，出现以下异常信息，producer和consumer都有，而且同时冒出来。
	发送端：
	Exception in thread &amp;#34;main&amp;#34; java.util.concurrent.TimeoutException: Timed out(1000) waiting for operation
	接收端：
	Exception in thread &amp;#34;main&amp;#34; java.util.concurrent.TimeoutException: Timed out waiting for operation
	随后google之，作者提供了解答：http://code.google.com/p/xmemcached/issues/detail?id=108
	作者给出的解释是：&amp;#8220;这主要是因为xmc的操作都是异步的，同步等待有个超时时间，默认的1秒在高并发或者存取大数据的时候通常是不够的。&amp;#8221;晕啊，表示不能接受这样的解释。
	随后目光开始关注Redis，Redis采用长连接，事件监听，不需要轮询，接收端等待消息，只接收字符串类型的消息，对消息的数据没有保证，不接收就没有了服务器端不保存，也不支持Queue的消息模式，就像JMS中的Topic消息那样一个发送端对应N个接收端每个接收端收到同样的消息。
	但我们将publish/subscribe和rpush/rpop 4个协议混合使用就可以完全满足我们的要求，客户端不轮训可以保证及时性和消息持久化的问题，而且还是Queue的模式。思路上通了后，做了压力测试，收发100w个消息开1000个线程，8秒以内搞定收发，表示毫无压力，体积小，部署简单比JMS方便，而且无单点，支持可散列。
	在压力测试的过程中发现使用Redis Java客户端需要注意的两个问题：1.接收端莫名其妙的异常退出，这是由于没有设置连接空闲的超时导致的，就和MySQL的8小时问题一样，在Redis客户端设置一下config.setMaxIdle(num) 就好了。2.发送端由于发送大量请求会崩溃，出现超时错误，例如：JedisConnectionException: java.net.SocketTimeoutException: [...]&lt;img src=&quot;http://www1.feedsky.com/t1/584467540/javaBloger/feedsky/s.gif?r=http://item.feedsky.com/~feedsky/javaBloger/~8046889/584467540/6154110/1/item.html&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</description><category>Memcached</category><category>Kestrel</category><category>JMS</category><category>Jgroups</category><category>NoSQL</category><category>keyvalue</category><category>性能</category><category>存储</category><category>redis</category><category>分布式</category><pubDate>Mon, 04 Apr 2011 13:00:24 +0800</pubDate><author>H.E.</author><comments>http://www.javabloger.com/article/mq-kestrel-redis-for-java.html#comments</comments><guid isPermaLink="false">http://www.javabloger.com/?p=1552</guid><dc:creator>H.E.</dc:creator><fs:srclink>http://www.javabloger.com/article/mq-kestrel-redis-for-java.html?source=rss</fs:srclink><fs:srcfeed>http://www.javabloger.com/index.php/feed/</fs:srcfeed><fs:itemid>feedsky/javaBloger/~8046889/584467540/6154110</fs:itemid></item></channel></rss>
