[原创]Discuz! BBS缓存整体方案

[ 文章作者:陈臻 本文版本:v1.0 最后修改:2009.6.22 转载请注明原文链接:http://www.54chen.com/c/611 ]

DZ的缓存方案是经典之作,不论是系统的主动缓存还是帖子内容的被动缓存。在我前面的博文【[原创]Discuz! BBS的主动缓存和被动缓存】里所讲述的是DZ的缓存常用的一种方法,下面再说在DZ系统里如何决定一个内容是不是要缓存。

所有的数据全都缓存,不失为一个好办法。但是,在数据更新要求及时的环境下,例如帖子回复的内容要求立即显示等地,又不得不对其缓存进行更新。所以,基本上每一个成熟的系统,都不会去把所有的东西缓存起来。这时是不是让各位很困惑,缓存就是一把双刃剑,用好了系统效率事半功倍,用得不好,产品功能将受到严重影响。DZ就是一个缓存与不缓存选取得当的系统。

我们一起进入DZviewthread.php,也就是负责显示帖子内容的一个文件。代码一开始有这样一个判断:

$page = max($page, 1);

if($cachethreadlife && $forum['threadcaches'] && !$discuz_uid && $page == 1 && !$forum['special']) {

       viewthread_loadcache();

}

这是什么意思呢?基本上就是在说,当一些系统的设置都满足的时候,只要是第一页就去执行viewthread_loadcache(),各位已经等不及看这个函数的意思了吧,且慢,先说说为什么选中了第一页。在经过大家长期的总结下,发现一个成熟论坛大多数时间会员都会停留在帖子的第一页,所以,DZ大胆地只将第一页进行缓存。

DZ真的是只将第一页进行缓存吗?答案是否定的,下面我们来看viewthread_loadcache()这个函数里的内容。

这个函数写在了viewthread.php538行,看到这个函数的第一感觉,是专业。DZ的多年开发,已经将论坛的行为研究深深刻在了代码里。如下这段代码,这个函数里的$threadcachemark这个变量,被定义为与帖子的显示顺序、是否加精、此版最后回复天数、帖子浏览数、回复数、每页显示条数进行运算得到的一个值,如果这个值小于了版块的设置,这个帖子的内容才会生效。就也是说,DZ甚至还不是但凡第一页就缓存!

$threadcachemark = 100 - (

              $forum['displayorder'] * 15 +

              $forum['digest'] * 10 +

              min($forum['views'] / max($forum['livedays'], 10) * 2, 50) +

              max(-10, (15 - $forum['lastpostdays'])) +

              min($forum['replies'] / $_DCACHE['settings']['postperpage'] * 1.5, 15));

这个经典的公式从何而来?由笔者有幸参加的一次DZ的培训得知,这个公式是多年来长期的积累,不断的尝试,才总结所得。至于更多的细节,大概只有DZ的总设计师才能得知。不过我们也可以从代码里得到一些提示,帖子的属性是可以作为是否缓存的权值的,而这个权值,直接决定了缓存与否。

这样的选取在DZ里到处可见,在存在分页的地方,只需要记住,前两页或者前一页,以及最后两页或最后一页,永远比中间的更值得缓存。如果读者的系统需要一个缓存方案,建议全局统计一下所有的用户关注的点,学习DZ思想,将这些关键的点数值化,就一定也能得出一个合适的公式。

一个简约的缓存,每个细节的方案,筑成了DZ整体的坚实。

提示:平时在设计系统的时候,也许并不能考虑到这么细,如果不是受到磁盘空间的限制,您并不需要担心按照什么方案来缓存,用一刀切的方案也不错,也就是把大部分看上去很常用的数据都缓存了,但你需要更多考虑去对比是否需要更新缓存了,比如用最后回复的时间去对比,很多开源系统就都是这样干的。

Scp和rsync的限制流量(速度)方法

有些机房会限制机器的流量,为了不触及底线,在使用scp和rsync的时候都要注意。

为了避免你的scp或者rsync因为无良&懒惰的OPS设置防火墙的偷懒而造成的断流现象,我们必须对自己的数据传输进行一定的限流措施,慢一点总比被掐了的好。因此(限制为 1M Bytes/s):

  scp -l 10000 某个大文件   你的账号@远程的机器
或者rsync是(限制为 60k Bytes/s):
  rsync -auvz --progress --delete --bwlimit=60 远程的文件  本地的文件
  rsync -auvz --progress --delete --bwlimit=60 本地的文件  远程的文件

Twitter Api 中文文档 [前言][515更新]

[ 翻译:陈臻 本文版本:v1.1 最后修改:2009.5.15 转载请注明原文链接:http://www.54chen.com/c/591 原稿:twitter wiki 完成2%]

前言

(每个开发者在开始使用api前都必须知道的概念)

开始使用api前必读

(细读这一节,你将掌握大多数经验丰富的开发者知识)

【不知道为什么,这一节的内容在wiki里被人删除了】

每一个开发者都必须知道的事情

(每个twitter api开发者都必须知道的基础知识)

0)FAQ的内容

当你开始开发的时候,熟悉FAQ的内容并且知道问题所在。

1)twitter其实有两份api

目前twitter api存在两个分立的版本。大部分的开发者都混用这两份api来完成开发。将REST和Search的api分离是不理想的,完全是由于历史原因。如果开发周期允许的话,我们打算合并RESTSearch的api完善之。api预览里的前言部分说明了这段历史。

2)你不能无限次地调用

api的使用频率是有限制的。你可以阅读《我们有个雷管》(这个名字好雷哦)来学习下。

3)此api是完全基于HTTP的

从twitter api检索数据的方法需要发送GET请求。提交、修改或者删除数据使用POST请求。DELETE请求也是可用来删除数据。如果你没有使用正确的方法请求数据,使用特殊HTTP方法的api就返回一个错误。HTTP的返回(有链接)是丰富多彩的。

4)此api是RESTful的源

twitter api企图确保按照REST的原则来设计。只需要简单修改你请求的扩展上的格式就可以取到你所指定的格式。本文档指明了对每一种方法都有哪些格式是可用的。目前api支持的数据格式有:XML、JSON、RSS、Atom联合供稿格式。有个别方法只支持其中的某些格式。

5)参数都有确定的期望值

有些api方法有必选的和可选的参数。在发起请求的时候要注意两件事情:

1.参数值必须是utf8编码,并且加上urlencode。

2.翻页的起始值是1不是0

在twitter api中有两个特殊的参数:

1. callback:仅在返回格式是JSON的时候使用,用这个参数指定一个回调函数来包装你的返回。例如:附加&callback=myFancyFunction在你的请求上,将会返回:myFancyFunction(...)。此参数只能包含字母数字和下划线,其他非法的字符将会丢弃。

2. suppress_response_codes:当出现这个参数的时候,所有的返回都将以200的结果返回-甚至是错误的时候。这个参数的存在是为了解决js和flash会拦截所有非200的返回这个问题。一旦使用这个参数,要判断错误就只能依靠解析返回的信息体。请小心使用,因为错误信息可能会改变。

前面提到过,api有些方法通过发送不同的HTTP头可以得到不同的结果。用参数和HTTP头可以得到同样的效果时,优先使用参数。

6)分页限制

REST API的限制

使用时间线REST API,客户端通过page和count参数最多可请求3200条状态。超过这个值将返回一个200状态值并且为空的所请求格式数据。twitter还维护了一个包含一个用户发出的所有tweets的数据库。尽管如此,为了确保网站的性能,做这样人工的限制是恰当的。

Search API的限制

使用Search API,客户端通过page和rpp参数最多可请求1500条状态。一次请求走出这个数量将会返回200状态和所请求格式的空值。这个人工限制对确保搜索系统的性能是恰当的。我们还依靠在允许搜索的更新上指定一个时间来限制了搜索索引的范围。当前这个限制是大约一个月的样子,但因为每天增加的用户用户不得不动态缩减。

7)编码影响到状态发送的字数

twitter api支持utf-8编码。请注意尖括号已经被实体编码(就是编码了html的关键字),以预防使用JSON API输出的嵌入式用户被跨站式脚本攻击。编码的实体将算入这140个字符的限制中。当请求XML时,返回是utf-8编码的。所有不在标准ASCII范围内的符号和字符都将被转义成HTML实体。

8)使用twitter api你所有需要的就是命令行

如果你的系统里有curl,那你已经拥有了最好的使用twitter api的工具。这有一些例子:

1.使用RSS格式取到公共时间线,不需要认证:curl http://twitter.com/statuses/public_timeline.rss

2.使用XML格式取到所有你follow的人的更新,需要认证:curl -u username:password http://twitter.com/statuses/friends_timeline.xml

3.仅查看2中的头信息:curl --head -u username:password http://twitter.com/statuses/friends_timeline.xml

4.发送一个状态并且取得JSON返回:curl -u username:password -d status="your message here" http://twitter.com/statuses/update.json

学习更多相关的curl和api请等候翻译。

9)这里有几乎每一种编程语言的twitter api库

社区里创建了许多的api库并且乐于分享。

API概述

(过去、现在和将来的twitter api)
twitter api包含了两部分,这完全是由于历史原因。最初的时候Summize公司是一家独立的公司专门给twitter数据提供搜索功能。Summize后来被收购,更名为Twitter Search。更名网站很容易,但要完全整合Twitter Search和它的api到Twitter的底层代码却很难。统一api已经被我们提上日程,但Search api和REST api将会作为独立的实体一直到资源允许。

twitter REST api允许开发者得到核心的twitter数据。这包括更新时间,状态数据,用户信息。Search api提供给开发者与Twitter Search和趋势数据。开发者对于这两者需要注意的是频率限制和输出格式的影响。

想学习更多的api方法和数据,请阅读 twitter api技术文档(还没译)。

其们公示目前的缺陷和改进情况。当前的缺陷和改进事项可以看issue list。长期目标会记录在路线图文档中。(有两个连接没有译)。

API会定期更新并增加新的功能。偶尔会去掉一些功能。所有这些更新都会在以下的地方公布:

  • @twitterapi
  • Google group
  • Changelog

频率限制

(为什么api会有限制以及会对应用开发带来什么影响)
twitter api只允许客户端在一定时间里调用有限的次数。这两种api的策略不太一样。

REST API 限制

默认一小时内只能请求REST API 100次。REST API还有基于账号和IP的限制。需要身份验证的api请求记验证的用户数,而不需要身份验证的请求则记IP数。
频率限制仅适用于使用HTTP GET方法请求信息的方法。而使用HTTP POST向twitter提交内容的方法不受此限制,例如statuses/update方法。另外,请求account/rate_limit_status 方法不算。为了保持健康使用阻止垃圾信息,这些不受限制的方法还是会受到每天更新和follow数的限制。[未完待续]

内部培训--memcached协议详解[原创][总结]

[ 文章作者:陈臻 本文版本:v1.0 最后修改:2009.5.12 转载请注明原文链接:http://www.54chen.com/c/584 ]

本次讲座讲师是校内网高手张洁同学,主题是“memcached协议详解及java client分析比较”,java client分析比较线条化,只有在现场才能明白,此处只回顾memcached协议详解,为易于理解,标题段落有调整。

一.连接

安装好memcached,直接通过telnet localhost 11211连接。11211是memcache默认的端口。

二.协议

2.1store (存储)

(可用命令)set/add/replace/prepend/append

<command name> <key> <flags> <exptime> <bytes> [noreply]\r\n

exptime 只能精确到秒 例如:

set name 0 0 5<回车>

zhangjie<回车>

STORED 区别:set可能覆盖,add不能覆盖,prepend是续在前面,append是续在后面。

另:[noreply] 是新版中增加的标志,可以让服务器端不用返回。

2.2 cas(compare and set)

最新版的命令。目的保证执行的原子性。

例如:

cas some 0 0 10 2

意思是:检查some的值的版本是不是2,是2才把10存进去,

2.3 get/gets

get <key>*

get key1\r\n

get key1 key2 key3\r\n gets与get相比,返回结果会多一个版本号:

gets some

VALUE some 0 10 2

2008-03-20

END 2.4 delete(没得说的)

2.5 incr/decr(自增和自减)

2.6 stats(运行状态)

STAT curr_items 1

STAT total_items 7

STAT bytes 58

STAT curr_connections 5

STAT total_connections 6

STAT connection_structures 6

STAT cmd_get 12

STAT cmd_set 11

STAT get_hits 8

STAT get_misses 4

三.两个java client

spymemcached

  http://code.google.com/p/spymemcached

Java memcached client

  http://www.whalin.com/memcached

关于环状的一致性hash很有意思,有时间研究研究。

[54陈新闻]hhhjob新版(2.0)正式发布了!

hhhjob简介:http://www.hhhjob.com

hhhjob是两年前在学校里开始筹划的一个公益组织,正式上线应该是在08年初的时候,上线后受到了来自各大高校同学的支持,并与现在的大学英语四六级查分站99宿舍建立了良好的合作伙伴关系,08年末受主机商影响,hhhjob经历了很长一段离线时间,以下地址是长期的离线时期所挂靠的页面,欢迎围观:

http://www.54chen.com/hhhjob

hhhjob 2.0简介:

新版的hhhjob同传承了原来的光荣传统,同样非常努力、非常勤奋地收集来自各大名企的师姐师兄,同时号召大家共享出来名企的求职经验和要求,希望能为寻找工作的朋友提供真正有效的信息和真正有用的职位。

组织成员:
总体方案:tangyu 、cc0cc 、偏偏
策划:tangyu
程序:cc0cc
日常事务: zeno、莞尔、enya、ruyi、Missfly、asura、莫非非、alexlee、dingxx、king、dennis、javawz、guyu、wahaha

在此一并感谢dbanotes.net的Fenng同学和twitter上一帮有意思的朋友,你们的意见都将是hhhjob组织未来发展的强心剂。

这次新版本还有一个特色是黑名单企业的提交,是来自guyu同学的奇思妙想。

[54陈科学院]802.1x源代码下载

免责声明:

本程序仅供学习编程使用,非商业用途,所有分析过程均遵循《中华人民共和国计算机软件保护条例》。

功能:

mynet是我在大学时期在xdkui老兄的vc源码参考下,完成的一套gnome程序,它解决了linux下802.1x拔号上网问题,同时友好的界面能使你轻松使用。

截图:

代码分析:

[中秋零献] 神州数码802.1x局域网UDP拔号软件MyNet-Gnome源代码大分析(Part1)

[中秋零献] 神州数码802.1x局域网UDP拔号软件MyNet-Gnome源代码大分析(Part2)

[中秋零献] 神州数码802.1x局域网UDP拔号软件MyNet-Gnome源代码大分析(Part3)关键逻辑

[中秋零献续集] 神州数码802.1x局域网UDP拔号软件MyNet-Gnome源代码大分析(Part4)getaccess线程内的故事

索取代码,请猛击此处进入此页面留下邮箱。

[原创][实测]MySQL时间字段究竟使用INT还是DateTime?

[ 文章作者:陈臻 本文版本:v1.0 最后修改:2009.4.27 转载请注明原文链接:http://www.54chen.com/c/560 ]

环境:
Windows XP PHP Version 5.2.9
MySQL Server 5.1

第一步、创建一个表date_test(非定长、int时间)

CREATE TABLE `test`.`date_test` (
`id` INT NOT NULL AUTO_INCREMENT ,
`start_time` INT NOT NULL ,
`some_content` VARCHAR( 255 ) NOT NULL ,
PRIMARY KEY ( `id` )
) ENGINE = InnoDB;

第二步、创建第二个表date_test2(定长、int时间)

CREATE TABLE `test`.`date_test2` (
`id` INT NOT NULL AUTO_INCREMENT ,
`start_time` INT NOT NULL ,
`some_content` CHAR( 255 ) NOT NULL ,
PRIMARY KEY ( `id` )
) ENGINE = InnoDB;

第三步、创建第三个date_test3(varchar、datetime时间)

CREATE TABLE `test`.`date_test3` (
`id` INT NOT NULL AUTO_INCREMENT ,
`start_time` DATETIME NOT NULL ,
`some_content` VARCHAR( 255 ) NOT NULL ,
PRIMARY KEY ( `id` )
) ENGINE = InnoDB;

第四步、创建第四个表date_test3(char、datetime时间)

CREATE TABLE `test`.`date_test4` (
`id` INT NOT NULL AUTO_INCREMENT ,
`start_time` DATETIME NOT NULL ,
`some_content` CHAR( 255 ) NOT NULL ,
PRIMARY KEY ( `id` )
) ENGINE = InnoDB;

ok,现在我们开始做测试,环境是php,先向各个表插入一百万条数据。插入的时候分200次,每次进库5000条。

表一执行记录:页面运行时间: 26.5997889042 秒,插入的时候发现一个有趣的现象:SELECT count( id ) FROM `date_test` WHERE 1 的结果是100w,而直接select * from `date_test`却是1,000,374条结果。(后来看到这是一个可能接近的值,请参看MySQL FAQ 3.11)。
表二执行记录:页面运行时间: 62.3908278942 秒,这次记录是1,000,066条。
表三执行记录:页面运行时间: 30.2576560974 秒,这次的是1,000,224条。
表四执行记录:页面运行时间: 67.5393900871 秒,这次的是:1,000,073条。

现在把四个表的start_time字段一一加上索引。

测试四个表的更新,分别update 100条记录,并记录时间:
表一:页面运行时间: 2.62180089951 秒(非定长,int时间)
表二:页面运行时间: 2.5475358963 秒(定长,int时间)
表三:页面运行时间: 2.45077300072 秒(varchar,datetime时间)
表四:页面运行时间: 2.82798409462 秒(char,datetime时间)

测试四个表的读取,分别select 100条随机记录,以主键id为条件查询,并记录时间:
表一:页面运行时间: 0.382651090622 秒(非定长,int时间)
表二:页面运行时间: 0.542181015015 秒(定长,int时间)
表三:页面运行时间: 0.334048032761 秒(varchar,datetime时间)
表四:页面运行时间: 0.506206989288 秒(char,datetime时间)

测试四个表的读取,分别select 10条随机记录,以star_time为条件查询,并记录时间:
表一:页面运行时间: 30.1972880363 秒(非定长,int时间)
表二:页面运行时间: 65.1926910877 秒(定长,int时间)
表三:页面运行时间: 39.7210869789 秒(varchar,datetime时间)
表四:页面运行时间: 70.4632740021 秒(char,datetime时间)

因为量比较小,所以我们默认即使是微小的变化,也是有意义的。

结论:

大数据量下,如果存在大量的select * from table where 时间>XX这样的查询,在MySQL5.1时使用int换datetime是有意义的。

[54chen出品][打酱油]在线一对一和陌生人聊天的网站

      打酱油(http://www.dajoyo.com)是一种生活方式,既不是简单的路过,也不是单纯的看热闹。

      和一个随机的陌生人聊天。谁也不知道你是谁,谁也不知道你会遇见谁。可以放心倾诉、交友甚至发泄,因为大家都在打酱油。
       聊天对象虽然是随机的,陌生的,不过如果你愿意,谁也不能阻止你透露自己的个人信息。朋友,或许就从打酱油开始。缘分,是天注定吗?那么现在就开始:

 

如果有什么问题,欢迎在这里留言,很乐意听到大家的意见。

【友情提示】

打酱油使用了最新的p2p技术,需要穿透您的网络,所以当您的网络防火墙安全性设置较高时会出现连接错误,出现这样的问题时,请尝试将防火墙安全级别调低,另外请有链接出错或者进入无反应的朋友提供您的网络情况,帮助打酱油成长。

[原创][整理]校内网CTO黄晶讲述网站架构变迁-54chen回忆版

[文章作者:陈臻 本文版本:v1.1 最后修改:2009.4.13 转载请注明原文链接:http://www.54chen.com/c/539 ]

这是一次公司内部的交流会,主题是校内的发展史和构架讲解,主讲人是校内网CTO黄晶,其中关于架构变迁的一段个人觉得是很具有代表性的过程,特在会上作了大概的笔记,现在是凌晨一点不到,正好清醒头脑进行回忆总结。

每个网站的发展都会按照一个大致相同的路线去完成,当然这里说的是每个相对成功的网站。

第一阶段:

这一阶段没有太大的访问量,甚至只有一台服务器就搞定了所有的访问。DB和前端的代码全都在一起,压力不高。忆者注:我觉得在alexa没进五万的时候,只要不是特殊的应用,基本都在此列吧。

第二阶段:

网站初具规模,DB压力大增,单独的一台DB已经满足不了现在的访问量,开始考虑读写分离的Master-slave库,使用三个及以上的服务器。忆者注:这时网站的alexa基本上会在1-3万的位置,每天的ip在5-10w的样子,当然,DB我们都认为是MySql。

第三阶段:

访问量继续增加,增加到了DB的压力在Master的机器上非常的明显了,Master开始出现吃不消的情况,出现写耗尽。主从也已经不能满足要求,需要进一步解决负载问题,此时要引入Mysql Proxy程序,进行中间层代理,实现负载均衡,易于扩展。忆者注:这时网站已经不可限量了,先恭喜下你的网站能用到这段。

第四阶段:

网站继续发展,进而出现了数据量的成倍增长,原来的N台DB都出现了一个问题,数据量巨大,无法完成正常速度的读写。此时,需要对网站按功能进行垂直划分,比如用户注册登录是一部分、UGC又是另一部分。与此同时,对数据本身进行水平划分,也就是Hash散表或者是散库。

第五阶段:

真的没了。再往下玩就灭了。

其实再进一步第五第六阶段,就是无法预想的未来了,也许有什么突飞猛进的科学技术发明也说不好。

今天和yahoo的agentZhang(openResty作者)聊起,他说到第五个阶段其实应该是BigTable,的确很强大,来自google的作品。不过美中不足的是,它并不像我相像中的那样能够顺利过渡到第五阶段。以下论述来自infoQ:
Todd从定义BigTable的适用范围开始论述。由于BigTable引入的各种代价,只有在以下情况下使用BigTable才能带来益处:a)需要伸缩到巨量的用户数,b)更新与读取操作相比比例很小。Todd还着重强调为了“优化读取速度和可伸缩性”,所采取的理论路线与关系数据库中的做法存在根本的分歧,很可能初看起来是违背直觉甚至相当冒险的。

Gae Java支持试用手记

一直都对gae冷眼旁观,今天得知支持java,甚是兴奋,是否暗示python也向java低头了,记一篇手记,送给万千不怕功夫网的同志。

首先用你的GAE账号登录http://appengine.google.com/start/newtos,当然,如果你没有GAE账号的话,得申请一下,过程要用手机接验证码,传说是不要钱的。

点上,发送submit。

登录进GAE,有一个明显的黄条提醒:Interested in trying our new Java language support? Learn more

点learn more进去后Sign up to try Google App Engine for Java。downloading the SDK.这是SDK下载。

点sign me up。

Thanks for signing up. Once your account is activated, you will receive an email with more information.

然后等待激活java支持,激活了会有邮件通知。

====

google 提供了一个eclipse的插件,十分好用,遗憾之处在于,update install相当的慢,公司的网络也一度最快为1k/s...

下面是此次Google Campfire上关于GAE的一些有用的链接:

申请试用GAE for JAVA的链接页面

Google Code Blog上介绍GAE的最新功能

Google Campfire首页介绍GAE JAVA

GAE JAVA的入门指南