<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>UGC广播站</title>
	<atom:link href="http://ugc.renren.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://ugc.renren.com</link>
	<description>UGC-- User Generated Content(用户原创内容)  人人网UGC团队博客，走近我们的产品、技术和文化。</description>
	<lastBuildDate>Fri, 23 Jul 2010 03:57:48 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.4</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>一场技术的圣战：rose开源框架之portal</title>
		<link>http://ugc.renren.com/2010/06/10/rose-portal/</link>
		<comments>http://ugc.renren.com/2010/06/10/rose-portal/#comments</comments>
		<pubDate>Thu, 10 Jun 2010 04:15:35 +0000</pubDate>
		<dc:creator>UGC.FM</dc:creator>
				<category><![CDATA[生产力电台]]></category>

		<guid isPermaLink="false">http://ugc.renren.com/?p=204</guid>
		<description><![CDATA[作者：人人网架构师 王志亮  人人网UGC团队博客
2010年的6月9日是一个圣战的日子，零点一到就有人开始，好戏也如约在晚上7点发生。人人网战场是SJ的公共主页：http://page.renren.com/sj
 
对不同人，这个日子意味着不同，滋味也不同。作为人人网技术团队，我们要保证服务能力、用户体验能够应付得了这个挑战。
 
某一个服务器的能力总有限，为了应付突然增长的读写量，web服务架构、内部服务架构、数据库架构等要能够轻松通过服务器调配来满足。就web服务器而言，我们增加了1倍的机器。现在再回头来看监控的数据，一切显得美好。这个期间整个服务做到了服务能力没有中断。除此之外，在这次圣战中，其中还有一项我们独有的技术起到了重要的作用：rose portal ，下面作一个介绍：
 
图1是sj的主页：
 

图1 sj在人人网的公共主页
这个页面分为三列：

左边有 “推荐给好友”、“基本信息”、“相册”;
中间有“给SJ留言”、“好友留言”;
右边有“好友”，“人人的用户还关注”等。


在后台，这些被分解为不同的模块，我们称之为”window”。这每一个window都意味着可能连接一个独立的服务集群，比如基本信息服务、留言服务、好友服务、相册服务等等。这样，一个公共主页就等于多个独立的、可配置的window模块组成，如图2所示 ：

图2 公共主页的window模块组成
随着伟大圣战的深入，这个页面就变成这样(右边的栏目不见了)，如图3所示：

图3 圣战进行中时模块的自动保护
产品同学看到此情此景，仍然很开心：“只要留言的window能在，其它的没在不要紧”
但是不一会，继续恶化，如图4所示：

图4 圣战进行中压力进一步增加
甚至到了图5的情形：
 

图5 圣战进行中压力进一步增加
黄晶看着公共主页呈现出这种状况时，笑着形容这样的图“缺胳膊少腿”：“怎么还没加机器”。当公共主页技术团队把机器逐步增加一倍的时候，这种情况变少了，甚至就没有了。
虽然这些页面看起来“缺胳膊少腿”，但要知道在以前，这种情况，我们整个页面的某个模块堵了可会导致用户浏览器长期空白，直至最后提示网页不可显示。这给用户带来很不好的体验，同时因为网页一直不释放连接，恶性循环导致web服务器最后全哑了。
好在，早在半年前我们开发了rose portal框架，解决了此问题，rose portal是一个服务端portal技术，基于rose框架 (也就是servlet容器) 下的服务端portal技术，rose portal不是Java常说的portlet技术，也不是基于ajax的客户端portal技术。
rose poral提供这些特性；

能够将一个页面分为多个窗口；
开发者使用一个主控制器，在主控制器中不断通过portal.addWindow方法，将请求并发转发给多个窗口；
每个窗口有单独的控制器处理逻辑、可以返回独立视图就像一个web请求一样；
框架能够处理并发转发、并发逻辑处理、并发渲染，并最后统一返回把html输出给浏览器；
提供了“整体超时控制”手段，使得某个窗口因一时服务能力下降时不影响整个页面的输出；

 
这里有一个portal开发示例：
http://code.google.com/p/paoding-rose/wiki/Rose_Portal_Demo
 
献上现在最新的sj主页（2010/6/10 10:46）作为结束，如图6，目前粉丝 粉丝 21w+、留言146w+，谢谢（另感谢李伟博同学，以上图片均是他收集的）：
 

图6 最新的sj主页
]]></description>
			<content:encoded><![CDATA[<p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0.8em; margin-left: 0px; padding: 0px;">作者：人人网架构师 王志亮  <a style="color: #096dbb; text-decoration: none;" href="http://ugc.renren.com/">人人网UGC团队博客</a></p>
<p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0.8em; margin-left: 0px; padding: 0px;"><span style="padding: 0px; margin: 0px;">2010</span><span style="padding: 0px; margin: 0px;">年的</span><span style="padding: 0px; margin: 0px;">6</span><span style="padding: 0px; margin: 0px;">月</span><span style="padding: 0px; margin: 0px;">9</span><span style="padding: 0px; margin: 0px;">日是一个圣战的日子，零点一到就有人开始，好戏也如约在晚上7点发生。人人网战场是</span><span style="padding: 0px; margin: 0px;">SJ</span><span style="padding: 0px; margin: 0px;">的公共主页：</span><span style="padding: 0px; margin: 0px;"><a style="color: #005eac; cursor: pointer; text-decoration: none; padding: 0px; margin: 0px;" href="http://page.renren.com/sj" onclick="pageTracker._trackPageview('/outgoing/page.renren.com/sj?referer=');">http://page.renren.com/sj</a></span></p>
<p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0.8em; margin-left: 0px; padding: 0px;"><span style="padding: 0px; margin: 0px;"> </span></p>
<p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0.8em; margin-left: 0px; padding: 0px;"><span style="padding: 0px; margin: 0px;">对不同人，这个日子意味着不同，滋味也不同。作为人人网技术团队，我们要保证服务能力、用户体验能够应付得了这个挑战。</span></p>
<p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0.8em; margin-left: 0px; padding: 0px;"><span style="padding: 0px; margin: 0px;"> </span></p>
<p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0.8em; margin-left: 0px; padding: 0px;"><span style="padding: 0px; margin: 0px;">某一个服务器的能力总有限，为了应付突然增长的读写量，</span><span style="padding: 0px; margin: 0px;">web</span><span style="padding: 0px; margin: 0px;">服务架构、内部服务架构、数据库架构等要能够轻松通过服务器调配来满足。就</span><span style="padding: 0px; margin: 0px;">web</span><span style="padding: 0px; margin: 0px;">服务器而言，我们增加了</span><span style="padding: 0px; margin: 0px;">1</span><span style="padding: 0px; margin: 0px;">倍的机器。现在再回头来看监控的数据，一切显得美好。这个期间整个服务做到了服务能力没有中断。除此之外，在这次圣战中，其中还有一项我们<strong>独有的</strong>技术起到了重要的作用：</span><span style="padding: 0px; margin: 0px;"><a style="color: #005eac; cursor: pointer; text-decoration: none; padding: 0px; margin: 0px;" href="http://code.google.com/p/paoding-rose/" onclick="pageTracker._trackPageview('/outgoing/code.google.com/p/paoding-rose/?referer=');">rose portal</a> </span><span style="padding: 0px; margin: 0px;">，下面作一个介绍：</span></p>
<p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0.8em; margin-left: 0px; padding: 0px;"><span style="padding: 0px; margin: 0px;"> </span></p>
<p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0.8em; margin-left: 0px; padding: 0px;"><span style="padding: 0px; margin: 0px;">图1是</span><span style="padding: 0px; margin: 0px;">sj</span><span style="padding: 0px; margin: 0px;">的主页：</span></p>
<p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0.8em; margin-left: 0px; padding: 0px;"><span style="padding: 0px; margin: 0px;"> </span></p>
<p><img style="max-width: 550px; padding: 0px; margin: 0px;" src="http://fmn.xnimg.cn/fmn038/20100610/1050/p_large_Xif0_1280000026732d14.jpg" alt="" /><span id="more-204"></span></p>
<p>图1 sj在人人网的公共主页</p>
<p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0.8em; margin-left: 0px; padding: 0px;"><span style="padding: 0px; margin: 0px;">这个页面分为三列：</span></p>
<ul style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 30px; list-style-type: disc; list-style-position: outside; list-style-image: initial; margin: 0px;">
<li style="padding: 0px; margin: 0px;"><span style="padding: 0px; margin: 0px;">左边有</span> <span style="padding: 0px; margin: 0px;">“推荐给好友”、“基本信息”、“相册”</span><span style="padding: 0px; margin: 0px;">;</span></li>
<li style="padding: 0px; margin: 0px;"><span style="padding: 0px; margin: 0px;">中间有“给</span><span style="padding: 0px; margin: 0px;">SJ</span><span style="padding: 0px; margin: 0px;">留言”、“好友留言”</span><span style="padding: 0px; margin: 0px;">;</span></li>
<li style="padding: 0px; margin: 0px;">右边有“好友”，“人人的用户还关注”等。</li>
</ul>
<p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0.8em; margin-left: 0px; padding: 0px;">
<p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0.8em; margin-left: 0px; padding: 0px;"><span style="padding: 0px; margin: 0px;">在后台，这些被分解为不同的模块，我们称之为</span><span style="padding: 0px; margin: 0px;">”window”</span><span style="padding: 0px; margin: 0px;">。这每一个</span><span style="padding: 0px; margin: 0px;">window</span><span style="padding: 0px; margin: 0px;">都意味着可能连接一个独立的服务集群，比如基本信息服务、留言服务、好友服务、相册服务等等。这样，一个公共主页就等于多个独立的、可配置的</span><span style="padding: 0px; margin: 0px;">window</span><span style="padding: 0px; margin: 0px;">模块组成，如图2所示 ：</span></p>
<p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0.8em; margin-left: 0px; padding: 0px;"><img style="max-width: 550px; padding: 0px; margin: 0px;" src="http://fmn.xnimg.cn/fmn036/20100610/1050/p_large_Xwkz_1280000026742d14.jpg" alt="" /></p>
<p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0.8em; margin-left: 0px; padding: 0px;">图2 公共主页的<span style="padding: 0px; margin: 0px;">window</span><span style="padding: 0px; margin: 0px;">模块组成</span></p>
<p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0.8em; margin-left: 0px; padding: 0px;"><span style="padding: 0px; margin: 0px;">随着伟大圣战的深入，这个页面就变成这样</span><span style="padding: 0px; margin: 0px;">(</span><span style="padding: 0px; margin: 0px;">右边的栏目不见了</span><span style="padding: 0px; margin: 0px;">)，如图3所示</span><span style="padding: 0px; margin: 0px;">：</span></p>
<p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0.8em; margin-left: 0px; padding: 0px;"><img style="max-width: 550px; padding: 0px; margin: 0px;" src="http://fmn.xnimg.cn/fmn036/20100610/1050/p_large_TOhn_1280000026752d14.jpg" alt="" /></p>
<p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0.8em; margin-left: 0px; padding: 0px;">图3 圣战进行中时模块的自动保护</p>
<p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0.8em; margin-left: 0px; padding: 0px;"><span style="padding: 0px; margin: 0px;">产品同学看到此情此景，仍然很开心：“只要留言的</span><span style="padding: 0px; margin: 0px;">window</span><span style="padding: 0px; margin: 0px;">能在，其它的没在不要紧”</span></p>
<p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0.8em; margin-left: 0px; padding: 0px;"><span style="padding: 0px; margin: 0px;">但是不一会，继续恶化，如图4所示：</span></p>
<p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0.8em; margin-left: 0px; padding: 0px;"><img style="max-width: 550px; padding: 0px; margin: 0px;" src="http://fmn.xnimg.cn/fmn045/20100610/1050/p_large_RIeQ_1280000026762d14.jpg" alt="" /></p>
<p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0.8em; margin-left: 0px; padding: 0px;">图4 圣战进行中压力进一步增加</p>
<p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0.8em; margin-left: 0px; padding: 0px;"><span style="padding: 0px; margin: 0px;">甚至到了图5的情形：</span></p>
<p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0.8em; margin-left: 0px; padding: 0px;"><span style="padding: 0px; margin: 0px;"> </span></p>
<p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0.8em; margin-left: 0px; padding: 0px;"><img style="max-width: 550px; padding: 0px; margin: 0px;" src="http://fmn.xnimg.cn/fmn042/20100610/1050/p_large_RTjT_1280000026772d14.jpg" alt="" /></p>
<p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0.8em; margin-left: 0px; padding: 0px;">图5 圣战进行中压力进一步增加</p>
<p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0.8em; margin-left: 0px; padding: 0px;"><a style="color: #005eac; cursor: pointer; text-decoration: none; padding: 0px; margin: 0px;" href="http://topaz.renren.com/" target="_blank" onclick="pageTracker._trackPageview('/outgoing/topaz.renren.com/?referer=');">黄晶</a><span style="padding: 0px; margin: 0px;">看着公共主页呈现出这种状况时，笑着形容这样的图“缺胳膊少腿”：“怎么还没加机器”。当公共主页技术团队把机器逐步增加一倍的时候，这种情况变少了，甚至就没有了。</span></p>
<p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0.8em; margin-left: 0px; padding: 0px;"><span style="padding: 0px; margin: 0px;">虽然这些页面看起来“缺胳膊少腿”，<strong>但要知道在以前，这种情况，我们整个页面的某个模块堵了可会导致用户浏览器长期空白，直至最后提示网页不可显示。这给用户带来很不好的体验，同时因为网页一直不释放连接，恶性循环导致</strong></span><strong><span style="padding: 0px; margin: 0px;">web</span></strong><strong><span style="padding: 0px; margin: 0px;">服务器最后全哑了。</span></strong></p>
<p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0.8em; margin-left: 0px; padding: 0px;"><span style="padding: 0px; margin: 0px;">好在，早在半年前我们开发了</span><span style="padding: 0px; margin: 0px;">rose portal</span><span style="padding: 0px; margin: 0px;">框架，解决了此问题，</span><span style="padding: 0px; margin: 0px;">rose portal</span><span style="padding: 0px; margin: 0px;">是一个<strong>服务端</strong></span><strong><span style="padding: 0px; margin: 0px;">portal</span></strong><span style="padding: 0px; margin: 0px;">技术，基于</span><span style="padding: 0px; margin: 0px;">rose</span><span style="padding: 0px; margin: 0px;">框架</span> <span style="padding: 0px; margin: 0px;">(</span><span style="padding: 0px; margin: 0px;">也就是</span><span style="padding: 0px; margin: 0px;">servlet</span><span style="padding: 0px; margin: 0px;">容器</span><span style="padding: 0px; margin: 0px;">) </span><span style="padding: 0px; margin: 0px;">下的服务端</span><span style="padding: 0px; margin: 0px;">portal</span><span style="padding: 0px; margin: 0px;">技术，</span><span style="padding: 0px; margin: 0px;">rose portal</span><span style="padding: 0px; margin: 0px;">不是</span><span style="padding: 0px; margin: 0px;">Java</span><span style="padding: 0px; margin: 0px;">常说的</span><span style="padding: 0px; margin: 0px;">portlet</span><span style="padding: 0px; margin: 0px;">技术，也不是基于</span><span style="padding: 0px; margin: 0px;">ajax</span><span style="padding: 0px; margin: 0px;">的客户端</span><span style="padding: 0px; margin: 0px;">portal</span><span style="padding: 0px; margin: 0px;">技术。</span></p>
<p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0.8em; margin-left: 0px; padding: 0px;"><span style="padding: 0px; margin: 0px;">rose poral</span><span style="padding: 0px; margin: 0px;">提供这些特性；</span></p>
<ol style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 30px; list-style-position: outside; list-style-type: decimal; list-style-image: initial; margin: 0px;">
<li style="padding: 0px; margin: 0px;"><span style="padding: 0px; margin: 0px;">能够将一个页面分为多个窗口；</span></li>
<li style="padding: 0px; margin: 0px;"><span style="padding: 0px; margin: 0px;">开发者使用一个主控制器，在主控制器中不断通过</span><span style="padding: 0px; margin: 0px;">portal.addWindow</span><span style="padding: 0px; margin: 0px;">方法，将请求<strong>并发</strong>转发给多个窗口；</span></li>
<li style="padding: 0px; margin: 0px;"><span style="padding: 0px; margin: 0px;">每个窗口有单独的控制器处理逻辑、可以返回独立视图就像一个</span><span style="padding: 0px; margin: 0px;">web</span><span style="padding: 0px; margin: 0px;">请求一样；</span></li>
<li style="padding: 0px; margin: 0px;"><span style="padding: 0px; margin: 0px;">框架能够处理<strong>并发转发</strong>、<strong>并发逻辑处理</strong>、<strong>并发渲染</strong>，并最后统一返回把</span><span style="padding: 0px; margin: 0px;">html</span><span style="padding: 0px; margin: 0px;">输出给浏览器；</span></li>
<li style="padding: 0px; margin: 0px;"><span style="padding: 0px; margin: 0px;">提供了“整体超时控制”手段，使得某个窗口因一时服务能力下降时不影响整个页面的输出；</span></li>
</ol>
<p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0.8em; margin-left: 0px; padding: 0px;"><span style="padding: 0px; margin: 0px;"> </span></p>
<p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0.8em; margin-left: 0px; padding: 0px;"><span style="padding: 0px; margin: 0px;">这里有一个</span><span style="padding: 0px; margin: 0px;">portal</span><span style="padding: 0px; margin: 0px;">开发示例：</span></p>
<p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0.8em; margin-left: 0px; padding: 0px;"><span style="padding: 0px; margin: 0px;"><a style="color: #005eac; cursor: pointer; text-decoration: none; padding: 0px; margin: 0px;" href="http://code.google.com/p/paoding-rose/wiki/Rose_Portal_Demo" onclick="pageTracker._trackPageview('/outgoing/code.google.com/p/paoding-rose/wiki/Rose_Portal_Demo?referer=');">http://code.google.com/p/paoding-rose/wiki/Rose_Portal_Demo</a></span></p>
<p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0.8em; margin-left: 0px; padding: 0px;"><span style="padding: 0px; margin: 0px;"> </span></p>
<p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0.8em; margin-left: 0px; padding: 0px;"><span style="padding: 0px; margin: 0px;">献上现在最新的</span><span style="padding: 0px; margin: 0px;">sj</span><span style="padding: 0px; margin: 0px;">主页（</span><span style="padding: 0px; margin: 0px;">2010/6/10 10:46</span><span style="padding: 0px; margin: 0px;">）</span>作为结束，如图6<span style="padding: 0px; margin: 0px;">，目前粉丝 </span>粉丝 21w+、留言146w+，谢谢<span style="padding: 0px; margin: 0px;">（另感谢</span><a style="color: #005eac; cursor: pointer; text-decoration: none; padding: 0px; margin: 0px;" href="http://www.renren.com/profile.do?id=68464" target="_blank" onclick="pageTracker._trackPageview('/outgoing/www.renren.com/profile.do?id=68464&amp;referer=');">李伟博</a><span style="padding: 0px; margin: 0px;">同学，以上图片均是他收集的）</span>：</p>
<p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0.8em; margin-left: 0px; padding: 0px;"><span style="padding: 0px; margin: 0px;"> </span></p>
<p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0.8em; margin-left: 0px; padding: 0px;"><img style="max-width: 550px; padding: 0px; margin: 0px;" src="http://fmn.xnimg.cn/fmn038/20100610/1050/p_large_yRWR_1282000049062d14.jpg" alt="" /></p>
<p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0.8em; margin-left: 0px; padding: 0px;">图6 最新的sj主页</p>
]]></content:encoded>
			<wfw:commentRss>http://ugc.renren.com/2010/06/10/rose-portal/feed/</wfw:commentRss>
		<slash:comments>23</slash:comments>
		</item>
		<item>
		<title>人人网分享协议意见征询稿</title>
		<link>http://ugc.renren.com/2010/06/03/share-open-graph-protocol/</link>
		<comments>http://ugc.renren.com/2010/06/03/share-open-graph-protocol/#comments</comments>
		<pubDate>Thu, 03 Jun 2010 10:45:08 +0000</pubDate>
		<dc:creator>UGC.FM</dc:creator>
				<category><![CDATA[生产力电台]]></category>

		<guid isPermaLink="false">http://ugc.renren.com/?p=185</guid>
		<description><![CDATA[作者：人人网技术民工 冷昊 人人网UGC团队博客
share.renren.com 已经成为人人网上的一大热门应用，优质的内容通过分享在好友间迅速传播。为了提高站外内容的传播效率，我们试图制定出一套开放内容协议(open graph protocol)，任何网页只要遵守该协议，share.renren.com就能从页面上提取最有效的信息并呈现给用户。
下面是协议初稿，有任何意见，请在留言中提出，谢谢！
Protocol Element 协议元素
 说明:
1. Null 表示是否允许为空
2. Mult 表示是否允许重复
3. Y 允许
4. N 禁止
Base element 基本类型

og:type 网页资源类型标识



 Null
 Mult


N
N



content enum:

● video 视频
● audio 音频
● link 链接
● photo 图片
● product 产品

og:title 标题描述



 Null
 Mult


N
N



og:image 缩略图



 Null
 Mult


Y
Y



og:url 当前内容链接



 Null
 Mult


Y
N



rr:appid 如果您的网站是CONNECT到renren.com的，请提供该ID



 Null
 Mult


Y
N




Video Element 视频
og:videosrc 视频资源链接，例如可是播放视频的flash地址



 Null
 Mult


N
Y



og:width 视频的宽度



 Null
 Mult


Y
Y



og:height 视频的高度



 Null
 Mult


Y
Y



例如：
&#60;meta property=&#8221;og:type&#8221; [...]]]></description>
			<content:encoded><![CDATA[<p>作者：人人网技术民工 <a style="color: #096dbb; text-decoration: none;" title="www.lenghao.com" href="http://www.lenghao.com/" target="_blank" onclick="pageTracker._trackPageview('/outgoing/www.lenghao.com/?referer=');">冷昊</a> <a style="color: #096dbb; text-decoration: none;" href="../" target="_blank">人人网UGC团队博客</a></p>
<p><a title="分享" href="http://share.renren.com" target="_blank" onclick="pageTracker._trackPageview('/outgoing/share.renren.com?referer=');">share.renren.com</a> 已经成为人人网上的一大热门应用，优质的内容通过分享在好友间迅速传播。为了提高站外内容的传播效率，我们试图制定出一套<strong>开放内容协议(open graph protocol)</strong>，任何网页只要遵守该协议，<a title="分享" href="http://share.renren.com" target="_blank" onclick="pageTracker._trackPageview('/outgoing/share.renren.com?referer=');">share.renren.com</a>就能从页面上提取最有效的信息并呈现给用户。</p>
<p>下面是协议初稿，有任何意见，请在留言中提出，谢谢！</p>
<h1>Protocol Element 协议元素</h1>
<p><span style="color: #808080;"> 说明:<br />
1. Null 表示是否允许为空<br />
2. Mult 表示是否允许重复<br />
3. Y 允许<br />
4. N 禁止</span></p>
<h2><span style="color: #008000;"><span id="more-185"></span><span style="color: #000000;"><strong>Base element 基本类型</strong></span></span></h2>
<div>
<p><span style="color: #008000;">og:type</span> 网页资源类型标识</p>
<table border="1" cellspacing="0">
<tbody>
<tr>
<th> Null</th>
<th> Mult</th>
</tr>
<tr>
<td>N</td>
<td>N</td>
</tr>
</tbody>
</table>
<p>content enum:</p>
<ul>
<li>● video 视频</li>
<li>● audio 音频</li>
<li>● link 链接</li>
<li>● photo 图片</li>
<li>● product 产品</li>
</ul>
<p><span style="color: #008000;">og:title</span> 标题描述</p>
<table border="1" cellspacing="0">
<tbody>
<tr>
<th> Null</th>
<th> Mult</th>
</tr>
<tr>
<td>N</td>
<td>N</td>
</tr>
</tbody>
</table>
<p><span style="color: #008000;">og:image</span> 缩略图</p>
<table border="1" cellspacing="0">
<tbody>
<tr>
<th> Null</th>
<th> Mult</th>
</tr>
<tr>
<td>Y</td>
<td>Y</td>
</tr>
</tbody>
</table>
<p><span style="color: #008000;">og:url</span> 当前内容链接</p>
<table border="1" cellspacing="0">
<tbody>
<tr>
<th> Null</th>
<th> Mult</th>
</tr>
<tr>
<td>Y</td>
<td>N</td>
</tr>
</tbody>
</table>
<p><span style="color: #ff0000;">rr</span><span style="color: #008000;">:appid</span> 如果您的网站是<a href="http://app.renren.com/connect" target="_blank" onclick="pageTracker._trackPageview('/outgoing/app.renren.com/connect?referer=');">CONNECT</a>到renren.com的，请提供该ID</p>
<table border="1" cellspacing="0">
<tbody>
<tr>
<th> Null</th>
<th> Mult</th>
</tr>
<tr>
<td>Y</td>
<td>N</td>
</tr>
</tbody>
</table>
<p><br/></p>
<h2>Video Element 视频</h2>
<p><span style="color: #008000;">og:videosrc</span> 视频资源链接，例如可是播放视频的flash地址</p>
<table border="1" cellspacing="0">
<tbody>
<tr>
<th> Null</th>
<th> Mult</th>
</tr>
<tr>
<td>N</td>
<td>Y</td>
</tr>
</tbody>
</table>
<p><span style="color: #008000;">og:width </span>视频的宽度</p>
<table border="1" cellspacing="0">
<tbody>
<tr>
<th> Null</th>
<th> Mult</th>
</tr>
<tr>
<td>Y</td>
<td>Y</td>
</tr>
</tbody>
</table>
<p><span style="color: #008000;">og:height</span> 视频的高度</p>
<table border="1" cellspacing="0">
<tbody>
<tr>
<th> Null</th>
<th> Mult</th>
</tr>
<tr>
<td>Y</td>
<td>Y</td>
</tr>
</tbody>
</table>
<p>例如：</p>
<blockquote><p><em><span style="color: #888888;">&lt;meta property=&#8221;og:type&#8221; content=&#8221;video&#8221; /&gt;<br />
&lt;meta property=&#8221;og:title&#8221; content=&#8221;五月天_突然好想你 MV现场版&#8221; /&gt;<br />
&lt;meta property=&#8221;og:image&#8221; content=&#8221;http://g1.ykimg.com/0100641F464AC21FF0B3ED00F48F151F43D4BF-5F0F-BD39-76EA-E5E20A1887C4&#8243; /&gt;<br />
&lt;meta property=&#8221;og:url&#8221; content=&#8221;http://v.youku.com/v_show/id_XMTIyMTY5NzMy.html&#8221; /&gt;<br />
&lt;meta property=&#8221;og:videosrc&#8221; content=&#8221;http://player.youku.com/player.php/sid/XMTIyMTY5NzMy&amp;isAutoPlay=true/v.swf&#8221; /&gt;<br />
&lt;meta property=&#8221;og:width&#8221; content=&#8221;500&#8243; /&gt;<br />
&lt;meta property=&#8221;og:height&#8221; content=&#8221;416&#8243; /&gt;</span></em></p></blockquote>
<p><em><br />
</em></p>
<div id="_mcePaste" style="position: absolute; left: -10000px; top: 184px; width: 1px; height: 1px; overflow: hidden;">&lt;meta property=&#8221;og:type&#8221; content=&#8221;video&#8221; /&gt;</div>
<div id="_mcePaste" style="position: absolute; left: -10000px; top: 184px; width: 1px; height: 1px; overflow: hidden;">&lt;meta property=&#8221;og:title&#8221; content=&#8221;五月天_突然好想你 MV现场版&#8221; /&gt;</div>
<div id="_mcePaste" style="position: absolute; left: -10000px; top: 184px; width: 1px; height: 1px; overflow: hidden;">&lt;meta property=&#8221;og:image&#8221; content=&#8221;http://g1.ykimg.com/0100641F464AC21FF0B3ED00F48F151F43D4BF-5F0F-BD39-76EA-E5E20A1887C4&#8243; /&gt;</div>
<div id="_mcePaste" style="position: absolute; left: -10000px; top: 184px; width: 1px; height: 1px; overflow: hidden;">&lt;meta property=&#8221;og:url&#8221; content=&#8221;http://v.youku.com/v_show/id_XMTIyMTY5NzMy.html&#8221; /&gt;</div>
<div id="_mcePaste" style="position: absolute; left: -10000px; top: 184px; width: 1px; height: 1px; overflow: hidden;">&lt;meta property=&#8221;og:videosrc&#8221; content=&#8221;http://player.youku.com/player.php/sid/XMTIyMTY5NzMy&amp;isAutoPlay=true/v.swf&#8221; /&gt;</div>
<div id="_mcePaste" style="position: absolute; left: -10000px; top: 184px; width: 1px; height: 1px; overflow: hidden;">&lt;meta property=&#8221;og:width&#8221; content=&#8221;500&#8243; /&gt;</div>
<div id="_mcePaste" style="position: absolute; left: -10000px; top: 184px; width: 1px; height: 1px; overflow: hidden;">&lt;meta property=&#8221;og:height&#8221; content=&#8221;416&#8243; /&gt;</div>
<h2>Audio Element 音频</h2>
<p><span style="color: #993300;">类似 http://domain/some.mp3  直接从mp3获取信息，以下指从音乐播放网页获取</span><br />
<span style="color: #008000;"> og:audiosrc</span> 音乐资源链接，例如可是播放歌曲的flash地址</p>
<table border="1" cellspacing="0">
<tbody>
<tr>
<th> Null</th>
<th> Mult</th>
</tr>
<tr>
<td>N</td>
<td>Y</td>
</tr>
</tbody>
</table>
<p><span style="color: #008000;">og:artist</span> 音乐家</p>
<table border="1" cellspacing="0">
<tbody>
<tr>
<th> Null</th>
<th> Mult</th>
</tr>
<tr>
<td>Y</td>
<td>N</td>
</tr>
</tbody>
</table>
<p>例如：</p>
<blockquote><p><span style="color: #808080;"><em>&lt;meta property=&#8221;og:type&#8221; content=&#8221;audio&#8221; /&gt;<br />
&lt;meta property=&#8221;og:title&#8221; content=&#8221;小酒窝&#8221; /&gt;<br />
&lt;meta property=&#8221;og:image&#8221; content=&#8221;http://&#8230;./xx.jpg&#8221; /&gt;<br />
&lt;meta property=&#8221;og:url&#8221; content=&#8221;http://somedomain.com/aaamp3.html&#8221; /&gt;<br />
&lt;meta property=&#8221;og:audiosrc&#8221; content=&#8221;http://somedomain.com/audioplayer.swf?s=xxx.mp3&#8243; /&gt;<br />
&lt;meta property=&#8221;og:artist&#8221; content=&#8221;林俊杰A,</em></span><span style="color: #808080;"><em>林俊杰B</em></span><span style="color: #808080;"><em>&#8221; /&gt;</em></span></p></blockquote>
<h2>Commen Page Element 普通网页</h2>
<p><span style="color: #008000;">og:abstract</span> 内容摘要</p>
<table border="1" cellspacing="0">
<tbody>
<tr>
<th> Null</th>
<th> Mult</th>
</tr>
<tr>
<td>N</td>
<td>N</td>
</tr>
</tbody>
</table>
<p><span style="color: #008000;">og:contentid</span> 内容主体的ID，用来标识当前页面主要内容所处的HTML标签的ID</p>
<table border="1" cellspacing="0">
<tbody>
<tr>
<th> Null</th>
<th> Mult</th>
</tr>
<tr>
<td>Y</td>
<td>N</td>
</tr>
</tbody>
</table>
<p>例如：</p>
<blockquote><p><span style="color: #808080;"><em>&lt;meta property=&#8221;og:type&#8221; content=&#8221;link&#8221; /&gt;<br />
&lt;meta property=&#8221;og:title&#8221; content=&#8221;文艺青年摄影装逼完全指南v2.4 *冲片+针孔教程&#8221; /&gt;<br />
&lt;meta property=&#8221;og:image&#8221; content=&#8221;http://t.douban.com/pics/nav/lg_main_a6.png&#8221; /&gt;<br />
&lt;meta property=&#8221;og:url&#8221; content=&#8221;http://www.douban.com/group/topic/10560486/&#8221; /&gt;<br />
&lt;meta property=&#8221;og:abstract&#8221; content=&#8221;前言：本人从00年开始玩数码相机，之后一直致力于从事摄影装逼这一光荣的职业，在此将自己多年总结的经验传授给大家，让大家在这条光辉的道路上少走弯路，一逼到底。鉴于咱们入单反装逼的文青们一开始预算都不多，本文将会主要侧重于如何在有限的器材的情况下装逼最大化，你要是已经有若干红圈儿金圈儿SBEX什么的，想必此篇文章的主旨你早已心领神会，就算你说自己不装逼，就像有人混豆瓣还死活不承认自己是文青。本文中所有图片，除了特别注明，均为本人亲自拍摄，是本人装逼之路的真实见证。欢迎转载，但是最近更新可能会比较频繁，请把原帖地址 &#8221; /&gt;<br />
&lt;meta property=&#8221;og:contentid&#8221; content=&#8221;topic&#8221; /</em></span><em>&gt; </em></p></blockquote>
<h2>Graphic Element 图片</h2>
<p><span style="color: #008000;"> og:photo</span> 图片列表</p>
<table border="1" cellspacing="0">
<tbody>
<tr>
<th> Null</th>
<th> Mult</th>
</tr>
<tr>
<td>Y</td>
<td>Y</td>
</tr>
</tbody>
</table>
<p><span style="color: #008000;">og:width</span> 图片宽度</p>
<table border="1" cellspacing="0">
<tbody>
<tr>
<th> Null</th>
<th> Mult</th>
</tr>
<tr>
<td>Y</td>
<td>Y</td>
</tr>
</tbody>
</table>
<p><span style="color: #008000;">og:height</span> 图片高度</p>
<table border="1" cellspacing="0">
<tbody>
<tr>
<th> Null</th>
<th> Mult</th>
</tr>
<tr>
<td>Y</td>
<td>Y</td>
</tr>
</tbody>
</table>
<p>例如：</p>
<blockquote><p><span style="color: #808080;"><em>&lt;meta property=&#8221;og:type&#8221; content=&#8221;photo&#8221; /&gt;<br />
&lt;meta property=&#8221;og:title&#8221; content=&#8221;發国·招贴(2)&#8221; /&gt;<br />
&lt;meta property=&#8221;og:image&#8221; content=&#8221;http://t.douban.com/view/photo/icon/public/p487762954.jpg&#8221; /&gt;<br />
&lt;meta property=&#8221;og:url&#8221; content=&#8221;http://www.douban.com/photos/photo/487762954/&#8221; /&gt;<br />
&lt;meta property=&#8221;og:photo&#8221; content=&#8221;http://t.douban.com/view/photo/photo/public/p487762954.jpg&#8221; /&gt;<br />
&lt;meta property=&#8221;og:photo&#8221; content=&#8221;http://t.douban.com/view/photo/photo/public/p355702734.jpg&#8221; /&gt;</em></span></p></blockquote>
<h2>Product Element 商品</h2>
<p><span style="color: #008000;">og:price</span> 产品价格</p>
<table border="1" cellspacing="0">
<tbody>
<tr>
<th> Null</th>
<th> Mult</th>
</tr>
<tr>
<td>N</td>
<td>N</td>
</tr>
</tbody>
</table>
<p><span style="color: #008000;">og:description</span> 产品描述</p>
<table border="1" cellspacing="0">
<tbody>
<tr>
<th> Null</th>
<th> Mult</th>
</tr>
<tr>
<td>Y</td>
<td>N</td>
</tr>
</tbody>
</table>
<p><span style="color: #008000;">og:nick</span> 店铺名</p>
<table border="1" cellspacing="0">
<tbody>
<tr>
<th> Null</th>
<th> Mult</th>
</tr>
<tr>
<td>Y</td>
<td>N</td>
</tr>
</tbody>
</table>
<p><span style="color: #008000;">og:postfee</span> 运费</p>
<table border="1" cellspacing="0">
<tbody>
<tr>
<th> Null</th>
<th> Mult</th>
</tr>
<tr>
<td>Y</td>
<td>N</td>
</tr>
</tbody>
</table>
<p>例如：</p>
<blockquote><p><em><span style="color: #808080;">&lt;meta property=&#8221;og:type&#8221; content=&#8221;product&#8221; /&gt;<br />
&lt;meta property=&#8221;og:title&#8221; content=&#8221;蚁族&#8212;大学毕业生聚居村实录&#8221; /&gt;<br />
&lt;meta property=&#8221;og:image&#8221; content=&#8221;http://img39.ddimg.cn/8/8/20684969-1_b.jpg&#8221; /&gt;<br />
&lt;meta property=&#8221;og:url&#8221; content=&#8221;http://product.dangdang.com/product.aspx?product_id=20684969&amp;ref=book-02-L&#8221; /&gt;<br />
&lt;meta property=&#8221;og:price&#8221; content=&#8221;18.80&#8243; /&gt;<br />
&lt;meta property=&#8221;og:postfee&#8221; content=&#8221;5.00&#8243; /&gt;<br />
&lt;meta property=&#8221;og:description&#8221; content=&#8221;“蚁族”，是对“高校毕业生低收入聚居群体”的典型概括。该群体高知、弱小、聚居，是继三大弱势群体（农民、农民工、下岗职工）之后的第四大弱势群体：他们受过高等教育，主要从事保险推销、电子器材销售、广告营销、餐饮服务等临时性工作，有的甚至处于失业半失业状态；他们平均月收入低于两千元，绝大多数没有“三险”和劳动合同；他们平均年龄集中在22—29岁之间，九成属于“80后”一代；他们主要聚居于城乡结合部或近郊农村，形成独特的“聚居村”。他们是有如蚂蚁般的“弱小强者”，他们是鲜为人知的庞大群体。&#8221; /&gt;<br />
&lt;meta property=&#8221;og:nick&#8221; content=&#8221;当当网&#8221; /&gt;</span></em></p></blockquote>
<hr /><strong>应用指南</strong></p>
<h2>参与到open graph protocol的好处</h2>
<ul>
<li>● 能够正确的分享您的内容到renren.com</li>
<li>● 帮助您的内容更有效的在sns网络中传播</li>
</ul>
<h2>您应该如何参与到open graph protocol来</h2>
<ul>
<li>● 按照您网页的类型，在head中加入meta标签,并填上相应的内容</li>
<li>● 如果一个页面上有多个需要标识出的内容怎么办？<br />
您可以重复meta标签，我们将认为 <strong>og:type</strong> 标签是每一段内容的起始处，例如：</li>
</ul>
<blockquote><p><span style="color: #808080;"><em><span style="color: #808080;">&lt;meta property=&#8221;og:type&#8221; content=&#8221;video&#8221; /&gt;<br />
&lt;meta property=&#8221;og:title&#8221; content=&#8221;五月天_突然好想你 MV现场版&#8221; /&gt;<br />
&lt;meta property=&#8221;og:image&#8221; content=&#8221;http://g1.ykimg.com/0100641F464AC21FF0B3ED00F48F151F43D4BF-5F0F-BD39-76EA-E5E20A1887C4&#8243; /&gt;<br />
&lt;meta property=&#8221;og:url&#8221; content=&#8221;http://v.youku.com/v_show/id_XMTIyMTY5NzMy.html&#8221; /&gt;<br />
&lt;meta property=&#8221;og:videosrc&#8221; content=&#8221;http://player.youku.com/player.php/sid/XMTIyMTY5NzMy&amp;isAutoPlay=true/v.swf&#8221; /&gt;<br />
&lt;meta property=&#8221;og:width&#8221; content=&#8221;500&#8243; /&gt;<br />
&lt;meta property=&#8221;og:height&#8221; content=&#8221;416&#8243; /&gt;</span></em></span></p>
<p><em><span style="color: #808080;">&lt;meta property=&#8221;og:type&#8221; content=&#8221;video&#8221; /&gt;<br />
&lt;meta property=&#8221;og:title&#8221; content=&#8221;五月天_突然好想你 MV现场版_AA&#8221; /&gt;<br />
&lt;meta property=&#8221;og:image&#8221; content=&#8221;http://g1.ykimg.com/0100641F464AC21FF0B3ED00F48F151F43D4BF-5F0F-BD39-76EA-E5E20A1887C44444&#8243; /&gt;<br />
&lt;meta property=&#8221;og:url&#8221; content=&#8221;http://v.youku.com/v_show/id_XMTIyMTY5NzMyyyyyyyyyyyyyyyy.html&#8221; /&gt;<br />
&lt;meta property=&#8221;og:videosrc&#8221; content=&#8221;http://player.youku.com/player.php/sid/XXXXXXXXXXXXMTIyMTY5NzMy&amp;isAutoPlay=true/y.swf&#8221; /&gt;<br />
&lt;meta property=&#8221;og:width&#8221; content=&#8221;600&#8243; /&gt;<br />
&lt;meta property=&#8221;og:height&#8221; content=&#8221;716&#8243; /&gt;</span></em></p>
<p><em><br />
</em></p>
<h2><em>不</em>方便提供meta标签形式怎么办？</h2>
</blockquote>
<ul>
<li>● 您可以提供XML格式的回调接口</li>
<li>● XML的标签格式和meta保持一致，例如:</li>
</ul>
<blockquote><p><span style="color: #808080;"><em>&lt;?xml version=&#8221;1.0&#8243; encoding=&#8221;UTF-8&#8243;?&gt;<br />
&lt;og <strong>xmlns:og=&#8221;http://share.renren.com/og&#8221;</strong></em><em>&gt;<br />
&lt;meta&gt;<br />
&lt;og:type&gt;video&lt;/og:type&gt;<br />
&lt;og:title&gt;五月天_突然好想你 MV现场版&lt;/og:title&gt;<br />
&#8230;<br />
&lt;/meta&gt;<br />
&lt;meta&gt;<br />
&lt;og:type&gt;video&lt;/og:type&gt;<br />
&lt;og:title&gt;五月天_突然好想你 MV现场版2222&lt;/og:title&gt;<br />
&#8230;<br />
&lt;/meta&gt;<br />
&lt;og&gt;</em></span></p></blockquote>
<div>
<ul>
<li>● 我们默认您的回调地址是 http://www.example.com/op/callback<br />
例如您的网页是 http://www.example.com/some.html， 我们将调用http://www.example.com/op/callback?link=http://www.example.com/some.html， 我们预期您会返回符合上面格式的HTML内容</li>
<li>● 我们还将提供给您注册接口到renren.com的功能</li>
</ul>
</div>
</div>
]]></content:encoded>
			<wfw:commentRss>http://ugc.renren.com/2010/06/03/share-open-graph-protocol/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>人人网中间层：实践篇</title>
		<link>http://ugc.renren.com/2010/02/20/renren-ice/</link>
		<comments>http://ugc.renren.com/2010/02/20/renren-ice/#comments</comments>
		<pubDate>Sat, 20 Feb 2010 10:19:35 +0000</pubDate>
		<dc:creator>UGC.FM</dc:creator>
				<category><![CDATA[生产力电台]]></category>

		<guid isPermaLink="false">http://ugc.renren.com/?p=182</guid>
		<description><![CDATA[作者：人人网技术经理 白伯纯  人人网UGC团队博客
人人网中间层：问题篇
人人网中间层：求解篇

之前的问题篇和求解篇描述了人人网在发展过程中遇到的问题，并且介绍了我们采用中间层来提高性能的解决方案。今天的实践篇将通过一个例子来实现一个中间层服务。
这个服务要达到的目的是快速的查询用户是否有效，数据将要使用bitset保存在内存中，每个用户一位，仅保存正整数约21亿，占用内存256M。
开始编码
下面的代码都在这个位置保存：http://gitorious.org/renren/bitserver。
接口定义
定义接口如下：

#include &#60;Ice/BuiltinSequences.ice&#62;
module renren {
struct BitSegment {
int begin;
int end;
Ice::ByteSeq data;
};
interface BitServer {
bool get(int offset);
Ice::BoolSeq gets(Ice::IntSeq offsets);
BitSegment getSegment(int begin, int end);
};
};

这个BitServer.ice文件，通过slice2cpp命令编译成为服务端的Skeleton文件：

slice2cpp -I/opt/Ice-3.3/slice BitServer.ice

服务端
有了上面生成的服务端文件后，就可以实现我们自己的业务功能了。
BitServerI.h和BitServerI.cpp，暂时只是实现了单个get的接口。

#ifndef __BitServerI_h__
#define __BitServerI_h__#include &#60;BitServer.h&#62;
#define SIZE_OF_BIT 2147483647
#include &#60;bitset&#62;
namespace renren
{
class BitServerI : virtual public BitServer
{
public:
void initialize();
virtual bool get(::Ice::Int,
const Ice::Current&#38;);
virtual ::Ice::BoolSeq gets(const ::Ice::IntSeq&#38;,
const Ice::Current&#38;);
virtual ::renren::BitSegment getSegment(::Ice::Int,
::Ice::Int,
const Ice::Current&#38;);
private:
std::bitset&#60;SIZE_OF_BIT&#62; bits_;
};
}
#endif


#include &#60;BitServerI.h&#62;
#include &#60;Ice/Ice.h&#62;int main(int argc, char** argv) {
int status = [...]]]></description>
			<content:encoded><![CDATA[<p>作者：人人网技术经理 白伯纯  <a onclick="pageTracker._trackPageview('/outgoing/ugc.fm/?referer=');pageTracker._trackPageview('/outgoing/ugc.fm/?referer=');" href="http://ugc.fm/">人人网UGC团队博客</a></p>
<p><a title="人人网中间层：问题篇的永久链接" rel="bookmark" href="../2009/12/28/renren-ice-problem/">人人网中间层：问题篇</a></p>
<p><a title="人人网中间层：求解篇的永久链接" rel="bookmark" href="../2010/01/11/renren-ice-part2/">人人网中间层：求解篇</a></p>
<div>
<p>之前的问题篇和求解篇描述了人人网在发展过程中遇到的问题，并且介绍了我们采用中间层来提高性能的解决方案。今天的实践篇将通过一个例子来实现一个中间层服务。<br />
这个服务要达到的目的是快速的查询用户是否有效，数据将要使用bitset保存在内存中，每个用户一位，仅保存正整数约21亿，占用内存256M。<span id="more-182"></span></p>
<h2>开始编码</h2>
<p>下面的代码都在这个位置保存：<a href="http://gitorious.org/renren/bitserver" onclick="pageTracker._trackPageview('/outgoing/gitorious.org/renren/bitserver?referer=');">http://gitorious.org/renren/bitserver</a>。</p>
<h2>接口定义</h2>
<p>定义接口如下：</p>
<div class="codesnip-container">
<div class="c codesnip" style="font-family: monospace;"><span class="co2">#include &lt;Ice/BuiltinSequences.ice&gt;</span><br />
module renren <span class="br0">{</span><br />
<span class="kw4">struct</span> BitSegment <span class="br0">{</span><br />
<span class="kw4">int</span> begin<span class="sy0">;</span><br />
<span class="kw4">int</span> end<span class="sy0">;</span><br />
Ice<span class="sy0">::</span><span class="me2">ByteSeq</span> data<span class="sy0">;</span><br />
<span class="br0">}</span><span class="sy0">;</span><br />
interface BitServer <span class="br0">{</span><br />
bool get<span class="br0">(</span><span class="kw4">int</span> offset<span class="br0">)</span><span class="sy0">;</span><br />
Ice<span class="sy0">::</span><span class="me2">BoolSeq</span> gets<span class="br0">(</span>Ice<span class="sy0">::</span><span class="me2">IntSeq</span> offsets<span class="br0">)</span><span class="sy0">;</span><br />
BitSegment getSegment<span class="br0">(</span><span class="kw4">int</span> begin<span class="sy0">,</span> <span class="kw4">int</span> end<span class="br0">)</span><span class="sy0">;</span><br />
<span class="br0">}</span><span class="sy0">;</span><br />
<span class="br0">}</span><span class="sy0">;</span></div>
</div>
<p>这个BitServer.ice文件，通过slice2cpp命令编译成为服务端的Skeleton文件：</p>
<div class="codesnip-container">
<div class="bash codesnip" style="font-family: monospace;">slice2cpp -I<span class="sy0">/</span>opt<span class="sy0">/</span>Ice-<span class="nu0">3.3</span><span class="sy0">/</span>slice BitServer.ice</div>
</div>
<h2>服务端</h2>
<p>有了上面生成的服务端文件后，就可以实现我们自己的业务功能了。<br />
BitServerI.h和BitServerI.cpp，暂时只是实现了单个get的接口。</p>
<div class="codesnip-container">
<div class="c codesnip" style="font-family: monospace;"><span class="co2">#ifndef __BitServerI_h__</span><br />
<span class="co2">#define __BitServerI_h__</span><span class="co2">#include &lt;BitServer.h&gt;</span></p>
<p><span class="co2">#define SIZE_OF_BIT 2147483647</span><br />
<span class="co2">#include &lt;bitset&gt;</span></p>
<p>namespace renren<br />
<span class="br0">{</span></p>
<p>class BitServerI <span class="sy0">:</span> virtual public BitServer<br />
<span class="br0">{</span><br />
public<span class="sy0">:</span><br />
<span class="kw4">void</span> initialize<span class="br0">(</span><span class="br0">)</span><span class="sy0">;</span></p>
<p>virtual bool get<span class="br0">(</span><span class="sy0">::</span><span class="me2">Ice</span><span class="sy0">::</span><span class="me2">Int</span><span class="sy0">,</span><br />
<span class="kw4">const</span> Ice<span class="sy0">::</span><span class="me2">Current</span><span class="sy0">&amp;</span><span class="br0">)</span><span class="sy0">;</span></p>
<p>virtual <span class="sy0">::</span><span class="me2">Ice</span><span class="sy0">::</span><span class="me2">BoolSeq</span> gets<span class="br0">(</span><span class="kw4">const</span> <span class="sy0">::</span><span class="me2">Ice</span><span class="sy0">::</span><span class="me2">IntSeq</span><span class="sy0">&amp;,</span><br />
<span class="kw4">const</span> Ice<span class="sy0">::</span><span class="me2">Current</span><span class="sy0">&amp;</span><span class="br0">)</span><span class="sy0">;</span></p>
<p>virtual <span class="sy0">::</span><span class="me2">renren</span><span class="sy0">::</span><span class="me2">BitSegment</span> getSegment<span class="br0">(</span><span class="sy0">::</span><span class="me2">Ice</span><span class="sy0">::</span><span class="me2">Int</span><span class="sy0">,</span><br />
<span class="sy0">::</span><span class="me2">Ice</span><span class="sy0">::</span><span class="me2">Int</span><span class="sy0">,</span><br />
<span class="kw4">const</span> Ice<span class="sy0">::</span><span class="me2">Current</span><span class="sy0">&amp;</span><span class="br0">)</span><span class="sy0">;</span><br />
private<span class="sy0">:</span><br />
std<span class="sy0">::</span><span class="me2">bitset</span><span class="sy0">&lt;</span>SIZE_OF_BIT<span class="sy0">&gt;</span> bits_<span class="sy0">;</span><br />
<span class="br0">}</span><span class="sy0">;</span></p>
<p><span class="br0">}</span></p>
<p><span class="co2">#endif</span></div>
</div>
<div class="codesnip-container">
<div class="c codesnip" style="font-family: monospace;"><span class="co2">#include &lt;BitServerI.h&gt;</span><br />
<span class="co2">#include &lt;Ice/Ice.h&gt;</span><span class="kw4">int</span> main<span class="br0">(</span><span class="kw4">int</span> argc<span class="sy0">,</span> <span class="kw4">char</span><span class="sy0">**</span> argv<span class="br0">)</span> <span class="br0">{</span><br />
<span class="kw4">int</span> status <span class="sy0">=</span> <span class="nu0">0</span><span class="sy0">;</span><br />
Ice<span class="sy0">::</span><span class="me2">CommunicatorPtr</span> ic<span class="sy0">;</span><br />
try<span class="br0">{</span><br />
ic <span class="sy0">=</span> Ice<span class="sy0">::</span><span class="me2">initialize</span><span class="br0">(</span>argc<span class="sy0">,</span> argv<span class="br0">)</span><span class="sy0">;</span><br />
Ice<span class="sy0">::</span><span class="me2">ObjectAdapterPtr</span> adapter <span class="sy0">=</span> ic<span class="sy0">-&gt;</span>createObjectAdapter<span class="br0">(</span><span class="st0">&#8220;BitServer&#8221;</span><span class="br0">)</span><span class="sy0">;</span><br />
renren<span class="sy0">::</span><span class="me2">BitServerI</span><span class="sy0">*</span> obj <span class="sy0">=</span> new renren<span class="sy0">::</span><span class="me2">BitServerI</span><span class="sy0">;</span><br />
obj<span class="sy0">-&gt;</span>initialize<span class="br0">(</span><span class="br0">)</span><span class="sy0">;</span><br />
adapter<span class="sy0">-&gt;</span>add<span class="br0">(</span>obj<span class="sy0">,</span> ic<span class="sy0">-&gt;</span>stringToIdentity<span class="br0">(</span><span class="st0">&#8220;BitServer&#8221;</span><span class="br0">)</span><span class="br0">)</span><span class="sy0">;</span><br />
adapter<span class="sy0">-&gt;</span>activate<span class="br0">(</span><span class="br0">)</span><span class="sy0">;</span><br />
ic<span class="sy0">-&gt;</span>waitForShutdown<span class="br0">(</span><span class="br0">)</span><span class="sy0">;</span><br />
<span class="br0">}</span> catch <span class="br0">(</span><span class="kw4">const</span> Ice<span class="sy0">::</span><span class="me2">Exception</span><span class="sy0">&amp;</span> e<span class="br0">)</span> <span class="br0">{</span><br />
std<span class="sy0">::</span><span class="me2">cerr</span> <span class="sy0">&lt;&lt;</span> e <span class="sy0">&lt;&lt;</span> std<span class="sy0">::</span><span class="me2">endl</span><span class="sy0">;</span><br />
status <span class="sy0">=</span> <span class="nu0">1</span><span class="sy0">;</span><br />
<span class="br0">}</span> catch <span class="br0">(</span><span class="kw4">const</span> std<span class="sy0">::</span><span class="me2">exception</span><span class="sy0">&amp;</span> e<span class="br0">)</span> <span class="br0">{</span><br />
std<span class="sy0">::</span><span class="me2">cerr</span> <span class="sy0">&lt;&lt;</span> e.<span class="me1">what</span><span class="br0">(</span><span class="br0">)</span> <span class="sy0">&lt;&lt;</span> std<span class="sy0">::</span><span class="me2">endl</span><span class="sy0">;</span><br />
status <span class="sy0">=</span> <span class="nu0">1</span><span class="sy0">;</span><br />
<span class="br0">}</span> catch <span class="br0">(</span>…<span class="br0">)</span> <span class="br0">{</span><br />
std<span class="sy0">::</span><span class="me2">cerr</span> <span class="sy0">&lt;&lt;</span> <span class="st0">&#8220;unknown exception&#8221;</span> <span class="sy0">&lt;&lt;</span> std<span class="sy0">::</span><span class="me2">endl</span><span class="sy0">;</span><br />
status <span class="sy0">=</span> <span class="nu0">1</span><span class="sy0">;</span><br />
<span class="br0">}</span><br />
<span class="kw1">if</span> <span class="br0">(</span>ic<span class="br0">)</span> <span class="br0">{</span><br />
try <span class="br0">{</span><br />
ic<span class="sy0">-&gt;</span>destroy<span class="br0">(</span><span class="br0">)</span><span class="sy0">;</span><br />
<span class="br0">}</span> catch <span class="br0">(</span><span class="kw4">const</span> Ice<span class="sy0">::</span><span class="me2">Exception</span><span class="sy0">&amp;</span> e<span class="br0">)</span> <span class="br0">{</span><br />
std<span class="sy0">::</span><span class="me2">cerr</span> <span class="sy0">&lt;&lt;</span> e <span class="sy0">&lt;&lt;</span> std<span class="sy0">::</span><span class="me2">endl</span><span class="sy0">;</span><br />
status <span class="sy0">=</span> <span class="nu0">1</span><span class="sy0">;</span><br />
<span class="br0">}</span> catch <span class="br0">(</span><span class="kw4">const</span> std<span class="sy0">::</span><span class="me2">exception</span><span class="sy0">&amp;</span> e<span class="br0">)</span> <span class="br0">{</span><br />
std<span class="sy0">::</span><span class="me2">cerr</span> <span class="sy0">&lt;&lt;</span> e.<span class="me1">what</span><span class="br0">(</span><span class="br0">)</span> <span class="sy0">&lt;&lt;</span> std<span class="sy0">::</span><span class="me2">endl</span><span class="sy0">;</span><br />
status <span class="sy0">=</span> <span class="nu0">1</span><span class="sy0">;</span><br />
<span class="br0">}</span> catch <span class="br0">(</span>…<span class="br0">)</span> <span class="br0">{</span><br />
std<span class="sy0">::</span><span class="me2">cerr</span> <span class="sy0">&lt;&lt;</span> <span class="st0">&#8220;unknown exception&#8221;</span> <span class="sy0">&lt;&lt;</span> std<span class="sy0">::</span><span class="me2">endl</span><span class="sy0">;</span><br />
status <span class="sy0">=</span> <span class="nu0">1</span><span class="sy0">;</span><br />
<span class="br0">}</span><br />
<span class="br0">}</span><br />
<span class="kw1">return</span> status<span class="sy0">;</span><br />
<span class="br0">}</span></p>
<p><span class="kw4">void</span><br />
renren<span class="sy0">::</span><span class="me2">BitServerI</span><span class="sy0">::</span><span class="me2">initialize</span><span class="br0">(</span><span class="br0">)</span> <span class="br0">{</span><br />
<span class="kw1">for</span> <span class="br0">(</span><span class="kw4">int</span> i<span class="sy0">=</span><span class="nu0">0</span><span class="sy0">;</span> i<span class="sy0">&lt;</span><span class="nu12">0xFFFFF</span><span class="sy0">;</span>i<span class="sy0">=</span>i<span class="sy0">+</span>2<span class="br0">)</span> <span class="br0">{</span><br />
bits_<span class="br0">[</span>i<span class="br0">]</span><span class="sy0">=</span><span class="kw2">true</span><span class="sy0">;</span><br />
<span class="br0">}</span><br />
<span class="br0">}</span></p>
<p>bool<br />
renren<span class="sy0">::</span><span class="me2">BitServerI</span><span class="sy0">::</span><span class="me2">get</span><span class="br0">(</span><span class="sy0">::</span><span class="me2">Ice</span><span class="sy0">::</span><span class="me2">Int</span> offset<span class="sy0">,</span><br />
<span class="kw4">const</span> Ice<span class="sy0">::</span><span class="me2">Current</span><span class="sy0">&amp;</span> current<span class="br0">)</span><br />
<span class="br0">{</span><br />
<span class="kw1">if</span><span class="br0">(</span>offset <span class="sy0">&lt;</span> 0<span class="br0">)</span> <span class="kw1">return</span> <span class="kw2">false</span><span class="sy0">;</span><br />
<span class="kw1">return</span> bits_<span class="br0">[</span>offset<span class="br0">]</span><span class="sy0">;</span><br />
<span class="br0">}</span></p>
<p><span class="sy0">::</span><span class="me2">Ice</span><span class="sy0">::</span><span class="me2">BoolSeq</span><br />
renren<span class="sy0">::</span><span class="me2">BitServerI</span><span class="sy0">::</span><span class="me2">gets</span><span class="br0">(</span><span class="kw4">const</span> <span class="sy0">::</span><span class="me2">Ice</span><span class="sy0">::</span><span class="me2">IntSeq</span><span class="sy0">&amp;</span> offsets<span class="sy0">,</span><br />
<span class="kw4">const</span> Ice<span class="sy0">::</span><span class="me2">Current</span><span class="sy0">&amp;</span> current<span class="br0">)</span><br />
<span class="br0">{</span><br />
<span class="kw1">return</span> <span class="sy0">::</span><span class="me2">Ice</span><span class="sy0">::</span><span class="me2">BoolSeq</span><span class="br0">(</span><span class="br0">)</span><span class="sy0">;</span><br />
<span class="br0">}</span></p>
<p><span class="sy0">::</span><span class="me2">renren</span><span class="sy0">::</span><span class="me2">BitSegment</span><br />
renren<span class="sy0">::</span><span class="me2">BitServerI</span><span class="sy0">::</span><span class="me2">getSegment</span><span class="br0">(</span><span class="sy0">::</span><span class="me2">Ice</span><span class="sy0">::</span><span class="me2">Int</span> begin<span class="sy0">,</span><br />
<span class="sy0">::</span><span class="me2">Ice</span><span class="sy0">::</span><span class="me2">Int</span> end<span class="sy0">,</span><br />
<span class="kw4">const</span> Ice<span class="sy0">::</span><span class="me2">Current</span><span class="sy0">&amp;</span> current<span class="br0">)</span><br />
<span class="br0">{</span><br />
<span class="kw1">return</span> <span class="sy0">::</span><span class="me2">renren</span><span class="sy0">::</span><span class="me2">BitSegment</span><span class="br0">(</span><span class="br0">)</span><span class="sy0">;</span><br />
<span class="br0">}</span></div>
</div>
<h2>客户端</h2>
<p>我们使用Java作为客户端，首先用slice2java工具生成Java的Proxy类。</p>
<div class="codesnip-container">
<div class="bash codesnip" style="font-family: monospace;">slice2java -I<span class="sy0">/</span>opt<span class="sy0">/</span>Ice-<span class="nu0">3.3</span><span class="sy0">/</span>slice BitServer.ice</div>
</div>
<p>然后自己实现客户端代码：</p>
<div class="codesnip-container">
<div class="java codesnip" style="font-family: monospace;"><span class="kw1">package</span> <span class="co2">renren</span><span class="sy0">;</span><span class="kw1">class</span> BitServerAdapter <span class="br0">{</span><br />
<span class="kw1">private</span> <span class="kw1">final</span> <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Astring+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky" onclick="pageTracker._trackPageview('/outgoing/www.google.com/search?hl=en_amp_q=allinurl_3Astring+java.sun.com_amp_btnI=I_27m_20Feeling_20Lucky&amp;referer=');"><span class="kw3">String</span></a> endpoints_<span class="sy0">;</span><br />
<span class="kw1">private</span> Ice.<span class="me1">Communicator</span> ic_<span class="sy0">;</span><br />
<span class="kw1">private</span> renren.<span class="me1">BitServerPrx</span> prx_<span class="sy0">;</span></p>
<p><span class="kw1">public</span> BitServerAdapter<span class="br0">(</span><a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Astring+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky" onclick="pageTracker._trackPageview('/outgoing/www.google.com/search?hl=en_amp_q=allinurl_3Astring+java.sun.com_amp_btnI=I_27m_20Feeling_20Lucky&amp;referer=');"><span class="kw3">String</span></a> endpoints<span class="br0">)</span> <span class="br0">{</span><br />
<span class="kw1">this</span>.<span class="me1">endpoints_</span> <span class="sy0">=</span> endpoints<span class="sy0">;</span><br />
<span class="br0">}</span></p>
<p><span class="kw1">public</span> <span class="kw4">void</span> initialize<span class="br0">(</span><span class="br0">)</span> <span class="br0">{</span><br />
ic_ <span class="sy0">=</span> Ice.<a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Autil+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky" onclick="pageTracker._trackPageview('/outgoing/www.google.com/search?hl=en_amp_q=allinurl_3Autil+java.sun.com_amp_btnI=I_27m_20Feeling_20Lucky&amp;referer=');"><span class="kw3">Util</span></a>.<span class="me1">initialize</span><span class="br0">(</span><span class="br0">)</span><span class="sy0">;</span><br />
prx_ <span class="sy0">=</span> renren.<span class="me1">BitServerPrxHelper</span>.<span class="me1">uncheckedCast</span><span class="br0">(</span>ic_.<span class="me1">stringToProxy</span><span class="br0">(</span>endpoints_<span class="br0">)</span><span class="br0">)</span><span class="sy0">;</span><br />
<span class="br0">}</span></p>
<p><span class="kw1">public</span> <span class="kw4">boolean</span> get<span class="br0">(</span><span class="kw4">int</span> id<span class="br0">)</span> <span class="br0">{</span><br />
<span class="kw1">return</span> prx_.<span class="me1">get</span><span class="br0">(</span>id<span class="br0">)</span><span class="sy0">;</span><br />
<span class="br0">}</span></p>
<p><span class="kw1">public</span> <span class="kw1">static</span> <span class="kw4">void</span> main<span class="br0">(</span><a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Astring+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky" onclick="pageTracker._trackPageview('/outgoing/www.google.com/search?hl=en_amp_q=allinurl_3Astring+java.sun.com_amp_btnI=I_27m_20Feeling_20Lucky&amp;referer=');"><span class="kw3">String</span></a><span class="br0">[</span><span class="br0">]</span> args<span class="br0">)</span> <span class="br0">{</span><br />
BitServerAdapter adapter <span class="sy0">=</span> <span class="kw1">new</span> BitServerAdapter<span class="br0">(</span>args<span class="br0">[</span>0<span class="br0">]</span><span class="br0">)</span><span class="sy0">;</span><br />
adapter.<span class="me1">initialize</span><span class="br0">(</span><span class="br0">)</span><span class="sy0">;</span><br />
<span class="kw4">boolean</span> ret <span class="sy0">=</span> adapter.<span class="me1">get</span><span class="br0">(</span><a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Ainteger+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky" onclick="pageTracker._trackPageview('/outgoing/www.google.com/search?hl=en_amp_q=allinurl_3Ainteger+java.sun.com_amp_btnI=I_27m_20Feeling_20Lucky&amp;referer=');"><span class="kw3">Integer</span></a>.<span class="me1">valueOf</span><span class="br0">(</span>args<span class="br0">[</span>1<span class="br0">]</span><span class="br0">)</span><span class="br0">)</span><span class="sy0">;</span><br />
<a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Asystem+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky" onclick="pageTracker._trackPageview('/outgoing/www.google.com/search?hl=en_amp_q=allinurl_3Asystem+java.sun.com_amp_btnI=I_27m_20Feeling_20Lucky&amp;referer=');"><span class="kw3">System</span></a>.<span class="me1">out</span>.<span class="me1">println</span><span class="br0">(</span>ret<span class="br0">)</span><span class="sy0">;</span><br />
<a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Asystem+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky" onclick="pageTracker._trackPageview('/outgoing/www.google.com/search?hl=en_amp_q=allinurl_3Asystem+java.sun.com_amp_btnI=I_27m_20Feeling_20Lucky&amp;referer=');"><span class="kw3">System</span></a>.<span class="me1">exit</span><span class="br0">(</span>0<span class="br0">)</span><span class="sy0">;</span><br />
<span class="br0">}</span><br />
<span class="br0">}</span></div>
</div>
<h2>性能测试</h2>
<p>完成了代码，来测试一下性能吧。<br />
首先启动服务器</p>
<div class="codesnip-container">
<div class="bash codesnip" style="font-family: monospace;">target<span class="sy0">/</span>bitserver –Ice.Config=config</div>
</div>
<p>再启动客户端</p>
<div class="codesnip-container">
<div class="bash codesnip" style="font-family: monospace;">java <span class="re5">-cp</span> <span class="sy0">/</span>opt<span class="sy0">/</span>Ice-3.3<span class="sy0">/</span>lib<span class="sy0">/</span>Ice.jar:target<span class="sy0">/</span>bitclient.jar \<br />
renren.BitServerAdapter “BitServer:default <span class="re5">-p</span> <span class="nu0">10000</span>” <span class="nu0">1022</span></div>
</div>
<p>在客户端调用增加循环50000次，单线程平均每秒处理一万次。</p>
<p>在多线程的环境下，单个服务器每秒可处理的请求8万次左右，已经超过了目前的需要。</p></div>
<div id="_mcePaste" style="overflow: hidden; position: absolute; left: -10000px; top: 0px; width: 1px; height: 1px;">作者：人人网技术经理 白伯纯  <a onclick="pageTracker._trackPageview('/outgoing/ugc.fm/?referer=');pageTracker._trackPageview('/outgoing/ugc.fm/?referer=');" href="http://ugc.fm/">人人网UGC团队博客</a></div>
]]></content:encoded>
			<wfw:commentRss>http://ugc.renren.com/2010/02/20/renren-ice/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>文本分析漫谈-分类器中的关键词提取</title>
		<link>http://ugc.renren.com/2010/02/01/keywords-extraction-overview/</link>
		<comments>http://ugc.renren.com/2010/02/01/keywords-extraction-overview/#comments</comments>
		<pubDate>Mon, 01 Feb 2010 10:51:49 +0000</pubDate>
		<dc:creator>liuw086</dc:creator>
				<category><![CDATA[生产力电台]]></category>

		<guid isPermaLink="false">http://ugc.renren.com/?p=105</guid>
		<description><![CDATA[作者：人人网UGC团队成员 刘威 人人网UGC团队博客
面对人人网海量的UGC，数据挖掘工作势在必行，能把用户最想要的信息推荐出来，是我们正在研究的课题之一。在推荐系统中，分类器是个非常重要的部分。
分类器的研究重点落在两个方面，一方面是文本关键词的提取，一方面是对已有关键词或标签的文本进行训练分类。下图为关键词提取在分类器中的位置

下文简单介绍关键词提取常用的方法。
基于词频（TFIDF）统计的方法
思想：常用TFIDF计算文本特征权重，权重高的为关键词，该方法简单，效果也不错。
在实际操作中常会对文本进行聚类处理，计算文本特征权重后，先对文本向量（在聚类操作中，常用文本的句子做为向量单位）利用余弦定理计算文本相似度或距离，然后通过聚类算法，将相似文本聚类。最后在各文本类中选择关键词，合并得出最终结果。这样先通过文本相似度聚类，提高了关键词准确率。下图为k-means聚类算法过程

TFIDF：TF（term frequency）为特征在文本中出现频率，IDF（inverse document frequency）文档中出现该词的频率log(D/Dｗ)，该公式的思想是：特征权重除了和出现频率成正比外，还和文档频率成反比（如果只有文本中包含该特征，则认为该特征更能体现文本的专有特性）。
特征权重=TF*IDF。
特征权重计算方法还有：用于VSM的信息熵算法，基于增益的对TFIDF改进算法算法等。
该方法常结合聚类算法一同使用。


基于词语共现图提取方法 
思想：文本中两个特征经常共现在文本的同一段落，则认为两个特征在意义上是相互关联的，共现概率越高，关联越紧密。
由此计算每个特征节点重要性，即与其他特征同现指数连乘，选取最重要的节点作为关键词。
其中最简单的特征同现指数可以用两个特征同现频率表示。
该方法在小规模文本集时并不能很好的反映特征间的关系。
因此文本集的大小会影响算法的稳定性和准确性。

基于词语网络的方法 
思想：它是词语共现图的发展，因此与同现图类似，每个特征为网络中的节点，网络的边表示特征间的关系，不同的是该算法引入了图论的模型及算法。
首先要提到最小世界网络（Small-World-Network）这个概念：具有高聚类系数，且平均路径长度短的网络。
其中图的聚类系数为所有节点的(实际边数/最多可能边数)和平均值； 
图的平均路径长度即：网络图中,任意两个节点间最短路径边数的平均值。
这种网络和我们以人为节点，人与人之间关系为边，构成的现实世界具有同样的特性：聚类系数高，平均路径短。同理，该模型适用于词语网络。下图为SWN的模型图


在该网络中，特征即为节点，边表示除了前面说的特征同现频率外，还有jaccard系数等计算方法。网络图构建完成后，提取关键词工作即转换为对关键节点的选择。而由于我们认为词语网络是适用于SWN模型的，那关键节点即为影响SWN性质的节点。在现实世界网络中，就相当于去寻找影响社会发展的人，一个公司中的关键人物一样。
通常寻找关键节点的方法有两种，一是直接衡量节点的属性值来判断节点的重要程度，如节点的度(节点到其他节点距离和的倒数)、节点中介性指标（Betweenness Centrality：其他节点间最短路径 经过该节点的概率）等。另一种是通过衡量删除节点后，对SWN性质的破坏程度，即衡量删除节点后聚类系数和平均路径长度的变化，决定该节点的重要度。
本期就先介绍到这里，下期将对词语网络中的一些关键点进行详细介绍，敬请关注文本分析系列！
注：本文纯属个人理解，如有失误，请不吝赐教！
]]></description>
			<content:encoded><![CDATA[<p>作者：人人网UGC团队成员 刘威 <a style="color: #096dbb; text-decoration: none;" href="http://ugc.renren.com/" target="_blank">人人网UGC团队博客</a></p>
<p>面对<a href="http://www.renren.com" onclick="pageTracker._trackPageview('/outgoing/www.renren.com?referer=');">人人网</a>海量的UGC，数据挖掘工作势在必行，能把用户最想要的信息推荐出来，是我们正在研究的课题之一。在推荐系统中，分类器是个非常重要的部分。</p>
<p>分类器的研究重点落在两个方面，一方面是文本关键词的提取，一方面是对已有关键词或标签的文本进行训练分类。下图为关键词提取在分类器中的位置</p>
<p style="text-align: center"><img class="aligncenter size-full wp-image-132" src="http://ugc.renren.com/wp-content/uploads/2010/01/text-classifer.gif" alt="text-classifer" /></p>
<p>下文简单介绍关键词提取常用的方法。<span id="more-105"></span></p>
<p><strong>基于词频（<a href="http://en.wikipedia.org/wiki/Tf–idf" onclick="pageTracker._trackPageview('/outgoing/en.wikipedia.org/wiki/Tf_idf?referer=');">TFIDF</a></strong><strong>）统计的方法</strong></p>
<p>思想：常用TFIDF计算文本特征权重，权重高的为关键词，该方法简单，效果也不错。</p>
<p>在实际操作中常会对文本进行聚类处理，计算文本特征权重后，先对文本向量（在聚类操作中，常用文本的句子做为向量单位）利用余弦定理计算文本相似度或距离，然后通过聚类算法，将相似文本聚类。最后在各文本类中选择关键词，合并得出最终结果。这样先通过文本相似度聚类，提高了关键词准确率。下图为<a href="http://en.wikipedia.org/wiki/Kmeans" onclick="pageTracker._trackPageview('/outgoing/en.wikipedia.org/wiki/Kmeans?referer=');">k-means</a>聚类算法过程</p>
<p style="text-align: center"><img class="size-medium wp-image-118  aligncenter" src="http://ugc.renren.com/wp-content/uploads/2010/01/k-means-300x225.png" alt="k-means" width="382" height="286" /></p>
<p><a href="http://en.wikipedia.org/wiki/Tf–idf" onclick="pageTracker._trackPageview('/outgoing/en.wikipedia.org/wiki/Tf_idf?referer=');">TFIDF</a>：TF（<span>term frequency</span>）为特征在文本中出现频率，IDF（<span>inverse document frequency</span>）<span>文档中出现该词的频率log(D/D</span>ｗ)<span>，该公式的思想是：特征权重除了和出现频率成正比外，还和文档频率成反比（如果只有文本中包含该特征，则认为该特征更能体现文本的专有特性）。</span></p>
<p><span>特征权重=TF*IDF。</span></p>
<p><span>特征权重计算方法还有：用于VSM的信息熵算法，基于增益的对TFIDF改进算法算法等。</span></p>
<p><span>该方法常结合聚类算法一同使用。</span></p>
<p><span><br />
</span></p>
<p><span><strong>基于词语共现图提取方法</strong> </span></p>
<p><span>思想：文本中两个特征经常共现在文本的同一段落，则认为两个特征在意义上是相互关联的，共现概率越高，关联越紧密。</span></p>
<p><span>由此计算每个特征节点重要性，即与其他特征同现指数连乘，选取最重要的节点作为关键词。</span></p>
<p><span>其中</span><span>最简单的</span><span>特征同现指数可以用两个特征同现频率表示。</span></p>
<p><span>该方法在小规模文本集时并不能很好的反映特征间的关系。</span></p>
<p><span>因此文本集的大小会影响算法的稳定性和准确性。</span></p>
<p style="text-align: center"><img class="aligncenter" src="http://ugc.renren.com/wp-content/uploads/2010/01/%E8%AF%8D%E8%AF%AD%E5%85%B1%E7%8E%B0%E5%9B%BE.gif" alt="co-occurrence-network" width="516" height="411" /></p>
<p><span><strong>基于词语网络的方法</strong> </span></p>
<p><span>思想：</span><span>它是词语共现图的发展，因此</span><span>与同现图类似，每个特征为网络中的节点，网络的边表示特征间的关系，不同的是该算法引入了图论的模型及算法。</span></p>
<p><span>首先要提到最小世界网络（</span><a href="http://en.wikipedia.org/wiki/Small-world_network" onclick="pageTracker._trackPageview('/outgoing/en.wikipedia.org/wiki/Small-world_network?referer=');">Small-World-Network</a><span>）这个概念：具有高聚类系数，且平均路径长度短的网络。</span></p>
<p><span>其中</span><span>图的聚类系数为所有节点的(实际边数/最多可能边数)和平均值；</span><span> </span></p>
<p><span>图的平均路径长度即：网络图中,任意两个节点间最短路径边数的平均值。</span></p>
<p><span>这种网络和我们以人为节点，人与人之间关系为边，构成的现实世界具有同样的特性：聚类系数高，平均路径短。同理，该模型适用于词语网络。下图为SWN的模型图</span></p>
<p><span><img class="aligncenter size-full wp-image-167" src="http://ugc.renren.com/wp-content/uploads/2010/01/small-world-network.bmp" alt="small-world-network" /><br />
</span></p>
<p><span>在该网络中，特征即为节点，边表示除了前面说的特征同现频率外，还有</span>jaccard系数等计算方法。网络图构建完成后，提取关键词工作即转换为对关键节点的选择。而由于我们认为词语网络是适用于SWN模型的，那关键节点即为影响SWN性质的节点。在现实世界网络中，就相当于去寻找影响社会发展的人，一个公司中的关键人物一样。</p>
<p>通常寻找关键节点的方法有两种，一是直接衡量节点的属性值来判断节点的重要程度，如节点的度(节点到其他节点距离和的倒数)、节点中介性指标（Betweenness Centrality：其他节点间最短路径 经过该节点的概率）等。另一种是通过衡量删除节点后，对SWN性质的破坏程度，即衡量删除节点后聚类系数和平均路径长度的变化，决定该节点的重要度。</p>
<p>本期就先介绍到这里，下期将对词语网络中的一些关键点进行详细介绍，敬请关注文本分析系列！</p>
<p>注：本文纯属个人理解，如有失误，请不吝赐教！</p>
]]></content:encoded>
			<wfw:commentRss>http://ugc.renren.com/2010/02/01/keywords-extraction-overview/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>人人网UGC海量存储系统Nuclear介绍 – 原理展望篇</title>
		<link>http://ugc.renren.com/2010/01/28/ugc-nuclear-guide-theory/</link>
		<comments>http://ugc.renren.com/2010/01/28/ugc-nuclear-guide-theory/#comments</comments>
		<pubDate>Thu, 28 Jan 2010 09:55:06 +0000</pubDate>
		<dc:creator>UGC.FM</dc:creator>
				<category><![CDATA[生产力电台]]></category>

		<guid isPermaLink="false">http://ugc.renren.com/?p=99</guid>
		<description><![CDATA[作者：人人网技术民工 冷昊 人人网UGC团队博客
书接上文。
原理篇
Nuclear系统构建于java之上，NIO组件使用Netty，数据序列化使用google的Protocol Buffers，Spring当然是用了的。下图是Nuclear系统内部的一个预览： 

嗯……其实这张图对各位看官意义不大，只是罗列出了Nuclear中的各个组件及简单的层次关系。下面着重分析分区、节点增减、路由的原理。
分区
前文讲到，我们是一个分布式的Key-Value存储系统，那么key对应的数据分布在什么节点上，需要遵守一定的规则。熟悉Memecached Client的同学一定清楚一致性Hash的应用，没错，Hash Ring就是我们的不二选择。在Nuclear中，数据分布在0~264的Hash Ring上，Nuclear集群初始化的时候，根据节点数均分整个Hash Ring。如下图所示：



 
在N=3时，A,B,C三个节点的配置就是系统需要的最少节点了。Nuclear中，顺时针的开始值和结束值确定一个分区管理的数据范围，同时规定分区的范围左开右闭。因此，如上图，我们记录A,B,C分别管理的分区范围是：
A {[c,a],[b, c],[a,b]}
B {[a,b],[c,a],[b,c]}
C {[b,c],[a,b],[c,a]}
可以看出，A处理管理自己的分区数据外，还会把自己管理的数据顺时针往前复制到2(N-1)个节点中。
节点变更
Nuclear增加节点时需要制定目标节点的名称，即增加的节点是用来分担目标节点的负载的。这点不同于Dynamo的分区策略，节点增加的时候会均衡的从现有的节点窃取分区，Nuclear中增加的节点只会影响到邻近的三个节点。加入我们在上面的例子中增加一个新节点N后分区图如下所示：



记录N,A,B,C管理的分区如下：
N {[c,n],[b,c],[a,b]}
A {[n,a],[c,n],[b,c]}
B {[a,b],[n,a],[c,n]}
C {[b,c],[a,b],[n,a]}
Nuclear的分区管理模块将自动的计算出需要同步到N上的数据:
A [a,b] =&#62; N
B [b,c] =&#62; N
C [c,n] =&#62; N
各位看官不难明白，其实就是把A,B,C不再需要的数据挪给新的节点了。删、替换节点原理大同小异，不再冗述。 
路由
Nuclear提供服务器端路由策略，Client的请求随机落在Node节点上，由接收到请求的节点处理后续的逻辑。相对于Client端路由来说，优点是Client无需知道Nuclear集群元数据，易于维护；缺点是会造成一定程度的延时，不过我们的测试结果显示延时在可接受范围之内。
两个设计上的Tips贡献给大家:
1. 万事皆异步
我们在编码的过程中走了一些弯路，同步的操作在高并发的情况下带来的性能下降是非常恐怖的，于是乎，Nuclear系统中任何的高并发操作都消除了Block。no waiting, no delay。
2. 根据系统负载控制后台线程的资源占用
Nuclear系统中有不少的后台线程默默无闻的做着各种辛苦的工作，但是它们同样会占用系统资源，我们的解决方案是根据系统负载动态调整线程的运行和停止，并达到平衡。


展望篇
Nuclear中计划在不远的将来(不远有多远?)实现如下功能：

Eventually Consistent 最终的一致性问题，在保重数据完整性上至关重要。
Async Store 异步数据库存储，各位可以参考：adbcj, async-mysql-connector
Read Cache
Balance Monitor 建立集群的负载监控体系，在新节点加入的时候可以自动去平衡负载最高的节点。

全文完^_^，谢谢各位的捧场，同时有任何好的建议欢迎提出！
参考资料：

Amazon&#8217;s Dynamo
http://www.allthingsdistributed.com/2007/10/amazons_dynamo.html
Cassandra
http://incubator.apache.org/cassandra/
Voldemort
http://project-voldemort.com/

]]></description>
			<content:encoded><![CDATA[<p><span style="font-family: Tahoma,Helvetica,Arial,sans-serif; font-size: 14px;">作者：人人网技术民工<span> </span><a style="color: #096dbb; text-decoration: none;" title="www.lenghao.com" onclick="pageTracker._trackPageview('/outgoing/www.lenghao.com/?referer=');pageTracker._trackPageview('/outgoing/www.lenghao.com?referer=');" href="http://www.lenghao.com/" target="_blank">冷昊</a><span> </span><a style="color: #096dbb; text-decoration: none;" href="../" target="_blank">人人网UGC团队博客</a></span></p>
<p><span style="font-family: Tahoma,Helvetica,Arial,sans-serif; font-size: 14px;">书接<a href="http://ugc.renren.com/2010/01/21/ugc-nuclear-guide-use/" target="_blank">上文</a>。</span></p>
<h1>原理篇</h1>
<p>Nuclear系统构建于java之上，NIO组件使用<a href="http://www.jboss.org/netty" target="_blank" onclick="pageTracker._trackPageview('/outgoing/www.jboss.org/netty?referer=');">Netty</a>，数据序列化使用google的<a href="http://code.google.com/apis/protocolbuffers/" target="_blank" onclick="pageTracker._trackPageview('/outgoing/code.google.com/apis/protocolbuffers/?referer=');">Protocol Buffers</a>，Spring当然是用了的。下图是Nuclear系统内部的一个预览：<span style="font-family: Tahoma,Helvetica,Arial,sans-serif; font-size: 14px;"> </span></p>
<p><img class="size-large wp-image-119 alignnone" title="Snap1" src="http://ugc.renren.com/wp-content/uploads/2010/01/Snap1-1024x768.jpg" alt="Nuclear Overview" width="614" height="461" /></p>
<p><span style="font-family: Tahoma,Helvetica,Arial,sans-serif; font-size: 14px;">嗯……其实这张图对各位看官意义不大，只是罗列出了Nuclear中的各个组件及简单的层次关系。下面着重分析分区、节点增减、路由的原理。</span></p>
<h2>分区</h2>
<p><span style="font-family: Tahoma,Helvetica,Arial,sans-serif; font-size: 14px;">前文讲到，我们是一个分布式的Key-Value存储系统，那么key对应的数据分布在什么节点上，需要遵守一定的规则。熟悉Memecached Client的同学一定清楚一致性Hash的应用，没错，Hash Ring就是我们的不二选择。在Nuclear中，数据分布在0~2<sup>64</sup>的Hash Ring上，Nuclear集群初始化的时候，根据节点数均分整个Hash Ring。如下图所示：<span id="more-99"></span><br />
</span></p>
<p><span style="font-family: Tahoma,Helvetica,Arial,sans-serif; font-size: 14px;"><img class="alignnone size-large wp-image-142" title="Snap3" src="http://ugc.renren.com/wp-content/uploads/2010/01/Snap3-1024x542.jpg" alt="Snap3" width="614" height="325" /><br />
</span></p>
<p><span style="font-family: Tahoma,Helvetica,Arial,sans-serif; font-size: 14px;"> </span></p>
<p><span style="font-family: Tahoma,Helvetica,Arial,sans-serif; font-size: 14px;">在N=3时，A,B,C三个节点的配置就是系统需要的最少节点了。Nuclear中，顺时针的开始值和结束值确定一个分区管理的数据范围，同时规定分区的范围左开右闭。因此，如上图，我们记录A,B,C分别管理的分区范围是：<br />
A {[c,a],[b, c],[a,b]}<br />
B {[a,b],[c,a],[b,c]}<br />
C {[b,c],[a,b],[c,a]}<br />
可以看出，A处理管理自己的分区数据外，还会把自己管理的数据顺时针往前复制到2</span><span style="font-family: Tahoma,Helvetica,Arial,sans-serif; font-size: 14px;">(N-1)</span><span style="font-family: Tahoma,Helvetica,Arial,sans-serif; font-size: 14px;">个节点中。</span></p>
<h2>节点变更</h2>
<p><span style="font-family: Tahoma,Helvetica,Arial,sans-serif; font-size: 14px;">Nuclear增加节点时需要制定目标节点的名称，即增加的节点是用来分担目标节点的负载的。这点不同于Dynamo的分区策略，节点增加的时候会均衡的从现有的节点窃取分区，Nuclear中增加的节点只会影响到邻近的三个节点。加入我们在上面的例子中增加一个新节点N后分区图如下所示：<br />
</span></p>
<p><span style="font-family: Tahoma,Helvetica,Arial,sans-serif; font-size: 14px;"><img class="alignnone size-large wp-image-141" title="Snap2" src="http://ugc.renren.com/wp-content/uploads/2010/01/Snap21-1024x583.jpg" alt="Snap2" width="614" height="350" /><br />
</span></p>
<p><span style="font-family: Tahoma,Helvetica,Arial,sans-serif; font-size: 14px;">记录N,A,B,C管理的分区如下：<br />
N {[c,n],[b,c],[a,b]}<br />
A {[n,a],[c,n],[b,c]}<br />
B {[a,b],[n,a],[c,n]}<br />
</span><span style="font-family: Tahoma,Helvetica,Arial,sans-serif; font-size: 14px;">C {[b,c],[a,b],[n,a]}<br />
Nuclear的分区管理模块将自动的计算出需要同步到N上的数据:<br />
A [a,b] =&gt; N<br />
B [b,c] =&gt; N<br />
C [c,n] =&gt; N<br />
各位看官不难明白，其实就是把A,B,C不再需要的数据挪给新的节点了。删、替换节点原理大同小异，不再冗述。 </span></p>
<h2><strong>路由</strong></h2>
<p><span style="font-family: Tahoma, Helvetica, Arial, sans-serif; font-size: 14px;">Nuclear提供服务器端路由策略，Client的请求随机落在Node节点上，由接收到请求的节点处理后续的逻辑。相对于Client端路由来说，优点是Client无需知道Nuclear集群元数据，易于维护；缺点是会造成一定程度的延时，不过我们的测试结果显示延时在可接受范围之内。</span></p>
<p><span style="font-family: Tahoma,Helvetica,Arial,sans-serif; font-size: 14px;"><em>两个设计上的Tips贡献给大家:</em><br />
1. 万事皆异步<br />
我们在编码的过程中走了一些弯路，同步的操作在高并发的情况下带来的性能下降是非常恐怖的，于是乎，Nuclear系统中任何的高并发操作都消除了Block。no waiting, no delay。</span></p>
<p>2. 根据系统负载控制后台线程的资源占用<br />
Nuclear系统中有不少的后台线程默默无闻的做着各种辛苦的工作，但是它们同样会占用系统资源，我们的解决方案是根据系统负载动态调整线程的运行和停止，并达到平衡。</p>
<p><span style="font-family: Tahoma,Helvetica,Arial,sans-serif; font-size: 14px;"><br />
</span></p>
<h1>展望篇</h1>
<p>Nuclear中计划在不远的将来(不远有多远?)实现如下功能：</p>
<ol>
<li>Eventually Consistent 最终的一致性问题，在保重数据完整性上至关重要。</li>
<li>Async Store 异步数据库存储，各位可以参考：<a href="http://code.google.com/p/adbcj/" target="_blank" onclick="pageTracker._trackPageview('/outgoing/code.google.com/p/adbcj/?referer=');">adbcj</a>, <a href="http://code.google.com/p/async-mysql-connector/" target="_blank" onclick="pageTracker._trackPageview('/outgoing/code.google.com/p/async-mysql-connector/?referer=');">async-mysql-connector</a></li>
<li>Read Cache</li>
<li>Balance Monitor 建立集群的负载监控体系，在新节点加入的时候可以自动去平衡负载最高的节点。</li>
</ol>
<hr />全文完^_^，谢谢各位的捧场，同时有任何好的建议欢迎提出！</p>
<p>参考资料：</p>
<ol>
<li>Amazon&#8217;s Dynamo<br />
<a href="http://www.allthingsdistributed.com/2007/10/amazons_dynamo.html" target="_blank" onclick="pageTracker._trackPageview('/outgoing/www.allthingsdistributed.com/2007/10/amazons_dynamo.html?referer=');">http://www.allthingsdistributed.com/2007/10/amazons_dynamo.html</a></li>
<li>Cassandra<br />
<a href="http://incubator.apache.org/cassandra/" target="_blank" onclick="pageTracker._trackPageview('/outgoing/incubator.apache.org/cassandra/?referer=');">http://incubator.apache.org/cassandra/</a></li>
<li>Voldemort<br />
<a href="http://project-voldemort.com/" target="_blank" onclick="pageTracker._trackPageview('/outgoing/project-voldemort.com/?referer=');">http://project-voldemort.com/</a></li>
</ol>
]]></content:encoded>
			<wfw:commentRss>http://ugc.renren.com/2010/01/28/ugc-nuclear-guide-theory/feed/</wfw:commentRss>
		<slash:comments>15</slash:comments>
		</item>
		<item>
		<title>人人网UGC海量存储系统Nuclear介绍 &#8211; 功能应用篇</title>
		<link>http://ugc.renren.com/2010/01/21/ugc-nuclear-guide-use/</link>
		<comments>http://ugc.renren.com/2010/01/21/ugc-nuclear-guide-use/#comments</comments>
		<pubDate>Thu, 21 Jan 2010 09:59:50 +0000</pubDate>
		<dc:creator>UGC.FM</dc:creator>
				<category><![CDATA[生产力电台]]></category>

		<guid isPermaLink="false">http://ugc.renren.com/?p=70</guid>
		<description><![CDATA[作者：人人网技术民工 冷昊 人人网UGC团队博客
书曰：工欲善其事，必先利其器。人人网作为国内第一大SNS网站，欲存海量UGC数据，必有海量存储系统。Nuclear存储系统在高性能、高可靠、可扩展的海量数据存储需求下横空出世，待小的给列位看官慢慢道来。
缘由篇
看过《人人网使用的开源软件列表》一文的看官一定知道人人网的关系型数据库使用的是MySQL，Key-Value存储使用的是Tokyo Cabinet，话说战斗在第一线的UGC Team的兄弟们发现，MySQL虽然已经被我们用上了散库、散表大法，但是每次数据达到服务器负载临界值时，必然得经过一番迁移数据的剧痛；使用TC也会存在这个问题，且TC只在某些特定的应用场景起作用。于是乎，我们开始需找能满足高性能、高可靠、可扩展等特性，同时能符合UGC应用场景的存储系统，下表列出我们的考察对象及需求。

TC在使用过程中发现单独使用TC会在某些时间点出现性能瓶颈；Voldemort目前的版本对扩展性支持不好；且Voldemort和Casscandra作为一个正在快速开发中的系统，我们尚未有勇气把它引入到生产环境中。追溯到Amazon的Dynamo系统，我们决定在其思想上开发自己的存储系统，Nuclear就是在这样的背景下诞生的。言归正传，给各位道来功能篇及应用篇。
功能篇
高可扩展
一个Nuclear集群支持1到n(n&#60;264)个节点(Node)的规模，每台服务器(Server)支持部署多个节点。当集群资源达到瓶颈时，可以通过增加新的节点来扩展。增加新节点的过程，系统服务无需停止，无需人工干预迁移数据。Nuclear理论上可以无限Scale-Out。
高可靠
单个节点的crash永远对系统的运行造成影响，不存在单点风险。数据的写入参考Dynamo的W+R&#62;N理论，简释之，例如设置系统每一份数据都存储在3个节点上(N=3)，那么读的话必须成功读到两个节点上的数据才认为读成功 (R=2)，写的话必须成功写到两个节点上才认为写成功( W=2)。系统永远可写入(Hinted HandOff)。
高性能
在Xeon E5405 CPU的服务器上，单节点每秒最高2.5w req/s。整个集群的性能取决于一致性级别、N、W、R数及底层存储引擎的选择。例举我们的一个测试数据：
节点数量：4 Node (Server配置： Xeon E5405，16G memory，千兆网卡)
存储引擎：Mysql5.0.45
参数：N=3 W=2 R=2
压力：100 Client Write Request
测试结果：单个Node 15862 req/s，从Client看平均单次请求耗时5ms(见图)， 99.51% 请求耗时 &#60; 50ms

存储
Nuclear本身的数据存储是基于Key-Value形式的，value的形式可以是富数据模型，也可以是List；如果底层的存储引擎是关系型的，那么Nuclear还提供弱结构化的查询功能。下面是Nuclear目前及计划中支持的存储引擎。

*Cassandra我们只使用其底层的存储引擎
应用篇
Nuclear组件介绍
普通节点(Node)
普通节点的职责是接收并处理来自Client的请求，管理该节点上的存储引擎。
中心节点(Seed)
中心节点维护着整个Nuclear集群的拓扑关系(membership)，它熟知每一个节点负责的数据区域。它定时对所有节点进行健康检测，因此熟知每一个节点当前的状态及负责的数据区域。
客户端(Nuclear Client)
提供简单有效的CRUD API。详情如下：
Get
@param key&#60;String&#62;
@param dataID&#60;Long&#62;
@param consistencyLevel
@return ByteString
List
@param key&#60;String&#62;
@param Condition&#60;?&#62;
@param consistencyLevel
@return List&#60;ByteString&#62;
Put
@param key&#60;String&#62;
@param dataID&#60;Long&#62;
@param value&#60;ByteString&#62;
@param consistencyLevel
Replace
同 Put
dataID可选
Delete
@param key&#60;String&#62;
@param dataID&#60;Long&#62;
@param consistencyLevel
NextDataID
@reutrn dataID&#60;Long&#62;
参数详解：
@param dataID&#60;Long&#62; dataID
每一条数据在Nuclear集群中的唯一标示，由系统提供。使用DataID而不是Key作为数据的唯一标示的目的是为了满足Key-&#62;List的需求。
@param consistencyLevel
一致性级别，Nuclear系统提供一致性级别选择如下：
DISCARD 请求发送至Node后即可，无需认为是否成功(List,Get不支持此级别)
MIN 至少成功请求一个Node
QUORUM 严格按照N+W&#62;R理论
DISCARDQUORUM 按照N+W&#62;R理论，但允许Hinted HandOff
ALL成功请求的节点数必须是N@param value&#60;ByteString&#62;
Nuclear系统存储的数据使用Google的protocol [...]]]></description>
			<content:encoded><![CDATA[<p>作者：人人网技术民工 <a title="www.lenghao.com" href="http://www.lenghao.com" target="_blank" onclick="pageTracker._trackPageview('/outgoing/www.lenghao.com?referer=');">冷昊</a> <a href="http://ugc.renren.com" target="_blank">人人网UGC团队博客</a></p>
<p>书曰：工欲善其事，必先利其器。人人网作为国内第一大SNS网站，欲存海量UGC数据，必有海量存储系统。Nuclear存储系统在<strong>高性能、高可靠、可扩展的海量数据存储</strong>需求下横空出世，待小的给列位看官慢慢道来。</p>
<h2>缘由篇</h2>
<p>看过《<a href="http://ugc.renren.com/2009/12/13/a-list-of-open-source-software-in-renren/" target="_blank">人人网使用的开源软件列表</a>》一文的看官一定知道人人网的关系型数据库使用的是MySQL，Key-Value存储使用的是<a href="http://1978th.net/tokyocabinet/" target="_blank" onclick="pageTracker._trackPageview('/outgoing/1978th.net/tokyocabinet/?referer=');">Tokyo Cabinet</a>，话说战斗在第一线的UGC Team的兄弟们发现，MySQL虽然已经被我们用上了散库、散表大法，但是每次数据达到服务器负载临界值时，必然得经过一番迁移数据的剧痛；使用TC也会存在这个问题，且TC只在某些特定的应用场景起作用。于是乎，我们开始需找能满足高性能、高可靠、可扩展等特性，同时能符合UGC应用场景的存储系统，下表列出我们的考察对象及需求。</p>
<p style="TEXT-ALIGN: center"><img class="size-full wp-image-71   aligncenter" title="Snap2" src="http://ugc.renren.com/wp-content/uploads/2010/01/Snap2.jpg" alt="Snap2" width="546" height="136" /></p>
<p><span id="more-70"></span>TC在使用过程中发现单独使用TC会在某些时间点出现性能瓶颈；<a href="http://project-voldemort.com/" target="_blank" onclick="pageTracker._trackPageview('/outgoing/project-voldemort.com/?referer=');">Voldemort</a>目前的版本对扩展性支持不好；且Voldemort和<a href="http://incubator.apache.org/cassandra/" target="_blank" onclick="pageTracker._trackPageview('/outgoing/incubator.apache.org/cassandra/?referer=');">Casscandra</a>作为一个正在快速开发中的系统，我们尚未有勇气把它引入到生产环境中。追溯到Amazon的<a href="http://www.allthingsdistributed.com/2007/10/amazons_dynamo.html" target="_blank" onclick="pageTracker._trackPageview('/outgoing/www.allthingsdistributed.com/2007/10/amazons_dynamo.html?referer=');">Dynamo</a>系统，我们决定在其思想上开发自己的存储系统，Nuclear就是在这样的背景下诞生的。言归正传，给各位道来功能篇及应用篇。</p>
<h2>功能篇</h2>
<h3>高可扩展</h3>
<p>一个Nuclear集群支持1到n(n&lt;2<sup>64</sup>)个节点(Node)的规模，每台服务器(Server)支持部署多个节点。当集群资源达到瓶颈时，可以通过增加新的节点来扩展。增加新节点的过程，系统服务无需停止，无需人工干预迁移数据。Nuclear理论上可以无限<strong>Scale-Out</strong>。</p>
<h3>高可靠</h3>
<p>单个节点的crash永远对系统的运行造成影响，不存在单点风险。数据的写入参考<a href="http://www.allthingsdistributed.com/2007/10/amazons_dynamo.html" target="_blank" onclick="pageTracker._trackPageview('/outgoing/www.allthingsdistributed.com/2007/10/amazons_dynamo.html?referer=');">Dynamo</a>的W+R&gt;N理论，简释之，例如设置系统每一份数据都存储在3个节点上(N=3)，那么读的话必须成功读到两个节点上的数据才认为读成功 (R=2)，写的话必须成功写到两个节点上才认为写成功( W=2)。系统永远可写入(Hinted HandOff)。</p>
<h3>高性能</h3>
<p>在Xeon E5405 CPU的服务器上，单节点每秒最高2.5w req/s。整个集群的性能取决于一致性级别、N、W、R数及底层存储引擎的选择。例举我们的一个测试数据：<br />
节点数量：4 Node (Server配置： Xeon E5405，16G memory，千兆网卡)<br />
存储引擎：Mysql5.0.45<br />
参数：N=3 W=2 R=2<br />
压力：100 Client Write Request<br />
测试结果：单个Node 15862 req/s，从Client看平均单次请求耗时5ms(见图)， 99.51% 请求耗时 &lt; 50ms</p>
<p style="TEXT-ALIGN: center"><img class="size-full wp-image-73 aligncenter" title="nnn1" src="http://ugc.renren.com/wp-content/uploads/2010/01/nnn1.jpg" alt="nnn1" width="559" height="341" /></p>
<h3>存储</h3>
<p>Nuclear本身的数据存储是基于Key-Value形式的，value的形式可以是富数据模型，也可以是List；如果底层的存储引擎是关系型的，那么Nuclear还提供弱结构化的查询功能。下面是Nuclear目前及计划中支持的存储引擎。</p>
<p style="text-align: center;"><img class="size-full wp-image-74 aligncenter" title="fff1" src="http://ugc.renren.com/wp-content/uploads/2010/01/fff1.jpg" alt="fff1" width="567" height="127" /><br />
*Cassandra我们只使用其底层的存储引擎</p>
<h2>应用篇</h2>
<h3>Nuclear组件介绍</h3>
<p><strong>普通节点(Node)<br />
</strong>普通节点的职责是接收并处理来自Client的请求，管理该节点上的存储引擎。</p>
<p><strong>中心节点(Seed)<br />
</strong>中心节点维护着整个Nuclear集群的拓扑关系(membership)，它熟知每一个节点负责的数据区域。它定时对所有节点进行健康检测，因此熟知每一个节点当前的状态及负责的数据区域。</p>
<p><strong>客户端(Nuclear Client)<br />
</strong>提供简单有效的CRUD API。详情如下：<br />
<em>Get</em><br />
@param key&lt;String&gt;<br />
@param <span style="color: #ff0000;">dataID&lt;Long&gt;</span><br />
@param <span style="color: #ff0000;">consistencyLevel</span><br />
@return ByteString</p>
<p><em>List</em><br />
@param key&lt;String&gt;<br />
@param <span style="color: #ff0000;">Condition&lt;?&gt;</span><br />
@param consistencyLevel<br />
@return List&lt;ByteString&gt;</p>
<p><em>Put</em><br />
@param key&lt;String&gt;<br />
@param dataID&lt;Long&gt;<br />
@param <span style="color: #ff0000;">value&lt;ByteString&gt;</span><br />
@param consistencyLevel</p>
<p><em>Replace</em><br />
同 <em>Put<br />
</em>dataID可选</p>
<p><em>Delete</em><br />
@param key&lt;String&gt;<br />
@param dataID&lt;Long&gt;<br />
@param consistencyLevel</p>
<p><em>NextDataID</em><br />
@reutrn dataID&lt;Long&gt;</p>
<p>参数详解：<br />
@param dataID&lt;Long&gt; dataID<br />
每一条数据在Nuclear集群中的唯一标示，由系统提供。使用DataID而不是Key作为数据的唯一标示的目的是为了满足Key-&gt;List的需求。</p>
<p>@param consistencyLevel<br />
一致性级别，Nuclear系统提供一致性级别选择如下：</p>
<li>DISCARD 请求发送至Node后即可，无需认为是否成功(List,Get不支持此级别)</li>
<li>MIN 至少成功请求一个Node</li>
<li>QUORUM 严格按照N+W&gt;R理论</li>
<li>DISCARDQUORUM 按照N+W&gt;R理论，但允许Hinted HandOff</li>
<li>ALL成功请求的节点数必须是N@param value&lt;ByteString&gt;<br />
Nuclear系统存储的数据使用Google的<a href="http://code.google.com/intl/zh-CN/apis/protocolbuffers/docs/overview.html" target="_blank" onclick="pageTracker._trackPageview('/outgoing/code.google.com/intl/zh-CN/apis/protocolbuffers/docs/overview.html?referer=');">protocol buffers</a>协议，因此存入和取出的数据都是google的 ByteString 类型</p>
<p>@param Condition<br />
结构化数据的条件查询参数，目前仅支持MySQL引擎下按DataID检索、排序及分页</p>
<p>Code Example:<br />
<img class="alignnone size-full wp-image-75" title="dddd" src="http://ugc.renren.com/wp-content/uploads/2010/01/dddd.jpg" alt="dddd" width="558" height="139" /></p>
<h3>系统部署图<br />
<img class="alignnone size-full wp-image-76" title="vvvv" src="http://ugc.renren.com/wp-content/uploads/2010/01/vvvv.jpg" alt="vvvv" width="556" height="295" /></h3>
<p>图释：每一个节点都会和其它的节点建立联系，但来自Client的请求只会落在普通节点上。</p>
<h3>集群管理</h3>
<p>Nuclear提供对节点的增、删、替换操作，面对使用者非常简单，只需要知晓仅有的几个命令即可。<br />
<strong>增加</strong>： <em>sh node.sh new A<br />
</em>node.sh是node启动的脚本；new标示当前节点为新增；A标示新增的节点去分担现有的A节点的负载。</p>
<p><strong>删除</strong>:  <em>delete node A</em><br />
进入Nuclear管理后台，执行该命令</p>
<p><strong>替换</strong>： <em>sh node.sh replace A</em><strong> </strong></p>
<p><strong>后台管理</strong>: <em>sh manage.sh nodeip nodeport</em><br />
目前提供如下功能点：</li>
<li>QPS查看</li>
<li>Node接收请求总数</li>
<li>Node处理请求耗时数据</li>
<li>节点信息查看</li>
<li>集群拓扑信息查看</li>
<li>动态更改节点工作线程数</li>
<hr />今天UGC的Nuclear系统介绍到此为止，下回分解 &lt;原理篇&gt; &lt;展望篇&gt;，尽请期待！</p>
]]></content:encoded>
			<wfw:commentRss>http://ugc.renren.com/2010/01/21/ugc-nuclear-guide-use/feed/</wfw:commentRss>
		<slash:comments>28</slash:comments>
		</item>
		<item>
		<title>人人网中间层：求解篇</title>
		<link>http://ugc.renren.com/2010/01/11/renren-ice-part2/</link>
		<comments>http://ugc.renren.com/2010/01/11/renren-ice-part2/#comments</comments>
		<pubDate>Mon, 11 Jan 2010 03:28:06 +0000</pubDate>
		<dc:creator>UGC.FM</dc:creator>
				<category><![CDATA[生产力电台]]></category>

		<guid isPermaLink="false">http://ugc.fm/?p=68</guid>
		<description><![CDATA[作者：人人网技术经理 白伯纯  人人网UGC团队博客
书接上文，为了提高性能，在人人网的技术结构中，在数据库和页面之间，有中间层。中间层高性能的基础是用内存代替磁盘。
用内存代替磁盘
数据库系统的最大瓶颈在磁盘IO，大量的小数据请求不是磁盘的强项。人人网中间层服务就是利用了内存代替硬盘的方法来提高整体性能。有了这层服务以后，以前的数据库关联查询被提前计算并缓存，需要访问时直接获取。
通用的Memcached缓存方案也有些不足，数据不能自己变化，也不能部分变化。于是人人网选择了自己实现缓存的方式。
在自己实现缓存的过程中，管理内存相对容易，通信协议是比较复杂的部分，我们在这方面选择了开源的Ice通信框架（http://www.zeroc.com）来完成繁琐的工作，至今它都工作的很好。
Ice通信框架在人人网完成了两件事，通信和定位。客户端通过IceGrid组件定位到需要的服务地址，将请求发送到中间层服务，中间层服务将结果返回。客户端只需要知道一个地址就可以找到所有的服务；同时，众多服务也可以在不同的服务器之间随意迁移。在现在的人人网有超过500个Ice写成的中间层服务在运行。
定制的内存数据
用Ice解决了通信和部署的问题后，中间层服务就是核心的数据结构管理。概括的说，就是灵活变化，保证速度。下面列举若干使用了中间层服务的情况
一份数据 多种排序
在人人网的好友页，有很多排序方式可以显示好友列表。每种列表都是从一个按ID排序的服务中获取的，再经过排序，缓存在各个顺序的列表中。
随时间变化的数据
在很多列表页面，都会显示“在线标志”，这个标志是冗余在各个列表的缓存当中，定期刷新的。这些需要和cache一起实现的业务逻辑，在人人网中间层当中非常普遍。
特殊类型
我们用了一个bit保存用户的激活状态。200M内存可以保存全部int范围的状态。并且查询和更新速度飞快。
接下来的实践篇将会用这个为例子展示中间层的实现。
]]></description>
			<content:encoded><![CDATA[<p>作者：人人网技术经理 白伯纯  <a href="http://ugc.fm/" onclick="pageTracker._trackPageview('/outgoing/ugc.fm/?referer=');">人人网UGC团队博客</a></p>
<p>书接上文，为了提高性能，在人人网的技术结构中，在数据库和页面之间，有中间层。中间层高性能的基础是用内存代替磁盘。</p>
<h2>用内存代替磁盘</h2>
<p>数据库系统的最大瓶颈在磁盘IO，大量的小数据请求不是磁盘的强项。人人网中间层服务就是利用了内存代替硬盘的方法来提高整体性能。有了这层服务以后，以前的数据库关联查询被提前计算并缓存，需要访问时直接获取。<br />
通用的Memcached缓存方案也有些不足，数据不能自己变化，也不能部分变化。于是人人网选择了自己实现缓存的方式。<br />
在自己实现缓存的过程中，管理内存相对容易，通信协议是比较复杂的部分，我们在这方面选择了开源的Ice通信框架（http://www.zeroc.com）来完成繁琐的工作，至今它都工作的很好。<br />
Ice通信框架在人人网完成了两件事，通信和定位。客户端通过IceGrid组件定位到需要的服务地址，将请求发送到中间层服务，中间层服务将结果返回。客户端只需要知道一个地址就可以找到所有的服务；同时，众多服务也可以在不同的服务器之间随意迁移。在现在的人人网有超过500个Ice写成的中间层服务在运行。<span id="more-68"></span></p>
<h2>定制的内存数据</h2>
<p>用Ice解决了通信和部署的问题后，中间层服务就是核心的数据结构管理。概括的说，就是灵活变化，保证速度。下面列举若干使用了中间层服务的情况</p>
<h3>一份数据 多种排序</h3>
<p>在人人网的好友页，有很多排序方式可以显示好友列表。每种列表都是从一个按ID排序的服务中获取的，再经过排序，缓存在各个顺序的列表中。</p>
<h3>随时间变化的数据</h3>
<p>在很多列表页面，都会显示“在线标志”，这个标志是冗余在各个列表的缓存当中，定期刷新的。这些需要和cache一起实现的业务逻辑，在人人网中间层当中非常普遍。</p>
<h3>特殊类型</h3>
<p>我们用了一个bit保存用户的激活状态。200M内存可以保存全部int范围的状态。并且查询和更新速度飞快。<br />
接下来的实践篇将会用这个为例子展示中间层的实现。</p>
]]></content:encoded>
			<wfw:commentRss>http://ugc.renren.com/2010/01/11/renren-ice-part2/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>人人网中间层：问题篇</title>
		<link>http://ugc.renren.com/2009/12/28/renren-ice-problem/</link>
		<comments>http://ugc.renren.com/2009/12/28/renren-ice-problem/#comments</comments>
		<pubDate>Mon, 28 Dec 2009 04:32:57 +0000</pubDate>
		<dc:creator>UGC.FM</dc:creator>
				<category><![CDATA[生产力电台]]></category>

		<guid isPermaLink="false">http://ugc.fm/?p=61</guid>
		<description><![CDATA[作者：人人网技术经理 白伯纯  人人网UGC团队博客首发
由开源软件组成的系统
与很多大型的网站一样，人人网的系统全部是由开源软件构建的。使用Nginx做前端接入，resin做容器，Memcached做通用cache，MySQL做数据库，使用Linux操作系统。
除了上述的部分外，人人网还有一个与众不同的中间层。中间层以服务的形式存在，位于MySQL和resin中间，提供高并发低成本的数据访问层。
数据库的压力
在上述结构系统中，数据库的性能往往成为系统瓶颈。人人网在发展的过程中不断重构，改变最大的就是数据库部分。大概的步骤是“优化SQL”，“业务拆分”，“垂直拆分”和“水平拆分”几个阶段，关于数据库优化的细节将来再引用到这里。
经过优化后的数据库，单台可以承担每秒3000次的主键查询。再提高性能的优化，我们采用的方案是使用中间层。
性能目标
增加中间层可以在不增加服务器数量的前提下，提高服务的整体性能，并且提高系统的可扩展性。这里简要列举一些使用中间层服务优化的效果。
实时更新的数据
用户的个人信息数据，目前的写操作500次/秒，读操作2万次/秒。这些数据分布在数十个数据表中，如果用数据库做10次主键查询，需要的时间将会非常可观。中间层的缓存服务把这个性能稳定在了99.9%的请求时间小于20ms。
判断好友关系，读操作900次/秒。这个操作现在使用6G内存存储了所有的好友关系，在2ms内返回任意两人的好友关系。
关联查询，仅好友列表就有1300次/秒。如果使用关联查询，数据库需要同步很多无用的字段。现在只需要两次内存请求，并且衍生出很多种类的排序。
大量聚合的访问
聚合的页面在SNS中是访问量最大的部分。首页集成的功能多达17个模块，这些模块之间的关系相对独立。为了快速的把这些数据集合在一起，就需要迅速获取数据。
我们对整体技术框架的要求是，关键页面执行时间要在100ms以内。
Session同步
众多的resin服务器之间，如何共享用户身份验证的结果，在各种session共享机制中，我们的方案是使用中间层服务来集中存储的。
待续
问题篇只是开端，接下来的“求解篇”将会分析人人网中间层的主要应用场景。“实践篇”将会举例一个典型的中间层服务。
[编者按：求解篇的内容会在下期广播中播出]
]]></description>
			<content:encoded><![CDATA[<p>作者：人人网技术经理 白伯纯  <a href="http://ugc.fm" onclick="pageTracker._trackPageview('/outgoing/ugc.fm?referer=');">人人网UGC团队博客</a>首发</p>
<h2><strong>由开源软件组成的系统</strong></h2>
<p>与很多大型的网站一样，人人网的系统全部是由开源软件构建的。使用Nginx做前端接入，resin做容器，Memcached做通用cache，MySQL做数据库，使用Linux操作系统。<br />
除了上述的部分外，人人网还有一个与众不同的中间层。中间层以服务的形式存在，位于MySQL和resin中间，提供高并发低成本的数据访问层。</p>
<h2><strong>数据库的压力</strong></h2>
<p>在上述结构系统中，数据库的性能往往成为系统瓶颈。人人网在发展的过程中不断重构，改变最大的就是数据库部分。大概的步骤是“优化SQL”，“业务拆分”，“垂直拆分”和“水平拆分”几个阶段，关于数据库优化的细节将来再引用到这里。<span id="more-61"></span><br />
经过优化后的数据库，单台可以承担每秒3000次的主键查询。再提高性能的优化，我们采用的方案是使用中间层。</p>
<h2><strong>性能目标</strong></h2>
<p>增加中间层可以在不增加服务器数量的前提下，提高服务的整体性能，并且提高系统的可扩展性。这里简要列举一些使用中间层服务优化的效果。</p>
<h3>实时更新的数据</h3>
<p>用户的个人信息数据，目前的写操作500次/秒，读操作2万次/秒。这些数据分布在数十个数据表中，如果用数据库做10次主键查询，需要的时间将会非常可观。中间层的缓存服务把这个性能稳定在了99.9%的请求时间小于20ms。<br />
判断好友关系，读操作900次/秒。这个操作现在使用6G内存存储了所有的好友关系，在2ms内返回任意两人的好友关系。<br />
关联查询，仅好友列表就有1300次/秒。如果使用关联查询，数据库需要同步很多无用的字段。现在只需要两次内存请求，并且衍生出很多种类的排序。</p>
<h3>大量聚合的访问</h3>
<p>聚合的页面在SNS中是访问量最大的部分。首页集成的功能多达17个模块，这些模块之间的关系相对独立。为了快速的把这些数据集合在一起，就需要迅速获取数据。<br />
我们对整体技术框架的要求是，关键页面执行时间要在100ms以内。</p>
<h3>Session同步</h3>
<p>众多的resin服务器之间，如何共享用户身份验证的结果，在各种session共享机制中，我们的方案是使用中间层服务来集中存储的。</p>
<h2>待续</h2>
<p>问题篇只是开端，接下来的“求解篇”将会分析人人网中间层的主要应用场景。“实践篇”将会举例一个典型的中间层服务。</p>
<p>[编者按：求解篇的内容会在下期广播中播出]</p>
]]></content:encoded>
			<wfw:commentRss>http://ugc.renren.com/2009/12/28/renren-ice-problem/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>技术架构两三语</title>
		<link>http://ugc.renren.com/2009/12/20/technical-architecture/</link>
		<comments>http://ugc.renren.com/2009/12/20/technical-architecture/#comments</comments>
		<pubDate>Sun, 20 Dec 2009 06:58:16 +0000</pubDate>
		<dc:creator>UGC.FM</dc:creator>
				<category><![CDATA[生产力电台]]></category>

		<guid isPermaLink="false">http://ugc.fm/?p=43</guid>
		<description><![CDATA[作者：人人网架构师 王志亮  人人网UGC团队博客首发
小的不才，斗胆发言
多角度定义架构
定义架构的最短形式是：“架构是一种结构”，太棒了，这是一种正确的理解，但世界还没太平。若做一个比喻，架构就像一个操作系统，不同的角度有不同的理解，不同的关切者有各自的着重点，多视点的不同理解都是架构需要的，也只有通过多视点来考察才能演化出一个有效的架构。
从静态的角度，架构要回答一个系统在技术上如何组织；从变化的角度，架构要回答如何支持系统不断产生的新功能、新变化以及适时的重构；从服务质量的角度，架构要平衡各种和用户体验有关的指标；从运维的角度，架构要回答如何充分利用计算机或网络资源及其扩展策略；从经济的角度，架构要回答如何在可行的基础上降低实现成本等等。
没有架构策略的系统，让我诅咒它散掉： 人们不知道如何简单一致地理解，不知道如何加入一个新功能，如何调高或调低某个服务质量指标，如何应付增大的访问，如何提高系统的容错能力或稳定性，如何充分省钱。没有良好架构支持的系统，出来混的迟早要还！我们诅咒他散掉。
如何得到一个良好的架构？
只言片语
像妈妈那样优生
架构所要做的是一个“细节还未完全落实的技术决策，这个决策是一个框架、是一种权衡、是一个路线图”，这个决策规定了整个系统的技术“风格”和后续技术发展方向。
系统的开发是一个从无到有的过程，需要不断地迭代：功能上不断地丰富，技术上不断地完善。如果把一个系统比喻一个人，怎么让这个人不断地往健康、完备的方向成长就是我们的目的了。一开始，这个人并不完善，包括很多器官并不成熟，甚至没有，通过营养的摄入，时间的沉淀，不断地重构最终成功。人也需要重构？！不是吗？血液的60天一变换，牙齿的两次生长等等(注1)，有一个专业术语“新陈代谢”！ 当一个人新陈代谢的能力下降的时候，也就是老了。
在系统从无到有的过程，架构要着眼于未来，落实于现在，规划迭代、优化的路径。这个架构要支持目前最紧迫的任务：“生出来”，也要支持以后能不断地新陈代谢的可能性，两者缺一不可。
像理想那样追求
系统的每个阶段都很重要，一个好的起点并不意味着一直会好下去，制定了各种策略后，贯彻、执行是最重要的课题。没有人一开始就想把一件事情做糟糕，但这个世界就是这样，很多事情都会变坏，越来越不可控。导致如此境地的主观原因就是自己没有设法去维护、坚持、贯彻原先的理想。作为一个程序员或架构员，要不断审视自己开发的系统，主动维护系统的架构，如若发现有对架构产生破坏的地方，应该适时纠正，坚持零容忍。如果不零容忍会怎样？千里之堤溃于蚁穴，我们诅咒他散掉。
谁来做架构？
架构师这样的一个帽子，很多人会闪闪躲躲。
国外多少年的工作经验才可能成就一个架构师，而国内3、5年工作经验的小毛头就说自己是个架构师了。通常认为，架构师理应无所不能，一旦有人被称为架构师，他就应该接受重重的检验。总之，那些自称是架构师的人在冒着道德风险。但，同学们不要胆却，所谓时势造英雄。有人称你是一个英雄，那是因为你被需要，要勇敢地站出来，扮演好自己的角色是对岗位的敬畏。当我把你看成是一位架构师的时候，我需要你不断地给自己暗示，不断地以理想的架构师来要求自己，和同学们在工作中学习，一项一项地突破自己，把工作做好。
一个组织可能会明确地任命一些人为架构师，但大部分的组织可能不会。但在一个项目团队中总有需要有人完成类似的工作，这可能是一个人，也可能是整个团队在商量的气氛中完成。
我的意见是：如果你愿意，你就是架构师！
架构模式
当一个问题、一个系统可以采用很多解决方式来设计时，我们采用什么方式并且以一致的思想、方式解决这个问题时，这就是风格了，当这种风格具有可复用性那就是一种模式了。在编程上，我们有“设计模式”的指导，在架构上，我们也应该总结一些良好的模式出来，应用在不同的情况。关于这方面的资料，目前并不难找。
小的不才，发言结束。请多指教。
注1：周期数字没有核实准确性，但意思已到。
]]></description>
			<content:encoded><![CDATA[<p>作者：人人网架构师 王志亮  <a href="http://ugc.fm" onclick="pageTracker._trackPageview('/outgoing/ugc.fm?referer=');">人人网UGC团队博客</a>首发</p>
<p>小的不才，斗胆发言</p>
<p><span style="color: #ff6600;"><strong>多角度定义架构</strong></span></p>
<p>定义架构的最短形式是：“架构是一种结构”，太棒了，这是一种正确的理解，但世界还没太平。若做一个比喻，架构就像一个操作系统，不同的角度有不同的理解，不同的关切者有各自的着重点，多视点的不同理解都是架构需要的，也只有通过多视点来考察才能演化出一个有效的架构。<span id="more-43"></span></p>
<p>从静态的角度，架构要回答一个系统在技术上如何组织；从变化的角度，架构要回答如何支持系统不断产生的新功能、新变化以及适时的重构；从服务质量的角度，架构要平衡各种和用户体验有关的指标；从运维的角度，架构要回答如何充分利用计算机或网络资源及其扩展策略；从经济的角度，架构要回答如何在可行的基础上降低实现成本等等。</p>
<p>没有架构策略的系统，让我诅咒它散掉： 人们不知道如何简单一致地理解，不知道如何加入一个新功能，如何调高或调低某个服务质量指标，如何应付增大的访问，如何提高系统的容错能力或稳定性，如何充分省钱。没有良好架构支持的系统，出来混的迟早要还！我们诅咒他散掉。</p>
<p><strong><span style="color: #ff6600;">如何得到一个良好的架构？</span></strong><br />
只言片语</p>
<p><strong>像妈妈那样优生</strong></p>
<p>架构所要做的是一个“细节还未完全落实的技术决策，这个决策是一个框架、是一种权衡、是一个路线图”，这个决策规定了整个系统的技术“风格”和后续技术发展方向。</p>
<p>系统的开发是一个从无到有的过程，需要不断地迭代：功能上不断地丰富，技术上不断地完善。如果把一个系统比喻一个人，怎么让这个人不断地往健康、完备的方向成长就是我们的目的了。一开始，这个人并不完善，包括很多器官并不成熟，甚至没有，通过营养的摄入，时间的沉淀，不断地重构最终成功。人也需要重构？！不是吗？血液的60天一变换，牙齿的两次生长等等(注1)，有一个专业术语“新陈代谢”！ 当一个人新陈代谢的能力下降的时候，也就是老了。</p>
<p>在系统从无到有的过程，架构要着眼于未来，落实于现在，规划迭代、优化的路径。这个架构要支持目前最紧迫的任务：“生出来”，也要支持以后能不断地新陈代谢的可能性，两者缺一不可。</p>
<p><strong>像理想那样追求</strong></p>
<p>系统的每个阶段都很重要，一个好的起点并不意味着一直会好下去，制定了各种策略后，贯彻、执行是最重要的课题。没有人一开始就想把一件事情做糟糕，但这个世界就是这样，很多事情都会变坏，越来越不可控。导致如此境地的主观原因就是自己没有设法去维护、坚持、贯彻原先的理想。作为一个程序员或架构员，要不断审视自己开发的系统，主动维护系统的架构，如若发现有对架构产生破坏的地方，应该适时纠正，坚持零容忍。如果不零容忍会怎样？千里之堤溃于蚁穴，我们诅咒他散掉。</p>
<p><strong><span style="color: #ff6600;">谁来做架构？</span></strong></p>
<p>架构师这样的一个帽子，很多人会闪闪躲躲。</p>
<p>国外多少年的工作经验才可能成就一个架构师，而国内3、5年工作经验的小毛头就说自己是个架构师了。通常认为，架构师理应无所不能，一旦有人被称为架构师，他就应该接受重重的检验。总之，那些自称是架构师的人在冒着道德风险。但，同学们不要胆却，所谓时势造英雄。有人称你是一个英雄，那是因为你被需要，要勇敢地站出来，扮演好自己的角色是对岗位的敬畏。当我把你看成是一位架构师的时候，我需要你不断地给自己暗示，不断地以理想的架构师来要求自己，和同学们在工作中学习，一项一项地突破自己，把工作做好。</p>
<p>一个组织可能会明确地任命一些人为架构师，但大部分的组织可能不会。但在一个项目团队中总有需要有人完成类似的工作，这可能是一个人，也可能是整个团队在商量的气氛中完成。</p>
<p>我的意见是：如果你愿意，你就是架构师！</p>
<p><strong><span style="color: #ff6600;">架构模式</span></strong></p>
<p>当一个问题、一个系统可以采用很多解决方式来设计时，我们采用什么方式并且以一致的思想、方式解决这个问题时，这就是风格了，当这种风格具有可复用性那就是一种模式了。在编程上，我们有“设计模式”的指导，在架构上，我们也应该总结一些良好的模式出来，应用在不同的情况。关于这方面的资料，目前并不难找。</p>
<p>小的不才，发言结束。请多指教。</p>
<p>注1：周期数字没有核实准确性，但意思已到。</p>
]]></content:encoded>
			<wfw:commentRss>http://ugc.renren.com/2009/12/20/technical-architecture/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
		<item>
		<title>人人网使用的开源软件列表</title>
		<link>http://ugc.renren.com/2009/12/13/a-list-of-open-source-software-in-renren/</link>
		<comments>http://ugc.renren.com/2009/12/13/a-list-of-open-source-software-in-renren/#comments</comments>
		<pubDate>Sun, 13 Dec 2009 06:57:16 +0000</pubDate>
		<dc:creator>UGC.FM</dc:creator>
				<category><![CDATA[生产力电台]]></category>

		<guid isPermaLink="false">http://ugc.fm/?p=42</guid>
		<description><![CDATA[作者：人人网架构师 张洁 人人网UGC团队博客首发
MySQL
关系型数据库存储系统，我们的DBA团队很强大，每人管理上百台MySQL服务器，其他就不多说了，网上资料太多了
Tokyo Cabinet
一个key-value的存储引擎，日本人开发，国内很多公司也开始使用，我们内部很多地方也用它来代替MySQL来做存储，比如我们的搜索结果页的用户资料，就是用它来做一层MySQL外的冗余存储，目的是加快搜索结果页的显示。在key-value并需要持久存储的场景下，用它比MySQL更有效，Cabinet本身只是一个存储引擎，没有网络处理能力，你可以用它作为自己的某个系统的下层存储引擎，更好的是搭配Tokyo Tyrant使用。
Tokyo Tyrant
一个支持Memcached传输协议的网络接口，由Tokyo Cabinet的作者开发，目的是为Tokyo Cabinet提供网络接入能力，即Tokyo Tyrant处理网络连接，协议解析，然后调用Tokyo Cabinet的API来完成持久化存储。
ICE
一个跨语言的网络通讯框架，框架本身提供了强大的通讯能力，管理工具，负载均衡方案，其跨语言能力也是一个很大的亮点，基于这个框架之上，我们选用合适的语言来提供合适的服务，比如我们使用C++来开发Cache服务，使用Java来开发一些逻辑服务。框架本身可以很重，也可以很轻，具体要看你怎么用：）
Memcached
一个纯内存的key-value的cache系统，高效、稳定，使用广泛，如果你连它都没听说过就太out啦，memcached本身不具备分布式能力，需要依靠Client来实现分布，这里强调一点的是，你应该选择一致性Hash来做key的分布。各种语言的client都有，我们使用spymemcached作为java的Client，spymemcached是一个异步的NIO的memcached client，对网络IO的处理非常的精巧，也更加高效，同时因为提供异步操作方式，可以让你对Memcached的操作有更好的控制能力，Memcached到1.4.0版本之后，开始支持binary protocol，spymemcached对其也支持的比较好，使用binary protocol可以提高对协议的解析效率和网络IO的读写效率。
上面说到我们使用ICE自己开发了Cache服务，为什么我们还要用Memcached呢？主要在对Cache的操作粒度不一样，Memcached对Cache对象以binary byte作为一个整体来操作，需要频繁的序列化和反序列化，我们使用ICE提供的Cache服务，可以以Cache对象的一个或者多个字段来操作，比如一个用户对象，我们可以只更新它的姓名，而Memcached
Nginx
高效、稳定的Web Server，我们利用其代理能力，做跨IDC的请求代理，同时也将其和我们的Resin(Java Web 容器)搭配，放在Resin的前面来解决Resin的对网络连接处理能力弱的问题，在一些小地方也用它来做7层的负载均衡
Resin
一个Java Web Server，比Tomcat更高效，是我们主要的Java Web容器
Squid
代理服务器，我们用他来做图片文件的反向代理缓存
LVS
能提供4层的负载均衡，高效、高可用，高并发。我们用他替代了很多硬件的负载均衡设备
Struts
Java web框架，不过这个已经是历史了，我们开发了一套自己的Web框架替代了它，未来我们也会把我们的内部的这套Web框架开源出来
Lucence
基于Java的搜索引擎框架，用它我们构建了一个搜索集群来提供搜人的服务
Netty
一个Java的网络框架，和apache的mina类似，但比mina更高效，我们用来做一些小的服务
Ganglia
一个监控系统，帮组我们了解我们每台Server的资源利用情况
还有些小东西就不列出来了，最后要说的一点就是，对这些开源软件或者系统，我们都非常的了解，或者说知根知底，从API到内部实现原理，甚至到一些源码的细节。
]]></description>
			<content:encoded><![CDATA[<p>作者：人人网架构师 张洁 <a href="http://ugc.fm" onclick="pageTracker._trackPageview('/outgoing/ugc.fm?referer=');">人人网UGC团队博客</a>首发</p>
<p>MySQL<br />
关系型数据库存储系统，我们的DBA团队很强大，每人管理上百台MySQL服务器，其他就不多说了，网上资料太多了</p>
<p>Tokyo Cabinet<br />
一个key-value的存储引擎，日本人开发，国内很多公司也开始使用，我们内部很多地方也用它来代替MySQL来做存储，比如我们的搜索结果页的用户资料，就是用它来做一层MySQL外的冗余存储，目的是加快搜索结果页的显示。在key-value并需要持久<span id="more-42"></span>存储的场景下，用它比MySQL更有效，Cabinet本身只是一个存储引擎，没有网络处理能力，你可以用它作为自己的某个系统的下层存储引擎，更好的是搭配Tokyo Tyrant使用。</p>
<p>Tokyo Tyrant<br />
一个支持Memcached传输协议的网络接口，由Tokyo Cabinet的作者开发，目的是为Tokyo Cabinet提供网络接入能力，即Tokyo Tyrant处理网络连接，协议解析，然后调用Tokyo Cabinet的API来完成持久化存储。</p>
<p>ICE<br />
一个跨语言的网络通讯框架，框架本身提供了强大的通讯能力，管理工具，负载均衡方案，其跨语言能力也是一个很大的亮点，基于这个框架之上，我们选用合适的语言来提供合适的服务，比如我们使用C++来开发Cache服务，使用Java来开发一些逻辑服务。框架本身可以很重，也可以很轻，具体要看你怎么用：）</p>
<p>Memcached<br />
一个纯内存的key-value的cache系统，高效、稳定，使用广泛，如果你连它都没听说过就太out啦，memcached本身不具备分布式能力，需要依靠Client来实现分布，这里强调一点的是，你应该选择一致性Hash来做key的分布。各种语言的client都有，我们使用spymemcached作为java的Client，spymemcached是一个异步的NIO的memcached client，对网络IO的处理非常的精巧，也更加高效，同时因为提供异步操作方式，可以让你对Memcached的操作有更好的控制能力，Memcached到1.4.0版本之后，开始支持binary protocol，spymemcached对其也支持的比较好，使用binary protocol可以提高对协议的解析效率和网络IO的读写效率。<br />
上面说到我们使用ICE自己开发了Cache服务，为什么我们还要用Memcached呢？主要在对Cache的操作粒度不一样，Memcached对Cache对象以binary byte作为一个整体来操作，需要频繁的序列化和反序列化，我们使用ICE提供的Cache服务，可以以Cache对象的一个或者多个字段来操作，比如一个用户对象，我们可以只更新它的姓名，而Memcached</p>
<p>Nginx<br />
高效、稳定的Web Server，我们利用其代理能力，做跨IDC的请求代理，同时也将其和我们的Resin(Java Web 容器)搭配，放在Resin的前面来解决Resin的对网络连接处理能力弱的问题，在一些小地方也用它来做7层的负载均衡</p>
<p>Resin<br />
一个Java Web Server，比Tomcat更高效，是我们主要的Java Web容器</p>
<p>Squid<br />
代理服务器，我们用他来做图片文件的反向代理缓存</p>
<p>LVS<br />
能提供4层的负载均衡，高效、高可用，高并发。我们用他替代了很多硬件的负载均衡设备</p>
<p>Struts<br />
Java web框架，不过这个已经是历史了，我们开发了一套自己的Web框架替代了它，未来我们也会把我们的内部的这套Web框架开源出来</p>
<p>Lucence<br />
基于Java的搜索引擎框架，用它我们构建了一个搜索集群来提供搜人的服务</p>
<p>Netty<br />
一个Java的网络框架，和apache的mina类似，但比mina更高效，我们用来做一些小的服务</p>
<p>Ganglia<br />
一个监控系统，帮组我们了解我们每台Server的资源利用情况</p>
<p>还有些小东西就不列出来了，最后要说的一点就是，对这些开源软件或者系统，我们都非常的了解，或者说知根知底，从API到内部实现原理，甚至到一些源码的细节。</p>
]]></content:encoded>
			<wfw:commentRss>http://ugc.renren.com/2009/12/13/a-list-of-open-source-software-in-renren/feed/</wfw:commentRss>
		<slash:comments>23</slash:comments>
		</item>
	</channel>
</rss>

<!-- Dynamic page generated in 0.720 seconds. -->
<!-- Cached page generated by WP-Super-Cache on 2012-05-17 08:02:06 -->

