﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-庄周梦蝶-随笔分类-Hadoop与分布式</title><link>http://www.blogjava.net/killme2008/category/33789.html</link><description>生活、程序、未来</description><language>zh-cn</language><lastBuildDate>Mon, 04 Jun 2012 02:56:46 GMT</lastBuildDate><pubDate>Mon, 04 Jun 2012 02:56:46 GMT</pubDate><ttl>60</ttl><item><title>分布式消息中间件Metaq发布1.4.3</title><link>http://www.blogjava.net/killme2008/archive/2012/06/04/379895.html</link><dc:creator>dennis</dc:creator><author>dennis</author><pubDate>Mon, 04 Jun 2012 02:03:00 GMT</pubDate><guid>http://www.blogjava.net/killme2008/archive/2012/06/04/379895.html</guid><wfw:comment>http://www.blogjava.net/killme2008/comments/379895.html</wfw:comment><comments>http://www.blogjava.net/killme2008/archive/2012/06/04/379895.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/killme2008/comments/commentRss/379895.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/killme2008/services/trackbacks/379895.html</trackback:ping><description><![CDATA[<p style="margin: 0px; padding: 0px; font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; text-align: left; background-color: #f7f7f7; ">我们在维护的淘宝开源消息中间件的<a href="http://metaq.taobao.org/" style="color: #006699; ">metaq</a>的<a href="https://github.com/killme2008/Metamorphosis" style="color: #006699; ">github分支</a>，今天发布了1.4.2版本，主要做了如下改进：<br /><br />1.支持发送和订阅分离，可以细粒度地控制Broker或者某个Topic是否接收消息和接受订阅。服务端添加新选项acceptPublish和acceptSubscribe。<br /><br />2.更友好地关闭Broker，梳理关闭流程并通过JMX调用方法关闭替代原来简单的kill。<br /><br />3.更新<a href="https://github.com/killme2008/Metamorphosis/tree/master/contrib/python/meta-python" style="color: #006699; ">python客户端</a>到0.2版本，可以通过pip安装: &nbsp;pip install metaq<br /><br />4.发布ruby语言客户端<a href="https://github.com/killme2008/Metamorphosis/tree/master/contrib/ruby/meta-ruby" style="color: #006699; ">meta-ruby</a>&nbsp;0.1版本。<br /><br />5.其他小改进：升级gecko到1.1.1版本，升级quartz到2.1.4版本，添加集成测试工程和内部重构等。<br /><br />6.新文档<a href="https://github.com/killme2008/Metamorphosis/wiki/%E4%BD%BF%E7%94%A8Log4j%E6%89%A9%E5%B1%95%E5%8F%91%E9%80%81%E6%B6%88%E6%81%AF">《使用log4j扩展发送消息》</a><br /><br />简介：<a href="https://github.com/killme2008/Metamorphosis/wiki/%E4%BB%8B%E7%BB%8D" style="color: #006699; ">https://github.com/killme2008/Metamorphosis/wiki/介绍</a><br />下载：<a href="https://github.com/killme2008/Metamorphosis/downloads" style="color: #006699; ">https://github.com/killme2008/Metamorphosis/downloads</a></p><p style="margin: 0px; padding: 0px; font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25px; text-align: left; background-color: #f7f7f7; ">文档：<a href="https://github.com/killme2008/Metamorphosis/wiki" style="color: #006699; ">https://github.com/killme2008/Metamorphosis/wiki</a></p><img src ="http://www.blogjava.net/killme2008/aggbug/379895.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/killme2008/" target="_blank">dennis</a> 2012-06-04 10:03 <a href="http://www.blogjava.net/killme2008/archive/2012/06/04/379895.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>分布式消息中间件Metaq发布1.4.2</title><link>http://www.blogjava.net/killme2008/archive/2012/05/09/377748.html</link><dc:creator>dennis</dc:creator><author>dennis</author><pubDate>Wed, 09 May 2012 14:47:00 GMT</pubDate><guid>http://www.blogjava.net/killme2008/archive/2012/05/09/377748.html</guid><wfw:comment>http://www.blogjava.net/killme2008/comments/377748.html</wfw:comment><comments>http://www.blogjava.net/killme2008/archive/2012/05/09/377748.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/killme2008/comments/commentRss/377748.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/killme2008/services/trackbacks/377748.html</trackback:ping><description><![CDATA[<br />
&nbsp; &nbsp; <a href="https://github.com/killme2008/Metamorphosis/wiki/For_Developer">我们</a>在维护的淘宝开源消息中间件的<a href="https://github.com/killme2008/Metamorphosis">metaq</a>的github分支，今天发布了1.4.2版本，主要做了如下改进：<br />
<br />&nbsp; &nbsp; 1.添加了大量的使用和原理文档，参见<a href="https://github.com/killme2008/Metamorphosis/wiki">Wiki</a>。<br />&nbsp; &nbsp; 2.合并tools和server-wrapper工程，提供统一的脚本来管理Broker，管理Broker的工作变得非常容易，全部工作都可以通过metaServer.sh的脚本来执行。同时提供了bat启动脚本，用于在windows上启动Broker做测试。<br />&nbsp; &nbsp; 3.新功能：<br />&nbsp; &nbsp;（1）新的客户端API用来获取topic的分区列表<br />&nbsp; &nbsp;（2）新的客户端API用来获取Broker的统计信息<br />&nbsp; &nbsp;（3）异步复制的Slave可以自动获取Master的配置变更，例如Master在配置文件中新增或者删除了topic并顺利reload热加载成功后，slave可自动复制或者移除变更的topic，无需重启。<br />&nbsp; &nbsp;（4）新的统计项目，可以通过'stats config'协议获取Broker的配置文件。<br />&nbsp; &nbsp; 4.添加meta-python项目，一个python的客户端，暂时仅支持发送消息功能。<br />&nbsp; &nbsp; 5.其他小改进，如统计信息的优化、构建工具的整合等。<br />
<br />&nbsp; &nbsp; 更详细的发行日志请看<a href="https://github.com/killme2008/Metamorphosis/wiki/ReleaseNotes">RelaseNotes</a>。<br />
<br />&nbsp; &nbsp; 下载地址： &nbsp;<a href="https://github.com/killme2008/Metamorphosis/downloads">https://github.com/killme2008/Metamorphosis/downloads<br /></a>&nbsp; &nbsp; 入门指南： &nbsp;《<a href="https://github.com/killme2008/Metamorphosis/wiki/%E5%A6%82%E4%BD%95%E5%BC%80%E5%A7%8B">如何开始</a>》<br />&nbsp; &nbsp; 更多文档请看<a href="https://github.com/killme2008/Metamorphosis/wiki">Wiki</a>。<img src ="http://www.blogjava.net/killme2008/aggbug/377748.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/killme2008/" target="_blank">dennis</a> 2012-05-09 22:47 <a href="http://www.blogjava.net/killme2008/archive/2012/05/09/377748.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>淘宝开源MQ——metaq的详细文档</title><link>http://www.blogjava.net/killme2008/archive/2012/04/13/374110.html</link><dc:creator>dennis</dc:creator><author>dennis</author><pubDate>Fri, 13 Apr 2012 14:43:00 GMT</pubDate><guid>http://www.blogjava.net/killme2008/archive/2012/04/13/374110.html</guid><wfw:comment>http://www.blogjava.net/killme2008/comments/374110.html</wfw:comment><comments>http://www.blogjava.net/killme2008/archive/2012/04/13/374110.html#Feedback</comments><slash:comments>7</slash:comments><wfw:commentRss>http://www.blogjava.net/killme2008/comments/commentRss/374110.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/killme2008/services/trackbacks/374110.html</trackback:ping><description><![CDATA[<br />
<span style="font-size: 10pt; ">&nbsp; &nbsp; 最近陆陆续续补充了不少</span><a href="https://github.com/killme2008/Metamorphosis"><span style="font-size: 10pt; ">metaq</span></a><span style="font-size: 10pt; ">的文档，部分是直接从官方文档里摘抄出来，放在了</span><a href="https://github.com/killme2008/Metamorphosis/wiki"><span style="font-size: 10pt; ">github工程的wiki页</span></a><span style="font-size: 10pt; ">，有兴趣了解甚至使用meta的可以仔细阅读下，一份目录：</span>
<div id="wiki-content" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; border-image: initial; font: inherit; color: #333333; font-family: Helvetica, arial, freesans, clean, sans-serif; background-color: #ffffff; ">
<div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; border-image: initial; font: inherit; ">
<div id="wiki-body"  instapaper_body"="" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; border-image: initial; font: inherit; ">
<div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; border-image: initial; font: inherit; ">
<ul style="margin-top: 15px; margin-right: 0px; margin-bottom: 15px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 30px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; border-image: initial; font: inherit; ">
     <li style="margin-top: 15px; margin-right: 0px; margin-bottom: 15px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; border-image: initial; font-size: 14px; font: inherit; "><a href="https://github.com/killme2008/Metamorphosis/wiki/%E4%BB%8B%E7%BB%8D" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; border-image: initial; font-size: 14px; font: inherit; color: #4183c4; text-decoration: none; "><span style="font-size: 10pt; ">介绍</span></a></li>
     <li style="margin-top: 15px; margin-right: 0px; margin-bottom: 15px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; border-image: initial; font-size: 14px; font: inherit; "><a href="https://github.com/killme2008/Metamorphosis/wiki/%E6%A6%82%E5%BF%B5%E5%92%8C%E6%9C%AF%E8%AF%AD" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; border-image: initial; font-size: 14px; font: inherit; color: #4183c4; text-decoration: none; "><span style="font-size: 10pt; ">基础概念和术语定义</span></a></li>
     <li style="margin-top: 15px; margin-right: 0px; margin-bottom: 15px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; border-image: initial; font-size: 14px; font: inherit; "><a href="https://github.com/killme2008/Metamorphosis/wiki/%E6%B6%88%E6%81%AF%E7%9A%84%E5%8F%AF%E9%9D%A0%E6%80%A7%E3%80%81%E9%A1%BA%E5%BA%8F%E5%92%8C%E9%87%8D%E5%A4%8D" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; border-image: initial; font-size: 14px; font: inherit; color: #4183c4; text-decoration: none; "><span style="font-size: 10pt; ">消息的可靠性、顺序和重复</span></a></li>
     <li style="margin-top: 15px; margin-right: 0px; margin-bottom: 15px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; border-image: initial; font-size: 14px; font: inherit; "><a href="https://github.com/killme2008/Metamorphosis/wiki/%E5%A6%82%E4%BD%95%E5%BC%80%E5%A7%8B" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; border-image: initial; font-size: 14px; font: inherit; color: #4183c4; text-decoration: none; "><span style="font-size: 10pt; ">如何开始</span></a></li>
     <li style="margin-top: 15px; margin-right: 0px; margin-bottom: 15px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; border-image: initial; font-size: 14px; font: inherit; "><a href="https://github.com/killme2008/Metamorphosis/wiki/%E7%AE%80%E5%8D%95%E4%BE%8B%E5%AD%90" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; border-image: initial; font-size: 14px; font: inherit; color: #4183c4; text-decoration: none; "><span style="font-size: 10pt; ">简单例子</span></a></li>
     <li style="margin-top: 15px; margin-right: 0px; margin-bottom: 15px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; border-image: initial; font-size: 14px; font: inherit; "><a href="https://github.com/killme2008/Metamorphosis/wiki/%E9%85%8D%E7%BD%AE%E7%AE%A1%E7%90%86" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; border-image: initial; font-size: 14px; font: inherit; color: #4183c4; text-decoration: none; "><span style="font-size: 10pt; ">服务端配置管理</span></a></li>
     <li style="margin-top: 15px; margin-right: 0px; margin-bottom: 15px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; border-image: initial; font-size: 14px; font: inherit; "><a href="https://github.com/killme2008/Metamorphosis/wiki/%E9%9B%86%E7%BE%A4%E5%92%8C%E8%B4%9F%E8%BD%BD%E5%9D%87%E8%A1%A1" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; border-image: initial; font-size: 14px; font: inherit; color: #4183c4; text-decoration: none; "><span style="font-size: 10pt; ">集群和负载均衡</span></a></li>
     <li style="margin-top: 15px; margin-right: 0px; margin-bottom: 15px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; border-image: initial; font-size: 14px; font: inherit; "><a href="https://github.com/killme2008/Metamorphosis/wiki/HA" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; border-image: initial; font-size: 14px; font: inherit; color: #4183c4; text-decoration: none; "><span style="font-size: 10pt; ">高可用配置(异步复制和同步复制)</span></a></li>
     <li style="margin-top: 15px; margin-right: 0px; margin-bottom: 15px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; border-image: initial; font-size: 14px; font: inherit; "><a href="https://github.com/killme2008/Metamorphosis/wiki/roadmap" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; border-image: initial; font-size: 14px; font: inherit; color: #4183c4; text-decoration: none; "><span style="font-size: 10pt; ">路线图</span></a></li>
     <li style="margin-top: 15px; margin-right: 0px; margin-bottom: 15px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; border-image: initial; font-size: 14px; font: inherit; "><a href="https://github.com/killme2008/Metamorphosis/wiki/Faq-chinese" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; border-image: initial; font-size: 14px; font: inherit; color: #4183c4; text-decoration: none; "><span style="font-size: 10pt; ">FAQ</span></a></li>
     <li style="margin-top: 15px; margin-right: 0px; margin-bottom: 15px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; border-image: initial; font-size: 14px; font: inherit; "><a href="https://github.com/killme2008/Metamorphosis/wiki/%E6%9C%80%E4%BD%B3%E5%AE%9E%E8%B7%B5" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; border-image: initial; font-size: 14px; font: inherit; color: #4183c4; text-decoration: none; "><span style="font-size: 10pt; ">最佳实践</span></a></li>
     <li style="margin-top: 15px; margin-right: 0px; margin-bottom: 15px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; border-image: initial; font-size: 14px; font: inherit; "><a href="http://code.taobao.org/p/metamorphosis/file/2154/%E8%AF%A6%E7%BB%86%E6%89%8B%E5%86%8C.docx" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; border-image: initial; font-size: 14px; font: inherit; color: #4183c4; text-decoration: none; "><span style="font-size: 10pt; ">官方手册(word文档)</span></a></li>
</ul>
<h1 style="line-height: 1.6; "><span style="font-size: 10pt; ">&nbsp; &nbsp; Developer</span></h1>
<ul style="margin-top: 15px; margin-right: 0px; margin-bottom: 15px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 30px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; border-image: initial; font: inherit; ">
     <li style="margin-top: 15px; margin-right: 0px; margin-bottom: 15px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; border-image: initial; font-size: 14px; font: inherit; "><a href="https://github.com/killme2008/Metamorphosis/wiki/For_Developer" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; border-image: initial; font-size: 14px; font: inherit; color: #4183c4; text-decoration: none; "><span style="font-size: 10pt; ">参与贡献</span></a></li>
     <li style="margin-top: 15px; margin-right: 0px; margin-bottom: 15px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; border-image: initial; font-size: 14px; font: inherit; "><a href="https://github.com/killme2008/Metamorphosis/wiki/design" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; border-image: initial; font-size: 14px; font: inherit; color: #4183c4; text-decoration: none; "><span style="font-size: 10pt; ">设计</span></a></li>
     <li style="margin-top: 15px; margin-right: 0px; margin-bottom: 15px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; border-image: initial; font-size: 14px; font: inherit; "><a href="https://github.com/killme2008/Metamorphosis/wiki/%E5%8D%8F%E8%AE%AE" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; border-image: initial; font-size: 14px; font: inherit; color: #4183c4; text-decoration: none; "><span style="font-size: 10pt; ">通讯协议</span></a></li>
     <li style="margin-top: 15px; margin-right: 0px; margin-bottom: 15px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; border-image: initial; font-size: 14px; font: inherit; "><a href="https://github.com/killme2008/Metamorphosis/wiki/%E6%B6%88%E6%81%AF%E7%9A%84%E5%AD%98%E5%82%A8" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; border-image: initial; font-size: 14px; font: inherit; color: #4183c4; text-decoration: none; "><span style="font-size: 10pt; ">消息的存储</span></a></li>
</ul>
<h1 style="line-height: 1.6; "><span style="font-size: 10pt; ">关联项目</span></h1>
<ul style="margin-top: 15px; margin-right: 0px; margin-bottom: 0px !important; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 30px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; border-image: initial; font: inherit; ">
     <li style="margin-top: 15px; margin-right: 0px; margin-bottom: 15px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; border-image: initial; font-size: 14px; font: inherit; "><a href="https://github.com/killme2008/metamorphosis-example" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; border-image: initial; font-size: 14px; font: inherit; color: #4183c4; text-decoration: none; "><span style="font-size: 10pt; ">metamorphosis-example</span></a><span style="font-size: 10pt; ">:示例项目</span></li>
     <li style="margin-top: 15px; margin-right: 0px; margin-bottom: 15px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; border-image: initial; font-size: 14px; font: inherit; "><a href="https://github.com/killme2008/storm-metamorphosis-spout" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; border-image: initial; font-size: 14px; font: inherit; color: #4183c4; text-decoration: none; "><span style="font-size: 10pt; ">storm-metamorphosis-spout</span></a><span style="font-size: 10pt; ">:使用metamorphosis作为twitter storm的spout源</span></li>
     <li style="margin-top: 15px; margin-right: 0px; margin-bottom: 15px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; border-image: initial; font-size: 14px; font: inherit; "><a href="https://github.com/killme2008/meta-python" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; border-image: initial; font-size: 14px; font: inherit; color: #4183c4; text-decoration: none; "><span style="font-size: 10pt; ">meta-python</span></a><span style="font-size: 10pt; ">: metamorphosis的python语言客户端。目前只支持发送消息功能。</span></li>
</ul>
</div>
</div>
</div>
</div>
<div id="gollum-footer" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; border-image: initial; font: inherit; line-height: 19px; color: #333333; font-family: Helvetica, arial, freesans, clean, sans-serif; background-color: #ffffff; "></div>
&nbsp; &nbsp;&nbsp;<br />
<div><span style="font-size: 10pt; ">&nbsp; &nbsp; 后续还会继续补充。</span><br />
</div><img src ="http://www.blogjava.net/killme2008/aggbug/374110.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/killme2008/" target="_blank">dennis</a> 2012-04-13 22:43 <a href="http://www.blogjava.net/killme2008/archive/2012/04/13/374110.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>淘宝开源metaq的python客户端</title><link>http://www.blogjava.net/killme2008/archive/2012/03/21/372405.html</link><dc:creator>dennis</dc:creator><author>dennis</author><pubDate>Wed, 21 Mar 2012 11:08:00 GMT</pubDate><guid>http://www.blogjava.net/killme2008/archive/2012/03/21/372405.html</guid><wfw:comment>http://www.blogjava.net/killme2008/comments/372405.html</wfw:comment><comments>http://www.blogjava.net/killme2008/archive/2012/03/21/372405.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/killme2008/comments/commentRss/372405.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/killme2008/services/trackbacks/372405.html</trackback:ping><description><![CDATA[&nbsp; &nbsp; 前面一篇博客介绍了我在github上的一个<a href="https://github.com/killme2008/Metamorphosis">metaq</a>分支，今天下午写了个metaq的python客户端，目前仅支持发送消息功能，不过麻雀虽小，五脏俱全，客户端和zookeeper的交互和连接管理之类都还具备，不出意外，我们会首先用上。第一次正儿八经地写python代码，写的不好的地方请尽管拍砖，多谢。<br />&nbsp; &nbsp; 项目叫meta-python，仍然放在github上：<a href="https://github.com/killme2008/meta-python">https://github.com/killme2008/meta-python<br /><br /></a>&nbsp; &nbsp; 使用需要先安装zkpython这个库，具体安装<a href="http://www.zlovezl.cn/articles/40/" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; border-image: initial; font: inherit; color: #4183c4; text-decoration: none; font-family: Helvetica, arial, freesans, clean, sans-serif; line-height: 22px; background-color: #ffffff; ">这篇博客</a>，使用很简单，发送消息：<br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />-->&nbsp; &nbsp;&nbsp;<span style="color: #0000FF; ">from</span>&nbsp;metamorphosis&nbsp;<span style="color: #0000FF; ">import</span>&nbsp;Message,MessageProducer,SendResult<br />&nbsp;&nbsp;&nbsp;&nbsp;p=MessageProducer(<span style="color: #800000; ">"</span><span style="color: #800000; ">topic</span><span style="color: #800000; ">"</span>)<br />&nbsp;&nbsp;&nbsp;&nbsp;message=Message(<span style="color: #800000; ">"</span><span style="color: #800000; ">topic</span><span style="color: #800000; ">"</span>,<span style="color: #800000; ">"</span><span style="color: #800000; ">message&nbsp;body</span><span style="color: #800000; ">"</span>)<br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">print</span>&nbsp;p.send(message)<br />&nbsp;&nbsp;&nbsp;&nbsp;p.close()</div><br />&nbsp; &nbsp;&nbsp;<div style="display: inline-block; ">MessageProducer就是消息发送者，它的构造函数接受至少一个topic，默认的zk_servers为localhost:2181，可以通过zk_servers参数指定你的zookeeper集群:<br /><br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />-->p=MessageProducer(<span style="color: #800000; ">"</span><span style="color: #800000; ">topic</span><span style="color: #800000; ">"</span>,zk_servers=<span style="color: #800000; ">"</span><span style="color: #800000; ">192.168.1.100:2191,192.168.1.101:2181</span><span style="color: #800000; ">"</span>)</div><span style="background-color: #eeeeee; "><br /></span><span style="background-color: #eeeeee; ">更多参数请直接看源码吧。一个本机的性能测试（meta和客户端都跑在我的机器上，机器是Mac MC700，osx 10.7，磁盘没有升级过）：<br /></span><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #0000FF; ">from</span>&nbsp;metamorphosis&nbsp;<span style="color: #0000FF; ">import</span>&nbsp;Message,MessageProducer<br /><span style="color: #0000FF; ">from</span>&nbsp;time&nbsp;<span style="color: #0000FF; ">import</span>&nbsp;time<br />p=MessageProducer(<span style="color: #800000; ">"</span><span style="color: #800000; ">avos-fetch-tasks</span><span style="color: #800000; ">"</span>)<br />message=Message(<span style="color: #800000; ">"</span><span style="color: #800000; ">avos-fetch-tasks</span><span style="color: #800000; ">"</span>,<span style="color: #800000; ">"</span><span style="color: #800000; ">http://www.taobao.com</span><span style="color: #800000; ">"</span>)<br />start=time()<br /><span style="color: #0000FF; ">for</span>&nbsp;i&nbsp;<span style="color: #0000FF; ">in</span>&nbsp;range(0,10000):<br />&nbsp;&nbsp;&nbsp;&nbsp;sent=p.send(message)<br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>&nbsp;<span style="color: #0000FF; ">not</span>&nbsp;sent.success:<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">print</span>&nbsp;<span style="color: #800000; ">"</span><span style="color: #800000; ">send&nbsp;failed</span><span style="color: #800000; ">"</span><br />finish=time()<br />secs=finish-start<br /><span style="color: #0000FF; ">print</span>&nbsp;<span style="color: #800000; ">"</span><span style="color: #800000; ">duration:%s&nbsp;seconds</span><span style="color: #800000; ">"</span>&nbsp;%&nbsp;(secs)<br /><span style="color: #0000FF; ">print</span>&nbsp;<span style="color: #800000; ">"</span><span style="color: #800000; ">tps:%s&nbsp;msgs/second</span><span style="color: #800000; ">"</span>&nbsp;%&nbsp;(10000/secs)<br />p.close()</div><span style="background-color: #eeeeee; "><br />&nbsp;结果：<br /><br /><br /></span><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />-->duration:1.85962295532&nbsp;seconds<br />tps:5377.43415749&nbsp;msgs/second</div></div><img src ="http://www.blogjava.net/killme2008/aggbug/372405.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/killme2008/" target="_blank">dennis</a> 2012-03-21 19:08 <a href="http://www.blogjava.net/killme2008/archive/2012/03/21/372405.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>淘宝开源MQ——metamorphosis的github分支</title><link>http://www.blogjava.net/killme2008/archive/2012/03/16/372019.html</link><dc:creator>dennis</dc:creator><author>dennis</author><pubDate>Fri, 16 Mar 2012 02:39:00 GMT</pubDate><guid>http://www.blogjava.net/killme2008/archive/2012/03/16/372019.html</guid><wfw:comment>http://www.blogjava.net/killme2008/comments/372019.html</wfw:comment><comments>http://www.blogjava.net/killme2008/archive/2012/03/16/372019.html#Feedback</comments><slash:comments>10</slash:comments><wfw:commentRss>http://www.blogjava.net/killme2008/comments/commentRss/372019.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/killme2008/services/trackbacks/372019.html</trackback:ping><description><![CDATA[<br />
&nbsp; &nbsp; 上周我在淘宝的同事开源了一个消息中间件<a href="http://metaq.taobao.org/">metamorphosis</a>，放在了<a href="http://metaq.taobao.org/">淘蝌蚪</a>上。我从淘蝌蚪的svn上fork了一个github的分支，放在了这里：<br />
<div>&nbsp;1.主体工程：<a href="https://github.com/killme2008/Metamorphosis">https://github.com/killme2008/Metamorphosis<br />
</a>
<div style="display: inline !important; ">&nbsp;2.示例项目：<a href="https://github.com/killme2008/metamorphosis-example">https://github.com/killme2008/metamorphosis-example<br />
</a></div>
<div>&nbsp;3.Twitter storm的spout项目：<a href="https://github.com/killme2008/storm-metamorphosis-spout">https://github.com/killme2008/storm-metamorphosis-spout<br />
</a></div>
&nbsp;&nbsp; &nbsp; <br />
&nbsp; &nbsp; 主要做了一些pom文件的简化，发布1.4.0.2版本到maven central仓库，并且写了几个简单的入门文档，提供了一个完整打包可运行的下载，有兴趣的自己看github页面吧。 Wiki文档放在：<br />
&nbsp; &nbsp;&nbsp;<a href="https://github.com/killme2008/Metamorphosis/wiki">https://github.com/killme2008/Metamorphosis/wiki</a><br />
&nbsp; &nbsp;<br />
&nbsp; &nbsp; &nbsp;客户端Maven依赖包括，可自行选择添加：<br />
<div style="font-size: 13px; border-top-width: 1px; border-right-width: 1px; border-bottom-width: 1px; border-left-width: 1px; border-top-style: solid; border-right-style: solid; border-bottom-style: solid; border-left-style: solid; border-top-color: #cccccc; border-right-color: #cccccc; border-bottom-color: #cccccc; border-left-color: #cccccc; border-image: initial; padding-right: 5px; padding-bottom: 4px; padding-left: 4px; padding-top: 4px; width: 98%; word-break: break-all; background-color: #eeeeee; "><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #0000FF; ">&lt;</span><span style="color: #800000; ">dependency</span><span style="color: #0000FF; ">&gt;</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">&lt;</span><span style="color: #800000; ">groupId</span><span style="color: #0000FF; ">&gt;</span>com.taobao.metamorphosis<span style="color: #0000FF; ">&lt;/</span><span style="color: #800000; ">groupId</span><span style="color: #0000FF; ">&gt;</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">&lt;</span><span style="color: #800000; ">artifactId</span><span style="color: #0000FF; ">&gt;</span>metamorphosis-client<span style="color: #0000FF; ">&lt;/</span><span style="color: #800000; ">artifactId</span><span style="color: #0000FF; ">&gt;</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">&lt;</span><span style="color: #800000; ">version</span><span style="color: #0000FF; ">&gt;</span>1.4.0.2<span style="color: #0000FF; ">&lt;/</span><span style="color: #800000; ">version</span><span style="color: #0000FF; ">&gt;</span><br />
<span style="color: #0000FF; ">&lt;/</span><span style="color: #800000; ">dependency</span><span style="color: #0000FF; ">&gt;</span><br />
<br />
<span style="color: #0000FF; ">&lt;</span><span style="color: #800000; ">dependency</span><span style="color: #0000FF; ">&gt;</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">&lt;</span><span style="color: #800000; ">groupId</span><span style="color: #0000FF; ">&gt;</span>com.taobao.metamorphosis<span style="color: #0000FF; ">&lt;/</span><span style="color: #800000; ">groupId</span><span style="color: #0000FF; ">&gt;</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">&lt;</span><span style="color: #800000; ">artifactId</span><span style="color: #0000FF; ">&gt;</span>metamorphosis-client-extension<span style="color: #0000FF; ">&lt;/</span><span style="color: #800000; ">artifactId</span><span style="color: #0000FF; ">&gt;</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">&lt;</span><span style="color: #800000; ">version</span><span style="color: #0000FF; ">&gt;</span>1.4.0.2<span style="color: #0000FF; ">&lt;/</span><span style="color: #800000; ">version</span><span style="color: #0000FF; ">&gt;</span><br />
<span style="color: #0000FF; ">&lt;/</span><span style="color: #800000; ">dependency</span><span style="color: #0000FF; ">&gt;</span><br />
<br />
<span style="color: #0000FF; ">&lt;</span><span style="color: #800000; ">dependency</span><span style="color: #0000FF; ">&gt;</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">&lt;</span><span style="color: #800000; ">groupId</span><span style="color: #0000FF; ">&gt;</span>com.taobao.metamorphosis<span style="color: #0000FF; ">&lt;/</span><span style="color: #800000; ">groupId</span><span style="color: #0000FF; ">&gt;</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">&lt;</span><span style="color: #800000; ">artifactId</span><span style="color: #0000FF; ">&gt;</span>storm-metamorphosis-spout<span style="color: #0000FF; ">&lt;/</span><span style="color: #800000; ">artifactId</span><span style="color: #0000FF; ">&gt;</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">&lt;</span><span style="color: #800000; ">version</span><span style="color: #0000FF; ">&gt;</span>1.0.0<span style="color: #0000FF; ">&lt;/</span><span style="color: #800000; ">version</span><span style="color: #0000FF; ">&gt;</span><br />
<span style="color: #0000FF; ">&lt;/</span><span style="color: #800000; ">dependency</span><span style="color: #0000ff; ">&gt;</span></div>
</div>
<br />&nbsp; &nbsp; &nbsp;ps.我开通了新浪微博，有兴趣相互关注下：<a href="http://weibo.com/fnil">http://weibo.com/fnil</a>，你看，偏见是可以改变的。<img src ="http://www.blogjava.net/killme2008/aggbug/372019.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/killme2008/" target="_blank">dennis</a> 2012-03-16 10:39 <a href="http://www.blogjava.net/killme2008/archive/2012/03/16/372019.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>storm常见问题解答</title><link>http://www.blogjava.net/killme2008/archive/2011/12/19/366763.html</link><dc:creator>dennis</dc:creator><author>dennis</author><pubDate>Mon, 19 Dec 2011 07:25:00 GMT</pubDate><guid>http://www.blogjava.net/killme2008/archive/2011/12/19/366763.html</guid><wfw:comment>http://www.blogjava.net/killme2008/comments/366763.html</wfw:comment><comments>http://www.blogjava.net/killme2008/archive/2011/12/19/366763.html#Feedback</comments><slash:comments>7</slash:comments><wfw:commentRss>http://www.blogjava.net/killme2008/comments/commentRss/366763.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/killme2008/services/trackbacks/366763.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp; 最近有朋友给我邮件问一些storm的问题，集中解答在这里。<br /><strong>一、我有一个数据文件，或者我有一个系统里面有数据，怎么导入storm做计算？</strong><br /><br />你需要实现一个Spout，Spout负责将数据emit到storm系统里，交给bolts计算。怎么实现spout可以参考官方的kestrel spout实现：<br /><a href="https://github.com/nathanmarz/storm-kestrel">https://github.com/nathanmarz/storm-kestrel</a><br /><br />如果你的数据源不支持事务性消费，那么就无法得到storm提供的可靠处理的保证，也没必要实现ISpout接口中的ack和fail方法。<br /><br /><strong>二、Storm为了保证tuple的可靠处理，需要保存tuple信息，这会不会导致内存OOM？</strong><br /><br />Storm为了保证tuple的可靠处理，acker会保存该节点创建的tuple id的xor值，这称为ack value，那么每ack一次，就将tuple id和ack value做异或(xor)。当所有产生的tuple都被ack的时候， ack value一定为0。这是个很简单的策略，对于每一个tuple也只要占用约20个字节的内存。对于100万tuple，也才20M左右。关于可靠处理看这个：<br /><a href="https://github.com/nathanmarz/storm/wiki/Guaranteeing-message-processing">https://github.com/nathanmarz/storm/wiki/Guaranteeing-message-processing</a><br /><br /><strong>三、Storm计算后的结果保存在哪里？可以保存在外部存储吗？</strong><br /><br />Storm不处理计算结果的保存，这是应用代码需要负责的事情，如果数据不大，你可以简单地保存在内存里，也可以每次都更新数据库，也可以采用NoSQL存储。storm并没有像s4那样提供一个Persist API，根据时间或者容量来做存储输出。这部分事情完全交给用户。<br /><br />数据存储之后的展现，也是你需要自己处理的，storm UI只提供对topology的监控和统计。<br /><br /><strong>四、Storm怎么处理重复的tuple？</strong><br /><br />因为Storm要保证tuple的可靠处理，当tuple处理失败或者超时的时候，spout会fail并重新发送该tuple，那么就会有tuple重复计算的问题。这个问题是很难解决的，storm也没有提供机制帮助你解决。一些可行的策略：<br />（1）不处理，这也算是种策略。因为实时计算通常并不要求很高的精确度，后续的批处理计算会更正实时计算的误差。<br />（2）使用第三方集中存储来过滤，比如利用mysql,memcached或者redis根据逻辑主键来去重。<br />（3）使用bloom filter做过滤，简单高效。<br /><br /><strong>五、Storm的动态增删节点</strong><br /><br />我在storm和s4里比较里谈到的动态增删节点，是指storm可以动态地添加和减少supervisor节点。对于减少节点来说，被移除的supervisor上的worker会被nimbus重新负载均衡到其他supervisor节点上。在storm 0.6.1以前的版本，增加supervisor节点不会影响现有的topology，也就是现有的topology不会重新负载均衡到新的节点上，在扩展集群的时候很不方便，需要重新提交topology。因此我在storm的邮件列表里提了这个问题，storm的开发者nathanmarz创建了一个issue 54并在0.6.1提供了rebalance命令来让正在运行的topology重新负载均衡，具体见：<br /><a href="https://github.com/nathanmarz/storm/issues/54">https://github.com/nathanmarz/storm/issues/54</a><br />和0.6.1的变更：<br /><a href="http://groups.google.com/group/storm-user/browse_thread/thread/24a8fce0b2e53246">http://groups.google.com/group/storm-user/browse_thread/thread/24a8fce0b2e53246</a><br /><br />storm并不提供机制来动态调整worker和task数目。<br /><br /><strong>六、Storm UI里spout统计的complete latency的具体含义是什么？为什么emit的数目会是acked的两倍？</strong><br />这个事实上是storm邮件列表里的一个问题。Storm作者marz的解答：<br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #000000; ">The&nbsp;complete&nbsp;latency&nbsp;is&nbsp;the&nbsp;time&nbsp;<strong>from&nbsp;the&nbsp;spout&nbsp;emitting&nbsp;a&nbsp;tuple&nbsp;to&nbsp;that<br />tuple&nbsp;being&nbsp;acked&nbsp;on&nbsp;the&nbsp;spout</strong>.&nbsp;So&nbsp;it&nbsp;tracks&nbsp;the&nbsp;time&nbsp;</span><span style="color: #0000FF; ">for</span><span style="color: #000000; ">&nbsp;the&nbsp;whole&nbsp;tuple<br />tree&nbsp;to&nbsp;be&nbsp;processed.<br /><br />If&nbsp;you&nbsp;dive&nbsp;into&nbsp;the&nbsp;spout&nbsp;component&nbsp;in&nbsp;the&nbsp;UI,&nbsp;you</span><span style="color: #000000; ">'</span><span style="color: #000000; ">ll&nbsp;see&nbsp;that&nbsp;a&nbsp;lot&nbsp;of</span><span style="color: #000000; "><br /></span><span style="color: #000000; ">the&nbsp;emitted</span><span style="color: #000000; ">/</span><span style="color: #000000; ">transferred&nbsp;is&nbsp;on&nbsp;the&nbsp;__ack</span><span style="color: #000000; ">*</span><span style="color: #000000; ">&nbsp;stream.&nbsp;<strong>This&nbsp;is&nbsp;the&nbsp;spout<br />communicating&nbsp;with&nbsp;the&nbsp;ackers&nbsp;which&nbsp;take&nbsp;care&nbsp;of&nbsp;tracking&nbsp;the&nbsp;tuple&nbsp;trees. </strong><br /></span></div><br />简单地说，complete latency表示了tuple从emit到被acked经过的时间，可以认为是tuple以及该tuple的后续子孙（形成一棵树）整个处理时间。其次spout的emit和transfered还统计了spout和acker之间内部的通信信息，比如对于可靠处理的spout来说，会在emit的时候同时发送一个_ack_init给acker，记录tuple id到task id的映射，以便ack的时候能找到正确的acker task。<br /><br /><img src ="http://www.blogjava.net/killme2008/aggbug/366763.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/killme2008/" target="_blank">dennis</a> 2011-12-19 15:25 <a href="http://www.blogjava.net/killme2008/archive/2011/12/19/366763.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Storm源码浅析之topology的提交</title><link>http://www.blogjava.net/killme2008/archive/2011/12/01/364112.html</link><dc:creator>dennis</dc:creator><author>dennis</author><pubDate>Thu, 01 Dec 2011 13:48:00 GMT</pubDate><guid>http://www.blogjava.net/killme2008/archive/2011/12/01/364112.html</guid><wfw:comment>http://www.blogjava.net/killme2008/comments/364112.html</wfw:comment><comments>http://www.blogjava.net/killme2008/archive/2011/12/01/364112.html#Feedback</comments><slash:comments>10</slash:comments><wfw:commentRss>http://www.blogjava.net/killme2008/comments/commentRss/364112.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/killme2008/services/trackbacks/364112.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp; 原文：<a href="http://www.blogjava.net/killme2008/archive/2011/11/17/364112.html">http://www.blogjava.net/killme2008/archive/2011/11/17/364112.html</a><br />&nbsp;&nbsp;&nbsp; 作者：dennis (killme2008@gmail.com)<br />&nbsp;&nbsp;&nbsp; 转载请注明出处。<br /><br />&nbsp;&nbsp;&nbsp; 最近一直在读twitter开源的这个分布式流计算框架&#8212;&#8212;storm的源码，还是有必要记录下一些比较有意思的地方。我按照storm的主要概念进行组织，并且只分析我关注的东西，因此称之为浅析。&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <br /><br />一、介绍<br />&nbsp;&nbsp;&nbsp; Storm的开发语言主要是Java和Clojure，其中Java定义骨架，而Clojure编写核心逻辑。源码统计结果：<br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000; ">180</span><span style="color: #000000; ">&nbsp;text&nbsp;files.<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000; ">177</span><span style="color: #000000; ">&nbsp;unique&nbsp;files.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000; ">7</span><span style="color: #000000; ">&nbsp;files&nbsp;ignored.<br /><br />http:</span><span style="color: #008000; ">//</span><span style="color: #008000; ">cloc.sourceforge.net&nbsp;v&nbsp;1.55&nbsp;&nbsp;T=1.0&nbsp;s&nbsp;(171.0&nbsp;files/s,&nbsp;46869.0&nbsp;lines/s)</span><span style="color: #008000; "><br /></span><span style="color: #000000; ">-------------------------------------------------------------------------------</span><span style="color: #000000; "><br />Language&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;files&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;blank&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;comment&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;code<br /></span><span style="color: #000000; ">-------------------------------------------------------------------------------</span><span style="color: #000000; "><br />Java&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000; ">125</span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000; ">5010</span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000; ">2414</span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000; ">25661</span><span style="color: #000000; "><br />Lisp&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000; ">33</span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000; ">732</span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000; ">283</span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000; ">4871</span><span style="color: #000000; "><br />Python&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000; ">7</span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000; ">742</span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000; ">433</span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000; ">4675</span><span style="color: #000000; "><br />CSS&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000; ">1</span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000; ">12</span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000; ">45</span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000; ">1837</span><span style="color: #000000; "><br /><a title="" href="http://www.ruby-lang.org">ruby</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000; ">2</span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000; ">22</span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000; ">0</span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000; ">104</span><span style="color: #000000; "><br />Bourne&nbsp;Shell&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000; ">1</span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000; ">0</span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000; ">0</span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000; ">6</span><span style="color: #000000; "><br />Javascript&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000; ">2</span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000; ">1</span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000; ">15</span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000; ">6</span><span style="color: #000000; "><br /></span><span style="color: #000000; ">-------------------------------------------------------------------------------</span><span style="color: #000000; "><br />SUM:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000; ">171</span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000; ">6519</span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000; ">3190</span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000; ">37160</span><span style="color: #000000; "><br /></span><span style="color: #000000; ">-------------------------------------------------------------------------------</span></div><br />&nbsp; &nbsp; Java代码25000多行，而Clojure(Lisp)只有4871行，说语言不重要再次证明是扯淡。<br />&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <br />二、Topology和Nimbus &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <br />&nbsp;&nbsp;&nbsp; Topology是storm的核心理念，将spout和bolt组织成一个topology，运行在storm集群里，完成实时分析和计算的任务。这里我主要想介绍下topology部署到storm集群的大概过程。提交一个topology任务到Storm集群是通过StormSubmitter.submitTopology方法提交：<br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #000000; ">StormSubmitter.submitTopology(name,&nbsp;conf,&nbsp;builder.createTopology());</span></div>&nbsp;&nbsp;&nbsp; 我们将topology打成jar包后，利用bin/storm这个python脚本，执行如下命令：<br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #000000; ">bin</span><span style="color: #000000; ">/</span><span style="color: #000000; ">storm&nbsp;jar&nbsp;xxxx.jar&nbsp;com.taobao.MyTopology&nbsp;args</span></div>&nbsp;&nbsp;&nbsp; 将jar包提交给storm集群。storm脚本会启动JVM执行Topology的main方法，执行submitTopology的过程。而submitTopology会将jar文件上传到nimbus，上传是通过socket传输。在storm这个python脚本的jar方法里可以看到：<br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #0000FF; ">def</span><span style="color: #000000; ">&nbsp;jar(jarfile,&nbsp;klass,&nbsp;</span><span style="color: #000000; ">*</span><span style="color: #000000; ">args):&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;exec_storm_class(&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;klass,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;jvmtype</span><span style="color: #000000; ">=</span><span style="color: #800000; ">"</span><span style="color: #800000; ">-client</span><span style="color: #800000; ">"</span><span style="color: #000000; ">,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;extrajars</span><span style="color: #000000; ">=</span><span style="color: #000000; ">[jarfile,&nbsp;CONF_DIR,&nbsp;STORM_DIR&nbsp;</span><span style="color: #000000; ">+</span><span style="color: #000000; ">&nbsp;</span><span style="color: #800000; ">"</span><span style="color: #800000; ">/bin</span><span style="color: #800000; ">"</span><span style="color: #000000; ">],&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;args</span><span style="color: #000000; ">=</span><span style="color: #000000; ">args,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<strong>prefix</strong></span><strong><span style="color: #000000; ">=</span><span style="color: #800000; ">"</span><span style="color: #800000; ">export&nbsp;STORM_JAR=</span><span style="color: #800000; ">"</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">+</span><span style="color: #000000; ">&nbsp;jarfile&nbsp;</span><span style="color: #000000; ">+</span><span style="color: #000000; ">&nbsp;</span><span style="color: #800000; ">"</span><span style="color: #800000; ">;</span><span style="color: #800000; ">"</span></strong><span style="color: #000000; "><strong>)</strong> <br /></span></div>&nbsp;&nbsp;&nbsp;&nbsp; 将jar文件的地址设置为环境变量STORM_JAR，这个环境变量在执行submitTopology的时候用到：<br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #008000; ">//</span><span style="color: #008000; ">StormSubmitter.java&nbsp;</span><span style="color: #008000; "><br /></span><span style="color: #0000FF; ">private</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">static</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">void</span><span style="color: #000000; ">&nbsp;submitJar(Map&nbsp;conf)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">if</span><span style="color: #000000; ">(submittedJar</span><span style="color: #000000; ">==</span><span style="color: #0000FF; ">null</span><span style="color: #000000; ">)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;LOG.info(</span><span style="color: #000000; ">"</span><span style="color: #000000; ">Jar&nbsp;not&nbsp;uploaded&nbsp;to&nbsp;master&nbsp;yet.&nbsp;Submitting&nbsp;jar<img src="http://www.blogjava.net/Images/dot.gif" alt="" /></span><span style="color: #000000; ">"</span><span style="color: #000000; ">);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;localJar&nbsp;</span><span style="color: #000000; ">=</span><strong><span style="color: #000000; ">&nbsp;System.getenv(</span><span style="color: #000000; ">"</span><span style="color: #000000; ">STORM_JAR</span><span style="color: #000000; ">"</span></strong><span style="color: #000000; "><strong>)</strong>;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;submittedJar&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;submitJar(conf,&nbsp;localJar);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;</span><span style="color: #0000FF; ">else</span><span style="color: #000000; ">&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;LOG.info(</span><span style="color: #000000; ">"</span><span style="color: #000000; ">Jar&nbsp;already&nbsp;uploaded&nbsp;to&nbsp;master.&nbsp;Not&nbsp;submitting&nbsp;jar.</span><span style="color: #000000; ">"</span><span style="color: #000000; ">);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;}</span></div>&nbsp;&nbsp;&nbsp; 通过环境变量找到jar包的地址，然后上传。利用环境变量传参是个小技巧。<br /><br />&nbsp;&nbsp;&nbsp; 其次，nimbus在接收到jar文件后，存放到数据目录的inbox目录，<strong>nimbus数据目录的结构</strong>：<br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #000000; ">-</span><span style="color: #000000; ">nimbus<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000; ">-</span><span style="color: #000000; ">inbox<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000; ">-</span><span style="color: #000000; ">stormjar</span><span style="color: #000000; ">-</span><span style="color: #000000; ">57f1d694</span><span style="color: #000000; ">-</span><span style="color: #000000; ">2865</span><span style="color: #000000; ">-</span><span style="color: #000000; ">4b3b</span><span style="color: #000000; ">-</span><span style="color: #000000; ">8a7c</span><span style="color: #000000; ">-</span><span style="color: #000000; ">99104fc0aea3.jar<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000; ">-</span><span style="color: #000000; ">stormjar</span><span style="color: #000000; ">-</span><span style="color: #000000; ">76b4e316</span><span style="color: #000000; ">-</span><span style="color: #000000; ">b430</span><span style="color: #000000; ">-</span><span style="color: #000000; ">4215</span><span style="color: #000000; ">-</span><span style="color: #000000; ">9e26</span><span style="color: #000000; ">-</span><span style="color: #000000; ">4f33ba4ee520.jar<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000; ">-</span><span style="color: #000000; ">stormdist<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000; ">-</span><span style="color: #000000; ">storm</span><span style="color: #000000; ">-</span><span style="color: #000000; ">id<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000; ">-</span><span style="color: #000000; ">stormjar.jar<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000; ">-</span><span style="color: #000000; ">stormconf.ser<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000; ">-</span><span style="color: #000000; ">stormcode.ser</span></div>&nbsp;&nbsp;&nbsp;&nbsp; 其中inbox用于存放提交的jar文件，每个jar文件都重命名为stormjar加上一个32位的UUID。而stormdist存放的是启动topology后生成的文件，每个topology都分配一个唯一的id，ID的规则是&#8220;name-计数-时间戳&#8221;。启动后的topology的jar文件名命名为storm.jar ,而它的配置经过java序列化后存放在stormconf.ser文件，而stormcode.ser是将topology本身序列化后存放的文件。<strong>这些文件在部署的时候，supervisor会从这个目录下载这些文件，然后在supervisor本地执行这些代码。</strong><br />&nbsp;&nbsp;&nbsp; 进入重点，topology任务的分配过程(zookeeper路径说明忽略root):<br />1.在zookeeper上创建/taskheartbeats/{storm id} 路径，用于任务的心跳检测。storm对zookeeper的一个重要应用就是利用zk的临时节点做存活检测。task将定时刷新节点的时间戳，然后nimbus会检测这个时间戳是否超过timeout设置。<br />2.从topology中获取bolts,spouts设置的并行数目以及全局配置的最大并行数，然后产生task id列表，如[1 2 3 4]<br />3.在zookeeper上创建/tasks/{strom id}/{task id}路径，并存储task信息<br />4.开始分配任务（内部称为assignment)， 具体步骤：<br />&nbsp;(1)从zk上获得已有的assignment(新的toplogy当然没有了）<br />&nbsp;(2)查找所有可用的slot，所谓slot就是可用的worker，在所有supervisor上配置的多个worker的端口。<br />&nbsp;(3)将任务均匀地分配给可用的worker，这里有两种情况：<br />&nbsp;(a)task数目比worker多，例如task是[1 2 3 4],可用的slot只有[host1:port1 host2:port1]，那么最终是这样分配<br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #000000; ">{</span><span style="color: #000000; ">1</span><span style="color: #000000; ">:&nbsp;[host1:port1]&nbsp;</span><span style="color: #000000; ">2</span><span style="color: #000000; ">&nbsp;:&nbsp;[host2:port1]<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000; ">3</span><span style="color: #000000; ">&nbsp;:&nbsp;[host1:port1]&nbsp;</span><span style="color: #000000; ">4</span><span style="color: #000000; ">&nbsp;:&nbsp;[host2:port1]}</span></div>，可以看到任务平均地分配在两个worker上。<br />(b)如果task数目比worker少，例如task是[1 2]，而worker有[host1:port1 host1:port2 host2:port1 host2:port2]，那么首先会将woker排序，<strong>将不同host间隔排列</strong>，保证task不会全部分配到同一个worker上，也就是将worker排列成<br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #000000; ">[host1:port1&nbsp;host2:port1&nbsp;host1:port2&nbsp;host2:port2]</span></div>，然后分配任务为<br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #000000; ">{</span><span style="color: #000000; ">1</span><span style="color: #000000; ">:&nbsp;host1:port1&nbsp;,&nbsp;</span><span style="color: #000000; ">2</span><span style="color: #000000; ">&nbsp;:&nbsp;host2:port2}</span></div><br />(4)记录启动时间<br />(5)判断现有的assignment是否跟重新分配的assignment相同，如果相同，不需要变更，否则更新assignment到zookeeper的/assignments/{storm id}上。<br />5.启动topology，所谓启动，只是将zookeeper上/storms/{storm id}对应的数据里的active设置为true。<br />6.nimbus会检查task的心跳，如果发现task心跳超过超时时间，那么会重新跳到第4步做re-assignment。<br /><img src ="http://www.blogjava.net/killme2008/aggbug/364112.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/killme2008/" target="_blank">dennis</a> 2011-12-01 21:48 <a href="http://www.blogjava.net/killme2008/archive/2011/12/01/364112.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>storm集群的监控</title><link>http://www.blogjava.net/killme2008/archive/2011/12/01/365329.html</link><dc:creator>dennis</dc:creator><author>dennis</author><pubDate>Thu, 01 Dec 2011 13:02:00 GMT</pubDate><guid>http://www.blogjava.net/killme2008/archive/2011/12/01/365329.html</guid><wfw:comment>http://www.blogjava.net/killme2008/comments/365329.html</wfw:comment><comments>http://www.blogjava.net/killme2008/archive/2011/12/01/365329.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/killme2008/comments/commentRss/365329.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/killme2008/services/trackbacks/365329.html</trackback:ping><description><![CDATA[<br />&nbsp;&nbsp;&nbsp; 所谓兵马未动，粮草先行，准备将<a href="https://github.com/nathanmarz/storm/wiki">storm</a>用在某个项目中做实时数据分析。无论任何系统，一定要有监控系统并存，当故障发生的时候你能第一个知道，而不是让别人告诉你，那处理故障就很被动了。<br /><br />&nbsp;&nbsp;&nbsp; 因此我写了这么个项目，取名叫storm-monitor，放在了github上<br /><br />&nbsp;&nbsp;&nbsp;&nbsp; <a href="https://github.com/killme2008/storm-monitor">https://github.com/killme2008/storm-monitor</a><br /><br />&nbsp;&nbsp;&nbsp; 主要功能如下：<br />1.监控supervisor数目是否正确，当supervisor挂掉的时候会发送警告。<br />2.监控nimbus是否正常运行，monitor会尝试连接nimbus，如果连接失败就认为nimbus挂掉。<br />3.监控topology是否正常运行，包括它是否正常部署，是否有运行中的任务。<br /><br />&nbsp;&nbsp;&nbsp; 当故障发生的时候通过alarm方法警告用户，开放出去的只是简单地打日志。因为每个公司的告警接口不一样，所以你需要自己扩展，修改alarm.clj即可。我们这儿就支持旺旺告警和手机短信告警。<br /><br />&nbsp;&nbsp;&nbsp; 基本的原理很简单，对supervisor和topology的监控是通过zookeeper来间接地监控，通过定期查看path是否存在。对nimbus的监控是每次起一个短连接连上去，连不上去即认为挂掉。<br /><br />&nbsp;&nbsp;&nbsp; 整个项目也是用clojure写。你的机器需要安装<a href="https://github.com/technomancy/leiningen">lein</a>和<a href="https://github.com/kumarshantanu/lein-exec">exec</a>插件，然后将你的storm.yaml拷贝到conf目录下，编辑monitor.yaml设定监控参数如检查间隔等，最后启动start.sh脚本即可。默认日志输出在logs/monitor.log。<br /><img src ="http://www.blogjava.net/killme2008/aggbug/365329.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/killme2008/" target="_blank">dennis</a> 2011-12-01 21:02 <a href="http://www.blogjava.net/killme2008/archive/2011/12/01/365329.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Yahoo! s4和Twitter storm的粗略比较</title><link>http://www.blogjava.net/killme2008/archive/2011/11/08/363238.html</link><dc:creator>dennis</dc:creator><author>dennis</author><pubDate>Tue, 08 Nov 2011 14:25:00 GMT</pubDate><guid>http://www.blogjava.net/killme2008/archive/2011/11/08/363238.html</guid><wfw:comment>http://www.blogjava.net/killme2008/comments/363238.html</wfw:comment><comments>http://www.blogjava.net/killme2008/archive/2011/11/08/363238.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/killme2008/comments/commentRss/363238.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/killme2008/services/trackbacks/363238.html</trackback:ping><description><![CDATA[<table border="2" cellpadding="2" cellspacing="2" width="804"><tbody><tr><td>Items\Projects<br /></td>
            <td>Yahoo! s4<br /></td>
            <td>Twitter Storm<br /></td>
        </tr>
        <tr>
            <td>协议<br /></td>
            <td>Apache license 2.0<br /></td>
            <td>Eclipse Public License 1.0<br /></td>
        </tr>
        <tr>
            <td>开发语言<br /></td>
            <td>Java<br /></td>
            <td>Clojure,Java,Clojure编写了核心代码</td>
        </tr>
        <tr>
            <td>结构<br /></td>
            <td>去中心化的对等结构<br /></td>
            <td>有中心节点nimbus，但非关键</td>
        </tr>
        <tr>
            <td>通信<br /></td>
            <td>可插拔的通讯层，目前是基于UDP的实现</td>
            <td>基于facebook开源的thrift框架</td>
        </tr>
        <tr>
            <td>事件/Stream<br /></td>
            <td>&lt;K,A&gt;序列，用户可自定义事件类</td>
            <td>提供Tuple类，用户不可自定义事件类，<br />但是可以命名field和注册序列化器</td>
        </tr>
        <tr>
            <td>处理单元</td>
            <td>Processing Elements，内置PE处理<br />count,join和aggregate等常见任务</td>
            <td>Bolt，没有内置任务，提供IBasicBolt处理<br />自动ack</td>
        </tr>
        <tr>
            <td>第三方交互<br /></td>
            <td>提供API,Client Adapter/Driver，第三方客户端输入或者输出事件</td>
            <td>定义Spout用于产生Stream，没有标准输出API</td>
        </tr>
        <tr>
            <td>持久化</td>
            <td>提供Persist API规范，可根据频率或者次数做<br />持久化<br /></td>
            <td>无特定API，用户可自行选择处理<br /></td></tr><tr><td>可靠处理</td><td>&nbsp;无，可能会丢失事件</td><td>&nbsp;提供对事件处理的可靠保证（可选）</td></tr><tr><td>路由</td><td>EventType + Keyed attribute + value匹配<br />内置count,join和aggregate标准任务</td><td>Stream Groupings:<br />Shuffle,Fields,All,Global,None,Direct<br />非常灵活的路由方式</td></tr><tr><td>多语言支持</td><td>&nbsp;暂时只支持Java</td><td>多语言支持良好，本身支持Java,Clojure，<br />其他非JVM语言通过thrift和进程间通讯</td></tr><tr><td>Failover<br /></td><td>&nbsp;部分支持，数据无法failover</td><td>&nbsp;部分支持，数据同样无法failover</td></tr><tr><td>Load Balance<br /></td><td>不支持</td><td>&nbsp;不支持</td></tr><tr><td>&nbsp;并行处理</td><td>&nbsp;取决于节点数目，不可调节</td><td>&nbsp;可配置worker和task数目，storm会尽量将worker和task均匀分布</td></tr><tr><td>动态增删节点</td><td>不支持 <br /></td><td>&nbsp;支持</td></tr><tr><td>动态部署<br /></td><td>&nbsp;不支持</td><td>&nbsp;支持</td></tr><tr><td>web管理</td><td>&nbsp;不支持</td><td>&nbsp;支持</td></tr><tr><td>代码成熟度</td><td>&nbsp;半成品</td><td>&nbsp;成熟</td></tr><tr><td>活跃度</td><td>&nbsp;低</td><td>&nbsp;活跃</td></tr><tr><td>编程</td><td>&nbsp;编程 + XML配置<br /></td><td>&nbsp; 纯编程<br /></td></tr><tr><td>参考文档</td><td>&nbsp;<a href="http://docs.s4.io/">http://docs.s4.io/</a></td><td><a href="https://github.com/nathanmarz/storm/wiki/">https://github.com/nathanmarz/storm/wiki/</a><br /><a href="http://xumingming.sinaapp.com/category/storm/">http://xumingming.sinaapp.com/category/storm/</a> （非常好的中文翻译)<br /></td></tr></tbody></table><img src ="http://www.blogjava.net/killme2008/aggbug/363238.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/killme2008/" target="_blank">dennis</a> 2011-11-08 22:25 <a href="http://www.blogjava.net/killme2008/archive/2011/11/08/363238.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Zookeeper的web管理应用</title><link>http://www.blogjava.net/killme2008/archive/2011/06/06/351793.html</link><dc:creator>dennis</dc:creator><author>dennis</author><pubDate>Sun, 05 Jun 2011 17:13:00 GMT</pubDate><guid>http://www.blogjava.net/killme2008/archive/2011/06/06/351793.html</guid><wfw:comment>http://www.blogjava.net/killme2008/comments/351793.html</wfw:comment><comments>http://www.blogjava.net/killme2008/archive/2011/06/06/351793.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.blogjava.net/killme2008/comments/commentRss/351793.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/killme2008/services/trackbacks/351793.html</trackback:ping><description><![CDATA[&nbsp; &nbsp; Update: 如果遇到在search不存在的path报段错误，这是node-zookeeper的一个bug，我暂时修复了下并提交了pull request，你可以暂时用我修改的node-zookeeper &nbsp;<a href="https://github.com/killme2008/node-zookeeper">https://github.com/killme2008/node-zookeeper<br /></a><br />&nbsp;&nbsp;&nbsp; 我们已经开始在产品使用<a href="http://zookeeper.apache.org/">zookeeper</a>了，那么维护工具也必然需要，所谓兵马未动，粮草先行。请同事帮忙看过几个开源项目后，并没有特别让人满意的。<br />&nbsp;&nbsp;&nbsp; 我想要的功能比较简单。首先，希望能将zookeeper集群的数据展示为树形结构，跟zookeeper模型保持一致。可以逐步展开每层的节点，每次展开都是延迟加载从zk里取数据，这样不会对zk造成太大压力。其次，除了展示树形结构外，我还希望它能展示每个path的属性和数据，更进一步，如果数据是文本的，我希望它可编辑。当然，因为编辑功能是比较危险的行为，我还希望这个管理工具有个简单的授权验证机制。<br /><br />&nbsp;&nbsp;&nbsp; 最终，我自己写了这么个东西，取名为<a href="https://github.com/killme2008/node-zk-browser">node-zk-browser</a>，基于node.js的<a href="http://expressjs.com/">express.js</a>框架和<a href="https://github.com/yfinkelstein/node-zookeeper">node-zookeeper</a>客户端实现的。我将它放在了github上<br /><br />&nbsp;&nbsp;&nbsp;<a href="https://github.com/killme2008/node-zk-browser"> https://github.com/killme2008/node-zk-browser</a><br /><br />&nbsp;&nbsp;&nbsp; 你可以自己搭建这个小app， npm几乎能帮你搞定大部分工作。界面不美观，实用为主，几张运行时截图<br /><br /><br /><img alt="" src="http://www.blogjava.net/images/blogjava_net/killme2008/zk1.png" height="494" width="531" /><br /><br /><img alt="" src="http://www.blogjava.net/images/blogjava_net/killme2008/zk2.png" height="579" width="618" /><br /><br /><br /><img alt="" src="http://www.blogjava.net/images/blogjava_net/killme2008/zk3.png" height="187" width="639" /><img src ="http://www.blogjava.net/killme2008/aggbug/351793.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/killme2008/" target="_blank">dennis</a> 2011-06-06 01:13 <a href="http://www.blogjava.net/killme2008/archive/2011/06/06/351793.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>最近关注过的一些项目</title><link>http://www.blogjava.net/killme2008/archive/2011/01/20/343284.html</link><dc:creator>dennis</dc:creator><author>dennis</author><pubDate>Thu, 20 Jan 2011 15:23:00 GMT</pubDate><guid>http://www.blogjava.net/killme2008/archive/2011/01/20/343284.html</guid><wfw:comment>http://www.blogjava.net/killme2008/comments/343284.html</wfw:comment><comments>http://www.blogjava.net/killme2008/archive/2011/01/20/343284.html#Feedback</comments><slash:comments>10</slash:comments><wfw:commentRss>http://www.blogjava.net/killme2008/comments/commentRss/343284.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/killme2008/services/trackbacks/343284.html</trackback:ping><description><![CDATA[<br />
&nbsp;&nbsp;&nbsp; 最近因为空闲时间有一些，所以去看了不少开源项目，大部分东西如果看过不记录下来，其实还是相当于没看，所以想想还是有必要摘要记录一下。<br />
<br />
&nbsp;&nbsp;&nbsp; 首先是去了解了<a href="http://hadoop.apache.org/zookeeper/">zookeeper</a>这个项目，基于paxos算法的分布式服务组件，同事对此有非常深入的研究和介绍，具体可以看我们的<a href="http://rdc.taobao.com/team/jm/archives/category/rpc-soa">团队Blog</a>。令我感慨的是这么一个非常难以理解的算法，却用一个简单的树状目录模型表达出来，并且在这个模型的基础上衍生出种种应用：集群感知、分布式锁、分布式队列、分布式并发原语等等，具体可以看文档给出的<a href="http://hadoop.apache.org/zookeeper/docs/r3.3.2/recipes.html">recipes</a>。在实现这些应用的时候，突出强调的是避免网络风暴，例如分布式锁的实现，竞争创建子节点，节点序列号最小的获取锁，其他节点等待，但是等待在什么条件上是有讲究的，如果所有节点都等待最小节点的删除事件，那么当最小节点释放锁的时候，就需要广播消息给所有其他等待的节点；换一个思路，如果每个等待节点只是等待比它序列号小的节点上，那么就可以避免这种广播风暴，变成一个顺序唤醒的过程。因此尽管有了zookeeper帮助实现分布式这些服务，但是要实现好仍然有一定难度，具体可以参考官方例子。我本来萌生了基于zookeeper实现一套封装好的类似j.u.c的服务框架，后来在邮件列表发现已经有人搞了这么一个基础类库放在github上:<a href="https://github.com/openUtility/menagerie">https://github.com/openUtility/menagerie</a> 。不过我没有继续深入了，有兴趣的朋友可以瞧瞧。<br />
<br />
&nbsp;&nbsp;&nbsp; 然后又去看了我们淘宝开源的<a title="TimeTunnel" href="http://code.taobao.org/project/view/411/">TimeTunnel</a>。TimeTunnel你可以理解成一个消息中间件，它整个设计跟我们的产品相当接近，但是两者的目的完全不同，tt强调的是高吞吐量，而notify强调的则是可靠性。TT的通讯层直接采用Facebook的thrift，并且利用zookeeper做集群管理和路由。TT的代码质量很好，有兴趣可以拉出来看一下，并且对zookeeper的应用也是一个典型的案例。TT在高可用性上的方案也很有特色，所有的服务器节点形成一个环，两两相互主辅备份，一个节点挂了，后续节点仍然可以提供服务直到主节点回来，有点类似一致性哈希的概念。节点的主从关系和顺序也是通过zookeeper保证。消息顺序的实现是通过称为router的路由到固定节点做传输，router默认是策略不是固定而是RR。TT的数据存储优先放在内存，并设置了一个内存状况监视的组件，当发现内存放不下的时候，swap到磁盘文件缓存，实现类似内存换页的功能。正常情况数据都应该在内存，当然如果可靠级别要求高的话可以先存磁盘再传输。TT目前仍然还是比较适合传输日志这样的文本增量数据，并且提供了TailFile这样的python脚本帮你做这个事情，这个脚本可以通过checkpoint做断点续传。在学习这个项目的时候，发现文档有很大问题，要么错误，要么遗漏，并且代码也不是最新的，我估计开源出来外面的人用的还不太多，希望慢慢能搞的更好一些。<br />
<br />
&nbsp;&nbsp;&nbsp; 跟TT类似，另一个追求高吞吐量的MQ是linkedin开源的<a title="kafka" href="http://sna-projects.com/kafka/">kafka</a>。Kafka就跟这个名字一样，设计非常独特。首先，kafka的开发者们认为不需要在内存里缓存什么数据，操作系统的文件缓存已经足够完善和强大，只要你不搞随机写，顺序读写的性能是非常高效的。kafka的数据只会顺序append，数据的删除策略是累积到一定程度或者超过一定时间再删除。Kafka另一个独特的地方是将消费者信息保存在客户端而不是MQ服务器，这样服务器就不用记录消息的投递过程，每个客户端都自己知道自己下一次应该从什么地方什么位置读取消息，消息的投递过程也是采用客户端主动pull的模型，这样大大减轻了服务器的负担。Kafka还强调减少数据的序列化和拷贝开销，它会将一些消息组织成Message Set做批量存储和发送，并且客户端在pull数据的时候，尽量以zero-copy的方式传输，利用sendfile（对应java里的FileChannel.transferTo/transferFrom）这样的高级IO函数来减少拷贝开销。可见，kafka是一个精心设计，特定于某些应用的MQ系统，这种偏向特定领域的MQ系统我估计会越来越多，垂直化的产品策略值的考虑。<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp; 在此期间，我还重新去看了activemq和hornetq的存储实现，从实现上大家都大同小异，append log + data file的模式。Activemq采用异步队列写来提高吞吐量，而Hornetq干脆就直接利用JNI调用原生aio来实现高性能。在搜索Java的aio实现的时候，碰巧发现Mina的沙箱里有个aioj的实现，源码在：<a href="https://svn.apache.org/repos/asf/mina/sandbox/mheath/aioj/">https://svn.apache.org/repos/asf/mina/sandbox/mheath/aioj/</a> 。我测试了完全可用，也尝试改造我们的磁盘存储组件，可惜提升不多，估计不从整个设计上调整服务器，不大可能从aio上获益。<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp; 最近也重新看起了clojure的一些开源项目，clojure的开源资源在github上也非常丰富，有待挖掘，下次有机会再尝试介绍一二。<br />
&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; <br />
<br /><img src ="http://www.blogjava.net/killme2008/aggbug/343284.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/killme2008/" target="_blank">dennis</a> 2011-01-20 23:23 <a href="http://www.blogjava.net/killme2008/archive/2011/01/20/343284.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>第一个MapReduce任务</title><link>http://www.blogjava.net/killme2008/archive/2008/08/23/223844.html</link><dc:creator>dennis</dc:creator><author>dennis</author><pubDate>Sat, 23 Aug 2008 03:08:00 GMT</pubDate><guid>http://www.blogjava.net/killme2008/archive/2008/08/23/223844.html</guid><wfw:comment>http://www.blogjava.net/killme2008/comments/223844.html</wfw:comment><comments>http://www.blogjava.net/killme2008/archive/2008/08/23/223844.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/killme2008/comments/commentRss/223844.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/killme2008/services/trackbacks/223844.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp; 前两天在公司内网上搭了个2个节点hadoop集群，暂时没有多大实际意义，仅用作自己的测试。遇到的问题在阿里巴巴这位仁兄的《<a href="http://www.infoq.com/cn/articles/hadoop-config-tip">Hadoop集群配置和使用技巧</a>》都有提到的。也遇到了reduce任务卡住的问题，只需要在每个节点的/etc/hosts将集群中的机器都配置上即可解决。<br />
&nbsp;&nbsp; 今天将一个日志统计任务用Hadoop MapReduce框架重新实现了一次，数据量并不大，每天分析一个2G多的日志文件罢了。先前是用Ruby配合cat、grep命令搞定，运行一次在50多秒左右，如果纯粹采用Ruby的话CPU占用率非常高而且慢的无法忍受，利用IO.popen调用linux的cat、grep命令先期处理就好多了。看看这个MapReduce任务：<br />
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">class</span><span style="color: #000000;">&nbsp;GameCount&nbsp;</span><span style="color: #0000ff;">extends</span><span style="color: #000000;">&nbsp;Configured&nbsp;</span><span style="color: #0000ff;">implements</span><span style="color: #000000;"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;org.apache.hadoop.util.Tool&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">static</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">class</span><span style="color: #000000;">&nbsp;MapClass&nbsp;</span><span style="color: #0000ff;">extends</span><span style="color: #000000;">&nbsp;MapReduceBase&nbsp;</span><span style="color: #0000ff;">implements</span><span style="color: #000000;"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Mapper</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">LongWritable,&nbsp;Text,&nbsp;Text,&nbsp;IntWritable</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">&nbsp;{<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">private</span><span style="color: #000000;">&nbsp;Pattern&nbsp;pattern;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">void</span><span style="color: #000000;">&nbsp;configure(JobConf&nbsp;job)&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;gameName&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;job.get(</span><span style="color: #000000;">"</span><span style="color: #000000;">mapred.mapper.game</span><span style="color: #000000;">"</span><span style="color: #000000;">);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pattern&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;Pattern.compile(</span><span style="color: #000000;">"</span><span style="color: #000000;">play\\sgame\\s</span><span style="color: #000000;">"</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">+</span><span style="color: #000000;">&nbsp;gameName<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">+</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">.*uid=(\\d+),score=(-?\\d+),money=(-?\\d+)</span><span style="color: #000000;">"</span><span style="color: #000000;">);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@Override<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">void</span><span style="color: #000000;">&nbsp;map(LongWritable&nbsp;key,&nbsp;Text&nbsp;value,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;OutputCollector</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">Text,&nbsp;IntWritable</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">&nbsp;output,&nbsp;Reporter&nbsp;reporter)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">throws</span><span style="color: #000000;">&nbsp;IOException&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;text&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;value.toString();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Matcher&nbsp;matcher&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;pattern.matcher(text);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;total&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">0</span><span style="color: #000000;">;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;"> 总次数</span><span style="color: #008000;"><br />
</span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">while</span><span style="color: #000000;">&nbsp;(matcher.find())&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;record&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;Integer.parseInt(matcher.group(</span><span style="color: #000000;">2</span><span style="color: #000000;">));<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;output.collect(</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;Text(matcher.group(</span><span style="color: #000000;">1</span><span style="color: #000000;">)),&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;IntWritable(<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;record));<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;total&nbsp;</span><span style="color: #000000;">+=</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">1</span><span style="color: #000000;">;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;output.collect(</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;Text(</span><span style="color: #000000;">"</span><span style="color: #000000;">total</span><span style="color: #000000;">"</span><span style="color: #000000;">),&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;IntWritable(total));<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">static</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">class</span><span style="color: #000000;">&nbsp;ReduceClass&nbsp;</span><span style="color: #0000ff;">extends</span><span style="color: #000000;">&nbsp;MapReduceBase&nbsp;</span><span style="color: #0000ff;">implements</span><span style="color: #000000;"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Reducer</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">Text,&nbsp;IntWritable,&nbsp;Text,&nbsp;IntWritable</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">&nbsp;{<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@Override<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">void</span><span style="color: #000000;">&nbsp;reduce(Text&nbsp;key,&nbsp;Iterator</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">IntWritable</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">&nbsp;values,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;OutputCollector</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">Text,&nbsp;IntWritable</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">&nbsp;output,&nbsp;Reporter&nbsp;reporter)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">throws</span><span style="color: #000000;">&nbsp;IOException&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;sum&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">0</span><span style="color: #000000;">;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">while</span><span style="color: #000000;">&nbsp;(values.hasNext())&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sum&nbsp;</span><span style="color: #000000;">+=</span><span style="color: #000000;">&nbsp;values.next().get();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;output.collect(key,&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;IntWritable(sum));<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">static</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;printUsage()&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.println(</span><span style="color: #000000;">"</span><span style="color: #000000;">gamecount&nbsp;[-m&nbsp;&lt;maps&gt;]&nbsp;[-r&nbsp;&lt;reduces&gt;]&nbsp;&lt;input&gt;&nbsp;&lt;output&gt;&nbsp;&lt;gamename&gt;</span><span style="color: #000000;">"</span><span style="color: #000000;">);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ToolRunner.printGenericCommandUsage(System.out);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">-</span><span style="color: #000000;">1</span><span style="color: #000000;">;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
<br />
&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;"> </span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;run(String[]&nbsp;args)&nbsp;</span><span style="color: #0000ff;">throws</span><span style="color: #000000;">&nbsp;Exception&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;JobConf&nbsp;conf&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;JobConf(getConf(),&nbsp;GameCount.</span><span style="color: #0000ff;">class</span><span style="color: #000000;">);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;conf.setJobName(</span><span style="color: #000000;">"</span><span style="color: #000000;">gamecount</span><span style="color: #000000;">"</span><span style="color: #000000;">);<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color: #000000;"> conf.setOutputKeyClass(Text.</span><span style="color: #0000ff;">class</span><span style="color: #000000;">);<br />
</span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; conf.setOutputValueClass(IntWritable.</span><span style="color: #0000ff;">class</span><span style="color: #000000;">);<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;conf.setMapperClass(MapClass.</span><span style="color: #0000ff;">class</span><span style="color: #000000;">);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;conf.setCombinerClass(ReduceClass.</span><span style="color: #0000ff;">class</span><span style="color: #000000;">);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;conf.setReducerClass(ReduceClass.</span><span style="color: #0000ff;">class</span><span style="color: #000000;">);<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;List</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">String</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">&nbsp;other_args&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;ArrayList</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">String</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">for</span><span style="color: #000000;">&nbsp;(</span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;i&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">0</span><span style="color: #000000;">;&nbsp;i&nbsp;</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">&nbsp;args.length;&nbsp;</span><span style="color: #000000;">++</span><span style="color: #000000;">i)&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">try</span><span style="color: #000000;">&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;(</span><span style="color: #000000;">"</span><span style="color: #000000;">-m</span><span style="color: #000000;">"</span><span style="color: #000000;">.equals(args[i]))&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;conf.setNumMapTasks(Integer.parseInt(args[</span><span style="color: #000000;">++</span><span style="color: #000000;">i]));<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;</span><span style="color: #0000ff;">else</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;(</span><span style="color: #000000;">"</span><span style="color: #000000;">-r</span><span style="color: #000000;">"</span><span style="color: #000000;">.equals(args[i]))&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;conf.setNumReduceTasks(Integer.parseInt(args[</span><span style="color: #000000;">++</span><span style="color: #000000;">i]));<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;</span><span style="color: #0000ff;">else</span><span style="color: #000000;">&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;other_args.add(args[i]);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;</span><span style="color: #0000ff;">catch</span><span style="color: #000000;">&nbsp;(NumberFormatException&nbsp;except)&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(</span><span style="color: #000000;">"</span><span style="color: #000000;">ERROR:&nbsp;Integer&nbsp;expected&nbsp;instead&nbsp;of&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">+</span><span style="color: #000000;">&nbsp;args[i]);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;printUsage();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;</span><span style="color: #0000ff;">catch</span><span style="color: #000000;">&nbsp;(ArrayIndexOutOfBoundsException&nbsp;except)&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(</span><span style="color: #000000;">"</span><span style="color: #000000;">ERROR:&nbsp;Required&nbsp;parameter&nbsp;missing&nbsp;from&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">+</span><span style="color: #000000;">&nbsp;args[i&nbsp;</span><span style="color: #000000;">-</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">1</span><span style="color: #000000;">]);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;printUsage();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;Make&nbsp;sure&nbsp;there&nbsp;are&nbsp;exactly&nbsp;2&nbsp;parameters&nbsp;left.</span><span style="color: #008000;"><br />
</span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;(other_args.size()&nbsp;</span><span style="color: #000000;">!=</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">3</span><span style="color: #000000;">)&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(</span><span style="color: #000000;">"</span><span style="color: #000000;">ERROR:&nbsp;Wrong&nbsp;number&nbsp;of&nbsp;parameters:&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">+</span><span style="color: #000000;">&nbsp;other_args.size()&nbsp;</span><span style="color: #000000;">+</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">&nbsp;instead&nbsp;of&nbsp;2.</span><span style="color: #000000;">"</span><span style="color: #000000;">);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;printUsage();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FileInputFormat.setInputPaths(conf,&nbsp;other_args.get(</span><span style="color: #000000;">0</span><span style="color: #000000;">));<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FileOutputFormat.setOutputPath(conf,&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;Path(other_args.get(</span><span style="color: #000000;">1</span><span style="color: #000000;">)));<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;conf.set(</span><span style="color: #000000;">"</span><span style="color: #000000;">mapred.mapper.game</span><span style="color: #000000;">"</span><span style="color: #000000;">,&nbsp;args[</span><span style="color: #000000;">2</span><span style="color: #000000;">]);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;JobClient.runJob(conf);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">0</span><span style="color: #000000;">;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">static</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">void</span><span style="color: #000000;">&nbsp;main(String[]&nbsp;args)&nbsp;</span><span style="color: #0000ff;">throws</span><span style="color: #000000;">&nbsp;Exception&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">long</span><span style="color: #000000;">&nbsp;start&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;System.nanoTime();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;res&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;ToolRunner.run(</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;Configuration(),&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;GameCount(),&nbsp;args);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(</span><span style="color: #000000;">"</span><span style="color: #000000;">running&nbsp;time:</span><span style="color: #000000;">"</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">+</span><span style="color: #000000;">&nbsp;(System.nanoTime()&nbsp;</span><span style="color: #000000;">-</span><span style="color: #000000;">&nbsp;start)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">/</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">1000000</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">+</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">&nbsp;ms</span><span style="color: #000000;">"</span><span style="color: #000000;">);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.exit(res);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
<br />
}<br />
</span></div>
&nbsp;&nbsp;&nbsp; 代码没啥好解释的，就是分析类似"play game DouDiZhu result:uid=1871653,score=-720,money=0"这样的字符串，分析每天玩家玩游戏的次数、分数等。打包成GameCount.jar，执行：<br />
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #000000;">hadoop&nbsp;jar&nbsp;GameCount.jar&nbsp;test.GameCount&nbsp;</span><span style="color: #000000;">/</span><span style="color: #000000;">usr</span><span style="color: #000000;">/</span><span style="color: #000000;">logs</span><span style="color: #000000;">/</span><span style="color: #000000;">test.log&nbsp;</span><span style="color: #000000;">/</span><span style="color: #000000;">usr</span><span style="color: #000000;">/</span><span style="color: #000000;">output&nbsp;GameName</span></div>
<br />
&nbsp;&nbsp; 统计的运行时间在100多秒，适当增加map和reduce任务个数没有多大改善，不过CPU占用率还是挺高的。<br />
<br />
<br /><img src ="http://www.blogjava.net/killme2008/aggbug/223844.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/killme2008/" target="_blank">dennis</a> 2008-08-23 11:08 <a href="http://www.blogjava.net/killme2008/archive/2008/08/23/223844.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>远程调用的语义</title><link>http://www.blogjava.net/killme2008/archive/2008/08/19/223133.html</link><dc:creator>dennis</dc:creator><author>dennis</author><pubDate>Tue, 19 Aug 2008 15:47:00 GMT</pubDate><guid>http://www.blogjava.net/killme2008/archive/2008/08/19/223133.html</guid><wfw:comment>http://www.blogjava.net/killme2008/comments/223133.html</wfw:comment><comments>http://www.blogjava.net/killme2008/archive/2008/08/19/223133.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/killme2008/comments/commentRss/223133.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/killme2008/services/trackbacks/223133.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp; 远程调用由于涉及到服务器和客户端等多个节点以及需要通过网络通讯等，会引入更多的故障可能。本地调用的语义都是<strong>恰好一次</strong>，不会多也不会少。而远程调用的语义就比较复杂，依据三个选择将产生不同的语义：<br />
1）重发请求消息：客户端是否重发请求，直到收到应答或者认定服务器故障为止<br />
2）过滤重复消息：当客户端重发请求时候，服务器是否过滤重复的请求<br />
3）重传结果：服务器是否保存结果消息的历史，以便服务器不用重新执行操作就能重传结果。<br />
<br />
对这三个选择的不同组合将产生三种可能的远程调用语义：<br />
重发请求消息 过滤重复消息 重传结果&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 语义<br />
<br />
否&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 不适用&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 不适用&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 或许<br />
是&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 否&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 重新执行操作&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 至少一次<br />
是&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 是&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 重传结果&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 至多一次<br />
<strong><br />
或许调用语义</strong>：远程方法可能执行一次，或者根本不执行（在消息遗漏或者服务器崩溃的情况下）<br />
<br />
<strong>至少一次调用语义</strong>：远程方法要嘛至少执行一次并返回结果，要嘛返回一个异常。因为启用了重发请求消息，服务器也重新执行操作，因此远程调用至少执行一次，除非服务器崩溃；但是，由于服务器重新执行操作，如果调用不是幂等的，那么多次重复执行将产生副作用叠加，可能不符合预期需求。对于幂等操作，至少一次调用语义是可以接受的。<br />
<br />
<strong>至多一次调用语义</strong>：在此语义下，服务器会过滤重复的请求，并且缓存执行的结果重传而非重新执行。因此远程调用同样也是返回调用结果，或者一个异常。在返回结果的情况下，可以确认服务器恰好执行一次，与本地调用语义一样，不会有副作用叠加。如果返回异常，就是通知调用者没有返回结果，远程调用要嘛执行了一次，要嘛根本没有执行。总之，远程调用至多执行一次。<br />
<br />
Java RMI的调用语义是至多一次。<br />
<br />
<br /><img src ="http://www.blogjava.net/killme2008/aggbug/223133.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/killme2008/" target="_blank">dennis</a> 2008-08-19 23:47 <a href="http://www.blogjava.net/killme2008/archive/2008/08/19/223133.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>从HDFS看分布式文件系统的设计需求</title><link>http://www.blogjava.net/killme2008/archive/2008/08/15/222360.html</link><dc:creator>dennis</dc:creator><author>dennis</author><pubDate>Fri, 15 Aug 2008 14:38:00 GMT</pubDate><guid>http://www.blogjava.net/killme2008/archive/2008/08/15/222360.html</guid><wfw:comment>http://www.blogjava.net/killme2008/comments/222360.html</wfw:comment><comments>http://www.blogjava.net/killme2008/archive/2008/08/15/222360.html#Feedback</comments><slash:comments>3</slash:comments><wfw:commentRss>http://www.blogjava.net/killme2008/comments/commentRss/222360.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/killme2008/services/trackbacks/222360.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp; 分布式文件系统的设计需求大概是这么几个：透明性、并发控制、可伸缩性、容错以及安全需求等。我想试试从这几个角度去观察HDFS的设计和实现，可以更清楚地看出HDFS的应用场景和设计理念。<br id="vqtw" />
&nbsp;&nbsp;&nbsp; 首先是透明性，如果按照开放分布式处理的标准确定就有8种透明性：访问的透明性、位置的透明性、并发透明性、复制透明性、故障透明性、移动透明性、性能透明性和伸缩透明性。对于分布式文件系统，最重要的是希望能达到5个透明性要求：<br id="d_bf" />
1）访问的透明性：用户能通过相同的操作来访问本地文件和远程文件资源。HDFS可以做到这一点，如果HDFS设置成本地文件系统，而非分布式，那么读写
分布式HDFS的程序可以不用修改地读写本地文件，要做修改的是配置文件。可见，HDFS提供的访问的透明性是不完全的，毕竟它构建于java之上，不能
像NFS或者AFS那样去修改unix内核，同时将本地文件和远程文件以一致的方式处理。<br id="ag5a" />
2）位置的透明性：使用单一的文件命名空间，在不改变路径名的前提下，文件或者文件集合可以被重定位。HDFS集群只有一个Namenode来负责文件系
统命名空间的管理，文件的block可以重新分布复制，block可以增加或者减少副本，副本可以跨机架存储，而这一切对客户端都是透明的。<br id="uqk2" />
3）移动的透明性，这一点与位置的透明性类似，HDFS中的文件经常由于节点的失效、增加或者replication因子的改变或者重新均衡等进行着复制或者移动，而客户端和客户端程序并不需要改变什么，Namenode的edits日志文件记录着这些变更。<br id="u0lr" />
4）性能的透明性和伸缩的透明性：HDFS的目标就是构建在大规模廉价机器上的分布式文件系统集群，可伸缩性毋庸置疑，至于性能可以参考它首页上的一些benchmark。<br id="y43o" />
<br id="y43o0" />
&nbsp;&nbsp;&nbsp;
其次是并发控制，客户端对于文件的读写不应该影响其他客户端对同一个文件的读写。要想实现近似原生文件系统的单个文件拷贝语义，分布式文件系统需要做出复
杂的交互，例如采用时间戳，或者类似回调承诺（类似服务器到客户端的RPC回调，在文件更新的时候；回调有两种状态：有效或者取消。客户端通过检查回调承
诺的状态，来判断服务器上的文件是否被更新过）。HDFS并没有这样做，它的机制非常简单，任何时间都只允许一个写的客户端，文件经创建并写入之后不再改
变，它的模型是<font id="nekf33" face="宋体, SimSun"></font>write-one-read-many<font id="nekf35" face="宋体, SimSun"></font>，
一次写，多次读。这与它的应用场合是一致，HDFS的文件大小通常是兆至T级的，这些数据不会经常修改，最经常的是被顺序读并处理，随机读很少，因此
HDFS非常适合MapReduce框架或者web
crawler应用。HDFS文件的大小也决定了它的客户端不能像某些分布式文件系统那样缓存常用到的几百个文件。<br id="eg92" />
<br id="eg920" />
&nbsp;&nbsp;&nbsp;
第三，文件复制功能，一个文件可以表示为其内容在不同位置的多个拷贝。这样做带来了两个好处：访问同个文件时可以从多个服务器中获取从而改善服务的伸缩
性，另外就是提高了容错能力，某个副本损坏了，仍然可以从其他服务器节点获取该文件。HDFS文件的block为了容错都将被备份，根据配置的
replication因子来，默认是3。副本的存放策略也是很有讲究，一个放在本地机架的节点，一个放在同一机架的另一节点，另一个放在其他机架上。这
样可以最大限度地防止因故障导致的副本的丢失。不仅如此，HDFS读文件的时候也将优先选择从同一机架乃至同一数据中心的节点上读取block。<br id="y5m0" />
<br id="y5m00" />
&nbsp;&nbsp;&nbsp; 第四，硬件和操作系统的异构性。由于构建在java平台上，HDFS的跨平台能力毋庸置疑，得益于java平台已经封装好的文件IO系统，HDFS可以在不同的操作系统和计算机上实现同样的客户端和服务端程序。<br id="xbtj" />
<br id="xbtj0" />
&nbsp;&nbsp;&nbsp; 第五，容错能力，在分布式文件系统中，尽量保证文件服务在客户端或者服务端出现问题的时候能正常使用是非常重要的。HDFS的容错能力大概可以分为两个方面：文件系统的容错性以及Hadoop本身的容错能力。文件系统的容错性通过这么几个手段：<br id="eumk" />
1）在Namenode和Datanode之间维持心跳检测，当由于网络故障之类的原因，导致Datanode发出的心跳包没有被Namenode正常收
到的时候，Namenode就不会将任何新的IO操作派发给那个Datanode，该Datanode上的数据被认为是无效的，因此Namenode会检
测是否有文件block的副本数目小于设置值，如果小于就自动开始复制新的副本并分发到其他Datanode节点。<br id="cm_y" />
2）检测文件block的完整性，HDFS会记录每个新创建的文件的所有block的校验和。当以后检索这些文件的时候，从某个节点获取block，会首先确认校验和是否一致，如果不一致，会从其他Datanode节点上获取该block的副本。<br id="n8ip" />
3）集群的负载均衡，由于节点的失效或者增加，可能导致数据分布的不均匀，当某个Datanode节点的空闲空间大于一个临界值的时候，HDFS会自动从其他Datanode迁移数据过来。<br id="eps9" />
4）Namenode上的fsimage和edits日志文件是HDFS的核心数据结构，如果这些文件损坏了，HDFS将失效。<font id="nekf515" face="宋体, SimSun"><span id="nekf516" lang="zh-CN">因而，</span></font>Namenode<font id="nekf517" face="宋体, SimSun"><span id="nekf518" lang="zh-CN">可以配置成支持维护多
个</span></font>FsImage<font id="nekf519" face="宋体, SimSun"><span id="nekf520" lang="zh-CN">和</span></font>Editlog<font id="nekf521" face="宋体, SimSun"><span id="nekf522" lang="zh-CN">的拷贝。任何对</span></font>FsImage<font id="nekf523" face="宋体, SimSun"><span id="nekf524" lang="zh-CN">或者</span></font>Editlog<font id="nekf525" face="宋体, SimSun"><span id="nekf526" lang="zh-CN">的修改，都将同步到它们的副本上。</span></font><font id="nekf533" face="宋体, SimSun"><span id="nekf534" lang="zh-CN">它总是选取最近的一致的</span></font>FsImage<font id="nekf535" face="宋体, SimSun"><span id="nekf536" lang="zh-CN">和</span></font>Editlog<font id="nekf537" face="宋体, SimSun"><span id="nekf538" lang="zh-CN">使用。</span></font>Namenode<font id="nekf540" face="宋体, SimSun"><span id="nekf541" lang="zh-CN">在</span></font>HDFS<font id="nekf542" face="宋体, SimSun"><span id="nekf543" lang="zh-CN">是单点存在，如果</span></font>Namenode<font id="nekf544" face="宋体, SimSun"><span id="nekf545" lang="zh-CN">所在的机器错误，手工的干预是必须的。</span></font><br id="mnfv" />
5)文件的删除，删除并不是马上从Namenode移出namespace，而是放在/<font id="nekf685" face="宋体, SimSun"></font>trash<font id="nekf687" face="宋体, SimSun"><span id="nekf688" lang="zh-CN">目录随时可恢复，直到超过设置时间才被正式移除。<br id="ggsm" />
</span></font>&nbsp;&nbsp;&nbsp; 再说Hadoop本身的容错性，Hadoop支持升级和回滚，当升级Hadoop软件时出现bug或者不兼容现象，可以通过回滚恢复到老的Hadoop版本。<br id="w3lt" />
&nbsp;&nbsp;&nbsp; 最后一个就是安全性问题，HDFS的安全性是比较弱的，只有简单的与unix文件系统类似的文件许可控制，未来版本会实现类似NFS的kerberos验证系统。<br id="rafz" />
<br id="rafz0" />
&nbsp;&nbsp;&nbsp;
总结下：HDFS作为通用的分布式文件系统并不适合，它在并发控制、缓存一致性以及小文件读写的效率上是比较弱的。但是它有自己明确的设计目标，那就是支
持大的数据文件（兆至T级），并且这些文件以顺序读为主，以文件读的高吞吐量为目标，并且与MapReduce框架紧密结合。<br id="mnfv2" />
<br id="mnfv3" />
<br id="k85y" />
<br id="k85y0" />
&nbsp;&nbsp; <br id="h0870" /><img src ="http://www.blogjava.net/killme2008/aggbug/222360.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/killme2008/" target="_blank">dennis</a> 2008-08-15 22:38 <a href="http://www.blogjava.net/killme2008/archive/2008/08/15/222360.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>HDFS用户指南（翻译）</title><link>http://www.blogjava.net/killme2008/archive/2008/08/14/222097.html</link><dc:creator>dennis</dc:creator><author>dennis</author><pubDate>Thu, 14 Aug 2008 12:24:00 GMT</pubDate><guid>http://www.blogjava.net/killme2008/archive/2008/08/14/222097.html</guid><wfw:comment>http://www.blogjava.net/killme2008/comments/222097.html</wfw:comment><comments>http://www.blogjava.net/killme2008/archive/2008/08/14/222097.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.blogjava.net/killme2008/comments/commentRss/222097.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/killme2008/services/trackbacks/222097.html</trackback:ping><description><![CDATA[HDFS用户指南<br id="o3qg" />
原文地址：http://hadoop.apache.org/core/docs/current/hdfs_user_guide.html<br id="jh7z" />
译者：dennis zhuang(killme2008@gmail.com),有错误请指正，多谢。<br id="o3qg0" />
<h2 id="o3qg1" class="h3">目的<br id="o3qg2" />
</h2>
<div id="o3qg3" class="section">
<p id="o3qg4">本文档可以作为使用Hadoop分布式文件系统用户的起点，无论是将HDFS应用在一个Hadoop集群中还是作为一个单独的分布式文件系统使用。HDFS被设计成可以马上在许多环境中工作起来，那么一些HDFS的运行知识肯定能大大地帮助你对一个集群做配置改进和诊断。<br id="bz6u" />
</p>
</div>
<a style="width: 20px; height: 20px; text-indent: 20px; background-repeat: no-repeat; background-image: url(/CuteSoft_Client/CuteEditor/Load.ashx?type=image&amp;file=anchor.gif);" id="o3qg6" name="N1001B"></a><a style="width: 20px; height: 20px; text-indent: 20px; background-repeat: no-repeat; background-image: url(/CuteSoft_Client/CuteEditor/Load.ashx?type=image&amp;file=anchor.gif);" id="o3qg7" name="Overview"></a>
<h2 id="o3qg8" class="h3">概览<br id="l_0z" />
</h2>
<div id="o3qg9" class="section">
<p id="o3qg10">HDFS是Hadoop应用的主要分布式存储。一个HDFS集群由一个管理文件系统元数据的NameNode，和存储实际
数据的一些Datanode组成。HDFS的架构在这里有详细描述。这个用户指南主要提供给需要跟HDFS集群打交道的用户或者管理员。HDFS架构文章
中的图描绘了Namenode、Datanode和客户端们之间的基本交互。本质上，客户端与Namenode通讯获取或者修改文件的元数据，与
Datanode进行实际的IO操作。<br id="l_0z0" />
</p>
<p id="l_0z1">下面的列表应该是大多数用户关心的HDFS突出特点。斜体字的术语将在后面详细描述。</p>
<p id="fvr_">1）Hadoop，包括HDFS，非常适合廉价机器上的分布式存储和分布式处理。它是容错的、可伸缩的，并且非常易于扩展。并且，以简单性和适用性著称的Map-Reduce是Hadoop不可或缺的组成部分。</p>
<p id="ag1q">2）HDFS的默认配置适合于大多数安装的应用。通常情况下，只有在一个非常大规模的集群上才需要修改默认配置。</p>
<p id="d26i">3）HDFS是用java编写的，支持大多数平台。</p>
<p id="queu">4）支持shell命令行风格的HDFS目录交互。</p>
<p id="ufzm">5）Namenode和Datanode都内建了web服务器，可以方便地查看集群的状态</p>
<p id="jafv">6）HDFS经常性地实现新的特性和改进，下面是HDFS中的一些有用特性的子集：</p>
<p id="c.lr">&nbsp;&nbsp; <em id="v3zz">文件许可和授权</em></p>
<p id="c.lr0">&nbsp;&nbsp; <em id="v3zz0">Rack awareness</em>:当调度任务和分配存储的时候将节点的物理位置考虑进去。</p>
<p id="cbpn">&nbsp;&nbsp; <em id="v3zz1">Safemode(安全模式）</em>：用于维护的一个管理状态</p>
<p id="tej-">&nbsp;&nbsp; <em id="v3zz2">fsck</em>： 诊断文件系统的一个工具，用来查找丢失的文件或者block</p>
<p id="z_lu">&nbsp;&nbsp; <em id="v3zz3">Rebalancer</em>:当数据在Datanode间没有均匀分布的时候，用于重新平衡集群的工具</p>
<p id="p1gp">&nbsp;&nbsp; <em id="v3zz4">升级和回滚</em>：当Hadoop软件升级，在升级遇到不可预期的问题的时候，可以回滚到HDFS升级前的状态</p>
<p id="fzza">&nbsp;&nbsp; <em id="v3zz5">二级Namenode</em>：帮助Namenode维持包含了HDFS修改的日志的文件（edits日志文件,下文谈到）大小在限制范围内。<br id="ubzs" />
</p>
</div>
<a style="width: 20px; height: 20px; text-indent: 20px; background-repeat: no-repeat; background-image: url(/CuteSoft_Client/CuteEditor/Load.ashx?type=image&amp;file=anchor.gif);" id="o3qg41" name="N10083"></a><a style="width: 20px; height: 20px; text-indent: 20px; background-repeat: no-repeat; background-image: url(/CuteSoft_Client/CuteEditor/Load.ashx?type=image&amp;file=anchor.gif);" id="o3qg42" name="Pre-requisites"></a>
<h2 id="o3qg43" class="h3">前提条件<br id="px_d" />
</h2>
<div id="o3qg44" class="section">
<p id="o3qg45">下面的文档描述了一个Hadoop集群的安装和设置：<br id="px_d0" />
</p>
<ul id="o3qg46">
    <li id="o3qg47">
    <a id="o3qg48" href="http://hadoop.apache.org/core/docs/current/quickstart.html">Hadoop Quickstart</a>，给初次使用用户 <br id="bb4w" />
    </li>
    <li id="o3qg49">
    <a id="o3qg50" href="http://hadoop.apache.org/core/docs/current/cluster_setup.html">Hadoop Cluster Setup</a> 大规模、分布式集群<br id="p8d9" />
    </li>
</ul>
<p id="o3qg51"><br id="tegj" />
</p>
<p id="tegj0">本文档的剩余部分假设你已经搭设并运行了一个至少拥有一个Datanode的HDFS。基于本文档的目的，Namenode和Datanode可以运行在同一台机器上。<br id="tegj1" />
</p>
</div>
<a style="width: 20px; height: 20px; text-indent: 20px; background-repeat: no-repeat; background-image: url(/CuteSoft_Client/CuteEditor/Load.ashx?type=image&amp;file=anchor.gif);" id="o3qg52" name="N100A1"></a><a style="width: 20px; height: 20px; text-indent: 20px; background-repeat: no-repeat; background-image: url(/CuteSoft_Client/CuteEditor/Load.ashx?type=image&amp;file=anchor.gif);" id="o3qg53" name="Web+Interface"></a>
<h2 id="o3qg54" class="h3"> Web接口 </h2>
<div id="o3qg55" class="section">
<p id="o3qg56">Namenode和Datanode分别跑了一个内置的web服务器，来展现集群当前状态的一些基本信息。在默认配置
下，Namenode的首页地址是http://namenode:50070（namenode就是Namenode节点所在机器IP或者名称）。这个
页面列出了集群中的所有datanode以及集群的基本统计。web接口同样可以用于浏览文件系统（点击Namenode首页上的&#8220;Browse
the file system"链接）。<br id="lb5-" />
</p>
</div>
<a style="width: 20px; height: 20px; text-indent: 20px; background-repeat: no-repeat; background-image: url(/CuteSoft_Client/CuteEditor/Load.ashx?type=image&amp;file=anchor.gif);" id="o3qg58" name="N100AE"></a><a style="width: 20px; height: 20px; text-indent: 20px; background-repeat: no-repeat; background-image: url(/CuteSoft_Client/CuteEditor/Load.ashx?type=image&amp;file=anchor.gif);" id="o3qg59" name="Shell+Commands"></a>
<h2 id="o3qg60" class="h3">Shell命令<br id="wep4" />
</h2>
<div id="o3qg61" class="section">
<p id="o3qg62">Hadoop包括了多种shell风格的命令，用于跟HDFS或者Hadoop支持的其他文件系统交互。命令
bin/hadoop fs -help 可以列出Hadoop shell支持的命令。更进一步，bin/hadoop fs -help
command
可以展现特定命令command的帮助细节。这些命令支持一般文件系统的操作，例如拷贝文件、修改文件权限等。同时也支持了部分HDFS特有的命令，例如
修改文件的replication因子。<br id="wep40" />
</p>
<a style="width: 20px; height: 20px; text-indent: 20px; background-repeat: no-repeat; background-image: url(/CuteSoft_Client/CuteEditor/Load.ashx?type=image&amp;file=anchor.gif);" id="o3qg65" name="N100BD"></a><a style="width: 20px; height: 20px; text-indent: 20px; background-repeat: no-repeat; background-image: url(/CuteSoft_Client/CuteEditor/Load.ashx?type=image&amp;file=anchor.gif);" id="o3qg66" name="DFSAdmin+Command"></a>
<h3 id="o3qg67" class="h4"> DFSAdmin命令 </h3>
<p id="o3qg68">
<span id="o3qg69" class="codefrag">'bin/hadoop dfsadmin'</span>
命令支持一些HDFS管理功能的操作。'bin/hadoop dfsadmin -help'可以列出所有当前支持的命令。例如：</p>
<ul id="o3qg71">
    <li id="o3qg72">
    <span id="o3qg73" class="codefrag">-report</span>
    : 报告HDFS的基本统计信息。部分信息同时展现在Namenode的web首页上。&nbsp;
    </li>
    <li id="o3qg74">
    <span id="o3qg75" class="codefrag">-safemode</span>
    : 尽管通常并不需要，管理员还是可以通过手工操作进入或者离开safemode状态
    </li>
    <li id="o3qg77">
    <span id="o3qg78" class="codefrag">-finalizeUpgrade</span>
    : 移除上一次升级时集群所做的备份。
    </li>
</ul>
</div>
<a style="width: 20px; height: 20px; text-indent: 20px; background-repeat: no-repeat; background-image: url(/CuteSoft_Client/CuteEditor/Load.ashx?type=image&amp;file=anchor.gif);" id="o3qg79" name="N100E6"></a><a style="width: 20px; height: 20px; text-indent: 20px; background-repeat: no-repeat; background-image: url(/CuteSoft_Client/CuteEditor/Load.ashx?type=image&amp;file=anchor.gif);" id="o3qg80" name="Secondary+Namenode"></a>
<h2 id="o3qg81" class="h3"> 二级Namenode </h2>
<div id="o3qg82" class="section">
<p id="o3qg83">Namenode将对文件系统的修改存储在一个原生文件系统文件中（名为edits的文件）。当Namenode启动的时
候，它从映像文件（fsimage)读取HDFS的状态，然后将edits日志文件中的修改作用在此内存状态上，接着将得到的新的HDFS状态写回
fsimage，后续的正常操作开始于一个空的edits日志文件。由于Namenode仅仅在启动的时候将fsimage和edits合并，因此在一个
大的集群上经过一定时间操作后，edits文件将会非常大。由此带来的一个副作用就是下次Namenode的重新启动将花费很长时间。二级
Namenode就是为了解决这个问题，它会周期性地合并fsimage和edits日志文件，并且将edits日志文件的大小保持在限制范围内。通常它
会跑在另一个机器上，因为它的内存要求跟主namenode一样。二级Namenode可以通过'bin/start-dfs.sh'启动在conf
/masters配置文件里配置的节点上。<br id="s4h2" />
</p>
</div>
<a style="width: 20px; height: 20px; text-indent: 20px; background-repeat: no-repeat; background-image: url(/CuteSoft_Client/CuteEditor/Load.ashx?type=image&amp;file=anchor.gif);" id="o3qg93" name="N1010B"></a><a style="width: 20px; height: 20px; text-indent: 20px; background-repeat: no-repeat; background-image: url(/CuteSoft_Client/CuteEditor/Load.ashx?type=image&amp;file=anchor.gif);" id="o3qg94" name="Rebalancer"></a>
<h2 id="o3qg95" class="h3"> Rebalancer </h2>
<div id="o3qg96" class="section">
<p id="o3qg97">HDFS的数据可能不会总是在Datanode之间分布得很一致。一个常见的原因是往现有的集群中加入了新的Datanode。当分配block的时候，Namenode依据几个参数来决定哪个datanode来接受这些block。一些需要考虑的因素如下：</p>
<p id="i-5q">1）一个block的副本存放在正在写该block的节点上</p>
<p id="fj63">2）需要将一个block的副本扩展到其他机架上，防止因为整个机架故障导致的数据丢失。</p>
<p id="ik23">3）副本之一通常放在同一个机架的另一个节点上，减少跨机架的网络IO</p>
<p id="dswx">4）将HDFS数据均匀一致地分布在集群中的datanode上。</p>
<p id="dswx0">&nbsp;&nbsp;&nbsp; 基于这些相互竞争的因素，数据可能不会在Datanode之间扩展得一致。HDFS给管理员提供了一个工具，用来分析block的分配情况和在datanode之间重新平衡数据。这个功能暂未实现，它的描述可以在这个&nbsp;<a id="o3qg105" href="http://issues.apache.org/jira/secure/attachment/12368261/RebalanceDesign6.pdf">PDF</a>文档中看到，记录编号<a id="o3qg106" href="http://issues.apache.org/jira/browse/HADOOP-1652">HADOOP-1652</a>.</p>
</div>
<a style="width: 20px; height: 20px; text-indent: 20px; background-repeat: no-repeat; background-image: url(/CuteSoft_Client/CuteEditor/Load.ashx?type=image&amp;file=anchor.gif);" id="o3qg107" name="N10132"></a><a style="width: 20px; height: 20px; text-indent: 20px; background-repeat: no-repeat; background-image: url(/CuteSoft_Client/CuteEditor/Load.ashx?type=image&amp;file=anchor.gif);" id="o3qg108" name="Rack+Awareness"></a>
<h2 id="o3qg109" class="h3"> Rack Awareness </h2>
<div id="o3qg110" class="section">
<p id="o3qg111">典型的大规模Hadoop集群是部署在数个机架上的，那么显然同一个机架内的节点间的网络通讯比之不同机架间节点间的网
络通讯更可取。另外，Namenode会尝试将block的副本分布在数个机架中以提高容错性。Hadoop让集群管理员来决定某个节点从属于哪个机架，
通过配置变量dfs.network.script来实现。当这个脚本有配置的时候，每个节点都运行该脚本来决定它的rackid。默认安装假设所有的节
点从属于同一个机架。这个特性和配置进一步的阐述在这个<a id="o3qg116" href="http://issues.apache.org/jira/secure/attachment/12345251/Rack_aware_HDFS_proposal.pdf">PDF</a>文档，编号为
<a id="o3qg117" href="http://issues.apache.org/jira/browse/HADOOP-692">HADOOP-692</a>。
</p>
</div>
<a style="width: 20px; height: 20px; text-indent: 20px; background-repeat: no-repeat; background-image: url(/CuteSoft_Client/CuteEditor/Load.ashx?type=image&amp;file=anchor.gif);" id="o3qg118" name="N10150"></a><a style="width: 20px; height: 20px; text-indent: 20px; background-repeat: no-repeat; background-image: url(/CuteSoft_Client/CuteEditor/Load.ashx?type=image&amp;file=anchor.gif);" id="o3qg119" name="Safemode"></a>
<h2 id="o3qg120" class="h3"> Safemod(安全模式） </h2>
<div id="o3qg121" class="section">
<p id="o3qg122">当Namenode启动的时候，它从fsimage和edits日志两个文件中加载文件系统的状态。然后等待
datanode报告他们的block信息，以便防止Namenode在确认block副本是否足够前过早地开始复制block。这段时间的
Namenode就是处于所谓safemode状态。处于safemode的Namenode也是HDFS集群的只读模型，此时不允许任何对文件系统或者
block的修改。正常情况下，Namenode会在开始后自动退出safemode。如果有需要，HDFS可以通过'bin/hadoop
dfsadmin
-safemode'命令显式地进入safemode状态。Namenode的web首页显示当前的safemode是否打开。更详细的描述和配置可以参
考<a id="o3qg128" href="http://hadoop.apache.org/core/docs/current/api/org/apache/hadoop/dfs/NameNode.html#setSafeMode%28org.apache.hadoop.dfs.FSConstants.SafeModeAction%29"><span id="o3qg129" class="codefrag">setSafeMode()</span></a>方法的JavaDoc。</p>
<p id="y.-h">译
注：详细介绍下safemode的配置参数，在safemode状态，Namenode会等待所有的datanode报告他们自己的block信息，看看
所有的block的副本是否达到最低要求的数目，这个数目可以通过dfs.replication.min参数配置，默认是1,也就是至少要求有一个副
本。当报告合格的Datanode的数目达到一定百分比，Namenode才会离开safemode状态。这个百分比也是可配置的，通过
dfs.safemode.<tt id="v23v">threshold.pct参数，默认是0.999f(也就是要求99.9%的Datanode
合格）。Namenode在合格的datanode数目达到要求的时候，并不是马上离开safemode状态，会有一个扩展时间，让剩余的
datanode来报告block信息，这个扩展时间默认是30秒，可以通过</tt><tt id="zwjf">dfs.safemode.extension参数配置，单位是毫秒。</tt>
</p>
</div>
<a style="width: 20px; height: 20px; text-indent: 20px; background-repeat: no-repeat; background-image: url(/CuteSoft_Client/CuteEditor/Load.ashx?type=image&amp;file=anchor.gif);" id="o3qg130" name="N1016E"></a><a style="width: 20px; height: 20px; text-indent: 20px; background-repeat: no-repeat; background-image: url(/CuteSoft_Client/CuteEditor/Load.ashx?type=image&amp;file=anchor.gif);" id="o3qg131" name="Fsck"></a>
<h2 id="o3qg132" class="h3"> Fsck </h2>
<div id="o3qg133" class="section">
<p id="o3qg134">HDFS提供了fsck命令用来检测各种各样的不一致性。fsck被设计用来报告各种文件的问题，例如某个文件丢失的
block，block的副本数目是否低于设置等。不同于传统的一般原生文件系统的fsck命令，hdfs的fsck命令并不修正所检测到的错误。通常情
况下，Namenode会自动修正大多数可以被修复的错误，HDFS的fsck不是Hadoop shel的命令，可以通过'bin/hadoop
fsck'执行，可以运行在整个文件系统上或者一个文件子集上。<br id="as3m" />
</p>
</div>
<a style="width: 20px; height: 20px; text-indent: 20px; background-repeat: no-repeat; background-image: url(/CuteSoft_Client/CuteEditor/Load.ashx?type=image&amp;file=anchor.gif);" id="o3qg137" name="N1017E"></a><a style="width: 20px; height: 20px; text-indent: 20px; background-repeat: no-repeat; background-image: url(/CuteSoft_Client/CuteEditor/Load.ashx?type=image&amp;file=anchor.gif);" id="o3qg138" name="Upgrade+and+Rollback"></a>
<h2 id="o3qg139" class="h3"> 升级和回滚 </h2>
<div id="o3qg140" class="section">
<p id="o3qg141">当升级某个集群的Hadoop的时候，正如任何软件的升级一样，可能会引入新的bug或者不兼容的修改导致现有的应用出
现过去没有发现的问题。在所有重要的HDFS安装应用中，是不允许出现因丢失任何数据需要从零开始重启HDFS的情况。HDFS允许管理员恢复到
Hadoop的早期版本，并且将集群的状态回滚到升级前。HDFS的升级细节请参考 <a id="o3qg143" href="http://wiki.apache.org/hadoop/Hadoop%20Upgrade">upgrade wiki</a>。HDFS在任何时间只能有一个备份，因此在升级前，管理员需要通过'bin/hadoop dfsadmin -finalizeUpgrade'命令移除现有的备份。下面简要描述了典型的升级过程：</p>
<p id="ctbn">1）在升级Hadoop前，如果已经存在备份，需要先结束（finalize)它。可以通过'dfsadmin -upgradeProgress status'命令查询集群是否需要执行finalize</p>
<p id="kpd3">2)停止集群，分发部署新版本的Hadoop</p>
<p id="ur8l">3）执行新版本的hadoop，通过添加 -upgrade 选项，例如/bin/start-dfs.sh -upgrade</p>
<p id="gmxl">4)大多数情况下，集群在升级后可以正常运行。一旦新的HDFS在运行若干天的操作后没有出现问题，那么就可以结束(finalize)这次升级。请注意，在升级前删除的文件并不释放在datanode上的实际磁盘空间,直到集群被结束（finalize)升级前。</p>
<p id="xsll">5）如果有需要回到老版本的Hadoop，那么可以：</p>
<p id="xsll0">&nbsp;&nbsp; a)停止集群，分发部署老版本的Hadoop</p>
<p id="xsll1">&nbsp;&nbsp; b)通过rollback选项启动集群，例如bin/start-dfs.sh -rollback<br id="ctbn0" />
</p>
<a style="width: 20px; height: 20px; text-indent: 20px; background-repeat: no-repeat; background-image: url(/CuteSoft_Client/CuteEditor/Load.ashx?type=image&amp;file=anchor.gif);" id="o3qg160" name="N101BF"></a><a style="width: 20px; height: 20px; text-indent: 20px; background-repeat: no-repeat; background-image: url(/CuteSoft_Client/CuteEditor/Load.ashx?type=image&amp;file=anchor.gif);" id="o3qg161" name="File+Permissions+and+Security"></a>
</div>
<h2 id="o3qg162" class="h3"> 文件许可和安全</h2>
<div id="o3qg163" class="section">
<p id="o3qg164">文件许可的设计与其他平台(如linux)
的文件系统类似。在当前实现，安全被限制在简单的文件许可上。启动Namenode的用户被作为HDFS的超级用户。HDFS的未来版本将支持网络验证，
例如Kerberos方案（译注：MIT开发的一个验证系统）的用户验证以及数据传输的加密。更详细的讨论参考<a id="o3qg166" href="http://hadoop.apache.org/core/docs/current/hdfs_permissions_guide.html"><em id="o3qg167">Permissions User and Administrator Guide</em></a>。
</p>
</div>
<a style="width: 20px; height: 20px; text-indent: 20px; background-repeat: no-repeat; background-image: url(/CuteSoft_Client/CuteEditor/Load.ashx?type=image&amp;file=anchor.gif);" id="o3qg168" name="N101D1"></a><a style="width: 20px; height: 20px; text-indent: 20px; background-repeat: no-repeat; background-image: url(/CuteSoft_Client/CuteEditor/Load.ashx?type=image&amp;file=anchor.gif);" id="o3qg169" name="Scalability"></a>
<h2 id="o3qg170" class="h3">伸缩性<br id="m-bp" />
</h2>
<div id="o3qg171" class="section">
<p id="o3qg172">Hadoop正运行在成千上万个节点的集群上。      <a id="o3qg173" href="http://wiki.apache.org/hadoop/PoweredBy">PoweredBy Hadoop</a>列
出了一些部署Hadoop在大规模集群上的组织和机构。HDFS在每个集群上只有一个Namenode节点，Namenode节点上可用内存是当前伸缩性
的主要限制。在非常大规模的集群上，增加HDFS中存储的文件的平均大小，将可以帮助提高集群的大小而不用增加Namenode的内存需求。默认的配置可
能不适合非常大规模的集群应用。<a id="o3qg174" href="http://wiki.apache.org/hadoop/FAQ">Hadoop FAQ</a>页列出了对于大规模Hadoop集群的配置改进建议。
</p>
</div>
<a style="width: 20px; height: 20px; text-indent: 20px; background-repeat: no-repeat; background-image: url(/CuteSoft_Client/CuteEditor/Load.ashx?type=image&amp;file=anchor.gif);" id="o3qg175" name="N101E3"></a><a style="width: 20px; height: 20px; text-indent: 20px; background-repeat: no-repeat; background-image: url(/CuteSoft_Client/CuteEditor/Load.ashx?type=image&amp;file=anchor.gif);" id="o3qg176" name="Related+Documentation"></a>
<h2 id="o3qg177" class="h3">关联文档<br id="n8q_" />
</h2>
<div id="o3qg178" class="section">
<p id="o3qg179">&nbsp;本用户指南可作为使用HDFS很好的一个起点，在本文档持续改进的同时，有一些非常有价值的关于Hadoop和HDFS的文档资料可供参考。下列资料可作为进一步探索的起点：<br id="ugay" />
</p>
<ul id="o3qg180">
    <li id="o3qg181">
    <a id="o3qg182" href="http://hadoop.apache.org/">Hadoop Home Page</a>
    : Hadoop一切的起始页。
    </li>
    <li id="o3qg183">
    <a id="o3qg184" href="http://wiki.apache.org/hadoop/FrontPage">Hadoop Wiki</a>
    :由社区维护的wiki文档。</li>
    <li id="o3qg185">
    <a id="o3qg186" href="http://wiki.apache.org/hadoop/FAQ">FAQ</a> from Hadoop Wiki.
    </li>
    <li id="o3qg187">
    Hadoop <a id="o3qg188" href="http://hadoop.apache.org/core/docs/current/api/">
    JavaDoc API</a>.
    </li>
    <li id="o3qg189">
    Hadoop User Mailing List :
    <a id="o3qg190" href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#99;&#111;&#114;&#101;&#45;&#117;&#115;&#101;&#114;&#64;&#104;&#97;&#100;&#111;&#111;&#112;&#46;&#97;&#112;&#97;&#99;&#104;&#101;&#46;&#111;&#114;&#103;">core-user[at]hadoop.apache.org</a>.
    </li>
    <li id="o3qg191">
    浏览<span id="o3qg192" class="codefrag">conf/hadoop-default.xml</span>文件，它包括了当前可用配置变量的概括介绍。
    </li>
</ul>
</div>
<br id="o3qg193" /><img src ="http://www.blogjava.net/killme2008/aggbug/222097.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/killme2008/" target="_blank">dennis</a> 2008-08-14 20:24 <a href="http://www.blogjava.net/killme2008/archive/2008/08/14/222097.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Hadoop分布式文件系统：架构和设计要点</title><link>http://www.blogjava.net/killme2008/archive/2008/06/05/206043.html</link><dc:creator>dennis</dc:creator><author>dennis</author><pubDate>Thu, 05 Jun 2008 06:29:00 GMT</pubDate><guid>http://www.blogjava.net/killme2008/archive/2008/06/05/206043.html</guid><wfw:comment>http://www.blogjava.net/killme2008/comments/206043.html</wfw:comment><comments>http://www.blogjava.net/killme2008/archive/2008/06/05/206043.html#Feedback</comments><slash:comments>23</slash:comments><wfw:commentRss>http://www.blogjava.net/killme2008/comments/commentRss/206043.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/killme2008/services/trackbacks/206043.html</trackback:ping><description><![CDATA[<p id="nekf0" class="western" style="margin-bottom: 0in;">Hadoop<font id="nekf1" face="宋体, SimSun"><span id="nekf2" lang="zh-CN">分布式文件系统：架构和设计要点</span></font><br id="nekf3" />
原文：http://hadoop.apache.org/core/docs/current/hdfs_design.html<br id="nekf4" />
<font id="nekf5" face="宋体, SimSun"><span id="nekf6" lang="zh-CN">一、前提和设计目标</span></font><br id="nekf7" />
1<font id="nekf8" face="宋体, SimSun"><span id="nekf9" lang="zh-CN">、硬件错误是常态，而非异常情况，</span></font>HDFS<font id="nekf10" face="宋体, SimSun"><span id="nekf11" lang="zh-CN">可能是有成百上千的</span></font>server<font id="nekf12" face="宋体, SimSun"><span id="nekf13" lang="zh-CN">组成，任何一个组件都有可能一直失效，因此错误检测和快速、自动的恢复是</span></font>HDFS<font id="nekf14" face="宋体, SimSun"><span id="nekf15" lang="zh-CN">的核心架构目标。</span></font><br id="nekf16" />
2<font id="nekf17" face="宋体, SimSun"><span id="nekf18" lang="zh-CN">、跑在</span></font>HDFS<font id="nekf19" face="宋体, SimSun"><span id="nekf20" lang="zh-CN">上的应用与一般的应用不同，它们主要是以流式读为主，做批量处理；比之关注数据访问的低延迟问题，更关键的在于数据访问的高吞吐量。</span></font><br id="nekf21" />
3<font id="nekf22" face="宋体, SimSun"><span id="nekf23" lang="zh-CN">、</span></font>HDFS<font id="nekf24" face="宋体, SimSun"><span id="nekf25" lang="zh-CN">以支持大数据集合为目标，一个存储在上面的典型文件大小一般都在千兆至</span></font>T<font id="nekf26" face="宋体, SimSun"><span id="nekf27" lang="zh-CN">字节，一个单一</span></font>HDFS<font id="nekf28" face="宋体, SimSun"><span id="nekf29" lang="zh-CN">实例应该能支撑数以千万计的文件。</span></font><br id="nekf30" />
4<font id="nekf31" face="宋体, SimSun"><span id="nekf32" lang="zh-CN">、
</span></font>HDFS<font id="nekf33" face="宋体, SimSun"><span id="nekf34" lang="zh-CN">应用对文件要求的是</span></font>write-one-read-many<font id="nekf35" face="宋体, SimSun"><span id="nekf36" lang="zh-CN">访问模型。一个文件经过创建、写，关闭之后就不需要改变。这一假设简化了数据一致性问
题，使高吞吐量的数据访问成为可能。典型的如</span></font>MapReduce<font id="nekf37" face="宋体, SimSun"><span id="nekf38" lang="zh-CN">框架，或者一个</span></font>web
crawler<font id="nekf39" face="宋体, SimSun"><span id="nekf40" lang="zh-CN">应用都很适合这个模型。</span></font><br id="nekf41" />
5<font id="nekf42" face="宋体, SimSun"><span id="nekf43" lang="zh-CN">、移动计算的代价比之移动数据的代价低。一个应用请求的计算，离它操作的数据越近就越高效，这在数据达到海量级别的时候更是如此。将计算移动到数据附近，比之将数据移动到应用所在显然更好，</span></font>HDFS<font id="nekf44" face="宋体, SimSun"><span id="nekf45" lang="zh-CN">提供给应用这样的接口。</span></font><br id="nekf46" />
6<font id="nekf47" face="宋体, SimSun"><span id="nekf48" lang="zh-CN">、在异构的软硬件平台间的可移植性。</span></font><br id="nekf49" />
<br id="nekf50" />
<font id="nekf51" face="宋体, SimSun"><span id="nekf52" lang="zh-CN">二、</span></font>Namenode<font id="nekf53" face="宋体, SimSun"><span id="nekf54" lang="zh-CN">和</span></font>Datanode<br id="nekf55" />
&nbsp;&nbsp;&nbsp;
HDFS<font id="nekf56" face="宋体, SimSun"><span id="nekf57" lang="zh-CN">采用</span></font>master/slave<font id="nekf58" face="宋体, SimSun"><span id="nekf59" lang="zh-CN">架构。一个</span></font>HDFS<font id="nekf60" face="宋体, SimSun"><span id="nekf61" lang="zh-CN">集群是有一个</span></font>Namenode<font id="nekf62" face="宋体, SimSun"><span id="nekf63" lang="zh-CN">和一定数目的</span></font>Datanode<font id="nekf64" face="宋体, SimSun"><span id="nekf65" lang="zh-CN">组成。</span></font>Namenode<font id="nekf66" face="宋体, SimSun"><span id="nekf67" lang="zh-CN">是一个中心服
务器，负责管理文件系统的</span></font>namespace<font id="nekf68" face="宋体, SimSun"><span id="nekf69" lang="zh-CN">和客户端对文件的访问。</span></font>Datanode<font id="nekf70" face="宋体, SimSun"><span id="nekf71" lang="zh-CN">在集群中一般是一个节点一个，负责管理节点上它们附带的存储。在内
部，一个文件其实分成一个或多个</span></font>block<font id="nekf72" face="宋体, SimSun"><span id="nekf73" lang="zh-CN">，这些</span></font>block<font id="nekf74" face="宋体, SimSun"><span id="nekf75" lang="zh-CN">存储在</span></font>Datanode<font id="nekf76" face="宋体, SimSun"><span id="nekf77" lang="zh-CN">集合里。</span></font>Namenode<font id="nekf78" face="宋体, SimSun"><span id="nekf79" lang="zh-CN">执行文件系统的</span></font>namespace<font id="nekf80" face="宋体, SimSun"><span id="nekf81" lang="zh-CN">操作，例如
打开、关闭、重命名文件和目录，同时决定</span></font>block<font id="nekf82" face="宋体, SimSun"><span id="nekf83" lang="zh-CN">到具体</span></font>Datanode<font id="nekf84" face="宋体, SimSun"><span id="nekf85" lang="zh-CN">节点的映射。</span></font>Datanode<font id="nekf86" face="宋体, SimSun"><span id="nekf87" lang="zh-CN">在</span></font>Namenode<font id="nekf88" face="宋体, SimSun"><span id="nekf89" lang="zh-CN">的指挥下进行</span></font>block<font id="nekf90" face="宋体, SimSun"><span id="nekf91" lang="zh-CN">的创
建、删除和复制。</span></font>Namenode<font id="nekf92" face="宋体, SimSun"><span id="nekf93" lang="zh-CN">和</span></font>Datanode<font id="nekf94" face="宋体, SimSun"><span id="nekf95" lang="zh-CN">都是设计成可以跑在普通的廉价的运行</span></font>linux<font id="nekf96" face="宋体, SimSun"><span id="nekf97" lang="zh-CN">的机器上。</span></font>HDFS<font id="nekf98" face="宋体, SimSun"><span id="nekf99" lang="zh-CN">采用</span></font>java<font id="nekf100" face="宋体, SimSun"><span id="nekf101" lang="zh-CN">语言开发，因此可以部
署在很大范围的机器上。一个典型的部署场景是一台机器跑一个单独的</span></font>Namenode<font id="nekf102" face="宋体, SimSun"><span id="nekf103" lang="zh-CN">节点，集群中的其他机器各跑一个</span></font>Datanode<font id="nekf104" face="宋体, SimSun"><span id="nekf105" lang="zh-CN">实例。这个架构并不排
除一台机器上跑多个</span></font>Datanode<font id="nekf106" face="宋体, SimSun"><span id="nekf107" lang="zh-CN">，不过这比较少见。</span></font><br id="nekf108" />
<img id="nekf109" src="http://docs.google.com/File?id=ddxkntwd_24fwt83gcp_b" name="graphics1" alt="" align="bottom" border="0" width="577" height="394" /><br id="nekf110" />
<font id="nekf111" face="宋体, SimSun"><span id="nekf112" lang="zh-CN">单一节点的</span></font>Namenode<font id="nekf113" face="宋体, SimSun"><span id="nekf114" lang="zh-CN">大大简化了系统的架构。</span></font>Namenode<font id="nekf115" face="宋体, SimSun"><span id="nekf116" lang="zh-CN">负责保管和管理所有的</span></font>HDFS<font id="nekf117" face="宋体, SimSun"><span id="nekf118" lang="zh-CN">元数据，因而用户数据就不需要通过</span></font>Namenode<font id="nekf119" face="宋体, SimSun"><span id="nekf120" lang="zh-CN">（也就是说文件数据的读写是直接在</span></font>Datanode<font id="nekf121" face="宋体, SimSun"><span id="nekf122" lang="zh-CN">上）。</span></font><br id="nekf123" />
<br id="nekf124" />
<font id="nekf125" face="宋体, SimSun"><span id="nekf126" lang="zh-CN">三、文件系统的</span></font>namespace<br id="nekf127" />
&nbsp;&nbsp;
HDFS<font id="nekf128" face="宋体, SimSun"><span id="nekf129" lang="zh-CN">支持传统的层次型文件组织，与大多数其他文件系统类似，用户可以创建目录，并在其间创建、删除、移动和重命名文件。</span></font>HDFS<font id="nekf130" face="宋体, SimSun"><span id="nekf131" lang="zh-CN">不支持</span></font>user
quotas<font id="nekf132" face="宋体, SimSun"><span id="nekf133" lang="zh-CN">和访问权限，也不支持链接（</span></font>link)<font id="nekf134" face="宋体, SimSun"><span id="nekf135" lang="zh-CN">，不过当前的架构并不排除实现这些特性。</span></font>Namenode<font id="nekf136" face="宋体, SimSun"><span id="nekf137" lang="zh-CN">维护文件系统的</span></font>namespace<font id="nekf138" face="宋体, SimSun"><span id="nekf139" lang="zh-CN">，任何对文
件系统</span></font>namespace<font id="nekf140" face="宋体, SimSun"><span id="nekf141" lang="zh-CN">和文件属性的修改都将被</span></font>Namenode<font id="nekf142" face="宋体, SimSun"><span id="nekf143" lang="zh-CN">记录下来。应用可以设置</span></font>HDFS<font id="nekf144" face="宋体, SimSun"><span id="nekf145" lang="zh-CN">保存的文件的副本数目，文件副本的数目称为文件的
</span></font>replication<font id="nekf146" face="宋体, SimSun"><span id="nekf147" lang="zh-CN">因子，这个信息也是由</span></font>Namenode<font id="nekf148" face="宋体, SimSun"><span id="nekf149" lang="zh-CN">保存。</span></font><br id="nekf150" />
<br id="nekf151" />
<font id="nekf152" face="宋体, SimSun"><span id="nekf153" lang="zh-CN">四、数据复制</span></font><br id="nekf154" />
&nbsp;&nbsp;&nbsp;
HDFS<font id="nekf155" face="宋体, SimSun"><span id="nekf156" lang="zh-CN">被设计成在一个大集群中可以跨机器地可靠地存储海量的文件。它将每个文件存储成</span></font>block<font id="nekf157" face="宋体, SimSun"><span id="nekf158" lang="zh-CN">序列，除了最后一个</span></font>block<font id="nekf159" face="宋体, SimSun"><span id="nekf160" lang="zh-CN">，所有的</span></font>block<font id="nekf161" face="宋体, SimSun"><span id="nekf162" lang="zh-CN">都是同
样的大小。文件的所有</span></font>block<font id="nekf163" face="宋体, SimSun"><span id="nekf164" lang="zh-CN">为了容错都会被复制。每个文件的</span></font>block<font id="nekf165" face="宋体, SimSun"><span id="nekf166" lang="zh-CN">大小和</span></font>replication<font id="nekf167" face="宋体, SimSun"><span id="nekf168" lang="zh-CN">因子都是可配置的。</span></font>Replication<font id="nekf169" face="宋体, SimSun"><span id="nekf170" lang="zh-CN">因子可
以在文件创建的时候配置，以后也可以改变。</span></font>HDFS<font id="nekf171" face="宋体, SimSun"><span id="nekf172" lang="zh-CN">中的文件是</span></font>write-one<font id="nekf173" face="宋体, SimSun"><span id="nekf174" lang="zh-CN">，并且严格要求在任何时候只有一个</span></font>writer<font id="nekf175" face="宋体, SimSun"><span id="nekf176" lang="zh-CN">。</span></font>Namenode<font id="nekf177" face="宋体, SimSun"><span id="nekf178" lang="zh-CN">全权管
理</span></font>block<font id="nekf179" face="宋体, SimSun"><span id="nekf180" lang="zh-CN">的复制，它周期性地从集群中的每个</span></font>Datanode<font id="nekf181" face="宋体, SimSun"><span id="nekf182" lang="zh-CN">接收心跳包和一个</span></font>Blockreport<font id="nekf183" face="宋体, SimSun"><span id="nekf184" lang="zh-CN">。心跳包的接收表示该</span></font>Datanode<font id="nekf185" face="宋体, SimSun"><span id="nekf186" lang="zh-CN">节点正常工
作，而</span></font>Blockreport<font id="nekf187" face="宋体, SimSun"><span id="nekf188" lang="zh-CN">包括了该</span></font>Datanode<font id="nekf189" face="宋体, SimSun"><span id="nekf190" lang="zh-CN">上所有的</span></font>block<font id="nekf191" face="宋体, SimSun"><span id="nekf192" lang="zh-CN">组成的列表。</span></font></p>
<p id="nekf193" class="western" style="margin-bottom: 0in;"><img id="nekf194" src="http://docs.google.com/File?id=ddxkntwd_25gq43fcg4_b" name="graphics2" alt="" align="bottom" border="0" width="576" height="352" /><br id="nekf195" />
1<font id="nekf196" face="宋体, SimSun"><span id="nekf197" lang="zh-CN">、副本的存放，副本的存放是</span></font>HDFS<font id="nekf198" face="宋体, SimSun"><span id="nekf199" lang="zh-CN">可靠性和性能的关键。</span></font>HDFS<font id="nekf200" face="宋体, SimSun"><span id="nekf201" lang="zh-CN">采用一种称为</span></font>rack-aware<font id="nekf202" face="宋体, SimSun"><span id="nekf203" lang="zh-CN">的策略来改进数据的可靠性、有效性和网络带宽的利
用。这个策略实现的短期目标是验证在生产环境下的表现，观察它的行为，构建测试和研究的基础，以便实现更先进的策略。庞大的</span></font>HDFS<font id="nekf204" face="宋体, SimSun"><span id="nekf205" lang="zh-CN">实例一般运行在多个机
架的计算机形成的集群上，不同机架间的两台机器的通讯需要通过交换机，显然通常情况下，同一个机架内的两个节点间的带宽会比不同机架间的两台机器的带宽
大。</span></font><br id="nekf206" />
&nbsp;&nbsp;&nbsp; <font id="nekf207" face="宋体, SimSun"><span id="nekf208" lang="zh-CN">通过一个称为</span></font>Rack
Awareness<font id="nekf209" face="宋体, SimSun"><span id="nekf210" lang="zh-CN">的过程，</span></font>Namenode<font id="nekf211" face="宋体, SimSun"><span id="nekf212" lang="zh-CN">决定了每个</span></font>Datanode<font id="nekf213" face="宋体, SimSun"><span id="nekf214" lang="zh-CN">所属的</span></font>rack
id<font id="nekf215" face="宋体, SimSun"><span id="nekf216" lang="zh-CN">。一个简单但没有优化的策略就是将副本存放在单独的机架上。这样可以防止整个机架（非副本存放）失效的情况，并且允许读数据的时候可以从多个机架读
取。这个简单策略设置可以将副本分布在集群中，有利于组件失败情况下的负载均衡。但是，这个简单策略加大了写的代价，因为一个写操作需要传输</span></font>block<font id="nekf217" face="宋体, SimSun"><span id="nekf218" lang="zh-CN">到
多个机架。</span></font><br id="nekf219" />
&nbsp;&nbsp;&nbsp;
<font id="nekf220" face="宋体, SimSun"><span id="nekf221" lang="zh-CN">在大多数情况下，</span></font>replication<font id="nekf222" face="宋体, SimSun"><span id="nekf223" lang="zh-CN">因子是</span></font>3<font id="nekf224" face="宋体, SimSun"><span id="nekf225" lang="zh-CN">，</span></font>HDFS<font id="nekf226" face="宋体, SimSun"><span id="nekf227" lang="zh-CN">的存放策略是将一个副本存放在本地机架上的节点，一个副本放在同一机架上的另一个节点，最后一
个副本放在不同机架上的一个节点。机架的错误远远比节点的错误少，这个策略不会影响到数据的可靠性和有效性。三分之一的副本在一个节点上，三分之二在一个
机架上，其他保存在剩下的机架中，这一策略改进了写的性能。</span></font><br id="nekf228" />
<br id="nekf229" />
2<font id="nekf230" face="宋体, SimSun"><span id="nekf231" lang="zh-CN">、副本的选择，为了降低整体的带宽消耗和读延时，</span></font>HDFS<font id="nekf232" face="宋体, SimSun"><span id="nekf233" lang="zh-CN">会尽量让</span></font>reader<font id="nekf234" face="宋体, SimSun"><span id="nekf235" lang="zh-CN">读最近的副本。如果在</span></font>reader<font id="nekf236" face="宋体, SimSun"><span id="nekf237" lang="zh-CN">的同一个机架上有一个副本，那么就读该副本。如果一个</span></font>HDFS<font id="nekf238" face="宋体, SimSun"><span id="nekf239" lang="zh-CN">集群跨越多个数据中心，那么</span></font>reader<font id="nekf240" face="宋体, SimSun"><span id="nekf241" lang="zh-CN">也将首先尝试读本地数据中心的副本。</span></font><br id="nekf242" />
<br id="nekf243" />
3<font id="nekf244" face="宋体, SimSun"><span id="nekf245" lang="zh-CN">、</span></font>SafeMode<br id="nekf246" />
&nbsp;&nbsp;&nbsp;
Namenode<font id="nekf247" face="宋体, SimSun"><span id="nekf248" lang="zh-CN">启动后会进入一个称为</span></font>SafeMode<font id="nekf249" face="宋体, SimSun"><span id="nekf250" lang="zh-CN">的特殊状态，处在这个状态的</span></font>Namenode<font id="nekf251" face="宋体, SimSun"><span id="nekf252" lang="zh-CN">是不会进行数据块的复制的。</span></font>Namenode<font id="nekf253" face="宋体, SimSun"><span id="nekf254" lang="zh-CN">从所有的
</span></font>Datanode<font id="nekf255" face="宋体, SimSun"><span id="nekf256" lang="zh-CN">接收心跳包和</span></font>Blockreport<font id="nekf257" face="宋体, SimSun"><span id="nekf258" lang="zh-CN">。</span></font>Blockreport<font id="nekf259" face="宋体, SimSun"><span id="nekf260" lang="zh-CN">包括了某个</span></font>Datanode<font id="nekf261" face="宋体, SimSun"><span id="nekf262" lang="zh-CN">所有的数据块列表。每个</span></font>block<font id="nekf263" face="宋体, SimSun"><span id="nekf264" lang="zh-CN">都有指定的最
小数目的副本。当</span></font>Namenode<font id="nekf265" face="宋体, SimSun"><span id="nekf266" lang="zh-CN">检测确认某个</span></font>Datanode<font id="nekf267" face="宋体, SimSun"><span id="nekf268" lang="zh-CN">的数据块副本的最小数目，那么该</span></font>Datanode<font id="nekf269" face="宋体, SimSun"><span id="nekf270" lang="zh-CN">就会被认为是安全的；如果一定百分比（这
个参数可配置）的数据块检测确认是安全的，那么</span></font>Namenode<font id="nekf271" face="宋体, SimSun"><span id="nekf272" lang="zh-CN">将退出</span></font>SafeMode<font id="nekf273" face="宋体, SimSun"><span id="nekf274" lang="zh-CN">状态，接下来它会确定还有哪些数据块的副本没有达到指定数目，并将
这些</span></font>block<font id="nekf275" face="宋体, SimSun"><span id="nekf276" lang="zh-CN">复制到其他</span></font>Datanode<font id="nekf277" face="宋体, SimSun"><span id="nekf278" lang="zh-CN">。</span></font><br id="nekf279" />
<br id="nekf280" />
<font id="nekf281" face="宋体, SimSun"><span id="nekf282" lang="zh-CN">五、文件系统元数据的持久化</span></font><br id="nekf283" />
&nbsp;&nbsp;&nbsp;
Namenode<font id="nekf284" face="宋体, SimSun"><span id="nekf285" lang="zh-CN">存储</span></font>HDFS<font id="nekf286" face="宋体, SimSun"><span id="nekf287" lang="zh-CN">的元数据。对于任何对文件元数据产生修改的操作，</span></font>Namenode<font id="nekf288" face="宋体, SimSun"><span id="nekf289" lang="zh-CN">都使用一个称为</span></font>Editlog<font id="nekf290" face="宋体, SimSun"><span id="nekf291" lang="zh-CN">的事务日志记录下来。例如，
在</span></font>HDFS<font id="nekf292" face="宋体, SimSun"><span id="nekf293" lang="zh-CN">中创建一个文件，</span></font>Namenode<font id="nekf294" face="宋体, SimSun"><span id="nekf295" lang="zh-CN">就会在</span></font>Editlog<font id="nekf296" face="宋体, SimSun"><span id="nekf297" lang="zh-CN">中插入一条记录来表示；同样，修改文件的</span></font>replication<font id="nekf298" face="宋体, SimSun"><span id="nekf299" lang="zh-CN">因子也将往
</span></font>Editlog<font id="nekf300" face="宋体, SimSun"><span id="nekf301" lang="zh-CN">插入一条记录。</span></font>Namenode<font id="nekf302" face="宋体, SimSun"><span id="nekf303" lang="zh-CN">在本地</span></font>OS<font id="nekf304" face="宋体, SimSun"><span id="nekf305" lang="zh-CN">的文件系统中存储这个</span></font>Editlog<font id="nekf306" face="宋体, SimSun"><span id="nekf307" lang="zh-CN">。整个文件系统的</span></font>namespace<font id="nekf308" face="宋体, SimSun"><span id="nekf309" lang="zh-CN">，包括</span></font>block<font id="nekf310" face="宋体, SimSun"><span id="nekf311" lang="zh-CN">到文件
的映射、文件的属性，都存储在称为</span></font>FsImage<font id="nekf312" face="宋体, SimSun"><span id="nekf313" lang="zh-CN">的文件中，这个文件也是放在</span></font>Namenode<font id="nekf314" face="宋体, SimSun"><span id="nekf315" lang="zh-CN">所在系统的文件系统上。</span></font><br id="nekf316" />
&nbsp;&nbsp;&nbsp;
Namenode<font id="nekf317" face="宋体, SimSun"><span id="nekf318" lang="zh-CN">在内存中保存着整个文件系统</span></font>namespace<font id="nekf319" face="宋体, SimSun"><span id="nekf320" lang="zh-CN">和文件</span></font>Blockmap<font id="nekf321" face="宋体, SimSun"><span id="nekf322" lang="zh-CN">的映像。这个关键的元数据设计得很紧凑，因而一个带有</span></font>4G<font id="nekf323" face="宋体, SimSun"><span id="nekf324" lang="zh-CN">内存的
</span></font>Namenode<font id="nekf325" face="宋体, SimSun"><span id="nekf326" lang="zh-CN">足够支撑海量的文件和目录。当</span></font>Namenode<font id="nekf327" face="宋体, SimSun"><span id="nekf328" lang="zh-CN">启动时，它从硬盘中读取</span></font>Editlog<font id="nekf329" face="宋体, SimSun"><span id="nekf330" lang="zh-CN">和</span></font>FsImage<font id="nekf331" face="宋体, SimSun"><span id="nekf332" lang="zh-CN">，将所有</span></font>Editlog<font id="nekf333" face="宋体, SimSun"><span id="nekf334" lang="zh-CN">中的事务作
用（</span></font>apply)<font id="nekf335" face="宋体, SimSun"><span id="nekf336" lang="zh-CN">在内存中的</span></font>FsImage
<font id="nekf337" face="宋体, SimSun"><span id="nekf338" lang="zh-CN">，并将这个新版本的</span></font>FsImage<font id="nekf339" face="宋体, SimSun"><span id="nekf340" lang="zh-CN">从内存中</span></font>flush<font id="nekf341" face="宋体, SimSun"><span id="nekf342" lang="zh-CN">到硬盘上</span></font>,<font id="nekf343" face="宋体, SimSun"><span id="nekf344" lang="zh-CN">然后再</span></font>truncate<font id="nekf345" face="宋体, SimSun"><span id="nekf346" lang="zh-CN">这个旧的</span></font>Editlog<font id="nekf347" face="宋体, SimSun"><span id="nekf348" lang="zh-CN">，因为这个旧的</span></font>Editlog<font id="nekf349" face="宋体, SimSun"><span id="nekf350" lang="zh-CN">的事务都已经
作用在</span></font>FsImage<font id="nekf351" face="宋体, SimSun"><span id="nekf352" lang="zh-CN">上了。这个过程称为</span></font>checkpoint<font id="nekf353" face="宋体, SimSun"><span id="nekf354" lang="zh-CN">。在当前实现中，</span></font>checkpoint<font id="nekf355" face="宋体, SimSun"><span id="nekf356" lang="zh-CN">只发生在</span></font>Namenode<font id="nekf357" face="宋体, SimSun"><span id="nekf358" lang="zh-CN">启动时，在不久的将来我们将
实现支持周期性的</span></font>checkpoint<font id="nekf359" face="宋体, SimSun"><span id="nekf360" lang="zh-CN">。</span></font><br id="nekf361" />
&nbsp;&nbsp;&nbsp;
Datanode<font id="nekf362" face="宋体, SimSun"><span id="nekf363" lang="zh-CN">并不知道关于文件的任何东西，除了将文件中的数据保存在本地的文件系统上。它把每个</span></font>HDFS<font id="nekf364" face="宋体, SimSun"><span id="nekf365" lang="zh-CN">数据块存储在本地文件系统上隔离的文件中。
</span></font>Datanode<font id="nekf366" face="宋体, SimSun"><span id="nekf367" lang="zh-CN">并不在同一个目录创建所有的文件，相反，它用启发式地方法来确定每个目录的最佳文件数目，并且在适当的时候创建子目录。在同一个目录创建
所有的文件不是最优的选择，因为本地文件系统可能无法高效地在单一目录中支持大量的文件。当一个</span></font>Datanode<font id="nekf368" face="宋体, SimSun"><span id="nekf369" lang="zh-CN">启动时，它扫描本地文件系统，对这些本地
文件产生相应的一个所有</span></font>HDFS<font id="nekf370" face="宋体, SimSun"><span id="nekf371" lang="zh-CN">数据块的列表，然后发送报告到</span></font>Namenode<font id="nekf372" face="宋体, SimSun"><span id="nekf373" lang="zh-CN">，这个报告就是</span></font>Blockreport<font id="nekf374" face="宋体, SimSun"><span id="nekf375" lang="zh-CN">。</span></font><br id="nekf376" />
<br id="nekf377" />
<font id="nekf378" face="宋体, SimSun"><span id="nekf379" lang="zh-CN">六、通讯协议</span></font><br id="nekf380" />
&nbsp;&nbsp;&nbsp;
<font id="nekf381" face="宋体, SimSun"><span id="nekf382" lang="zh-CN">所有的</span></font>HDFS<font id="nekf383" face="宋体, SimSun"><span id="nekf384" lang="zh-CN">通讯协议都是构建在</span></font>TCP/IP<font id="nekf385" face="宋体, SimSun"><span id="nekf386" lang="zh-CN">协议上。客户端通过一个可配置的端口连接到</span></font>Namenode<font id="nekf387" face="宋体, SimSun"><span id="nekf388" lang="zh-CN">，通过</span></font>ClientProtocol<font id="nekf389" face="宋体, SimSun"><span id="nekf390" lang="zh-CN">与
</span></font>Namenode<font id="nekf391" face="宋体, SimSun"><span id="nekf392" lang="zh-CN">交互。而</span></font>Datanode<font id="nekf393" face="宋体, SimSun"><span id="nekf394" lang="zh-CN">是使用</span></font>DatanodeProtocol<font id="nekf395" face="宋体, SimSun"><span id="nekf396" lang="zh-CN">与</span></font>Namenode<font id="nekf397" face="宋体, SimSun"><span id="nekf398" lang="zh-CN">交互。从</span></font>ClientProtocol<font id="nekf399" face="宋体, SimSun"><span id="nekf400" lang="zh-CN">和
</span></font>Datanodeprotocol<font id="nekf401" face="宋体, SimSun"><span id="nekf402" lang="zh-CN">抽象出一个远程调用</span></font>(RPC<font id="nekf403" face="宋体, SimSun"><span id="nekf404" lang="zh-CN">），在设计上，</span></font>Namenode<font id="nekf405" face="宋体, SimSun"><span id="nekf406" lang="zh-CN">不会主动发起</span></font>RPC<font id="nekf407" face="宋体, SimSun"><span id="nekf408" lang="zh-CN">，而是是响应来自客户端和
</span></font>Datanode <font id="nekf409" face="宋体, SimSun"><span id="nekf410" lang="zh-CN">的</span></font>RPC<font id="nekf411" face="宋体, SimSun"><span id="nekf412" lang="zh-CN">请求。</span></font><br id="nekf413" />
<br id="nekf414" />
<font id="nekf415" face="宋体, SimSun"><span id="nekf416" lang="zh-CN">七、健壮性</span></font><br id="nekf417" />
&nbsp;&nbsp;&nbsp;
HDFS<font id="nekf418" face="宋体, SimSun"><span id="nekf419" lang="zh-CN">的主要目标就是实现在失败情况下的数据存储可靠性。常见的三种失败：</span></font>Namenode
failures, Datanode failures<font id="nekf420" face="宋体, SimSun"><span id="nekf421" lang="zh-CN">和网络分割（</span></font>network
partitions)<font id="nekf422" face="宋体, SimSun"><span id="nekf423" lang="zh-CN">。</span></font><br id="nekf424" />
1<font id="nekf425" face="宋体, SimSun"><span id="nekf426" lang="zh-CN">、硬盘数据错误、心跳检测和重新复制</span></font><br id="nekf427" />
&nbsp;&nbsp;&nbsp;
<font id="nekf428" face="宋体, SimSun"><span id="nekf429" lang="zh-CN">每个</span></font>Datanode<font id="nekf430" face="宋体, SimSun"><span id="nekf431" lang="zh-CN">节点都向</span></font>Namenode<font id="nekf432" face="宋体, SimSun"><span id="nekf433" lang="zh-CN">周期性地发送心跳包。网络切割可能导致一部分</span></font>Datanode<font id="nekf434" face="宋体, SimSun"><span id="nekf435" lang="zh-CN">跟</span></font>Namenode<font id="nekf436" face="宋体, SimSun"><span id="nekf437" lang="zh-CN">失去联系。
</span></font>Namenode<font id="nekf438" face="宋体, SimSun"><span id="nekf439" lang="zh-CN">通过心跳包的缺失检测到这一情况，并将这些</span></font>Datanode<font id="nekf440" face="宋体, SimSun"><span id="nekf441" lang="zh-CN">标记为</span></font>dead<font id="nekf442" face="宋体, SimSun"><span id="nekf443" lang="zh-CN">，不会将新的</span></font>IO<font id="nekf444" face="宋体, SimSun"><span id="nekf445" lang="zh-CN">请求发给它们。寄存在</span></font>dead
Datanode<font id="nekf446" face="宋体, SimSun"><span id="nekf447" lang="zh-CN">上的任何数据将不再有效。</span></font>Datanode<font id="nekf448" face="宋体, SimSun"><span id="nekf449" lang="zh-CN">的死亡可能引起一些</span></font>block<font id="nekf450" face="宋体, SimSun"><span id="nekf451" lang="zh-CN">的副本数目低于指定值，</span></font>Namenode<font id="nekf452" face="宋体, SimSun"><span id="nekf453" lang="zh-CN">不断地跟踪需要复制的
</span></font>block<font id="nekf454" face="宋体, SimSun"><span id="nekf455" lang="zh-CN">，在任何需要的情况下启动复制。在下列情况可能需要重新复制：某个</span></font>Datanode<font id="nekf456" face="宋体, SimSun"><span id="nekf457" lang="zh-CN">节点失效，某个副本遭到损坏，</span></font>Datanode<font id="nekf458" face="宋体, SimSun"><span id="nekf459" lang="zh-CN">上的硬盘错
误，或者文件的</span></font>replication<font id="nekf460" face="宋体, SimSun"><span id="nekf461" lang="zh-CN">因子增大。</span></font><br id="nekf462" />
<br id="nekf463" />
2<font id="nekf464" face="宋体, SimSun"><span id="nekf465" lang="zh-CN">、集群均衡</span></font><br id="nekf466" />
&nbsp;&nbsp;
HDFS<font id="nekf467" face="宋体, SimSun"><span id="nekf468" lang="zh-CN">支持数据的均衡计划，如果某个</span></font>Datanode<font id="nekf469" face="宋体, SimSun"><span id="nekf470" lang="zh-CN">节点上的空闲空间低于特定的临界点，那么就会启动一个计划自动地将数据从一个</span></font>Datanode<font id="nekf471" face="宋体, SimSun"><span id="nekf472" lang="zh-CN">搬移
到空闲的</span></font>Datanode<font id="nekf473" face="宋体, SimSun"><span id="nekf474" lang="zh-CN">。当对某个文件的请求突然增加，那么也可能启动一个计划创建该文件新的副本，并分布到集群中以满足应用的要求。这些均衡计划目前
还没有实现。</span></font><br id="nekf475" />
<br id="nekf476" />
3<font id="nekf477" face="宋体, SimSun"><span id="nekf478" lang="zh-CN">、数据完整性</span></font><br id="nekf479" />
&nbsp;
<font id="nekf480" face="宋体, SimSun"><span id="nekf481" lang="zh-CN">从某个</span></font>Datanode<font id="nekf482" face="宋体, SimSun"><span id="nekf483" lang="zh-CN">获取的数据块有可能是损坏的，这个损坏可能是由于</span></font>Datanode<font id="nekf484" face="宋体, SimSun"><span id="nekf485" lang="zh-CN">的存储设备错误、网络错误或者软件</span></font>bug<font id="nekf486" face="宋体, SimSun"><span id="nekf487" lang="zh-CN">造成的。</span></font>HDFS<font id="nekf488" face="宋体, SimSun"><span id="nekf489" lang="zh-CN">客户端
软件实现了</span></font>HDFS<font id="nekf490" face="宋体, SimSun"><span id="nekf491" lang="zh-CN">文件内容的校验和。当某个客户端创建一个新的</span></font>HDFS<font id="nekf492" face="宋体, SimSun"><span id="nekf493" lang="zh-CN">文件，会计算这个文件每个</span></font>block<font id="nekf494" face="宋体, SimSun"><span id="nekf495" lang="zh-CN">的校验和，并作为一个单独的隐藏文件保存这些
校验和在同一个</span></font>HDFS
namespace<font id="nekf496" face="宋体, SimSun"><span id="nekf497" lang="zh-CN">下。当客户端检索文件内容，它会确认从</span></font>Datanode<font id="nekf498" face="宋体, SimSun"><span id="nekf499" lang="zh-CN">获取的数据跟相应的校验和文件中的校验和是否匹配，如果不匹配，客户端可以选择
从其他</span></font>Datanode<font id="nekf500" face="宋体, SimSun"><span id="nekf501" lang="zh-CN">获取该</span></font>block<font id="nekf502" face="宋体, SimSun"><span id="nekf503" lang="zh-CN">的副本。</span></font><br id="nekf504" />
<br id="nekf505" />
4<font id="nekf506" face="宋体, SimSun"><span id="nekf507" lang="zh-CN">、元数据磁盘错误</span></font><br id="nekf508" />
&nbsp;&nbsp;&nbsp;
FsImage<font id="nekf509" face="宋体, SimSun"><span id="nekf510" lang="zh-CN">和</span></font>Editlog<font id="nekf511" face="宋体, SimSun"><span id="nekf512" lang="zh-CN">是</span></font>HDFS<font id="nekf513" face="宋体, SimSun"><span id="nekf514" lang="zh-CN">的核心数据结构。这些文件如果损坏了，整个</span></font>HDFS<font id="nekf515" face="宋体, SimSun"><span id="nekf516" lang="zh-CN">实例都将失效。因而，</span></font>Namenode<font id="nekf517" face="宋体, SimSun"><span id="nekf518" lang="zh-CN">可以配置成支持维护多
个</span></font>FsImage<font id="nekf519" face="宋体, SimSun"><span id="nekf520" lang="zh-CN">和</span></font>Editlog<font id="nekf521" face="宋体, SimSun"><span id="nekf522" lang="zh-CN">的拷贝。任何对</span></font>FsImage<font id="nekf523" face="宋体, SimSun"><span id="nekf524" lang="zh-CN">或者</span></font>Editlog<font id="nekf525" face="宋体, SimSun"><span id="nekf526" lang="zh-CN">的修改，都将同步到它们的副本上。这个同步操作可能会降低
</span></font>Namenode<font id="nekf527" face="宋体, SimSun"><span id="nekf528" lang="zh-CN">每秒能支持处理的</span></font>namespace<font id="nekf529" face="宋体, SimSun"><span id="nekf530" lang="zh-CN">事务。这个代价是可以接受的，因为</span></font>HDFS<font id="nekf531" face="宋体, SimSun"><span id="nekf532" lang="zh-CN">是数据密集的，而非元数据密集。当</span></font>Namenode<font id="nekf533" face="宋体, SimSun"><span id="nekf534" lang="zh-CN">重启的
时候，它总是选取最近的一致的</span></font>FsImage<font id="nekf535" face="宋体, SimSun"><span id="nekf536" lang="zh-CN">和</span></font>Editlog<font id="nekf537" face="宋体, SimSun"><span id="nekf538" lang="zh-CN">使用。</span></font><br id="nekf539" />
&nbsp;&nbsp;
Namenode<font id="nekf540" face="宋体, SimSun"><span id="nekf541" lang="zh-CN">在</span></font>HDFS<font id="nekf542" face="宋体, SimSun"><span id="nekf543" lang="zh-CN">是单点存在，如果</span></font>Namenode<font id="nekf544" face="宋体, SimSun"><span id="nekf545" lang="zh-CN">所在的机器错误，手工的干预是必须的。目前，在另一台机器上重启因故障而停止服务的</span></font>Namenode<font id="nekf546" face="宋体, SimSun"><span id="nekf547" lang="zh-CN">这个功能还没实现。</span></font><br id="nekf548" />
<br id="nekf549" />
5<font id="nekf550" face="宋体, SimSun"><span id="nekf551" lang="zh-CN">、快照</span></font><br id="nekf552" />
&nbsp;&nbsp;
<font id="nekf553" face="宋体, SimSun"><span id="nekf554" lang="zh-CN">快照支持某个时间的数据拷贝，当</span></font>HDFS<font id="nekf555" face="宋体, SimSun"><span id="nekf556" lang="zh-CN">数据损坏的时候，可以恢复到过去一个已知正确的时间点。</span></font>HDFS<font id="nekf557" face="宋体, SimSun"><span id="nekf558" lang="zh-CN">目前还不支持快照功能。</span></font><br id="nekf559" />
<br id="nekf560" />
<font id="nekf561" face="宋体, SimSun"><span id="nekf562" lang="zh-CN">八、数据组织</span></font><br id="nekf563" />
1<font id="nekf564" face="宋体, SimSun"><span id="nekf565" lang="zh-CN">、数据块</span></font><br id="nekf566" />
&nbsp;&nbsp;&nbsp;
<font id="nekf567" face="宋体, SimSun"><span id="nekf568" lang="zh-CN">兼容</span></font>HDFS<font id="nekf569" face="宋体, SimSun"><span id="nekf570" lang="zh-CN">的应用都是处理大数据集合的。这些应用都是写数据一次，读却是一次到多次，并且读的速度要满足流式读。</span></font>HDFS<font id="nekf571" face="宋体, SimSun"><span id="nekf572" lang="zh-CN">支持文件的</span></font>write-
once-read-many<font id="nekf573" face="宋体, SimSun"><span id="nekf574" lang="zh-CN">语义。一个典型的</span></font>block<font id="nekf575" face="宋体, SimSun"><span id="nekf576" lang="zh-CN">大小是</span></font>64MB<font id="nekf577" face="宋体, SimSun"><span id="nekf578" lang="zh-CN">，因而，文件总是按照</span></font>64M<font id="nekf579" face="宋体, SimSun"><span id="nekf580" lang="zh-CN">切分成</span></font>chunk<font id="nekf581" face="宋体, SimSun"><span id="nekf582" lang="zh-CN">，每个</span></font>chunk<font id="nekf583" face="宋体, SimSun"><span id="nekf584" lang="zh-CN">存储于不同的
</span></font>Datanode<br id="nekf585" />
2<font id="nekf586" face="宋体, SimSun"><span id="nekf587" lang="zh-CN">、步骤</span></font><br id="nekf588" />
&nbsp;&nbsp;&nbsp;
<font id="nekf589" face="宋体, SimSun"><span id="nekf590" lang="zh-CN">某个客户端创建文件的请求其实并没有立即发给</span></font>Namenode<font id="nekf591" face="宋体, SimSun"><span id="nekf592" lang="zh-CN">，事实上，</span></font>HDFS<font id="nekf593" face="宋体, SimSun"><span id="nekf594" lang="zh-CN">客户端会将文件数据缓存到本地的一个临时文件。应用的写被透明地重定向到
这个临时文件。当这个临时文件累积的数据超过一个</span></font>block<font id="nekf595" face="宋体, SimSun"><span id="nekf596" lang="zh-CN">的大小（默认</span></font>64M)<font id="nekf597" face="宋体, SimSun"><span id="nekf598" lang="zh-CN">，客户端才会联系</span></font>Namenode<font id="nekf599" face="宋体, SimSun"><span id="nekf600" lang="zh-CN">。</span></font>Namenode<font id="nekf601" face="宋体, SimSun"><span id="nekf602" lang="zh-CN">将文件名插入文件系
统的层次结构中，并且分配一个数据块给它，然后返回</span></font>Datanode<font id="nekf603" face="宋体, SimSun"><span id="nekf604" lang="zh-CN">的标识符和目标数据块给客户端。客户端将本地临时文件</span></font>flush<font id="nekf605" face="宋体, SimSun"><span id="nekf606" lang="zh-CN">到指定的
</span></font>Datanode<font id="nekf607" face="宋体, SimSun"><span id="nekf608" lang="zh-CN">上。当文件关闭时，在临时文件中剩余的没有</span></font>flush<font id="nekf609" face="宋体, SimSun"><span id="nekf610" lang="zh-CN">的数据也会传输到指定的</span></font>Datanode<font id="nekf611" face="宋体, SimSun"><span id="nekf612" lang="zh-CN">，然后客户端告诉</span></font>Namenode<font id="nekf613" face="宋体, SimSun"><span id="nekf614" lang="zh-CN">文件已经
关闭。此时</span></font>Namenode<font id="nekf615" face="宋体, SimSun"><span id="nekf616" lang="zh-CN">才将文件创建操作提交到持久存储。如果</span></font>Namenode<font id="nekf617" face="宋体, SimSun"><span id="nekf618" lang="zh-CN">在文件关闭前挂了，该文件将丢失。</span></font><br id="nekf619" />
&nbsp;&nbsp;
<font id="nekf620" face="宋体, SimSun"><span id="nekf621" lang="zh-CN">上述方法是对通过对</span></font>HDFS<font id="nekf622" face="宋体, SimSun"><span id="nekf623" lang="zh-CN">上运行的目标应用认真考虑的结果。如果不采用客户端缓存，由于网络速度和网络堵塞会对吞估量造成比较大的影响。</span></font><br id="nekf624" />
<br id="nekf625" />
3<font id="nekf626" face="宋体, SimSun"><span id="nekf627" lang="zh-CN">、流水线复制</span></font><br id="nekf628" />
&nbsp;&nbsp;&nbsp;
<font id="nekf629" face="宋体, SimSun"><span id="nekf630" lang="zh-CN">当某个客户端向</span></font>HDFS<font id="nekf631" face="宋体, SimSun"><span id="nekf632" lang="zh-CN">文件写数据的时候，一开始是写入本地临时文件，假设该文件的</span></font>replication<font id="nekf633" face="宋体, SimSun"><span id="nekf634" lang="zh-CN">因子设置为</span></font>3<font id="nekf635" face="宋体, SimSun"><span id="nekf636" lang="zh-CN">，那么客户端会从</span></font>Namenode
<font id="nekf637" face="宋体, SimSun"><span id="nekf638" lang="zh-CN">获取一张</span></font>Datanode<font id="nekf639" face="宋体, SimSun"><span id="nekf640" lang="zh-CN">列表来存放副本。然后客户端开始向第一个</span></font>Datanode<font id="nekf641" face="宋体, SimSun"><span id="nekf642" lang="zh-CN">传输数据，第一个</span></font>Datanode<font id="nekf643" face="宋体, SimSun"><span id="nekf644" lang="zh-CN">一小部分一小部分（</span></font>4kb)<font id="nekf645" face="宋体, SimSun"><span id="nekf646" lang="zh-CN">地接收数
据，将每个部分写入本地仓库，并且同时传输该部分到第二个</span></font>Datanode<font id="nekf647" face="宋体, SimSun"><span id="nekf648" lang="zh-CN">节点。第二个</span></font>Datanode<font id="nekf649" face="宋体, SimSun"><span id="nekf650" lang="zh-CN">也是这样，边收边传，一小部分一小部分地收，存储
在本地仓库，同时传给第三个</span></font>Datanode<font id="nekf651" face="宋体, SimSun"><span id="nekf652" lang="zh-CN">，第三个</span></font>Datanode<font id="nekf653" face="宋体, SimSun"><span id="nekf654" lang="zh-CN">就仅仅是接收并存储了。这就是流水线式的复制。</span></font><br id="nekf655" />
<br id="nekf656" />
<font id="nekf657" face="宋体, SimSun"><span id="nekf658" lang="zh-CN">九、可访问性</span></font><br id="nekf659" />
&nbsp;&nbsp;&nbsp;
HDFS<font id="nekf660" face="宋体, SimSun"><span id="nekf661" lang="zh-CN">给应用提供了多种访问方式，可以通过</span></font>DFSShell<font id="nekf662" face="宋体, SimSun"><span id="nekf663" lang="zh-CN">通过命令行与</span></font>HDFS<font id="nekf664" face="宋体, SimSun"><span id="nekf665" lang="zh-CN">数据进行交互，可以通过</span></font>java
API<font id="nekf666" face="宋体, SimSun"><span id="nekf667" lang="zh-CN">调用，也可以通过</span></font>C<font id="nekf668" face="宋体, SimSun"><span id="nekf669" lang="zh-CN">语言的封装</span></font>API<font id="nekf670" face="宋体, SimSun"><span id="nekf671" lang="zh-CN">访问，并且提供了浏览器访问的方式。正在开发通过</span></font>WebDav<font id="nekf672" face="宋体, SimSun"><span id="nekf673" lang="zh-CN">协议访问的方式。具体使用参考文档。</span></font><br id="nekf674" />
<font id="nekf675" face="宋体, SimSun"><span id="nekf676" lang="zh-CN">十、空间的回收</span></font><br id="nekf677" />
1<font id="nekf678" face="宋体, SimSun"><span id="nekf679" lang="zh-CN">、文件的删除和恢复</span></font><br id="nekf680" />
&nbsp;&nbsp;&nbsp;
<font id="nekf681" face="宋体, SimSun"><span id="nekf682" lang="zh-CN">用户或者应用删除某个文件，这个文件并没有立刻从</span></font>HDFS<font id="nekf683" face="宋体, SimSun"><span id="nekf684" lang="zh-CN">中删除。相反，</span></font>HDFS<font id="nekf685" face="宋体, SimSun"><span id="nekf686" lang="zh-CN">将这个文件重命名，并转移到</span></font>/trash<font id="nekf687" face="宋体, SimSun"><span id="nekf688" lang="zh-CN">目录。当文件还在</span></font>/trash<font id="nekf689" face="宋体, SimSun"><span id="nekf690" lang="zh-CN">目
录时，该文件可以被迅速地恢复。文件在</span></font>/trash<font id="nekf691" face="宋体, SimSun"><span id="nekf692" lang="zh-CN">中保存的时间是可配置的，当超过这个时间，</span></font>Namenode<font id="nekf693" face="宋体, SimSun"><span id="nekf694" lang="zh-CN">就会将该文件从</span></font>namespace<font id="nekf695" face="宋体, SimSun"><span id="nekf696" lang="zh-CN">中删除。
文件的删除，也将释放关联该文件的数据块。注意到，在文件被用户删除和</span></font>HDFS<font id="nekf697" face="宋体, SimSun"><span id="nekf698" lang="zh-CN">空闲空间的增加之间会有一个等待时间延迟。</span></font><br id="nekf699" />
&nbsp;&nbsp;&nbsp;
<font id="nekf700" face="宋体, SimSun"><span id="nekf701" lang="zh-CN">当被删除的文件还保留在</span></font>/trash<font id="nekf702" face="宋体, SimSun"><span id="nekf703" lang="zh-CN">目录中的时候，如果用户想恢复这个文件，可以检索浏览</span></font>/trash<font id="nekf704" face="宋体, SimSun"><span id="nekf705" lang="zh-CN">目录并检索该文件。</span></font>/trash<font id="nekf706" face="宋体, SimSun"><span id="nekf707" lang="zh-CN">目录仅仅保存被删除
文件的最近一次拷贝。</span></font>/trash<font id="nekf708" face="宋体, SimSun"><span id="nekf709" lang="zh-CN">目录与其他文件目录没有什么不同，除了一点：</span></font>HDFS<font id="nekf710" face="宋体, SimSun"><span id="nekf711" lang="zh-CN">在该目录上应用了一个特殊的策略来自动删除文件，目前的默认策略是
删除保留超过</span></font>6<font id="nekf712" face="宋体, SimSun"><span id="nekf713" lang="zh-CN">小时的文件，这个策略以后会定义成可配置的接口。</span></font><br id="nekf714" />
<br id="nekf715" />
2<font id="nekf716" face="宋体, SimSun"><span id="nekf717" lang="zh-CN">、</span></font>Replication<font id="nekf718" face="宋体, SimSun"><span id="nekf719" lang="zh-CN">因子的减小</span></font><br id="nekf720" />
&nbsp;&nbsp;&nbsp;
<font id="nekf721" face="宋体, SimSun"><span id="nekf722" lang="zh-CN">当某个文件的</span></font>replication<font id="nekf723" face="宋体, SimSun"><span id="nekf724" lang="zh-CN">因子减小，</span></font>Namenode<font id="nekf725" face="宋体, SimSun"><span id="nekf726" lang="zh-CN">会选择要删除的过剩的副本。下次心跳检测就将该信息传递给</span></font>Datanode<font id="nekf727" face="宋体, SimSun"><span id="nekf728" lang="zh-CN">，
</span></font>Datanode<font id="nekf729" face="宋体, SimSun"><span id="nekf730" lang="zh-CN">就会移除相应的</span></font>block<font id="nekf731" face="宋体, SimSun"><span id="nekf732" lang="zh-CN">并释放空间，同样，在调用</span></font>setReplication<font id="nekf733" face="宋体, SimSun"><span id="nekf734" lang="zh-CN">方法和集群中的空闲空间增加之间会有一个时间延迟。</span></font><br id="nekf735" />
<br id="nekf736" />
<font id="nekf737" face="宋体, SimSun"><span id="nekf738" lang="zh-CN">参考资料：</span></font><br id="nekf739" />
HDFS
Java API: http://hadoop.apache.org/core/docs/current/api/<br id="nekf740" />
HDFS
source code: http://hadoop.apache.org/core/version_control.html<br id="nekf741" />
&nbsp;&nbsp;&nbsp;
<br id="nekf742" />
<br id="nekf743" />
<br id="nekf744" />
<br id="nekf745" />
<br id="nekf746" />
<br id="nekf747" />
<br id="nekf748" />
<br id="nekf749" />
</p><img src ="http://www.blogjava.net/killme2008/aggbug/206043.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/killme2008/" target="_blank">dennis</a> 2008-06-05 14:29 <a href="http://www.blogjava.net/killme2008/archive/2008/06/05/206043.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>