﻿<?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>C++博客-Sheppard Y-随笔分类-开源</title><link>http://www.cppblog.com/yangsf5/category/20606.html</link><description>keep thinking keep coding.</description><language>zh-cn</language><lastBuildDate>Tue, 12 Jul 2016 17:05:14 GMT</lastBuildDate><pubDate>Tue, 12 Jul 2016 17:05:14 GMT</pubDate><ttl>60</ttl><item><title>读《Mysql性能调优与架构设计》笔记</title><link>http://www.cppblog.com/yangsf5/archive/2014/05/04/206818.html</link><dc:creator>Sheppard Y</dc:creator><author>Sheppard Y</author><pubDate>Sun, 04 May 2014 10:38:00 GMT</pubDate><guid>http://www.cppblog.com/yangsf5/archive/2014/05/04/206818.html</guid><wfw:comment>http://www.cppblog.com/yangsf5/comments/206818.html</wfw:comment><comments>http://www.cppblog.com/yangsf5/archive/2014/05/04/206818.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/yangsf5/comments/commentRss/206818.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/yangsf5/services/trackbacks/206818.html</trackback:ping><description><![CDATA[<div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"></div><div><div style="orphans: 2; text-align: -webkit-auto; widows: 2;"><div></div><fieldset><legend><span style="color: #ff0000; line-height: normal;">2016-07-12 日更新&nbsp;</span></legend><div><span style="line-height:normal;color:red;">此篇博客已经迁移到新博客，并做行文检查和优化排版：<br /></span><div></div></div><a href="http://blog.clawz.me/2014/05/04/14-note-of-mysql-book/"><div><div><span style="color:red;">http://blog.clawz.me/2014/05/04/14-note-of-mysql-book/</span></div></div></a></fieldset><a href="http://blog.clawz.me/2014/05/04/14-note-of-mysql-book/"><div><div></div></div></a><br /><font face="微软雅黑" size="3"><span style="line-height: normal;">一、背景</span></font></div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;这几天在review公司项目mysql这块的架构，网上google出来的东西大多是皮毛（特别一些中文站点里的，英文的话阅读和消化都比较慢，除非不得已），有些还明显有些错误。</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;之前看《Http权威指南》的甜头还在（加上有些积累现在看技术书速度也快了），所以赶紧找些质量高的mysql方面的书看，找到一本阿里人写的《Mysql性能调优与架构设计》，Fenng也有做序推荐。&nbsp; &nbsp; &nbsp;</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;正文部分为阅读笔记。</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"></div><span style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">二、硬件关键指标</span><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;下边列出是常见性能指标，具体指标的取舍也要看具体应用场景。具体设计时再回头参考书里里讲的例子。<br /><div>1.IO性能高的部件主要由磁盘和内存，各种与IO相关的板卡相关。</div><div>&nbsp; &nbsp; &nbsp;IO性能分为和IOPS（每秒可提供的IO访问次数）和每秒的IO总流量（IO吞吐量）。</div><div>2.CPU（SQL parse和优化），并发高的时候CPU每秒需要处理的请求就高，相应CPU处理能力需要比较强劲。</div><div>3.网络设备</div></div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"></div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">二、性能优化</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">（一）商业需求合理化</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;书里例子：实时更新一个论坛帖子总量的统计。</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;select count(*)语句简单，但是Innodb引擎还是耗时间。而这个需求的强实时更新没多少用户真正关心这个。定时更新可提高很大的性能。</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;这条自己已经知道了。</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">（二）系统架构最优化</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">（1）有几类数据不适合存到数据库中：</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;1.二进制多媒体数据（图片、音频、视频等），这类数据对数据库空间资源耗费非常严重，且这些数据的数据存储很消耗数据库主机的CPU资源。</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;2.流水队列数据，支持事务的存储引擎为了事务安全性和可恢复性，需要记录所有变更的日志信息，而流水队列数据会不断的被INSERT\UPDATE\DELETE，导致日志量很大。使用成熟的第三方队列软件处理，性能将会成倍提升。</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;3.超大文本数据，从5.0.3开始，VARCHAR，实际数据小于255字节时，实际存储空间和实际数据长度一样，可一旦长度超过255字节之后，所占用存储空间是实际数据长度的两倍。不光性能低下，还是浪费空间。</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">（2）是否合理利用了应用层的cache。</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">（3）数据层的存取实现都是最精简的吗。在程序里不要过度依赖面向对象思想。</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">（4）过度依赖数据库SQL语句的功能造成数据库操作效率低下。</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;尽量减少与mysql的交互次数和SQL复杂度。不要对可扩展性过度追求，导致系统设计时开分太李三，导致需要大量Join语句。</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">（5）重复执行相同的SQL造成资源浪费。</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">（三）逻辑实现精简化</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">（四）硬件设施理性化</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"></div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">三、合理利用锁机制来优化mysql</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"></div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">四、Query优化</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;主要优化思路和原则：</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">（1）优化更需要优化的Query。</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">（2）定位优化对象的性能瓶颈。</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">（3）明确的优化目标。</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">（4）从explain入手。</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">（5）多使用profile。</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">（6）永远用小结果集驱动大的结果集。</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">（7）尽可能在索引中完成排序。</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">（8）只取出自己需要的columns。</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">（9）仅仅使用最有效的过滤条件。</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">（10）尽可能避免复杂的join和子查询。</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"></div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">五、Schema设计的性能优化</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">（一）高校的模型设计</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">（1）不一定要追求范式</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">（2）适度冗余&#8212;&#8212;让query尽量减少join。</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">（3）大字段垂直分拆</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;字段特别大，访问频率又很低的字段拆出去。因为记录存储是一条一条的存放，查询某些数据时，也会读取到这个访问不高的大字段，比较浪费IO资源。</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">（4）大表水平分拆&#8212;&#8212;基于类型的分拆优化</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;把少量访问频率极高的记录水平拆分出去。例如论坛里的置顶帖子从普通讨论贴里分拆出去为单独的表。</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">（5）统计表&#8212;&#8212;准实时优化</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">（二）合适的数据类型</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;选择更小的数据类型，可以降低IO消耗。另外不同数据类型的CPU处理方式也不一样。例如通过整数类型代替浮点数或者字符类型。</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">（三）规范的对象命名</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;这条对性能没啥影响，但是对数据库的维护影响非常大。库的字段越来越多&#8230;&#8230;</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"></div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">六、mysql server性能优化</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"></div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">七、存储引擎优化</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"></div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">八、架构设计</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">（一）可扩展设计的基本原则</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">（二）mysql replication</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">（三）数据切分</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;水平切分和垂直切分，之前项目里做架构时已基本了解。</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">（四）cache和search的利用</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;cache就是memcache之类的。search主要用来做全文检索。</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">（五）mysql cluster</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">（六）高可用设计之思路及方案</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">（七）高可用设计之mysql监控</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"></div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"></div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"><hr /> &nbsp; &nbsp; &nbsp;看完上边后又在看《高性能mysql》第三版2013年初版的，美国人写的，这本是mysql的经典之作，比上边那本更好吧。就是内容详细，啥都有。详细的基准测试方法、特性细节（原理）、架构考虑，这几年mysql升级的特性（如分区等），讲述的mysql版本已经新到5.5~稍许5.6前瞻。还有作者都是相关经验很多年的大拿。内容写的也不枯燥，很向那些编程方面的经典书的书写风格。</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;时间宝贵，推荐看《高性能mysql》这本就行了。</div></div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"></div></div><img src ="http://www.cppblog.com/yangsf5/aggbug/206818.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/yangsf5/" target="_blank">Sheppard Y</a> 2014-05-04 18:38 <a href="http://www.cppblog.com/yangsf5/archive/2014/05/04/206818.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Docker应用调研</title><link>http://www.cppblog.com/yangsf5/archive/2014/04/26/206724.html</link><dc:creator>Sheppard Y</dc:creator><author>Sheppard Y</author><pubDate>Sat, 26 Apr 2014 08:05:00 GMT</pubDate><guid>http://www.cppblog.com/yangsf5/archive/2014/04/26/206724.html</guid><wfw:comment>http://www.cppblog.com/yangsf5/comments/206724.html</wfw:comment><comments>http://www.cppblog.com/yangsf5/archive/2014/04/26/206724.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/yangsf5/comments/commentRss/206724.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/yangsf5/services/trackbacks/206724.html</trackback:ping><description><![CDATA[<div><div></div><fieldset><legend><span style="color: #ff0000;">2016-07-12 日更新&nbsp;</span></legend><div><span style="color:red;">此篇博客已经迁移到新博客，并做行文检查和优化排版：</span></div><div></div><a href="http://blog.clawz.me/2014/04/26/14-docker-usage-research/"><div><span style="color:red;">http://blog.clawz.me/2014/04/26/14-docker-usage-research/</span></div></a></fieldset><a href="http://blog.clawz.me/2014/04/26/14-docker-usage-research/"><div></div></a><br />&nbsp;一、背景 <div>&nbsp; &nbsp; &nbsp;项目里编译打包客户端程序时经常出现问题，有环境不一致问题或者代码冲突问题。</div><div>&nbsp; &nbsp; &nbsp;之前了解过<a href="https://www.docker.io/">docker</a>可以应用环境作为一个一体化的服务来使用，所以想看看docker是否能给我们客户端同学提供些方便。</div><div></div><div>二、主要关注点</div><div>（一）docker能运行在哪些操作系统，mac、linux、windows？</div><div>&nbsp; &nbsp; &nbsp;都可以，docker现在release到0.10.0版了，还没到1.0的正式版。官方不推荐将当前的docker运用在生产环境中。</div><div>&nbsp; &nbsp; &nbsp;docker内部开发是在ubuntu上进行了，所以ubuntu上支持最好。mac和windows这些的docker运行方式，现在是在操作系统上装虚拟机（如VirtualBox），再在虚拟机里运行使用docker。</div><div></div><div>（二）docker容器里能运行什么环境，mac、linux、windows？</div><div>&nbsp; &nbsp; &nbsp;docker里能运行的系统称为image，目前image大多是linux。这也挺正常的，mac os x和windows都是商业收费的，怎么可能随便让搭建image。</div><div>&nbsp; &nbsp; &nbsp;所以我想用docker来服务我们客户端环境搭建的话，image的事情还得自己搞下。</div><div></div></div><img src ="http://www.cppblog.com/yangsf5/aggbug/206724.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/yangsf5/" target="_blank">Sheppard Y</a> 2014-04-26 16:05 <a href="http://www.cppblog.com/yangsf5/archive/2014/04/26/206724.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>claw设计草稿</title><link>http://www.cppblog.com/yangsf5/archive/2014/03/31/206404.html</link><dc:creator>Sheppard Y</dc:creator><author>Sheppard Y</author><pubDate>Mon, 31 Mar 2014 03:09:00 GMT</pubDate><guid>http://www.cppblog.com/yangsf5/archive/2014/03/31/206404.html</guid><wfw:comment>http://www.cppblog.com/yangsf5/comments/206404.html</wfw:comment><comments>http://www.cppblog.com/yangsf5/archive/2014/03/31/206404.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/yangsf5/comments/commentRss/206404.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/yangsf5/services/trackbacks/206404.html</trackback:ping><description><![CDATA[<div><div><div><div></div><fieldset><legend><span style="color: #ff0000; line-height: normal;">2016-07-12 日更新&nbsp;</span></legend><div><span style="line-height:normal;color:red;">此篇博客已经迁移到新博客，并做行文检查和优化排版：<br /></span><div></div></div><a href="http://blog.clawz.me/2014/03/31/14-claw-design/"><div><div><span style="color:red;">http://blog.clawz.me/2014/03/31/14-claw-design/</span></div></div></a></fieldset><a href="http://blog.clawz.me/2014/03/31/14-claw-design/"><div><div></div></div><span style="orphans: 2; text-align: -webkit-auto; widows: 2;"></span></a><span style="orphans: 2; text-align: -webkit-auto; widows: 2;"><br /><font face="微软雅黑" size="3"><span style="line-height: normal;">一、目标</span></font></span><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;参考云风skynet，实现go版本的开源服务器引擎。</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"></div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">二、细节</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">（一）服务</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;按服务来拆模块的好处不说了。只说go来的实现方式。go里有channel和goroutine。消息队列和轻量级线程都天然解决了。</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"></div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">（二）服务间的通信</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;同进程内的服务之间通信，直接往对方channel发消息即可。不同进程里靠各进程自己的harbor服务来转发。harbor服务来负责集群间的通信。</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;集群里设置一个master服务来做全局的名字服务，主要用于登记和同步集群里各个进程开启的各个服务。所有harbor启动后向master注册自己，master向所有harbor广播同步新加入的这个机器。</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"></div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">（三）组播</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;经常需要向某几个服务广播一个消息，组播问题。multicast服务来管理组播。</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"></div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">（四）日志</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;使用glog。</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"></div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">三、已实现的服务</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">（一）master和harbor</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;暂时master做为harbor的中心控制器的。后续会改进，做成harbor之间两两通信，减少对master的单点依赖。</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"></div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">（二）gate</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;gate用来做通常的网络监听用。目前的很简单，用户需要向这个服务器注册自己的包解析和处理器。</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"></div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">（三）web</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;web负责http的监听，template的加载cache，几个通用函数的提取。</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"></div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">四、ps</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;项目地址：<a href="https://github.com/yangsf5/claw">https://github.com/yangsf5/claw</a></div></div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"><a href="https://github.com/yangsf5/claw"></a></div></div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"></div></div><img src ="http://www.cppblog.com/yangsf5/aggbug/206404.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/yangsf5/" target="_blank">Sheppard Y</a> 2014-03-31 11:09 <a href="http://www.cppblog.com/yangsf5/archive/2014/03/31/206404.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>express的session中间件sessionID问题</title><link>http://www.cppblog.com/yangsf5/archive/2014/02/28/205993.html</link><dc:creator>Sheppard Y</dc:creator><author>Sheppard Y</author><pubDate>Fri, 28 Feb 2014 07:35:00 GMT</pubDate><guid>http://www.cppblog.com/yangsf5/archive/2014/02/28/205993.html</guid><wfw:comment>http://www.cppblog.com/yangsf5/comments/205993.html</wfw:comment><comments>http://www.cppblog.com/yangsf5/archive/2014/02/28/205993.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/yangsf5/comments/commentRss/205993.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/yangsf5/services/trackbacks/205993.html</trackback:ping><description><![CDATA[<div><div><div></div></div><fieldset><legend><span style="color: #ff0000;">2016-07-12 日更新&nbsp;</span></legend><div><div><span style="color:red;">此篇博客已经迁移到新博客，并做行文检查和优化排版：</span></div></div><a href="http://blog.clawz.me/2014/02/28/14-express-session-id-problem/"><div><span style="color:red;">http://blog.clawz.me/2014/02/28/14-express-session-id-problem/</span></div></a></fieldset><a href="http://blog.clawz.me/2014/02/28/14-express-session-id-problem/"><div></div><span style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"></span></a><span style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"><br />&nbsp; &nbsp; &nbsp;session中间件里的sessionID（以下简称sid）的算法为24byte的全随机。sid重复的可能性比较小，但理论上还是有重复的可能。</span><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;session中间件的session维护流程为：</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">（一）新session的创建</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">（1）将option里配的sessionStore挂到req上；</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">（2）修改res.end函数，在原函数基础上加入req.session.save操作（就是往sessionStore里存session）；</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">（3）新session的接入，因为是新session，所以cookie里没有sid信息。随机一个sid，以此sid来创建session，然后将session绑到req上；然后将req和res交给下个中间件或流程处理。</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">（二）旧session接入</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">（1）同上边的第（1）步；</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">（2）同上边的第（2）步；</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">（3）cookie里有sid，根据这个sid去sessionStore里取回session信息；如果session过期就取不到session了，就像上边的（3）里那样重新创建一个session。</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"></div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;为了完全消除sid的重复性带来的影响，就要检查新创建的sid是否已经存在与sessionStore里了。</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;session中间件的结构在express的以后版本中还会修改，所以我不想动session中间件的源码。于是只能在新session创建后的我自己的逻辑流程中来处理。逻辑流程中，当http包为登陆验证包时，将session中间件给创建的session的sid拿到sessionStore里去查下是否已被使用，如果使用就干掉当前session，并通知当前客户端重试。</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;干掉当前session有个技巧，就是直接（req.session=null;）这样即可，因为修改后的res.end里，判断如果req.session未定义，就不会再去调用req.session.save了。当前session是一定不能让他save的，否则就拿当前用户的信息覆盖了之前用此sid的用户，造成那个用户后续逻辑混乱。</div></div><img src ="http://www.cppblog.com/yangsf5/aggbug/205993.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/yangsf5/" target="_blank">Sheppard Y</a> 2014-02-28 15:35 <a href="http://www.cppblog.com/yangsf5/archive/2014/02/28/205993.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>了解云风的skynet</title><link>http://www.cppblog.com/yangsf5/archive/2014/01/16/205413.html</link><dc:creator>Sheppard Y</dc:creator><author>Sheppard Y</author><pubDate>Thu, 16 Jan 2014 03:25:00 GMT</pubDate><guid>http://www.cppblog.com/yangsf5/archive/2014/01/16/205413.html</guid><wfw:comment>http://www.cppblog.com/yangsf5/comments/205413.html</wfw:comment><comments>http://www.cppblog.com/yangsf5/archive/2014/01/16/205413.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/yangsf5/comments/commentRss/205413.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/yangsf5/services/trackbacks/205413.html</trackback:ping><description><![CDATA[<div></div><fieldset><legend><span style="color: #ff0000;">2016-07-11 日更新&nbsp;</span></legend><div style="display:inline-block;"><span style="color:red;">此篇博客已经迁移到新博客，并做行文检查和优化排版：</span></div><div></div><a href="http://blog.clawz.me/2014/01/16/14-cloudwu-skynet-research/"><div><span style="color:red;">http://blog.clawz.me/2014/01/16/14-cloudwu-skynet-research/</span></div></a></fieldset><a href="http://blog.clawz.me/2014/01/16/14-cloudwu-skynet-research/"><div></div><p style="margin-right: 0px; margin-left: 0px; font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2;"></p></a><p style="margin-right: 0px; margin-left: 0px; font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2;"><br /><br />（PS开始应用《暗时间》里提到的理论，将skynet用自己的话来总结并写下来，这样能充分思考并转述为自己的记忆线索）</p><p style="margin-right: 0px; margin-left: 0px; font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2;"><br /></p><p style="margin-right: 0px; margin-left: 0px; font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2;">一、skynet设计的理解</p><p style="margin-right: 0px; margin-left: 0px; font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2;">（一）单个skynet节点</p><p style="margin-right: 0px; margin-left: 0px; font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2;">（1）愿景</p><p style="margin-right: 0px; margin-left: 0px; font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2;">&nbsp;&nbsp;&nbsp;&nbsp;充分利用多核。最初想法是多进程。像咱们nodejs里多核就只能是多进程了，因为每个nodejs进程是单线程的。<br /></p><p style="margin-right: 0px; margin-left: 0px; font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2;">&nbsp;&nbsp;&nbsp;&nbsp;多进程是遵循unix设计哲学，工具链形式，分拆进程的形式来分拆模块，减少复杂度和耦合性，方便编程及维护。<br /></p><p style="margin-right: 0px; margin-left: 0px; font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2;">&nbsp;&nbsp;&nbsp;&nbsp;后来云风他们发现lua做为嵌入式脚本，写逻辑时很好用的，反正如何都要用lua，而且lua提供了沙盒，这样多进程可以变为单进程多个沙盒，这样综合了多进程和单进程多线程的优势。多线程里共享资源，在同一进程地址空间，访问更高效。<br /></p><p style="margin-right: 0px; margin-left: 0px; font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2;"><br /></p><p style="margin-right: 0px; margin-left: 0px; font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2;">（2）核心功能（门房？）</p><p style="margin-right: 0px; margin-left: 0px; font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2;">&nbsp;&nbsp;&nbsp;&nbsp;很精简，仅解决一个问题。</p><p style="margin-right: 0px; margin-left: 0px; font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2;">&nbsp;&nbsp;&nbsp;&nbsp;skynet里不实现具体游戏逻辑，后者些放到一个一个动态库里（so文件）。skynet将这些so注册到自己里边，每个so一个永不重复的id，类似于数据库的autoincreament。看描述这个id是skynet自己运行时当次维护的，而不是模块配置好终身的id。模块的永久有效唯一标示为名字，skynet提供了名字服务，可以给每个模块取一个易读的名字。<br /></p><p style="margin-right: 0px; margin-left: 0px; font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2;"><br /></p><p style="margin-right: 0px; margin-left: 0px; font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2;">（3）核心不解决什么问题</p><p style="margin-right: 0px; margin-left: 0px; font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2;">&nbsp;&nbsp;&nbsp;&nbsp;skynet主张所有服务在同一OS进程协作完成。核心里就没管跨机通讯，单个服务的崩溃和重启也没管，云风表示这些应该由上层处理，他有责任暴露错误，而不是隐藏。<br /></p><p style="margin-right: 0px; margin-left: 0px; font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2;">&nbsp;&nbsp;&nbsp;&nbsp;这个设计的原因，游戏和操作系统不一样，操作系统默认不信任任何进程，各进程崩溃什么的不应影响其他进程，所以某个进程挂了，他就安葬它，而其他进程美好的生活。单游戏是为玩家服务的，某个环节出错都有可能造成玩家利益混乱，所以那里错了就整个流程（服务器）挂掉吧。没有必要让出错模块被隔离开，而其他模块却继续提供服务导出未预知行为。<br /></p><p style="margin-right: 0px; margin-left: 0px; font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2;">&nbsp;&nbsp;&nbsp;&nbsp;上边说的东西应该上层考虑，使用lua的沙盒就能做策略隔离。<br /></p><p style="margin-right: 0px; margin-left: 0px; font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2;"><br /></p><p style="margin-right: 0px; margin-left: 0px; font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2;">（4）skynet运行时逻辑流</p><p style="margin-right: 0px; margin-left: 0px; font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2;">&nbsp;&nbsp;&nbsp;&nbsp;skynet负责且只负责将一个数据包从一个服务发送到同一进程的另一个服务里。发送服务直接调发送API，skynet收到数据包后，调用接受者服务的注册的callback，即发给了接受者服务。<br /></p><p style="margin-right: 0px; margin-left: 0px; font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2;">&nbsp;&nbsp;&nbsp;&nbsp;skynet保证在各模块初始化时、每个独立的callback调用时，都是相互线程安全的。这样编写服务的人就不需要考虑多线程的任何问题了，只需专心处理给他的一个个数据包。</p><p style="margin-right: 0px; margin-left: 0px; font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2;">&nbsp;&nbsp;&nbsp;&nbsp;PS：天龙的场景lua有点像这里的单个服务。不知天龙的跨线程切场景情况在这里也可以给简化为单线程？（回头看源码再研究这个问题）<br /></p><p style="margin-right: 0px; margin-left: 0px; font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2;"><br /></p><p style="margin-right: 0px; margin-left: 0px; font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2;">（5）消息调度</p><p style="margin-right: 0px; margin-left: 0px; font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2;">TODO</p><p style="margin-right: 0px; margin-left: 0px; font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2;"><br /></p><p style="margin-right: 0px; margin-left: 0px; font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2;">（6）gate和connection</p><p style="margin-right: 0px; margin-left: 0px; font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2;">TODO</p><p style="margin-right: 0px; margin-left: 0px; font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2;">&#8203;<br /></p><p style="margin-right: 0px; margin-left: 0px; font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2;">（二）skynet集群</p><p style="margin-right: 0px; margin-left: 0px; font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2;">&nbsp;&nbsp;&nbsp;&nbsp;集群里最多支持255个skynet节点，每个skynet节点有一个id，成为harbor id。这个id是集群层面指定，可以人为分配，也可以由一个中央服务器协调分配。</p><p style="margin-right: 0px; margin-left: 0px; font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2;">（1）集群间通信</p><p style="margin-right: 0px; margin-left: 0px; font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2;">&nbsp;&nbsp;&nbsp;&nbsp;skynet核心层纸负责在往外发消息时在source字段上加上自己的harbor id。而集群间的通信，是由单独的harbor服务来做的。skynet将是往集群其他节点发的消息，就转发到harbor内。harbor会跟集群内跟自己结识的skynet的harbor简历tcp链接。harbor把消息发给目标harbor。<br /></p><p style="margin-right: 0px; margin-left: 0px; font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2;">&nbsp;&nbsp;&nbsp;&nbsp;harbor间的通信为单向的tcp管道。<br /></p><p style="margin-right: 0px; margin-left: 0px; font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2;">&nbsp;&nbsp;&nbsp;&nbsp;master服务来同步全局的名字服务。每个skynet都会知道其他节点上装配了哪些服务，好路由过去。<br /></p><p style="margin-right: 0px; margin-left: 0px; font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2;"><br /></p><p style="margin-right: 0px; margin-left: 0px; font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2;">（2）组播</p><p style="margin-right: 0px; margin-left: 0px; font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2;">&nbsp;&nbsp;&nbsp;&nbsp;TODO</p><img src ="http://www.cppblog.com/yangsf5/aggbug/205413.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/yangsf5/" target="_blank">Sheppard Y</a> 2014-01-16 11:25 <a href="http://www.cppblog.com/yangsf5/archive/2014/01/16/205413.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>了解MongoDB</title><link>http://www.cppblog.com/yangsf5/archive/2013/12/05/204608.html</link><dc:creator>Sheppard Y</dc:creator><author>Sheppard Y</author><pubDate>Thu, 05 Dec 2013 11:07:00 GMT</pubDate><guid>http://www.cppblog.com/yangsf5/archive/2013/12/05/204608.html</guid><wfw:comment>http://www.cppblog.com/yangsf5/comments/204608.html</wfw:comment><comments>http://www.cppblog.com/yangsf5/archive/2013/12/05/204608.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/yangsf5/comments/commentRss/204608.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/yangsf5/services/trackbacks/204608.html</trackback:ping><description><![CDATA[<div></div><fieldset><legend><span style="color: #ff0000;">2016-07-11 日更新&nbsp;</span></legend><div><span style="color:red;">此篇博客已经迁移到新博客，并做行文检查和优化排版：</span></div><div></div><a href="http://blog.clawz.me/2013/12/05/13-mongodb-research/"><div><span style="color:red;">http://blog.clawz.me/2013/12/05/13-mongodb-research/</span></div></a></fieldset><a href="http://blog.clawz.me/2013/12/05/13-mongodb-research/"><div></div><p>&nbsp;</p></a><p><br />&nbsp; &nbsp; &#8203;MongoDB为k-v数据库，他们存储方式为BSON，操作接口基本都是JSON，查询，搜索都很方便。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&#8203;例如mysql里一个表，id和data，data为这条记录的数据，数据为了扩展，例如不同的记录的data可能包含很多字段，且字段不一定相同，以后也会有不少类型的字段。这时我把这些不确定的字段encode成一个xml或者json或者protobuf之类的数据流存到data里。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&#8203;这么做记录的具体数据关联的详细数据扩展很灵活了。但是想搜索data里的各字段时，在mysql数据库里就不那么方便了，基本要遍历。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&#8203;这个时候将这个data备份一份到MongoDB里，就很方便了。MongoDB里的每条记录为一个key-value，value即存储我们上边的data。这时我们取data里的字段做条件查询是MongoDB直接支持的。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&#8203;另外MongoDB支持自动切热备，自动分片等高级功能&#8230;&#8230;</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&#8203;但是另一方面，这个东西出来的不久，现在还不敢将他作为持久化的DB。上边的例子是mysql里有份数据为生产环境的依赖数据，备份到MongoDB的数据只是为了查询。MongoDB里数据出问题是没关系的。</p><img src ="http://www.cppblog.com/yangsf5/aggbug/204608.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/yangsf5/" target="_blank">Sheppard Y</a> 2013-12-05 19:07 <a href="http://www.cppblog.com/yangsf5/archive/2013/12/05/204608.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>pomelo源码分析（3）-pomelo-sync</title><link>http://www.cppblog.com/yangsf5/archive/2013/12/04/204582.html</link><dc:creator>Sheppard Y</dc:creator><author>Sheppard Y</author><pubDate>Wed, 04 Dec 2013 06:28:00 GMT</pubDate><guid>http://www.cppblog.com/yangsf5/archive/2013/12/04/204582.html</guid><wfw:comment>http://www.cppblog.com/yangsf5/comments/204582.html</wfw:comment><comments>http://www.cppblog.com/yangsf5/archive/2013/12/04/204582.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/yangsf5/comments/commentRss/204582.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/yangsf5/services/trackbacks/204582.html</trackback:ping><description><![CDATA[<div></div><fieldset><legend><span style="color: #ff0000;">2016-07-11 日更新&nbsp;</span></legend><div><span style="color:red;">此篇博客已经迁移到新博客，并做行文检查和优化排版：</span></div><div></div><a href="http://blog.clawz.me/2013/12/04/13-pomelo-read-source-3/"><div><span style="color:red;">http://blog.clawz.me/2013/12/04/13-pomelo-read-source-3/</span></div></a></fieldset><a href="http://blog.clawz.me/2013/12/04/13-pomelo-read-source-3/"><div></div><p>&nbsp;</p></a><p><br />&nbsp; &nbsp; 现在分析的版本为0.7版。pomelo-sync，pomelo里用于解决游戏进程中需要持久化的数据在内存与存储系统之间的同步问题。</p> <p>&nbsp;</p> <p>一、pomelo程序如何使用pomelo-sync</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;新版本的pomelo里增强了支持用户自行扩展的能力。用户只用在app.use(plugin,  opts)就可以了，具体请看pomelo的application.js里的use函数。需要这个plugin里有components成员。use函数里，pomelo将plugin的componets所指的组件load起来，并将opts传给这个plugin的components。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;pomelo-sync自身只负责实现db数据与内存数据间的定时同步，所以另一个项目pomelo-sync-plugin就将pomelo-sync封装成了一个componet。app.use(require('pomelo-sync-plugin',  opts)就完成了数据同步插件的装载。</p> <p>&nbsp;</p> <p>二、pomelo-sync</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;pomelo-sync在构造的时候，将参数里的client（与持久化层的链接）、mapping（如各种操作的sql语句的映射表）等赋值给自己的相应成员。最后开启定时刷内存数据到持久化层的计时器SyncTimer。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;对外接口不只在dbsync.js里，还分布在lib/commands下的几个文件里。其中exec/flush/sync等在commands/server.js里。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;</p> <p>（一）pomelo-sync.exec</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;pomelo-sync.exec函数，被用户程序调用。将用户的数据放入pomelo-sync.flushQueue或者pomelo-sync.mergerMap。</p> <p>&nbsp;</p> <p>（二）pomelo-sync.flush</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;pomelo-sync.flush函数，将单挑数据立即持久化。</p> <p>&nbsp;</p> <p>（二）pomelo-sync.sync</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;pomelo-sync.sync函数，被SyncTimer调用，也可以被用户程序调用，立即将全部内存数据持久化。sync函数里调用的是rewriter.js里的sync。rewriter.sync里将pomelo-sync.flushQueue和pomelo-sync.mergerMap里的数据通过rewrite.tick刷进持久层。rewriter.tick里是通过pomelo-sync.mapping里的映射调对应的sql语句来实现的。</p><img src ="http://www.cppblog.com/yangsf5/aggbug/204582.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/yangsf5/" target="_blank">Sheppard Y</a> 2013-12-04 14:28 <a href="http://www.cppblog.com/yangsf5/archive/2013/12/04/204582.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>top里显示的cpu百分比计算方式</title><link>http://www.cppblog.com/yangsf5/archive/2013/11/07/204148.html</link><dc:creator>Sheppard Y</dc:creator><author>Sheppard Y</author><pubDate>Thu, 07 Nov 2013 11:20:00 GMT</pubDate><guid>http://www.cppblog.com/yangsf5/archive/2013/11/07/204148.html</guid><wfw:comment>http://www.cppblog.com/yangsf5/comments/204148.html</wfw:comment><comments>http://www.cppblog.com/yangsf5/archive/2013/11/07/204148.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/yangsf5/comments/commentRss/204148.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/yangsf5/services/trackbacks/204148.html</trackback:ping><description><![CDATA[<pre style="font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; margin-top: 0px; margin-bottom: 0px; color: #333333; line-height: 17.99715805053711px;"><div id="LC1" style="padding-left: 10px;"><div></div><fieldset><legend><span style="color: #ff0000; line-height: 17.9972px;">2016-07-11 日更新</span></legend><div><span style="color:red;">此篇博客已经迁移到新博客，并做行文检查和优化排版：</span><br /><div></div></div><a href="http://blog.clawz.me/2013/11/07/13-top-source/"><div><div><span style="color:red;">http://blog.clawz.me/2013/11/07/13-top-source/</span></div></div></a></fieldset><a href="http://blog.clawz.me/2013/11/07/13-top-source/"><div><div></div></div></a><br /><br />&nbsp;top看到的cpu信息解释的不是很清晰，就看下源码怎么写的吧。</div><div id="LC2" style="padding-left: 10px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;程序很简单，基本都在top.c里。</div><div id="LC3" style="padding-left: 10px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;load里的cpu详细信息代码如下：</div><div id="LC4" style="padding-left: 10px;"></div><div id="LC5" style="padding-left: 10px;"><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #008080; ">&nbsp;1</span>&nbsp;<span style="color: #000000; ">smpcpu&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;cpus_refresh(smpcpu);<br /></span><span style="color: #008080; ">&nbsp;2</span>&nbsp;<span style="color: #000000; "><br /></span><span style="color: #008080; ">&nbsp;3</span>&nbsp;<span style="color: #000000; "></span><span style="color: #0000FF; ">if</span><span style="color: #000000; ">&nbsp;(CHKw(Curwin,&nbsp;View_CPUSUM))&nbsp;{<br /></span><span style="color: #008080; ">&nbsp;4</span>&nbsp;<span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;display&nbsp;just&nbsp;the&nbsp;1st&nbsp;/proc/stat&nbsp;line</span><span style="color: #008000; "><br /></span><span style="color: #008080; ">&nbsp;5</span>&nbsp;<span style="color: #008000; "></span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;summaryhlp(</span><span style="color: #000000; ">&amp;</span><span style="color: #000000; ">smpcpu[Cpu_tot],&nbsp;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">Cpu(s):</span><span style="color: #000000; ">"</span><span style="color: #000000; ">);<br /></span><span style="color: #008080; ">&nbsp;6</span>&nbsp;<span style="color: #000000; ">}&nbsp;</span><span style="color: #0000FF; ">else</span><span style="color: #000000; ">&nbsp;{<br /></span><span style="color: #008080; ">&nbsp;7</span>&nbsp;<span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">int</span><span style="color: #000000; ">&nbsp;i;<br /></span><span style="color: #008080; ">&nbsp;8</span>&nbsp;<span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">char</span><span style="color: #000000; ">&nbsp;tmp[SMLBUFSIZ];<br /></span><span style="color: #008080; ">&nbsp;9</span>&nbsp;<span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;display&nbsp;each&nbsp;cpu's&nbsp;states&nbsp;separately</span><span style="color: #008000; "><br /></span><span style="color: #008080; ">10</span>&nbsp;<span style="color: #008000; "></span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">for</span><span style="color: #000000; ">&nbsp;(i&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">0</span><span style="color: #000000; ">;&nbsp;i&nbsp;</span><span style="color: #000000; ">&lt;</span><span style="color: #000000; ">&nbsp;Cpu_tot;&nbsp;i</span><span style="color: #000000; ">++</span><span style="color: #000000; ">)&nbsp;{<br /></span><span style="color: #008080; ">11</span>&nbsp;<span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;snprintf(tmp,&nbsp;</span><span style="color: #0000FF; ">sizeof</span><span style="color: #000000; ">(tmp),&nbsp;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">Cpu%-3d:</span><span style="color: #000000; ">"</span><span style="color: #000000; ">,&nbsp;smpcpu[i].id);<br /></span><span style="color: #008080; ">12</span>&nbsp;<span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;summaryhlp(</span><span style="color: #000000; ">&amp;</span><span style="color: #000000; ">smpcpu[i],&nbsp;tmp);<br /></span><span style="color: #008080; ">13</span>&nbsp;<span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br /></span><span style="color: #008080; ">14</span>&nbsp;<span style="color: #000000; ">}</span></div></div><div id="LC21" style="padding-left: 10px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</div><div id="LC22" style="padding-left: 10px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Cpu_tot为cpu数量。</div><div id="LC23" style="padding-left: 10px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cpus_refresh函数里从/proc/stat文件里读入cpu信息，然后装入smpcpu里。smpcpu为大小为Cpu_tot+1个CPU_t成员的数组。</div><div id="LC24" style="padding-left: 10px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/proc/stat文件的头几行为：</div><div id="LC25" style="padding-left: 10px;"><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #000000; ">cpu&nbsp;</span><span style="color: #000000; ">%</span><span style="color: #000000; ">d&nbsp;</span><span style="color: #000000; ">%</span><span style="color: #000000; ">d&nbsp;<img src="http://www.cppblog.com/Images/dot.gif" alt="" /><br />cpu0&nbsp;</span><span style="color: #000000; ">%</span><span style="color: #000000; ">d&nbsp;</span><span style="color: #000000; ">%</span><span style="color: #000000; ">d&nbsp;<img src="http://www.cppblog.com/Images/dot.gif" alt="" /><br />cpu1&nbsp;</span><span style="color: #000000; ">%</span><span style="color: #000000; ">d&nbsp;</span><span style="color: #000000; ">%</span><span style="color: #000000; ">d&nbsp;<img src="http://www.cppblog.com/Images/dot.gif" alt="" /><br /><img src="http://www.cppblog.com/Images/dot.gif" alt="" /></span></div></div><div id="LC29" style="padding-left: 10px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;第一行的cpu信息装入smpcpu[Cpu_tot]，之后的cpu0\cpu1\...装入smpcpu[0]\smpcpu[1\...。</div><div id="LC30" style="padding-left: 10px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;View_CPUSUM这个由1键来控制的那个开关，开关关闭时只显示smpcpu的Cpu_tot，开关开启时显示的是smpcpu的下标0~Cpu_tot-1的成员。即，top的默认在开头显示的cpu详细信息显示的是/proc/stat的第一行处理后，按下1键，显示的时/proc/stat后续各cpu数据。</div><div id="LC31" style="padding-left: 10px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/proc/stat里都是数字，下边看看top里显示的百分比怎么算的。</div><div id="LC32" style="padding-left: 10px;"></div><div id="LC33" style="padding-left: 10px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CPU_t的定义：</div><div id="LC34" style="padding-left: 10px;"><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #008080; ">&nbsp;1</span>&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;These&nbsp;typedefs&nbsp;attempt&nbsp;to&nbsp;ensure&nbsp;consistent&nbsp;'ticks'&nbsp;handling</span><span style="color: #008000; "><br /></span><span style="color: #008080; ">&nbsp;2</span>&nbsp;<span style="color: #008000; "></span><span style="color: #000000; ">typedef&nbsp;unsigned&nbsp;</span><span style="color: #0000FF; ">long</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">long</span><span style="color: #000000; ">&nbsp;TIC_t;<br /></span><span style="color: #008080; ">&nbsp;3</span>&nbsp;<span style="color: #000000; ">typedef&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">long</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">long</span><span style="color: #000000; ">&nbsp;SIC_t;<br /></span><span style="color: #008080; ">&nbsp;4</span>&nbsp;<span style="color: #000000; "><br /></span><span style="color: #008080; ">&nbsp;5</span>&nbsp;<span style="color: #000000; "></span><span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;This&nbsp;structure&nbsp;stores&nbsp;a&nbsp;frame's&nbsp;cpu&nbsp;tics&nbsp;used&nbsp;in&nbsp;history<br /></span><span style="color: #008080; ">&nbsp;6</span>&nbsp;<span style="color: #008000; "></span><span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;calculations.&nbsp;&nbsp;It&nbsp;exists&nbsp;primarily&nbsp;for&nbsp;SMP&nbsp;support&nbsp;but&nbsp;serves<br /></span><span style="color: #008080; ">&nbsp;7</span>&nbsp;<span style="color: #008000; "></span><span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;all&nbsp;environments.</span><span style="color: #008000; "><br /></span><span style="color: #008080; ">&nbsp;8</span>&nbsp;<span style="color: #008000; "></span><span style="color: #000000; ">typedef&nbsp;</span><span style="color: #0000FF; ">struct</span><span style="color: #000000; ">&nbsp;CPU_t&nbsp;{<br /></span><span style="color: #008080; ">&nbsp;9</span>&nbsp;<span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TIC_t&nbsp;u,&nbsp;n,&nbsp;s,&nbsp;i,&nbsp;w,&nbsp;x,&nbsp;y,&nbsp;z;&nbsp;</span><span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;as&nbsp;represented&nbsp;in&nbsp;/proc/stat</span><span style="color: #008000; "><br /></span><span style="color: #008080; ">10</span>&nbsp;<span style="color: #008000; "></span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TIC_t&nbsp;u_sav,&nbsp;s_sav,&nbsp;n_sav,&nbsp;i_sav,&nbsp;w_sav,&nbsp;x_sav,&nbsp;y_sav,&nbsp;z_sav;&nbsp;</span><span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;in&nbsp;the&nbsp;order&nbsp;of&nbsp;our&nbsp;display</span><span style="color: #008000; "><br /></span><span style="color: #008080; ">11</span>&nbsp;<span style="color: #008000; "></span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;unsigned&nbsp;id;&nbsp;&nbsp;</span><span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;the&nbsp;CPU&nbsp;ID&nbsp;number</span><span style="color: #008000; "><br /></span><span style="color: #008080; ">12</span>&nbsp;<span style="color: #008000; "></span><span style="color: #000000; ">}&nbsp;CPU_t;</span></div></div><div id="LC48" style="padding-left: 10px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;每次从/proc/stat取的数据称为一帧的数据，会从到CPU_t结构体的第一行成员里，上次的数据即上一帧的数据就拷到CPU_t的第二排带_sav后缀的成员里，一一对应。</div><div id="LC49" style="padding-left: 10px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;summaryhlp函数里计算我们想看的cpu各详细指标的百分比。只取部分代码或伪码做演示：</div><div id="LC50" style="padding-left: 10px;"><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #008080; ">&nbsp;1</span>&nbsp;<span style="color: #000000; ">SIC_t&nbsp;u_frme,&nbsp;s_frme,&nbsp;n_frme,&nbsp;i_frme,&nbsp;w_frme,&nbsp;x_frme,&nbsp;y_frme,&nbsp;z_frme,&nbsp;tot_frme,&nbsp;tz;<br /></span><span style="color: #008080; ">&nbsp;2</span>&nbsp;<span style="color: #000000; "></span><span style="color: #0000FF; ">float</span><span style="color: #000000; ">&nbsp;scale;<br /></span><span style="color: #008080; ">&nbsp;3</span>&nbsp;<span style="color: #000000; ">u_frme&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;cpu</span><span style="color: #000000; ">-&gt;</span><span style="color: #000000; ">u&nbsp;</span><span style="color: #000000; ">-</span><span style="color: #000000; ">&nbsp;cpu</span><span style="color: #000000; ">-&gt;</span><span style="color: #000000; ">u_sav;<br /></span><span style="color: #008080; ">&nbsp;4</span>&nbsp;<span style="color: #000000; ">s_frme&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;cpu</span><span style="color: #000000; ">-&gt;</span><span style="color: #000000; ">s&nbsp;</span><span style="color: #000000; ">-</span><span style="color: #000000; ">&nbsp;cpu</span><span style="color: #000000; ">-&gt;</span><span style="color: #000000; ">s_sav;<br /></span><span style="color: #008080; ">&nbsp;5</span>&nbsp;<span style="color: #000000; "><img src="http://www.cppblog.com/Images/dot.gif" alt="" /><br /></span><span style="color: #008080; ">&nbsp;6</span>&nbsp;<span style="color: #000000; ">tot_frme&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;u_frme&nbsp;</span><span style="color: #000000; ">+</span><span style="color: #000000; ">&nbsp;s_frme&nbsp;</span><span style="color: #000000; ">+</span><span style="color: #000000; ">&nbsp;n_frme&nbsp;</span><span style="color: #000000; ">+</span><span style="color: #000000; ">&nbsp;i_frme&nbsp;</span><span style="color: #000000; ">+</span><span style="color: #000000; ">&nbsp;w_frme&nbsp;</span><span style="color: #000000; ">+</span><span style="color: #000000; ">&nbsp;x_frme&nbsp;</span><span style="color: #000000; ">+</span><span style="color: #000000; ">&nbsp;y_frme&nbsp;</span><span style="color: #000000; ">+</span><span style="color: #000000; ">&nbsp;z_frme;<br /></span><span style="color: #008080; ">&nbsp;7</span>&nbsp;<span style="color: #000000; "></span><span style="color: #0000FF; ">if</span><span style="color: #000000; ">&nbsp;(tot_frme&nbsp;</span><span style="color: #000000; ">&lt;</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">1</span><span style="color: #000000; ">)&nbsp;tot_frme&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">1</span><span style="color: #000000; ">;<br /></span><span style="color: #008080; ">&nbsp;8</span>&nbsp;<span style="color: #000000; ">scale&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">100.0</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">/</span><span style="color: #000000; ">&nbsp;(</span><span style="color: #0000FF; ">float</span><span style="color: #000000; ">)tot_frme;<br /></span><span style="color: #008080; ">&nbsp;9</span>&nbsp;<span style="color: #000000; "><br /></span><span style="color: #008080; ">10</span>&nbsp;<span style="color: #000000; ">us</span><span style="color: #000000; ">%</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;(</span><span style="color: #0000FF; ">float</span><span style="color: #000000; ">)u_frme&nbsp;</span><span style="color: #000000; ">*</span><span style="color: #000000; ">&nbsp;scale;<br /></span><span style="color: #008080; ">11</span>&nbsp;<span style="color: #000000; ">sy</span><span style="color: #000000; ">%</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;(</span><span style="color: #0000FF; ">float</span><span style="color: #000000; ">)s_frme&nbsp;</span><span style="color: #000000; ">*</span><span style="color: #000000; ">&nbsp;scale;<br /></span><span style="color: #008080; ">12</span>&nbsp;<span style="color: #000000; "><img src="http://www.cppblog.com/Images/dot.gif" alt="" /><br /></span><span style="color: #008080; ">13</span>&nbsp;<span style="color: #000000; ">cpu</span><span style="color: #000000; ">-&gt;</span><span style="color: #000000; ">u_sav&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;cpu</span><span style="color: #000000; ">-&gt;</span><span style="color: #000000; ">u;<br /></span><span style="color: #008080; ">14</span>&nbsp;<span style="color: #000000; ">cpu</span><span style="color: #000000; ">-&gt;</span><span style="color: #000000; ">s_sav&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;cpu</span><span style="color: #000000; ">-&gt;</span><span style="color: #000000; ">s;<br /></span><span style="color: #008080; ">15</span>&nbsp;<span style="color: #000000; "><img src="http://www.cppblog.com/Images/dot.gif" alt="" /></span></div></div><div id="LC67" style="padding-left: 10px;"></div><div id="LC68" style="padding-left: 10px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;每个进程占cpu百分比计算：</div><div id="LC69" style="padding-left: 10px;"><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #008080; ">1</span>&nbsp;<span style="color: #000000; ">Frame_tscale&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">100.0f</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">/</span><span style="color: #000000; ">&nbsp;((</span><span style="color: #0000FF; ">float</span><span style="color: #000000; ">)Hertz&nbsp;</span><span style="color: #000000; ">*</span><span style="color: #000000; ">&nbsp;(</span><span style="color: #0000FF; ">float</span><span style="color: #000000; ">)et&nbsp;</span><span style="color: #000000; ">*</span><span style="color: #000000; ">&nbsp;(Rc.mode_irixps&nbsp;</span><span style="color: #000000; ">?</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">1</span><span style="color: #000000; ">&nbsp;:&nbsp;Cpu_tot));<br /></span><span style="color: #008080; ">2</span>&nbsp;<span style="color: #000000; "></span><span style="color: #0000FF; ">float</span><span style="color: #000000; ">&nbsp;u&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;(</span><span style="color: #0000FF; ">float</span><span style="color: #000000; ">)p</span><span style="color: #000000; ">-&gt;</span><span style="color: #000000; ">pcpu&nbsp;</span><span style="color: #000000; ">*</span><span style="color: #000000; ">&nbsp;Frame_tscale;</span></div></div><div id="LC73" style="padding-left: 10px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;算的是两帧之间总时间片数量，各进程占的时间片数量百分比。</div></pre><img src ="http://www.cppblog.com/yangsf5/aggbug/204148.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/yangsf5/" target="_blank">Sheppard Y</a> 2013-11-07 19:20 <a href="http://www.cppblog.com/yangsf5/archive/2013/11/07/204148.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>pomelo0.5.5源码分析（2）-通信</title><link>http://www.cppblog.com/yangsf5/archive/2013/09/05/203041.html</link><dc:creator>Sheppard Y</dc:creator><author>Sheppard Y</author><pubDate>Thu, 05 Sep 2013 15:09:00 GMT</pubDate><guid>http://www.cppblog.com/yangsf5/archive/2013/09/05/203041.html</guid><wfw:comment>http://www.cppblog.com/yangsf5/comments/203041.html</wfw:comment><comments>http://www.cppblog.com/yangsf5/archive/2013/09/05/203041.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/yangsf5/comments/commentRss/203041.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/yangsf5/services/trackbacks/203041.html</trackback:ping><description><![CDATA[<div></div><fieldset><legend><span style="color: #ff0000;">2016-07-11 日更新&nbsp;</span></legend><div><span style="color:red;">此篇博客已经迁移到新博客，并做行文检查和优化排版：</span></div><div></div><a href="http://blog.clawz.me/2013/09/05/13-pomelo-read-source-2/"><div><span style="color:red;">http://blog.clawz.me/2013/09/05/13-pomelo-read-source-2/</span></div></a></fieldset><a href="http://blog.clawz.me/2013/09/05/13-pomelo-read-source-2/"><div></div><p>&nbsp;</p></a><p><br />一、客户端与服务器的通信</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;客户端的通信在pomelo-client里封装了。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;服务器与客户端的通信在connector里。底层提供websocket、tcp和socket.io三种方式的通信。</p> <p>（一）connector组件（components/connector.js）</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;组件构造函数里会this.connector从opts里取connector，或者默认为connectors/sioconnector.js。（connector的实现sioconnector和hybridconnector）</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;组件的start里会将this.server\this.session\this.connection分别映射到app的对应的组件上。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;组件的afterStart里this.connector.start，并监听this.connector的'connection'事件。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;'connection'事件处理为：</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;将connection关联一个session，监听socket的message事件，接受到message时decode  message，再将message交给server组件的handle，处理完回调里再将返回信息在connector组件的send里处理。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;另外监听session的'bind'事件，处理函数为，调用connection.addLoginedUser。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;组件里的send，encode  reponse的message，然后交给schedule组件的schedule。</p> <p>&nbsp;</p> <p>（二）hybridconnector的实现</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;connectors/hybridconnector.js以及connectors/hybird。hyrbird实现了原生socket和websocket两种。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;hybridconnector.start里会this.tcpServer=net.createServer，然后把以这个tcpServer为参数创建一个switcher。之后在switcher的'connection'事件里将tcpsocket装进hybridsocket。</p> <p>（1）hybrid/switcher.js</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;switcher构造函数接受一个server参数，并创建this.wsprocessor和this.tcpprocessor。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;switcher监听参数server的'connection'事件，事件处理函数里监听原生socket的'data'事件，判断data是否有http头，如果有，则调用wsprocessor.add，这个add会向外emit  'connection'（事件参数为原生socket），并向socket emit  'data'事件；否则非http，则调用tcpprocessor.add，这个add会以刚才的原生socket为参数创建一个tcpsocket，同时向tcpprocessor  emit 'connection'（事件参数为原生tcpsocket）、向这个原生socket emit 'data'事件。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;switcher也监听了this.wsprocessor和this.tcpprocessor的'connection'事件，处理为向switcher自己emit  'connection'。总结，switcher的职责，将socket的字节流data拼成包，以'message'事件向外emit一个个的完成包msg。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;刚才提到的tcpsocket.js这里处理原生socket的操作。监听了原生socket的'data'、'end'、'error'、'close'事件。例如在'data'处理时，当读入的流长度够一个包的body后就向tcpsocket  emit 'message'。</p> <p>（2）hybridsocket.js</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;将socket和websocket封装为统一接口。构造函数里接受一个id和socket参数。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;hybridsocket监听tcpsocket的'message'事件，将msg  decode，之后处理。例如Package.TYPE_DATA类型的msg，就将这个msg再向hybridsocket自己emit一个'message'事件，其他可能是'handshake'或'heartbeat'事件。</p> <p>&nbsp;</p> <p>（三）server组件</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;官方描述如下&#8220;模块使服务器具备处理客户端请求的能力。该模块主要实现了filter服务，根据当前服务器类型，加载对应handler/目录下的代码，并决定一个请求应该是在当前服务器处理还是应该路由给其他服务器处理。&#8221;，下面看看代码流程。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;组件的start里初始化filter和handler。</p> <p>&nbsp;</p> <p>二、服务器之间的通信</p> <p>&nbsp;</p> <p>&nbsp;</p> <p>三、框架调用</p> <p>&nbsp;</p> <p>四、session</p> <p>（一）session组件（components/session.js）</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;session组件直接用的common/service/sessionService。</p> <p>（二）sessionService</p> <p>（1）Session（object）</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;Session里维护的socket和user信息的之间的对应关系。每个socket有个对应的Session，验证用户身份后就将他们绑定。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;Session构造函数接受参数socket  id\frontendId\socket\service。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;Session通过bind\unbind函数将uid绑到this.uid里，并emit  'bind'\'unbind'事件。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;Session的set\get函数来给Session设取值，由this.settings维护。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;Session的send\sendBatch都是直接通过构造时传入的那个socket来操作。</p> <p>（2）MockLocalSession（object）</p> <p>（3）SessionService（object）</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;负责对Session的管理。构造函数里将this.sessions和this.uidMap初始为空表。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;SessionService的create负责new  Session，并放到this.sessions里。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;bind\unbind函数负责将传入的sid\uid对应绑定到this.sessions\this.uidMap里。uidMap里每个元素是个数组，所以每个uid可以对应多个session？（这个以后再具体了解下）</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;sendMessage\sendMessageByUid根据sid\uid往对应的session或sessions发消息。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;其他函数不一一列举了。</p> <p>&nbsp;</p> <p>（三）session的使用</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;看了下chatofpomelo里，是在connector/handler/entryHandler.js里的enter函数，直接用了session.bind。简单用法就是在自己项目的验证uid后自己绑定。</p> <p>&nbsp;</p> <p>五、pomelo-rpc</p> <p>（一）rpc-client</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;client.create\mailstation.create\mailstation.mailboxFactory挂载mailbox\</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;client.start(callback)\mailstation.start&amp;callback</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;client.addProxies(remote-calls)\proxy.create\</p> <p>（二）rpc-server</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;lib/rpc-server/server将远程调用处理下，加到opts.services里，然后通过gateway来listen端口和处理message。</p><img src ="http://www.cppblog.com/yangsf5/aggbug/203041.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/yangsf5/" target="_blank">Sheppard Y</a> 2013-09-05 23:09 <a href="http://www.cppblog.com/yangsf5/archive/2013/09/05/203041.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>pomelo0.5.5源码分析（1）-组件</title><link>http://www.cppblog.com/yangsf5/archive/2013/08/15/202563.html</link><dc:creator>Sheppard Y</dc:creator><author>Sheppard Y</author><pubDate>Thu, 15 Aug 2013 12:31:00 GMT</pubDate><guid>http://www.cppblog.com/yangsf5/archive/2013/08/15/202563.html</guid><wfw:comment>http://www.cppblog.com/yangsf5/comments/202563.html</wfw:comment><comments>http://www.cppblog.com/yangsf5/archive/2013/08/15/202563.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/yangsf5/comments/commentRss/202563.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/yangsf5/services/trackbacks/202563.html</trackback:ping><description><![CDATA[<div></div><fieldset><legend><span style="color: #ff0000;">2016-07-11 日更新&nbsp;</span></legend><div><span style="color:red;">此篇博客已经迁移到新博客，并做行文检查和优化排版：</span></div><div><a href="http://blog.clawz.me/2013/08/15/13-pomelo-read-source-1/"><span style="color:red;">http://blog.clawz.me/2013/08/15/13-pomelo-read-source-1/</span></a></div></fieldset><div><a href="http://blog.clawz.me/2013/08/15/13-pomelo-read-source-1/"></a></div><p>&nbsp;</p><p>&nbsp; &nbsp; 由于才接触nodejs几天，看源码时各种细节和设计方法都得熟悉下。结合chatofpomelo-websocket，先从pomelo的使用入口开始看。</p> <p>&nbsp;</p> <p>一、chatofpomelo的开启流程</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;Pomelo.createApp出来Application，然后Application.start就开启了。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;createApp时会调Application.init来做初始化。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;init里调AppUtil.defaultConfiguration来读入默认配置。例如从master.json里读入master配置（Application.master），从servers.json里读入服务器集群各进程的type、host和port配置（可以通过Application.get("__serverMap__")获取）。</p> <p>&nbsp;</p> <p>二、组件的挂载</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;组件放在components目录下。各组件可以通过Pomelo.components或者直接通过Pomelo来按名取。也可以通过Application.components来按名取（每个组件的名字在自己的name属性里，通常为js文件名加前后双下划线，例如connector.js的组件名为&#8220;__connector__&#8221;）。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;下面看下组件的挂载和运行。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;Pomelo里会遍历componets目录里的各个js文件，然后require到Pomelo里和Pomelo.components里。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;Application.start里先调用AppUtil.loadDefaultComponents，loadDefaultComponents里会根据Application.serverType来Application.load需要的components。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;Application.load里会将Pomelo里的components放到自己的components里。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;Application.start/stop/afterStart等方法会统一执行各components里的对应start/stop/afterStart等方法。</p> <p>&nbsp;</p> <p>三、ps</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&#8203;这篇发表后，在google里搜了下（我的一点恶趣味：经常发表随笔后会看看搜索引擎收录了没）&#8220;pomelo  源码分析  组件&#8221;，发现了pomelo官方wiki里关于组件的说明，奇怪之前准备看组件时没搜到。分析源码之前也浏览了下官方wiki，应该是偏向于了解大概了，各细节没了太大印象。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&#8203;不过官方已经有了也没关系，随笔给人参考的价值变小后，就当自己的笔记吧。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&#8203;另外网上也有些pomelo的源码分析了，但是看了眼，跟我想要的不太一样。</p> <p>&nbsp;</p> <p>附官方组件wiki：</p> <ol list-paddingleft-2"=""> <li> <p>Pomelo-Framework里的组件部分：<a href="https://github.com/NetEase/pomelo/wiki/Pomelo-Framework">https://github.com/NetEase/pomelo/wiki/Pomelo-Framework</a></p></li> <li> <p>Pomelo-组件：<a href="https://github.com/NetEase/pomelo/wiki/Pomelo-%E7%BB%84%E4%BB%B6">https://github.com/NetEase/pomelo/wiki/Pomelo-%E7%BB%84%E4%BB%B6</a></p></li></ol><p>&nbsp;</p><img src ="http://www.cppblog.com/yangsf5/aggbug/202563.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/yangsf5/" target="_blank">Sheppard Y</a> 2013-08-15 20:31 <a href="http://www.cppblog.com/yangsf5/archive/2013/08/15/202563.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>懒人厨房</title><link>http://www.cppblog.com/yangsf5/archive/2013/07/17/201910.html</link><dc:creator>Sheppard Y</dc:creator><author>Sheppard Y</author><pubDate>Wed, 17 Jul 2013 13:13:00 GMT</pubDate><guid>http://www.cppblog.com/yangsf5/archive/2013/07/17/201910.html</guid><wfw:comment>http://www.cppblog.com/yangsf5/comments/201910.html</wfw:comment><comments>http://www.cppblog.com/yangsf5/archive/2013/07/17/201910.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/yangsf5/comments/commentRss/201910.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/yangsf5/services/trackbacks/201910.html</trackback:ping><description><![CDATA[<div></div><fieldset><legend><span style="color: #ff0000;">2016-07-08 日更新&nbsp;</span></legend><div><span style="color:red;">此篇博客已经迁移到新博客，并做行文检查和优化排版：</span></div><div></div><a href="http://blog.clawz.me/2013/07/17/13-lazy-cook/"><div><span style="color:red;">http://blog.clawz.me/2013/07/17/13-lazy-cook/</span></div></a></fieldset><a href="http://blog.clawz.me/2013/07/17/13-lazy-cook/"><div></div><p>&nbsp;</p></a><p>&nbsp;</p><div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; 有时候忙了一天下班后，和女朋友都不想做饭，女朋友就受懒人天气app（里边突出显示重要信息，其他都没有，这样一眼就能看到想要的）的影响，考虑写个懒人厨房的app。</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp;&nbsp;&nbsp;&nbsp;其实女朋友想的懒人厨房跟那个懒人天气的关联就是&#8220;懒人&#8221;，：）</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp;&nbsp;&nbsp;&nbsp;女朋友在看android方面的资料，暂时又得快速写好app，我就先在github开个项目，先把想到的菜名给记下来吧，以后再慢慢看怎么去演变这个项目&#8212;&#8212;是只做开放文档形式，还是演变成个app之类的。</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp;&nbsp;&nbsp;&nbsp;项目网址：<a href="https://github.com/yangsf5/claw-lazycook">https://github.com/yangsf5/lazycook</a></div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"></div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"><hr /> &nbsp; &nbsp; &nbsp;这个后来没搞起来，老婆那也不想做了，哈哈哈。</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;简单谈下这个事情吧，感觉做菜复杂的话太耗费时间，可以靠多练习来增加熟练度，各个步骤也慢慢根据经验来优化，来做好时间统筹。</div></div><p><a href="https://github.com/yangsf5/claw-lazycook"></a></p><img src ="http://www.cppblog.com/yangsf5/aggbug/201910.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/yangsf5/" target="_blank">Sheppard Y</a> 2013-07-17 21:13 <a href="http://www.cppblog.com/yangsf5/archive/2013/07/17/201910.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>