﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-nod0620-随笔分类-工作</title><link>http://www.blogjava.net/nod0620/category/45830.html</link><description /><language>zh-cn</language><lastBuildDate>Wed, 31 Aug 2011 21:51:19 GMT</lastBuildDate><pubDate>Wed, 31 Aug 2011 21:51:19 GMT</pubDate><ttl>60</ttl><item><title>项目小结</title><link>http://www.blogjava.net/nod0620/archive/2011/08/31/357604.html</link><dc:creator>nod0620</dc:creator><author>nod0620</author><pubDate>Wed, 31 Aug 2011 07:50:00 GMT</pubDate><guid>http://www.blogjava.net/nod0620/archive/2011/08/31/357604.html</guid><wfw:comment>http://www.blogjava.net/nod0620/comments/357604.html</wfw:comment><comments>http://www.blogjava.net/nod0620/archive/2011/08/31/357604.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/nod0620/comments/commentRss/357604.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/nod0620/services/trackbacks/357604.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 去年年底和今年上半年，做了一个类似微博的sns的项目&#8212;求购项目，有求购消息，评论消息和好友关系，也和项目组的同学一起讨论了项目的设计，不敢说架构，因为好多底层的存储，分库分表的功能我厂的其它团队已经完成。<br />&nbsp;&nbsp;&nbsp; &nbsp; <br /><h3>表设计</h3>1.求购消息主要是图片和文字的说明，这个其实可以看成是个微博每个用户发表feed的表，但有些不同，这个下文再说，这里我们叫photo表，下面所说的图片就是求购消息。<br />考虑到求购消息比较多，所以需要进行分表，假设分8个表。<strong>由于业务的需求是：可以查看单张图片，可以看一个用户的图片列表，问题来了，我们按什么进行分表？</strong><br />看下表结构:<br /><img alt="" src="http://www.blogjava.net/images/blogjava_net/nod0620/photo.JPG" height="170" width="160" /><br /><br />id是图片的id，要查询单张图片的话，需要能快速的定位到哪一张表，而查询一个用户的图片列表的话，需要快速找到这个用户所有的图片，那么这个用户的图片应该是放在<br />一个表里面的，即通过user_id能路由到一张表，从而从这张表里面取得这个用户所有的图片。<strong>通过上面分析：如果选择user_id对表数量取模的值为选择存储的第几个表，<br />那么一个user_id所有的图片都在一张表里面了，这里对id就有要求，id对表数量取模的值要和user_id对表数量取模的值一致 。<br /></strong>这样做的结果是，id的值不是连续的，有些许的浪费，如果user_id分布不均的话，对于每个表的数据量也会分布不均<br /><br />2.评论表<br />对图片进行评论，对于单个图片来说有评论列表，对于单个用户来说，他能看到所有对他图片进行评论的评论列表，所以采用了两套表的方案，对于用photo_id分表的<br />的comment表，以及针对user_id分表的comment_u表<br /><img alt="" src="http://www.blogjava.net/images/blogjava_net/nod0620/comment.JPG" height="258" width="499" /><br /><br />3.好友关系表<br />这个类似于微薄里面的关注或者粉丝表,和评论表一样，这里需要两套表，一个是关注表，一个是粉丝表<br /><br /><br /><h3>Feed流</h3>当一个人关注另外一个人的时候，那么被关注的人发表的图片是能被另外一个人看到的，这和微博的feed流是一样的。<br />这里有两种方式实现，push模式(推模式)，pull模式(拉模式)。push模式：当一个用户发表图片的时候，检索这个用户的<br />粉丝表，为每个粉丝插入一条feed。pull模式：当一个用户发表图片的时候，只是存一份数据，当一个用户查看他的关注的用户的feed的时候，需要先检索关注表，然后检索每一个关注用户有没有新发的feed。<br /><br />push和pull模式各有利弊，当使用push模式的时候，如果一个用户(名人)的粉丝过多的话，那么每个粉丝插入一条feed对存储的压力就太大了(100000粉丝话，插入100000)，存储空间浪费也非常的严重。<br />pull模式的话，如果一个用户关注过多的时候，查询该用户的关注列表也是有很大的代价的<br /><br />项目用的是pull模式，注意到求购项目的特殊性，一般只是看最新的求购的消息，假设某个用户当前有1000条新feed，这个用户也不能完全的看完，所以认为只要取得最新的消息里面的若干条，其余的消息的话可以在历史feed列表里面看到或者下一次看到，这里就有个timeline的概念。当次取得最新消息后，需要把这个时间点保存，下次查询的时候，从这个时间点进行查询。<br /><br />项目具体的做法：<br />1.查询用户的关注列表<br />2.从cache中取出timeline<br />3.timeline为空的话，直接取出旧的feed 30条，更新timeline，其中最新的一条的创建时间为timeline<br />4.timeline不为空的话，取得timeline之后的feed，最大值为30条，查过30条，取得的是最旧的30条，更新timeline，其中最新的一条的创建时间为timeline。<br /><br /><br />第4步其实和微博的做法是不同的，假设有1000条feed，微博是一次性刷出来，而这个是一次刷出30条，这里有个博弈在里面：<br />一次刷新30条，刷新的次数多了，查询多了，但是一次1000条的单次查询压力大了，还有多少人看了30条之后继续刷新看的？ 所以我们采取降低单次刷新的代价，这样对服务器峰值的压力也就下来了<br /><br /><br /><h3>其它</h3>还有很多优化的点没有说出来，比如路由表取模的时候，是用位与操作的(18%16==18&amp;15)<br />还有各个能用到cache的地方尽量使用cache，对于读写的话，可以增加读写队列.<br />对于扩展，性能，后续考虑的：<br />当单个用户关注数超过一定数目，这个用户就需要特别的对待，比如用户关注单独的变成一张表，减少关注表的压力<br />对用户活跃度进行分析，活跃用户的feed使用pull和push模式相结合的模式<br />对于粉丝数很多的用户，可以单独成表，发的feed可以先push给一部分用户，让一部分用户先看到feed.<br /><br /><br /><br /><br /><br /><br /><img src ="http://www.blogjava.net/nod0620/aggbug/357604.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/nod0620/" target="_blank">nod0620</a> 2011-08-31 15:50 <a href="http://www.blogjava.net/nod0620/archive/2011/08/31/357604.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>