IT牛人博客聚合网站 发现IT技术最优秀的内容, 寻找IT技术的价值 http://www.udpwork.com/ zh_CN http://www.udpwork.com/about hourly 1 Sat, 19 May 2012 05:48:31 +0800 <![CDATA[Live in HK]]> http://www.udpwork.com/item/7321.html http://www.udpwork.com/item/7321.html#reviews Fri, 18 May 2012 23:52:01 +0800 lovelucy http://www.udpwork.com/item/7321.html 博主按:文章起始于2年前,主要是自己在香港求学、生活的点滴体会。断断续续地写,小段的短文拼起来就成了现在这个样子。我也阅读很多博客,比如阮一峰,比如王建硕,在每天面对代码工作之余,充满理性和智慧文字总能带给自己内心的愉悦。我开始决定尘埃落定博客的转型,不再只发技术文,也开始分享自己关于社会、人生的一些感悟和思考。

以下为正文。

从今天开始,记录HK生活。兼思考社会主义中国和资本主义中国的不同。

1

CUHK的校车是免费的。今天上车后人快坐满了还没开车,回头一看,后面发生了争执。原来是一位女士上车时没有出示证件,校巴交通组的admin在交涉:“Madam, could you please show your CU staff card?”其实平时都没人查的,今天不知道为什么查了。那位女士没有ID card,不耐烦地说“i forget. it’s not convenient…”但是这位admin执意要ID card:“are you staff in CU?”看样子是要赶人下车了。这已经耽误大家的时间了。这时,坐我前面的一位同学说话了:”excuse me, she is my professor. i’m student in her lab.”这是个善意的谎言。“OK, I trust you. next time, please wear your CU card.”

我居然有一点点感动了。据说在美国,有一种“无罪推定”的社会空气,人在潜意识中不会主动怀疑别人(更准确的说,是美国人觉得由于多疑而去调查,付出的成本,比相信而被骗,付出的成本更高。)我有一次买饮料,两瓶收了三瓶的钱,和售货员说,她看都没看就退了钱。对人的信任是文明的表现,但也给人钻空子的机会,比如有些华人学生,为了获得更高的信用额度,对银行说自己是PR(永久居民permenent resident),有的为了获取更高的退税,在报税材料上取巧。

2

室友买了3台iphone4,全是准备为国内的朋友带的。其实就是走私,但是海关一般也懒得查。香港有很多学生干这种事情,听说还有一个女生买了200台ipad,净赚2W。一是因为香港的便宜,二是国内的卖断货了买不到,而且功能上有诸多限制(例如wifi)。然后,到了深圳,室友改了人人网状态:“一般犯罪后都会有快感,比如过关成功……”

3

地铁上有电视屏幕,会滚动播放即时新闻。今天看到一个新闻说香港gov准备申办2023年的亚运会,征求民众意见,遭到主要政党反对,立法会三大政党都表明不支持的立场。民众主要关心的是对经济、生活的影响等很实际的point,而不是形象面子,“有钱还不如投在民生上”。这和中国只有一种声音有很大不同,因为有真理部,而官方也会朝那个方向引导,导致很多不明真相的群众其实利益受到损害也还很傻很天真地说,我支持***。

update: 终于,香港亚运申办被否决。昨晚上课的时候老师还聊到,it is impossible in China. In China, government is the king. 而在香港为了实现所谓的民主,花费了大量的时间和精力在议案的辩论审核上,这也是民主的弊端之一。

4

在学校上课,其实是一件很爽的事情。教授们都很有激情,老师和学生都很enjoy,看得出来为一节课做了很多准备。和大陆高校的很多老师照着放映的PPT念不同,这边的教学比较互动,学生可以随时打断老师提问。老师有时甚至会故意设置这种场景,例如有一位老师经常的伎俩就是:“any questions? there must be some questions.”而等有学生顺着他的思路提问后,他则大加赞赏“good question! actually i am just waiting for this question. haha~~”

香港的教授都有很牛逼的背景,随便抓一个就是哥伦比亚或者斯坦福phd,给我们上课的就有ACM和IEEE Fellow。其实越是牛逼的教授越是平易近人,我可以很随意地提问、探讨。相反不怎么牛的,比如某个老师,反而给我一些刻薄的印象。

5

香港拥有世界上最成功、最广泛使用的智能电子缴费系統。「八達通」作为一种非接触式智能卡已应用于差不多所有公共交通系统(地铁、公交、的士、轮船),以及许多零售商店、食肆及便利店。这是真正的全城一卡通,在小卖部、打印店都可以使用,比银行信用卡更普及,可见香港政府为谋取人民生活便利的推动力。市面上流通的八达通卡及产品逾2000万件,系统每天处理超过1100万次交易,一天交易额达1280万美元。
另一项令我惊讶的科技应用是智能建筑。学校的教学楼、图书馆,统统有部署智能安保系统,刷卡进入。某一间教室或卫生间没有人的时候,会自动关闭照明、空调以节能,并在来人后自动感应,开启相关设施。

6

今天是中文大学的undergraduate orientation day,相当于武大的校园开放日吧。学校里布置得十分热闹,到处都是展台,还有热情的“学长学姐”们介绍中大和学科专业。好多对未来满怀憧憬的中学生从一个展台到另外一个展台搜集宣传资料。这不禁让我回想起2年前的时光,于是我也装作新生,搜集了一大袋子各色精美的印刷品,并且装作听懂地听那些学弟学妹们把我当作学弟用粤语在我耳边亲切地介绍。

香港中文大学拥有独特的书院制度,就像联邦制一样。所有学生及教职员除了有各学术学科上之学院(Faculty),尚会各自隶属其中一间书院(College);书院负责专业学科以外之事宜,如通识教育、宿舍、辅导、奖学金等。对许多中大毕业生来说,在书院结识的友伴,书院宿舍内的某次促膝长谈或炽热讨论,都是日后回忆的重要片段。书院是紧密的小群体,师生密切交流,朋辈一同成长。所有中大全日制本科生都可选择一所书院,成为该院的一分子。每所书院都是独树一帜的,有各自的文化,但汇聚在一起,却塑造了中文大学的精神面貌。书院是和谐融洽的群体,各有宿舍、饭堂、图书馆及其他设施。书院着重全人发展,举办各种活动,让学生为自己的大学生活添上色彩。

7

上个星期去了趟深圳办理一些银行事务。我在taobao上买的东西,寄到一平那里,正好过去拿。从福田口岸过关后,很方便地直接乘地铁到深大,一平在那里等我。由于刚刚过完国庆,到处仍洋溢着节日气氛,街上每隔几米都有国旗飘扬,十分壮观。在香港完全是没有这种景象的,我很难表达这种复杂的感觉,只能说很“红”。一平想到了一个词帮我解决了这个问题,叫做“很社会主义”。

8

为了某门课程的assignment,这两三天度过了非人的生活。每天晚上奋战到1点多,早晨8点就被自己的意志逼迫醒来,然后一整天都在电脑前coding。其实这是一个group assignment,但是我的partner是一个local,并且原来是EE专业的,没有多少code experience,于是任务就落在了我的头上,他只能帮忙做点debug。更加悲剧的是,刚开始我们沟通都有困难,他不大懂国语,作为自封为普通话传播大使的我,感到压力很大。于是两个中国人用撇脚的英语交流起来。。。

昨晚24点是deadline,从早晨开始我就一直在security lab。这课的TA实在是大好人啊,每次我有问题他都帮忙,甚至亲自debug代码,都是牛人啊。一直搞到晚上10点半,饭都没吃。实在没办法,只好先把代码upload到服务器上了。

最后我出来的时候校巴都停运了,心里还担心要是地铁都停运了就真悲剧了。我只好走山路下去,翻山越岭跋山涉水,反而体验到了别样的校园。昏黄的路灯,斑驳的树影,山泉瀑布,流水潺潺。当然,我也早已听闻中大的物种多样性和武大相比有过之而无不及,武大曾经出现的蜈蚣、蛇之类的,听到周围夜晚不明生物的啼叫,在这里恐怕指不定还会跳出来什么呢。

好在终于回家了。今天demo的时候,有几个function没有完成,TA还是跟我说:Consider your backgroud, you did quite good.我说本来可以完成的,最后没时间了。TA说Next time, start early.想想也是,国庆还跑去澳门玩,之前完全没有考虑到工作量这么大。如释重负后,想了句诗:“日写代码三千行,不辞长作CS人。”

9

今天因为某炸药奖而敏感。地铁上的新闻画面,被暴力剥夺采访权的记者,“再不滚信不信我揍你?”当局令人生厌的丑恶嘴脸,自己因这样的祖国而无地自容。国内各大门户依然毫无音讯一片歌舞升平。

于是我开始思考,关于自由的话题。十八世纪的启蒙思想家伏尔泰曾说过:“我不同意你说的话,但我誓死捍卫你说话的权利”。它为民主在理论上划定一个界限,为我们描述了理想中的民主社会公民实现自己话语权的自然状态。但是,我们果真能达到这样一种状态吗?一、假设你是在对跟你一样的普通民众这样说话,那你手中有什么权力来保障其他民众自由说话的权利?你拥有这个资格吗? 二、假设你是在对当权者说这句话,那实际上就是对专制统治的授权和确认。于是在当前语境下这句话变得十分吊诡。

前天我们CUHK 10CS MSC的群突然热闹了一番,不知怎么谈到精英政治。Kris问我是否相信精英政治,我一口否决“并不存在绝对的精英”。什么是精英政治?香港是典型,说白了只是少数人掌控多数人的权利,愚弄大多数。赟哥道,“你要相信,在中国这么恶劣的政治环境下,能在政治这条路走远的绝对素质很高”。说,现在国家部委已经完全精英化了。每个大员都通三四国英语,学历都是正牌硕士以上,而且还是海归。大家头脑清晰,反应灵活,判断准确,清廉奉公,对现实有相当程度的认知,并且有足够能力执行合理政策。说,决策层都是OK的,只是地方官员和执行层太蠢太自私?那为什么每天那么多人怀疑国家最重大的政策呢?为什么***呢?我就说现在根本就不是精英政治,中国搞政治的都是投机分子。

有句话叫做“屁股决定脑袋”。

10

新学期了,刚来学校的两天没事,就在图书馆闲逛。上学期借过一本《李光耀回忆录》,是CUHK的推荐书目之一,介绍了新加坡的历史。李光耀写道:“一些国家原本就独立,一些国家争取到独立,新加坡的独立却是强加在它头上的……”读过几段不禁感慨,小国家大人物都有其艰辛的过往。只是繁体字看得还是有一点阅读障碍。还有很多文革的书,恐怕无法通过wall的审查在此不予细述。总体感觉就是,图书馆2楼一大片书架,全是禁书。。。

看了一天的书,有部《年鉴》系列挺有意思,是TW采编的关于我国的年度总结,每年一本,分门别类列出本年政治、经济、文化、军事、外交等等,极其详细。例如政治方面,从中央到地方谁谁谁卸任谁谁谁接替,外交方面涛哥某年某月某日和奥巴马通电话讨论了***。翻一下90年代的,负面报道居多,感受到相当的敌对口吻,大陆人民生活在水深火热之中。风水轮流转,大陆现在国力逐渐强大,特别是最近几年的《年鉴》,基本都是客观评述了。有一点感动是凡是涉及中国的词,他们都替换为中共。例如“2010年中国的外交” -> “2010年中共的外交”。TW当局是什么意思不言自明。

我细读了一些民国的前半部分历史,也就是辛亥前后北洋初期。国父几番革命推翻清朝,却妥协让袁世凯做总统,袁复辟中华帝国想当皇帝,又革命,后面段祺瑞和黎元洪又打得不可开交,真是tmd一片混乱……今年是辛亥100年,不知武汉会有怎样的纪念活动。前两天分享过TW的纪念广告视频(原谅我提供的Youtube链接,国内的视频网站上都被删除了),倒是十分感动。民国社会能发展到今天这般模样,实乃不易。

11

今天是星期六,出门的时候室友突然说:“糟了,忘记带零钱!”我问:“要干嘛?”室友说:“今天是星期六啊!”

原来,每当周末,香港的街上、火车站到处都有中学生募捐。每人胸前一个小箱子,如果你投个1元或者2元的硬币进去,他们就在你身上贴上一张小贴纸,表示你已经行善,然后就再没有其他中学生来找你捐钱。每周如此,每个人身上都贴着这样一个小贴纸,这已经成为整个社会的风气。

《新周刊》上最近有篇文章提到中国中产正在塌陷,中产正由“敏感阶层”转化到“愤怒阶层”。“让仇富者停止相互攻击的最好办法就是慈善。”这似乎越来越成为的一个突出问题,因为中国社会缺乏这种风气。说到慈善或者慈善家,我们往往觉得这是那些有钱企业家的事情,it is non of my business。然而可悲的是在国内就连那些富人,都在想着如何将资产转移到海外,如何移民逃离这个国度。或者没有一个具有公信力的组织,让人安心自己所捐会最终到达那些真正需要帮助的人手上。

香港人信奉基督,我遇到过好几次传教的。由于有自己的信仰,我礼貌回绝了很多教会的活动。但是我相信,真正的慈善,往往在这每周的一块钱两块钱里。

12

想当年在武大的时候,办了个ICBC学生卡仅仅1000元的信用额度。HK的银行十分慷慨,给我们学生这样的毫无收入人群发卡都给了8000额度的信用,并且逢年过节还有很多礼品赠送。

室友春节期间回了家,忘记了HK的信用卡里有300多的欠款要还。结果放完假回来收到账单,被罚了180元。仅仅因为还款迟了几天。

另一个故事是我们的一位老师在网上pay income tax,错选了没有足够余额的account去支付,而他自己却不知道,以为成功转账。结果第二个月,HK政府警告他没有纳税,罚了1000多。

信用在一个成熟社会真的是一件极其重要的事情。

13

日本发生大地震,并引发了海啸。紧接着便是核电站危机。

这两天媒体全在铺天盖地地关注着这场灾难以及事件的进展,网络上却开始出现各种声音。阴谋论者开始渲染地震是核试验引发的,日本早已储备核弹云云,各种反日分子开始幸灾乐祸说他们咎由自取,甚至连对灾难表示同情的人都遭到谩骂。

连街头小偷都不敢呵斥却高呼要灭掉小日本,我无法理解这些人的阴暗心理。作为一个普通人类,我只是在看到海啸淹没村庄的画面时感到痛心不已,人类在大自然面前显得多么渺小。日本媒体应急响应的速度让人感动,普通人的冷静沉着也令人钦佩。可笑的是,日本发生这么严重的事件一样秩序井然,一海之隔的中国却自己乱了起来。忽然就谣言四起,忽然超市里的食盐就被抢购一空。由此可见,大部分国人的科学素养仍旧很低,缺乏独立思考和对事物的判断能力。五四新文化运动已经过去90多年了,德先生,赛先生还没有成为中国人的朋友,五四,传到我们这里,只剩下一个青年节。对于那些谣言,我现在才理解了造谣者。当发生群体反应时,不管理性者多么深刻地理解这谣言的荒诞,也无法置身事外。因为群体已然影响了自己正常的生活,于是也只好加入这操蛋的疯狂中。与此同时,显然已经有“灾难投资者”们从中获利,呼啸而去。

1933年,富兰克林·德拉诺·罗斯福在大萧条时期就职美国总统,为了鼓舞民众,他在演讲中说到:“我们唯一值得恐惧的是恐惧本身。一种莫名其妙、丧失理智的、毫无根据的恐惧,它把人转退为进所需的种种努力化为泡影。”这或许也是当前最真实的写照。

14

最近HK政府被公立医院的抗议搞得焦头烂额。

事情要从十几年前的庄丰源案说起。庄丰源,一个1997年9月出生的孩子。他的父母都是内地人,赴港探亲期间生下了他,后一直由拥有香港居留权的祖父照顾。香港政府入境处根据《入境条例》,“在香港出生的中国公民若要成为永久性居民,则在其出生时或以后任何时间,其父母的任何一方必须已在香港定居或已享有香港居留权”为由,要将庄丰源遣返回内地。但根据《香港特区基本法》第二十四条,“在香港特别行政区成立以前或以后在香港出生的中国公民”可判定为香港永久性居民。司法界引发了争议,甚至后来要求人大释法。说实话,我现在仍然看不懂那些条文,特别是关于国籍解释的那一段。

庄丰源的祖父提起了诉讼,2001年,香港高等法院和香港终审法院相继裁定庄丰源胜诉,不论其父母是否已在港定居,在香港出生的中国籍子女都享有居港权。此案为内地孕妇赴港产子打开了大门。

2003年中国逐渐推出香港自由行政策,更多的孕妇可以通过旅行签证来往香港,这也逐渐催生了众多专业的赴港产子公司,提供出入境、医院预约等一条龙服务。由于拥有香港永久居民身份即可享受一系列资本主义福利,又不用计划生育,更不用说香港的教育和护照,于是来港分娩的人暴涨。医院的床位不够了,政府也头疼流动人口管理。之前很多人都是生完孩子就带回内地,只求一个香港身份。政府要不要为这些新生港人编制房屋预算?学校要不要考虑扩招应对未来纷涌而至的学童?这些都成为了问题。特别是医院,已经严重影响香港本地人的医疗服务,医生们每天工作24小时都接生不够,医生们愤怒了,开始骂政府了……

这些争议无不显示了香港人的身份危机。回归以前,香港与内地的交往不多。香港学校教授的中国历史,清朝之后的历史就没有了,新中国的发展更是一片空白,对于新一代来说,国家观念非常模糊。令人欣慰的是,以我的观察,香港人的国家意识正逐渐形成,或许是因为潜移默化的教育,即使很多人对中央政府持不同政见,当地居民亦开始认同自己也是中国人。这样的事情会慢慢在对岸上演吗?

15

很多人以为香港人均收入很高,属于“发达国家/地区”行列。其实,大部分民众的生活远没有想象中那般优越,普通老百姓同样也是蜗居在小小的房屋里,每天柴米油盐。住在上亿元的海滨别墅里的富人毕竟是少数。

可以说,香港的贫富差距是很大的。一般人唾手可得的物质,对低收入家庭却是来之不易。很多港产电影,例如《岁月神偷》、《老港正传》都描述了社会底层人民的平凡生活。但是,为什么香港能够保持稳定,人们尚能安居乐业?很多时候我们谈到中国的诸多问题,都归咎于国情,什么是国情?国情就是人多,要解决13亿人的问题不可谓不复杂,然而,香港的人口估计已超700万,是世界上人口密度最大的地方,“港人治港”是怎样做到的呢?

内地媒体多渲染香港政府公务员廉洁高效,说16.5万公务员,只有20余辆高官专车,访问外地仅乘坐经济舱出行,甚至特首参与世博会活动都是自掏腰包,诸如此类。这只是其中一个方面。更重要的,是整个社会的素质,社会各界对弱势群体生活状况的关心。若有社会资源分配失衡,立刻有媒体呐喊,立刻有议员在议会提案。

说到底,还是个体制。

END

本文可能持续更新。

猜你可能也喜欢:

乱弹与CUHK教授的晚宴

香港求职二三事

跨浏览器兼容 HTML5 Placeholder 的 jQuery 插件

Microsoft AJAX Translation WordPress Plugin

Google Earth为Android 3.0平板设备发布优化更新
无觅
]]>
博主按:文章起始于2年前,主要是自己在香港求学、生活的点滴体会。断断续续地写,小段的短文拼起来就成了现在这个样子。我也阅读很多博客,比如阮一峰,比如王建硕,在每天面对代码工作之余,充满理性和智慧文字总能带给自己内心的愉悦。我开始决定尘埃落定博客的转型,不再只发技术文,也开始分享自己关于社会、人生的一些感悟和思考。

以下为正文。

从今天开始,记录HK生活。兼思考社会主义中国和资本主义中国的不同。

1

CUHK的校车是免费的。今天上车后人快坐满了还没开车,回头一看,后面发生了争执。原来是一位女士上车时没有出示证件,校巴交通组的admin在交涉:“Madam, could you please show your CU staff card?”其实平时都没人查的,今天不知道为什么查了。那位女士没有ID card,不耐烦地说“i forget. it’s not convenient…”但是这位admin执意要ID card:“are you staff in CU?”看样子是要赶人下车了。这已经耽误大家的时间了。这时,坐我前面的一位同学说话了:”excuse me, she is my professor. i’m student in her lab.”这是个善意的谎言。“OK, I trust you. next time, please wear your CU card.”

我居然有一点点感动了。据说在美国,有一种“无罪推定”的社会空气,人在潜意识中不会主动怀疑别人(更准确的说,是美国人觉得由于多疑而去调查,付出的成本,比相信而被骗,付出的成本更高。)我有一次买饮料,两瓶收了三瓶的钱,和售货员说,她看都没看就退了钱。对人的信任是文明的表现,但也给人钻空子的机会,比如有些华人学生,为了获得更高的信用额度,对银行说自己是PR(永久居民permenent resident),有的为了获取更高的退税,在报税材料上取巧。

2

室友买了3台iphone4,全是准备为国内的朋友带的。其实就是走私,但是海关一般也懒得查。香港有很多学生干这种事情,听说还有一个女生买了200台ipad,净赚2W。一是因为香港的便宜,二是国内的卖断货了买不到,而且功能上有诸多限制(例如wifi)。然后,到了深圳,室友改了人人网状态:“一般犯罪后都会有快感,比如过关成功……”

3

地铁上有电视屏幕,会滚动播放即时新闻。今天看到一个新闻说香港gov准备申办2023年的亚运会,征求民众意见,遭到主要政党反对,立法会三大政党都表明不支持的立场。民众主要关心的是对经济、生活的影响等很实际的point,而不是形象面子,“有钱还不如投在民生上”。这和中国只有一种声音有很大不同,因为有真理部,而官方也会朝那个方向引导,导致很多不明真相的群众其实利益受到损害也还很傻很天真地说,我支持***。

update: 终于,香港亚运申办被否决。昨晚上课的时候老师还聊到,it is impossible in China. In China, government is the king. 而在香港为了实现所谓的民主,花费了大量的时间和精力在议案的辩论审核上,这也是民主的弊端之一。

4

在学校上课,其实是一件很爽的事情。教授们都很有激情,老师和学生都很enjoy,看得出来为一节课做了很多准备。和大陆高校的很多老师照着放映的PPT念不同,这边的教学比较互动,学生可以随时打断老师提问。老师有时甚至会故意设置这种场景,例如有一位老师经常的伎俩就是:“any questions? there must be some questions.”而等有学生顺着他的思路提问后,他则大加赞赏“good question! actually i am just waiting for this question. haha~~”

香港的教授都有很牛逼的背景,随便抓一个就是哥伦比亚或者斯坦福phd,给我们上课的就有ACM和IEEE Fellow。其实越是牛逼的教授越是平易近人,我可以很随意地提问、探讨。相反不怎么牛的,比如某个老师,反而给我一些刻薄的印象。

5

香港拥有世界上最成功、最广泛使用的智能电子缴费系統。「八達通」作为一种非接触式智能卡已应用于差不多所有公共交通系统(地铁、公交、的士、轮船),以及许多零售商店、食肆及便利店。这是真正的全城一卡通,在小卖部、打印店都可以使用,比银行信用卡更普及,可见香港政府为谋取人民生活便利的推动力。市面上流通的八达通卡及产品逾2000万件,系统每天处理超过1100万次交易,一天交易额达1280万美元。
另一项令我惊讶的科技应用是智能建筑。学校的教学楼、图书馆,统统有部署智能安保系统,刷卡进入。某一间教室或卫生间没有人的时候,会自动关闭照明、空调以节能,并在来人后自动感应,开启相关设施。

6

今天是中文大学的undergraduate orientation day,相当于武大的校园开放日吧。学校里布置得十分热闹,到处都是展台,还有热情的“学长学姐”们介绍中大和学科专业。好多对未来满怀憧憬的中学生从一个展台到另外一个展台搜集宣传资料。这不禁让我回想起2年前的时光,于是我也装作新生,搜集了一大袋子各色精美的印刷品,并且装作听懂地听那些学弟学妹们把我当作学弟用粤语在我耳边亲切地介绍。

香港中文大学拥有独特的书院制度,就像联邦制一样。所有学生及教职员除了有各学术学科上之学院(Faculty),尚会各自隶属其中一间书院(College);书院负责专业学科以外之事宜,如通识教育、宿舍、辅导、奖学金等。对许多中大毕业生来说,在书院结识的友伴,书院宿舍内的某次促膝长谈或炽热讨论,都是日后回忆的重要片段。书院是紧密的小群体,师生密切交流,朋辈一同成长。所有中大全日制本科生都可选择一所书院,成为该院的一分子。每所书院都是独树一帜的,有各自的文化,但汇聚在一起,却塑造了中文大学的精神面貌。书院是和谐融洽的群体,各有宿舍、饭堂、图书馆及其他设施。书院着重全人发展,举办各种活动,让学生为自己的大学生活添上色彩。

7

上个星期去了趟深圳办理一些银行事务。我在taobao上买的东西,寄到一平那里,正好过去拿。从福田口岸过关后,很方便地直接乘地铁到深大,一平在那里等我。由于刚刚过完国庆,到处仍洋溢着节日气氛,街上每隔几米都有国旗飘扬,十分壮观。在香港完全是没有这种景象的,我很难表达这种复杂的感觉,只能说很“红”。一平想到了一个词帮我解决了这个问题,叫做“很社会主义”。

8

为了某门课程的assignment,这两三天度过了非人的生活。每天晚上奋战到1点多,早晨8点就被自己的意志逼迫醒来,然后一整天都在电脑前coding。其实这是一个group assignment,但是我的partner是一个local,并且原来是EE专业的,没有多少code experience,于是任务就落在了我的头上,他只能帮忙做点debug。更加悲剧的是,刚开始我们沟通都有困难,他不大懂国语,作为自封为普通话传播大使的我,感到压力很大。于是两个中国人用撇脚的英语交流起来。。。

昨晚24点是deadline,从早晨开始我就一直在security lab。这课的TA实在是大好人啊,每次我有问题他都帮忙,甚至亲自debug代码,都是牛人啊。一直搞到晚上10点半,饭都没吃。实在没办法,只好先把代码upload到服务器上了。

最后我出来的时候校巴都停运了,心里还担心要是地铁都停运了就真悲剧了。我只好走山路下去,翻山越岭跋山涉水,反而体验到了别样的校园。昏黄的路灯,斑驳的树影,山泉瀑布,流水潺潺。当然,我也早已听闻中大的物种多样性和武大相比有过之而无不及,武大曾经出现的蜈蚣、蛇之类的,听到周围夜晚不明生物的啼叫,在这里恐怕指不定还会跳出来什么呢。

好在终于回家了。今天demo的时候,有几个function没有完成,TA还是跟我说:Consider your backgroud, you did quite good.我说本来可以完成的,最后没时间了。TA说Next time, start early.想想也是,国庆还跑去澳门玩,之前完全没有考虑到工作量这么大。如释重负后,想了句诗:“日写代码三千行,不辞长作CS人。”

9

今天因为某炸药奖而敏感。地铁上的新闻画面,被暴力剥夺采访权的记者,“再不滚信不信我揍你?”当局令人生厌的丑恶嘴脸,自己因这样的祖国而无地自容。国内各大门户依然毫无音讯一片歌舞升平。

于是我开始思考,关于自由的话题。十八世纪的启蒙思想家伏尔泰曾说过:“我不同意你说的话,但我誓死捍卫你说话的权利”。它为民主在理论上划定一个界限,为我们描述了理想中的民主社会公民实现自己话语权的自然状态。但是,我们果真能达到这样一种状态吗?一、假设你是在对跟你一样的普通民众这样说话,那你手中有什么权力来保障其他民众自由说话的权利?你拥有这个资格吗? 二、假设你是在对当权者说这句话,那实际上就是对专制统治的授权和确认。于是在当前语境下这句话变得十分吊诡。

前天我们CUHK 10CS MSC的群突然热闹了一番,不知怎么谈到精英政治。Kris问我是否相信精英政治,我一口否决“并不存在绝对的精英”。什么是精英政治?香港是典型,说白了只是少数人掌控多数人的权利,愚弄大多数。赟哥道,“你要相信,在中国这么恶劣的政治环境下,能在政治这条路走远的绝对素质很高”。说,现在国家部委已经完全精英化了。每个大员都通三四国英语,学历都是正牌硕士以上,而且还是海归。大家头脑清晰,反应灵活,判断准确,清廉奉公,对现实有相当程度的认知,并且有足够能力执行合理政策。说,决策层都是OK的,只是地方官员和执行层太蠢太自私?那为什么每天那么多人怀疑国家最重大的政策呢?为什么***呢?我就说现在根本就不是精英政治,中国搞政治的都是投机分子。

有句话叫做“屁股决定脑袋”。

10

新学期了,刚来学校的两天没事,就在图书馆闲逛。上学期借过一本《李光耀回忆录》,是CUHK的推荐书目之一,介绍了新加坡的历史。李光耀写道:“一些国家原本就独立,一些国家争取到独立,新加坡的独立却是强加在它头上的……”读过几段不禁感慨,小国家大人物都有其艰辛的过往。只是繁体字看得还是有一点阅读障碍。还有很多文革的书,恐怕无法通过wall的审查在此不予细述。总体感觉就是,图书馆2楼一大片书架,全是禁书。。。

看了一天的书,有部《年鉴》系列挺有意思,是TW采编的关于我国的年度总结,每年一本,分门别类列出本年政治、经济、文化、军事、外交等等,极其详细。例如政治方面,从中央到地方谁谁谁卸任谁谁谁接替,外交方面涛哥某年某月某日和奥巴马通电话讨论了***。翻一下90年代的,负面报道居多,感受到相当的敌对口吻,大陆人民生活在水深火热之中。风水轮流转,大陆现在国力逐渐强大,特别是最近几年的《年鉴》,基本都是客观评述了。有一点感动是凡是涉及中国的词,他们都替换为中共。例如“2010年中国的外交” -> “2010年中共的外交”。TW当局是什么意思不言自明。

我细读了一些民国的前半部分历史,也就是辛亥前后北洋初期。国父几番革命推翻清朝,却妥协让袁世凯做总统,袁复辟中华帝国想当皇帝,又革命,后面段祺瑞和黎元洪又打得不可开交,真是tmd一片混乱……今年是辛亥100年,不知武汉会有怎样的纪念活动。前两天分享过TW的纪念广告视频(原谅我提供的Youtube链接,国内的视频网站上都被删除了),倒是十分感动。民国社会能发展到今天这般模样,实乃不易。

11

今天是星期六,出门的时候室友突然说:“糟了,忘记带零钱!”我问:“要干嘛?”室友说:“今天是星期六啊!”

原来,每当周末,香港的街上、火车站到处都有中学生募捐。每人胸前一个小箱子,如果你投个1元或者2元的硬币进去,他们就在你身上贴上一张小贴纸,表示你已经行善,然后就再没有其他中学生来找你捐钱。每周如此,每个人身上都贴着这样一个小贴纸,这已经成为整个社会的风气。

《新周刊》上最近有篇文章提到中国中产正在塌陷,中产正由“敏感阶层”转化到“愤怒阶层”。“让仇富者停止相互攻击的最好办法就是慈善。”这似乎越来越成为的一个突出问题,因为中国社会缺乏这种风气。说到慈善或者慈善家,我们往往觉得这是那些有钱企业家的事情,it is non of my business。然而可悲的是在国内就连那些富人,都在想着如何将资产转移到海外,如何移民逃离这个国度。或者没有一个具有公信力的组织,让人安心自己所捐会最终到达那些真正需要帮助的人手上。

香港人信奉基督,我遇到过好几次传教的。由于有自己的信仰,我礼貌回绝了很多教会的活动。但是我相信,真正的慈善,往往在这每周的一块钱两块钱里。

12

想当年在武大的时候,办了个ICBC学生卡仅仅1000元的信用额度。HK的银行十分慷慨,给我们学生这样的毫无收入人群发卡都给了8000额度的信用,并且逢年过节还有很多礼品赠送。

室友春节期间回了家,忘记了HK的信用卡里有300多的欠款要还。结果放完假回来收到账单,被罚了180元。仅仅因为还款迟了几天。

另一个故事是我们的一位老师在网上pay income tax,错选了没有足够余额的account去支付,而他自己却不知道,以为成功转账。结果第二个月,HK政府警告他没有纳税,罚了1000多。

信用在一个成熟社会真的是一件极其重要的事情。

13

日本发生大地震,并引发了海啸。紧接着便是核电站危机。

这两天媒体全在铺天盖地地关注着这场灾难以及事件的进展,网络上却开始出现各种声音。阴谋论者开始渲染地震是核试验引发的,日本早已储备核弹云云,各种反日分子开始幸灾乐祸说他们咎由自取,甚至连对灾难表示同情的人都遭到谩骂。

连街头小偷都不敢呵斥却高呼要灭掉小日本,我无法理解这些人的阴暗心理。作为一个普通人类,我只是在看到海啸淹没村庄的画面时感到痛心不已,人类在大自然面前显得多么渺小。日本媒体应急响应的速度让人感动,普通人的冷静沉着也令人钦佩。可笑的是,日本发生这么严重的事件一样秩序井然,一海之隔的中国却自己乱了起来。忽然就谣言四起,忽然超市里的食盐就被抢购一空。由此可见,大部分国人的科学素养仍旧很低,缺乏独立思考和对事物的判断能力。五四新文化运动已经过去90多年了,德先生,赛先生还没有成为中国人的朋友,五四,传到我们这里,只剩下一个青年节。对于那些谣言,我现在才理解了造谣者。当发生群体反应时,不管理性者多么深刻地理解这谣言的荒诞,也无法置身事外。因为群体已然影响了自己正常的生活,于是也只好加入这操蛋的疯狂中。与此同时,显然已经有“灾难投资者”们从中获利,呼啸而去。

1933年,富兰克林·德拉诺·罗斯福在大萧条时期就职美国总统,为了鼓舞民众,他在演讲中说到:“我们唯一值得恐惧的是恐惧本身。一种莫名其妙、丧失理智的、毫无根据的恐惧,它把人转退为进所需的种种努力化为泡影。”这或许也是当前最真实的写照。

14

最近HK政府被公立医院的抗议搞得焦头烂额。

事情要从十几年前的庄丰源案说起。庄丰源,一个1997年9月出生的孩子。他的父母都是内地人,赴港探亲期间生下了他,后一直由拥有香港居留权的祖父照顾。香港政府入境处根据《入境条例》,“在香港出生的中国公民若要成为永久性居民,则在其出生时或以后任何时间,其父母的任何一方必须已在香港定居或已享有香港居留权”为由,要将庄丰源遣返回内地。但根据《香港特区基本法》第二十四条,“在香港特别行政区成立以前或以后在香港出生的中国公民”可判定为香港永久性居民。司法界引发了争议,甚至后来要求人大释法。说实话,我现在仍然看不懂那些条文,特别是关于国籍解释的那一段。

庄丰源的祖父提起了诉讼,2001年,香港高等法院和香港终审法院相继裁定庄丰源胜诉,不论其父母是否已在港定居,在香港出生的中国籍子女都享有居港权。此案为内地孕妇赴港产子打开了大门。

2003年中国逐渐推出香港自由行政策,更多的孕妇可以通过旅行签证来往香港,这也逐渐催生了众多专业的赴港产子公司,提供出入境、医院预约等一条龙服务。由于拥有香港永久居民身份即可享受一系列资本主义福利,又不用计划生育,更不用说香港的教育和护照,于是来港分娩的人暴涨。医院的床位不够了,政府也头疼流动人口管理。之前很多人都是生完孩子就带回内地,只求一个香港身份。政府要不要为这些新生港人编制房屋预算?学校要不要考虑扩招应对未来纷涌而至的学童?这些都成为了问题。特别是医院,已经严重影响香港本地人的医疗服务,医生们每天工作24小时都接生不够,医生们愤怒了,开始骂政府了……

这些争议无不显示了香港人的身份危机。回归以前,香港与内地的交往不多。香港学校教授的中国历史,清朝之后的历史就没有了,新中国的发展更是一片空白,对于新一代来说,国家观念非常模糊。令人欣慰的是,以我的观察,香港人的国家意识正逐渐形成,或许是因为潜移默化的教育,即使很多人对中央政府持不同政见,当地居民亦开始认同自己也是中国人。这样的事情会慢慢在对岸上演吗?

15

很多人以为香港人均收入很高,属于“发达国家/地区”行列。其实,大部分民众的生活远没有想象中那般优越,普通老百姓同样也是蜗居在小小的房屋里,每天柴米油盐。住在上亿元的海滨别墅里的富人毕竟是少数。

可以说,香港的贫富差距是很大的。一般人唾手可得的物质,对低收入家庭却是来之不易。很多港产电影,例如《岁月神偷》、《老港正传》都描述了社会底层人民的平凡生活。但是,为什么香港能够保持稳定,人们尚能安居乐业?很多时候我们谈到中国的诸多问题,都归咎于国情,什么是国情?国情就是人多,要解决13亿人的问题不可谓不复杂,然而,香港的人口估计已超700万,是世界上人口密度最大的地方,“港人治港”是怎样做到的呢?

内地媒体多渲染香港政府公务员廉洁高效,说16.5万公务员,只有20余辆高官专车,访问外地仅乘坐经济舱出行,甚至特首参与世博会活动都是自掏腰包,诸如此类。这只是其中一个方面。更重要的,是整个社会的素质,社会各界对弱势群体生活状况的关心。若有社会资源分配失衡,立刻有媒体呐喊,立刻有议员在议会提案。

说到底,还是个体制。

END

本文可能持续更新。

猜你可能也喜欢:

乱弹与CUHK教授的晚宴

香港求职二三事

跨浏览器兼容 HTML5 Placeholder 的 jQuery 插件

Microsoft AJAX Translation WordPress Plugin

Google Earth为Android 3.0平板设备发布优化更新
无觅
]]>
0
<![CDATA[持续学习]]> http://www.udpwork.com/item/7320.html http://www.udpwork.com/item/7320.html#reviews Fri, 18 May 2012 16:29:36 +0800 fenng http://www.udpwork.com/item/7320.html byFenng@dbanotes.net

知乎上有人说起「科班出身」这个话题,我大致写了一个回复。其实也是前几天我和前同事们分享提到的观点。很多人认为「科班出身」更加专业,而有些野路子半路出家也能做差不多的事情来,于是大家都疑惑,真的是这些人天赋异禀?

以计算机技术来说,大学本科学习的时间,不过四年而已,如果投入工作后,不能持续学习不能持续实践不能开拓思维的话,那么他的专业背景很可能停留在大学毕业那一刻而不再增长。而有些非科班的人,尽管起步阶段的积累不如科班的多,但他可能持续数年依然在学习实践、不停的开拓智域,那么你说,学了四年的人能和学了十年的人相比么?

如果读过《异类》这本书中,应该会对其中提到的「一万小时定律」,要成为某个领域的专家,需要一万小时的训练。大意也是如此。你想尽快成为众人仰慕的牛人,那么只有每天花更多的时间,下更大的功夫。那些牛人也不是一夜之间冒出来的,都是数年积累才可厚积薄发。就拿做产品来说,国内被人津津乐道的人物中,无论是搜索时代的俞军还是移动互联网时代的张小龙,最大的特点就是都够勤奋,肯下功夫。

无他,持续学习尔。跟是否科班没什么关系。只是这个环境中有耐心有恒心的人越来越少了。

--EOF--

最近文章|Recent Articles

本站赞助商:豆瓣网(Douban.com)

评论数(0)|添加评论 | 最近作者还说了什么? FollowFenng@Twitter

DBA Notes 理念: 用简约的技术取得最大的收益...

]]>
byFenng@dbanotes.net

知乎上有人说起「科班出身」这个话题,我大致写了一个回复。其实也是前几天我和前同事们分享提到的观点。很多人认为「科班出身」更加专业,而有些野路子半路出家也能做差不多的事情来,于是大家都疑惑,真的是这些人天赋异禀?

以计算机技术来说,大学本科学习的时间,不过四年而已,如果投入工作后,不能持续学习不能持续实践不能开拓思维的话,那么他的专业背景很可能停留在大学毕业那一刻而不再增长。而有些非科班的人,尽管起步阶段的积累不如科班的多,但他可能持续数年依然在学习实践、不停的开拓智域,那么你说,学了四年的人能和学了十年的人相比么?

如果读过《异类》这本书中,应该会对其中提到的「一万小时定律」,要成为某个领域的专家,需要一万小时的训练。大意也是如此。你想尽快成为众人仰慕的牛人,那么只有每天花更多的时间,下更大的功夫。那些牛人也不是一夜之间冒出来的,都是数年积累才可厚积薄发。就拿做产品来说,国内被人津津乐道的人物中,无论是搜索时代的俞军还是移动互联网时代的张小龙,最大的特点就是都够勤奋,肯下功夫。

无他,持续学习尔。跟是否科班没什么关系。只是这个环境中有耐心有恒心的人越来越少了。

--EOF--

最近文章|Recent Articles

本站赞助商:豆瓣网(Douban.com)

评论数(0)|添加评论 | 最近作者还说了什么? FollowFenng@Twitter

DBA Notes 理念: 用简约的技术取得最大的收益...

]]>
0
<![CDATA[使用 Emacs 微博]]> http://www.udpwork.com/item/7319.html http://www.udpwork.com/item/7319.html#reviews Thu, 17 May 2012 22:05:14 +0800 bigclean http://www.udpwork.com/item/7319.html 作者:Austin_____

简介

“使用 Emacs 的微博”(weibo.emacs)是一个在 Emacs 上使用的微博客户端。它使用 Elisp 语言编写,提供了察看时间线,察看微博及评论,察看图片,发表和转发微博,发表评论和回复的功能。它基于 Emacs,可以在 Windows, Linux 和 Mac 上使用。

功能

察看时间线

提供察看以下时间线的功能

  • 我的关注
  • 我的微博
  • 提到我的
  • 谁在说
  • 我的评论
  • 收到评论

察看微博和评论

提供察看某一条微博和评论的功能

发表微博,发表评论和回复评论

提供发表新微博,对某一条微薄发表评论及回复评论的功能

使用方法

安装

下载

项目主页下载最新的安装包(或者通过 git 更新到最新)。

安装
  • 将安装包解压到某一目录
  • 将该目录添加到load-path:
1
2
(add-to-list 'load-path "目录路径")
(require 'weibo)
配置

不需要配置,可直接使用

使用

开始

通过命令 weibo-timeline 开始察看时间线:M-x weibo-timeline

授权

第一次使用时,将会自动跳转到微博应用授权的页面,登录后确认授权,然后将提示的 pin 码输回 Emacs 的 mini-buffer 即可。

时间线界面

屏幕的最顶端,会出现如下三排提示:

微博:我的关注(a) 我的微博(i) 提到我的(@) 谁在说(w) 我的评论(o) 收到评论(c)

命令:发表微博(P) 察看(L) 转发(T) 评论(C) 回复(R)

操作:新消息(g) 刷新(r) 下一条(空格) 帮助(h) 退出(q)

微博行包括了不同的时间线及它们的切换方法。括号内的按键将在当前窗口显示对应的时间线:如提到我的(@),当按下@键时,将切换提到我的时间线。

命令行包括了可以在时间线中使用的命令。除了发表微博外,其他命令都应将光标移到对应的微博或者评论上使用。

操作行包括了可以在时间线中使用的其他命令,如获取新消息,移到下一条消息,以及退出等等。

切换时间线

使用微博行所提示的按键进行切换。

察看时间线

使用 Emacs 默认的组合键移动光标。此外p,n,b,f键可用来上下左右移动光标。当光标移动到某一条微博或评论时,可按L键察看其对应的微博和最新评论。当微博中有图片时,会在时间线中显示缩略图。将光标移到图片上,按Enter键,会在新窗口中打开原图(按q键退出图片察看)。其他命令如操作中所示。



发表微博

在时间线界面中按P,将出现名为“发表微博”的窗口。在此窗口中编辑你想要发表的微博。完成后,按\C-c\C-c(Ctrl-c, Ctrl-c)提交微博。如果在编辑中想取消发表,按\C-c\C-d将关闭发表窗口(注意:此时你所编辑的内容将消失)。



转发微博

在时间线中,将光标移至某一条微博,按T将出现名为“转发微博”的窗口。此时操作与发表微博类似,完成编辑后,按\C-c\C-c提交微博,按\C-c\C-d取消。

发表评论和回复

在时间线中,按”C”对当前光标所在的微博发表评论。此时将出现“发表评论”窗口,操作与发表微博相似:完成编辑后,按\C-c\C-c提交评论,按\C-c\C-d取消。在微博详情和评论时间线中,按R键可以对评论进行回复。



备注

注意并非所有命令都对所有时间线适用。比如你不能对微博进行回复和对评论进行转发。命令行将之包含当前时间线可用的命令。

问题和建议

如果发现 bug 和有任何建议,请在此处创建 bug 报告或者发邮件给我:austiny.cn(at)gmail.com

分享家:Addthis中国

相关日志

]]>
作者:Austin_____

简介

“使用 Emacs 的微博”(weibo.emacs)是一个在 Emacs 上使用的微博客户端。它使用 Elisp 语言编写,提供了察看时间线,察看微博及评论,察看图片,发表和转发微博,发表评论和回复的功能。它基于 Emacs,可以在 Windows, Linux 和 Mac 上使用。

功能

察看时间线

提供察看以下时间线的功能

  • 我的关注
  • 我的微博
  • 提到我的
  • 谁在说
  • 我的评论
  • 收到评论

察看微博和评论

提供察看某一条微博和评论的功能

发表微博,发表评论和回复评论

提供发表新微博,对某一条微薄发表评论及回复评论的功能

使用方法

安装

下载

项目主页下载最新的安装包(或者通过 git 更新到最新)。

安装
  • 将安装包解压到某一目录
  • 将该目录添加到load-path:
1
2
(add-to-list 'load-path "目录路径")
(require 'weibo)
配置

不需要配置,可直接使用

使用

开始

通过命令 weibo-timeline 开始察看时间线:M-x weibo-timeline

授权

第一次使用时,将会自动跳转到微博应用授权的页面,登录后确认授权,然后将提示的 pin 码输回 Emacs 的 mini-buffer 即可。

时间线界面

屏幕的最顶端,会出现如下三排提示:

微博:我的关注(a) 我的微博(i) 提到我的(@) 谁在说(w) 我的评论(o) 收到评论(c)

命令:发表微博(P) 察看(L) 转发(T) 评论(C) 回复(R)

操作:新消息(g) 刷新(r) 下一条(空格) 帮助(h) 退出(q)

微博行包括了不同的时间线及它们的切换方法。括号内的按键将在当前窗口显示对应的时间线:如提到我的(@),当按下@键时,将切换提到我的时间线。

命令行包括了可以在时间线中使用的命令。除了发表微博外,其他命令都应将光标移到对应的微博或者评论上使用。

操作行包括了可以在时间线中使用的其他命令,如获取新消息,移到下一条消息,以及退出等等。

切换时间线

使用微博行所提示的按键进行切换。

察看时间线

使用 Emacs 默认的组合键移动光标。此外p,n,b,f键可用来上下左右移动光标。当光标移动到某一条微博或评论时,可按L键察看其对应的微博和最新评论。当微博中有图片时,会在时间线中显示缩略图。将光标移到图片上,按Enter键,会在新窗口中打开原图(按q键退出图片察看)。其他命令如操作中所示。



发表微博

在时间线界面中按P,将出现名为“发表微博”的窗口。在此窗口中编辑你想要发表的微博。完成后,按\C-c\C-c(Ctrl-c, Ctrl-c)提交微博。如果在编辑中想取消发表,按\C-c\C-d将关闭发表窗口(注意:此时你所编辑的内容将消失)。



转发微博

在时间线中,将光标移至某一条微博,按T将出现名为“转发微博”的窗口。此时操作与发表微博类似,完成编辑后,按\C-c\C-c提交微博,按\C-c\C-d取消。

发表评论和回复

在时间线中,按”C”对当前光标所在的微博发表评论。此时将出现“发表评论”窗口,操作与发表微博相似:完成编辑后,按\C-c\C-c提交评论,按\C-c\C-d取消。在微博详情和评论时间线中,按R键可以对评论进行回复。



备注

注意并非所有命令都对所有时间线适用。比如你不能对微博进行回复和对评论进行转发。命令行将之包含当前时间线可用的命令。

问题和建议

如果发现 bug 和有任何建议,请在此处创建 bug 报告或者发邮件给我:austiny.cn(at)gmail.com

分享家:Addthis中国

相关日志

]]>
0
<![CDATA[关于logical standy上的DDL/DML修改]]> http://www.udpwork.com/item/7318.html http://www.udpwork.com/item/7318.html#reviews Thu, 17 May 2012 14:58:35 +0800 小荷 http://www.udpwork.com/item/7318.html 在logical standby环境下,备库基本上是一个独立的库,如果要在备库,以非sys用户对备库的数据进行DML修改,就会报错 ora-16224

au10qapap0tels2:ARS2AP:/opt/app/oracle/admin>  oerr ora 16224
16224, 00000, "Database Guard is enabled"
// *Cause: Operation could not be performed because database guard is enabled
// *Action: Verify operation is correct and disable database guard

我们需要在备库做一些操作,以避免报错。

检查备库状态,我们发现是处于standby状态:

SQL>selectguard_statusfromv$database;
 
GUARD_S
-------
STANDBY
 
SQL>

改其状态为none:

SQL>alterdatabaseguardnone;
 
Databasealtered.
 
SQL>
SQL>selectguard_statusfromv$database;
 
GUARD_S
-------
NONE
 
SQL>

让应用开发的同事进行DDL修改,如索引创建。

修改回standby状态:

alterdatabaseguardstandby;

在standby或all状态下,所有非sys用户,都无法对logical standby的数据进行修改,关于alter database guard [standby|all|none] 几个参数的解释如下:

  1. ALTER DATABASE GUARD ALL - prevents users making any changes - DEFAULT
  2. ALTER DATABASE GUARD STANDBY - prevents users making changes to data maintained by data guard sql apply,即对DBMS_LOGSTDBY.SKIP 跳过的表可进行DML操作,而其他需要SQL APPLY的对象都不能进行变更操作。
  3. ALTER DATABASE GUARD NONE - normal security
]]>
在logical standby环境下,备库基本上是一个独立的库,如果要在备库,以非sys用户对备库的数据进行DML修改,就会报错 ora-16224

au10qapap0tels2:ARS2AP:/opt/app/oracle/admin>  oerr ora 16224
16224, 00000, "Database Guard is enabled"
// *Cause: Operation could not be performed because database guard is enabled
// *Action: Verify operation is correct and disable database guard

我们需要在备库做一些操作,以避免报错。

检查备库状态,我们发现是处于standby状态:

SQL>selectguard_statusfromv$database;
 
GUARD_S
-------
STANDBY
 
SQL>

改其状态为none:

SQL>alterdatabaseguardnone;
 
Databasealtered.
 
SQL>
SQL>selectguard_statusfromv$database;
 
GUARD_S
-------
NONE
 
SQL>

让应用开发的同事进行DDL修改,如索引创建。

修改回standby状态:

alterdatabaseguardstandby;

在standby或all状态下,所有非sys用户,都无法对logical standby的数据进行修改,关于alter database guard [standby|all|none] 几个参数的解释如下:

  1. ALTER DATABASE GUARD ALL - prevents users making any changes - DEFAULT
  2. ALTER DATABASE GUARD STANDBY - prevents users making changes to data maintained by data guard sql apply,即对DBMS_LOGSTDBY.SKIP 跳过的表可进行DML操作,而其他需要SQL APPLY的对象都不能进行变更操作。
  3. ALTER DATABASE GUARD NONE - normal security
]]>
0
<![CDATA[剃头]]> http://www.udpwork.com/item/7317.html http://www.udpwork.com/item/7317.html#reviews Thu, 17 May 2012 12:28:22 +0800 Haidong Ji http://www.udpwork.com/item/7317.html 头发长了。吃完晚饭,遛完狗,我骑了洋车子(家乡土话。学名自行车)到镇中心的Hair Cuttery连锁店去理发。

常给我理发的来自越南的华裔女士今天不在。我不在乎发型,我的妆,从来都是清汤挂面,素面朝天,所以就告诉工作人员哪个理发师有空都可以。坐在那儿没几分钟,莎伦剃完了一个后,就给我理发。顺便说一句,进商店、到饭店预约等需要挂个名时,我都摇身一变,自称亚历克斯,能省点麻烦。

莎伦来这个店不到一星期,三四十岁的样子。她之前在Hair Cuttery的另一个连锁店。她说那个店里的发型师有矛盾,玩办公室政治,所以选择离开。其实我感觉这个店也不见得就能好到哪里去,我以前就注意到这儿的发型师们在该谁接电话、扫地等方面逗心眼儿、说风凉话。但话说回来,这东西和人的脾性有关,希望这地儿能和她的意。

就随便聊聊天,开开玩笑。莎伦住的远一点,买不起车,所以上班都是坐公共汽车,要转好几次。现在好一点,但冷天、雪天就不好受。但车也有车的麻烦,她说一想到上班高峰期那么多的车在路上而自己要和他们抢道开时就觉得公交也很不错。她没自己的房子,住公寓,我说那你考虑就近找个公寓住呀,最好一班汽车直达。她说正考虑,偏西北方的公寓可能便宜些。就聊起了网上找公寓的问题,说起有的Craig’s list上好像有变态在上面活跃,挺逗的。理了个平头后,我让她洗了下。理发和洗头共15块美元,我给了3块小费,总共18。

实际上我以为人进化到现在,毛发应当是下一个被淘汰的部件。这玩意儿没大用,碍事不说,还得花钱伺候它。小时候在季庄农村,都是邻居或遛乡的理发师用推子剃头,俺大也借别人的推子自己给我们剃过。遛乡的和镇上的理发室在剃头的同时也提供刮胡子业务。那时刮胡子就用泡沫,我不知那泡沫从哪里来。一般还有皮带子用来磨刮胡刀。

在厦大上学时,记得隔壁宿舍的林凯哥们激我剃光头,我的要求好像是要他请客买单。那是我的第一次光头。来美国后我好像也剃过一次光头,现在记不太清啦。

对于初到美国的中国人,剃头也可以算是个有趣的话题吧。我那会儿,90年代中后期,不少男留学生买个推子,互相帮助解决理发的难题,不知现在怎样。这里有好几个方面的因素吧。语言方面,一些词儿和描述方式会有困难。经济上,当时一换成人民币就是一大笔钱,能省则省。还有就是文化习俗方面也会有影响吧:剃头是一个肢体的接触,里面蕴含着文化习俗上的潜规则,在一个人生地不熟的环境里,让一个和自己种族、语言、文化、风俗等不同的人来摆弄自己的脑袋,心里稍有犯毛是完全可以理解的。我想国际人士初到中国可能也有这方面的挑战吧。慢慢了解熟悉后,就好了。我记不太清我留学时第一次去美国私人理发店花了多少钱,说了什么话,但尴尬和误解肯定有。后来常去那个店,还从店主也是理发员那儿买了辆自行车。

后来谈恋爱成家后,我曾不止一次要求老婆给我剃头,她绝不答应。瑞典理发比较贵,好几十上百美刀,所以她在瑞典时,都是让她姐姐给她做头发。在美国,她没办法,也得去理发厅。她姐姐几年前来过一次美国,还在这儿给她做头发。我爸第一次来美国时,我哥那儿有理发的家什儿,他又给我们哥俩在美国剃了回头,挺好。我想这对于双方,都会有一种亲近和满足吧。

儿子出生后,我们专门买了套剃头的家什儿,就给他用过一次。现在他是上初中的少年,留起长头发来啦!我现在想让他剪剪,但我说不大管用,得让孩娘来做这方面的工作。

]]>
头发长了。吃完晚饭,遛完狗,我骑了洋车子(家乡土话。学名自行车)到镇中心的Hair Cuttery连锁店去理发。

常给我理发的来自越南的华裔女士今天不在。我不在乎发型,我的妆,从来都是清汤挂面,素面朝天,所以就告诉工作人员哪个理发师有空都可以。坐在那儿没几分钟,莎伦剃完了一个后,就给我理发。顺便说一句,进商店、到饭店预约等需要挂个名时,我都摇身一变,自称亚历克斯,能省点麻烦。

莎伦来这个店不到一星期,三四十岁的样子。她之前在Hair Cuttery的另一个连锁店。她说那个店里的发型师有矛盾,玩办公室政治,所以选择离开。其实我感觉这个店也不见得就能好到哪里去,我以前就注意到这儿的发型师们在该谁接电话、扫地等方面逗心眼儿、说风凉话。但话说回来,这东西和人的脾性有关,希望这地儿能和她的意。

就随便聊聊天,开开玩笑。莎伦住的远一点,买不起车,所以上班都是坐公共汽车,要转好几次。现在好一点,但冷天、雪天就不好受。但车也有车的麻烦,她说一想到上班高峰期那么多的车在路上而自己要和他们抢道开时就觉得公交也很不错。她没自己的房子,住公寓,我说那你考虑就近找个公寓住呀,最好一班汽车直达。她说正考虑,偏西北方的公寓可能便宜些。就聊起了网上找公寓的问题,说起有的Craig’s list上好像有变态在上面活跃,挺逗的。理了个平头后,我让她洗了下。理发和洗头共15块美元,我给了3块小费,总共18。

实际上我以为人进化到现在,毛发应当是下一个被淘汰的部件。这玩意儿没大用,碍事不说,还得花钱伺候它。小时候在季庄农村,都是邻居或遛乡的理发师用推子剃头,俺大也借别人的推子自己给我们剃过。遛乡的和镇上的理发室在剃头的同时也提供刮胡子业务。那时刮胡子就用泡沫,我不知那泡沫从哪里来。一般还有皮带子用来磨刮胡刀。

在厦大上学时,记得隔壁宿舍的林凯哥们激我剃光头,我的要求好像是要他请客买单。那是我的第一次光头。来美国后我好像也剃过一次光头,现在记不太清啦。

对于初到美国的中国人,剃头也可以算是个有趣的话题吧。我那会儿,90年代中后期,不少男留学生买个推子,互相帮助解决理发的难题,不知现在怎样。这里有好几个方面的因素吧。语言方面,一些词儿和描述方式会有困难。经济上,当时一换成人民币就是一大笔钱,能省则省。还有就是文化习俗方面也会有影响吧:剃头是一个肢体的接触,里面蕴含着文化习俗上的潜规则,在一个人生地不熟的环境里,让一个和自己种族、语言、文化、风俗等不同的人来摆弄自己的脑袋,心里稍有犯毛是完全可以理解的。我想国际人士初到中国可能也有这方面的挑战吧。慢慢了解熟悉后,就好了。我记不太清我留学时第一次去美国私人理发店花了多少钱,说了什么话,但尴尬和误解肯定有。后来常去那个店,还从店主也是理发员那儿买了辆自行车。

后来谈恋爱成家后,我曾不止一次要求老婆给我剃头,她绝不答应。瑞典理发比较贵,好几十上百美刀,所以她在瑞典时,都是让她姐姐给她做头发。在美国,她没办法,也得去理发厅。她姐姐几年前来过一次美国,还在这儿给她做头发。我爸第一次来美国时,我哥那儿有理发的家什儿,他又给我们哥俩在美国剃了回头,挺好。我想这对于双方,都会有一种亲近和满足吧。

儿子出生后,我们专门买了套剃头的家什儿,就给他用过一次。现在他是上初中的少年,留起长头发来啦!我现在想让他剪剪,但我说不大管用,得让孩娘来做这方面的工作。

]]>
0
<![CDATA[为什么NoSQL和Hadoop该一起使用?]]> http://www.udpwork.com/item/7316.html http://www.udpwork.com/item/7316.html#reviews Thu, 17 May 2012 10:54:22 +0800 Guancheng http://www.udpwork.com/item/7316.html Cloudera和CouchBase最近以“为什么NoSQL和Hadoop该一起使用?”为题做了个主题分享,其中对传统IT架构和Big Data架构做了很好的对比,很值得一看。

冠诚, IBM中国研究院, 研究员
关注大规模分布式系统、并行计算。
任何与多核、并行、多线程有关的话题都可以找我聊聊:-)
我的邮箱是chenguancheng AT gmail.com

相关日志

]]>
Cloudera和CouchBase最近以“为什么NoSQL和Hadoop该一起使用?”为题做了个主题分享,其中对传统IT架构和Big Data架构做了很好的对比,很值得一看。

冠诚, IBM中国研究院, 研究员
关注大规模分布式系统、并行计算。
任何与多核、并行、多线程有关的话题都可以找我聊聊:-)
我的邮箱是chenguancheng AT gmail.com

相关日志

]]>
0
<![CDATA[关于 NetworkManager / PolicyKit / ConsoleKit 的那些屌事]]> http://www.udpwork.com/item/7315.html http://www.udpwork.com/item/7315.html#reviews Thu, 17 May 2012 09:07:00 +0800 log4d http://www.udpwork.com/item/7315.html 在使用 Awesome 的过程中,我又遇到了一个老问题「NetworkManager 在非 Gnome 环境启动后,会无法 添加 / 删除 / 编辑 无线连接」。明眼人一看就知道, 这是权限的问题。

问题描述

我的环境是ArchLinux / xmonad 0.10 / awesome v3.4.11 / GDM 3.4.1 / NetworkManager 0.9.4.0 , 下面我用 awesome 做示例,其他非 Gnome WM 也应该是类似配置。

我的 WM 启动流程是: 通过 GDM 启动 xmonad / awesome,启动 xsession 是/usr/share/xsessions/awesome.desktop, 内容如下

1
2
3
4
5
6
[Desktop Entry]
Name=Awesome
Comment=This session logs you into Awesome
Type=Application
Exec=ck-launch-session dbus-launch $HOME/.start-session.sh awesome
TryExec=/usr/bin/awesome

$HOME/.start-session.sh中的作用是启动nm-appletexec awesome

启动之后的情况是 NetworkManager 无线 编辑/删除 按钮变灰无法点击,或者可以点击, 但是会发生insufficient privileges 错误。

insufficient privileges

问题原因

这个问题是由 PolicyKit 和 ConsoleKit 启动不当引起的。

PolicyKit 是:

PolicyKit allows fine-tuned capabilities in desktop enviroment. Traditionally only privilaged user (root) was allowed to configure network. However while in server enviroment it is reasonable assumption it would be too limiting to not allowed to connect to hotspot on laptop. Still however you may not want to give full privilages to this person (like installing programs) or you want to limit options for some people (for example on your children laptops only ‘trusted’ networks with parential filters can be used). As far as I remember it works like:

  • Program send message to daemon via dbus about action
  • Daemon uses PolicyKit libraries/configuration (in fact PolicyKit daemon) to determine if user is allowed to perform action. It may happen that the certain confition must be fullfilled (like entering password or hardware access).
  • Deamon performs action according to it (returns auth error or perform action)

ConsoleKit 是:

In short consolekit is service which tracks user sessions (i.e. where user is logged in). It allows switching users without logging out [many user can be logged in on the same hardware at the same time with one user active]. It is also used to check if session is “local” i.e. if user have direct access to hardware (which may be considered more secure then remote access).

参考:What are ConsoleKit and PolicyKit? How do they work?

所以简而言之,ConsoleKit 是用来管理用户会话的,PolicyKit 是用来处理用户申请特殊权限的, 他们两个经常工作在一起。

有个 PolicyKit 认证 API 教程可以一看:

我的这个问题就是由于 PolicyKit 无法正确授权引起的。

问题解决

我开始吭次吭次的 Google,一会就找到了 Arch Wiki 中NetworkManager的解决办法:

1
exec ck-launch-session dbus-launch wm

写的很清楚,使用ck-launch-sessiondbus-launch 来加载 WM。但是我已经使用ck-launch-session来启动 WM 了。

随后我把怀疑的目光放到/usr/lib/polkit-gnome/polkit-gnome-authentication-agent-1这个程序给系统提供 PolicyKit 权限认证,请求时候会让用户输入密码,如下图:

PolicyKit Agent

可惜还是不行。

我甚至还参考Using gnome keyring in xmonad试图手工建立一个 Gnome Keyring。事实证明,Gnome Keyring 和这个问题无关。

最后,我用ck-list-sessions命令查看运行的用户 Session,发现同时运行着两个, 一个处于Active,一个不处于Active,这下真相大白了:GDM 启动时候会自己启动ck-launch-session,不用自己手动启动,否则会造成两个会话而无法正确授权。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
Session2:
  unix-user = '1000'
  realname = 'Jason Ti'
  seat = 'Seat1'
  session-type = ''
  active = TRUE
  x11-display = ':0'
  x11-display-device = '/dev/tty7'
  display-device = ''
  remote-host-name = ''
  is-local = TRUE
  on-since = '2012-05-17T00:54:31.706019Z'
  login-session-id = '2'
Session3:
  unix-user = '1000'
  realname = 'Jason Ti'
  seat = 'Seat1'
  session-type = ''
  active = False
  x11-display = ':0'
  x11-display-device = '/dev/tty7'
  display-device = ''
  remote-host-name = ''
  is-local = TRUE
  on-since = '2012-05-17T00:54:33.3465302Z'
  login-session-id = '2'

修正/usr/share/xsessions/awesome.desktop如下:

1
2
3
4
5
6
[Desktop Entry]
Name=Awesome
Comment=This session logs you into Awesome
Type=Application
Exec=$HOME/.start-session.sh awesome
TryExec=/usr/bin/awesome

事实上,在启动完 GDM 还没进入 WM 之前,Ctrl+Alt+F1切换到命令行下面,查看进程会发现

1
2
3
root       637     1  0 08:44 ?        00:00:00 /usr/lib/polkit-1/polkitd --no-debug
root      1072     1  0 08:44 ?        00:00:00 /usr/sbin/console-kit-daemon --no-daemon
rtkit     1260     1  0 08:45 ?        00:00:00 /usr/lib/rtkit-daemon

果不其然,PolicyKit 和 ConsoleKit 已经在运行了。

实测 Awesome / Xmonad 已经可以正常授权 NetworkManager 来编辑无线了。

]]>
在使用 Awesome 的过程中,我又遇到了一个老问题「NetworkManager 在非 Gnome 环境启动后,会无法 添加 / 删除 / 编辑 无线连接」。明眼人一看就知道, 这是权限的问题。

问题描述

我的环境是ArchLinux / xmonad 0.10 / awesome v3.4.11 / GDM 3.4.1 / NetworkManager 0.9.4.0 , 下面我用 awesome 做示例,其他非 Gnome WM 也应该是类似配置。

我的 WM 启动流程是: 通过 GDM 启动 xmonad / awesome,启动 xsession 是/usr/share/xsessions/awesome.desktop, 内容如下

1
2
3
4
5
6
[Desktop Entry]
Name=Awesome
Comment=This session logs you into Awesome
Type=Application
Exec=ck-launch-session dbus-launch $HOME/.start-session.sh awesome
TryExec=/usr/bin/awesome

$HOME/.start-session.sh中的作用是启动nm-appletexec awesome

启动之后的情况是 NetworkManager 无线 编辑/删除 按钮变灰无法点击,或者可以点击, 但是会发生insufficient privileges 错误。

insufficient privileges

问题原因

这个问题是由 PolicyKit 和 ConsoleKit 启动不当引起的。

PolicyKit 是:

PolicyKit allows fine-tuned capabilities in desktop enviroment. Traditionally only privilaged user (root) was allowed to configure network. However while in server enviroment it is reasonable assumption it would be too limiting to not allowed to connect to hotspot on laptop. Still however you may not want to give full privilages to this person (like installing programs) or you want to limit options for some people (for example on your children laptops only ‘trusted’ networks with parential filters can be used). As far as I remember it works like:

  • Program send message to daemon via dbus about action
  • Daemon uses PolicyKit libraries/configuration (in fact PolicyKit daemon) to determine if user is allowed to perform action. It may happen that the certain confition must be fullfilled (like entering password or hardware access).
  • Deamon performs action according to it (returns auth error or perform action)

ConsoleKit 是:

In short consolekit is service which tracks user sessions (i.e. where user is logged in). It allows switching users without logging out [many user can be logged in on the same hardware at the same time with one user active]. It is also used to check if session is “local” i.e. if user have direct access to hardware (which may be considered more secure then remote access).

参考:What are ConsoleKit and PolicyKit? How do they work?

所以简而言之,ConsoleKit 是用来管理用户会话的,PolicyKit 是用来处理用户申请特殊权限的, 他们两个经常工作在一起。

有个 PolicyKit 认证 API 教程可以一看:

我的这个问题就是由于 PolicyKit 无法正确授权引起的。

问题解决

我开始吭次吭次的 Google,一会就找到了 Arch Wiki 中NetworkManager的解决办法:

1
exec ck-launch-session dbus-launch wm

写的很清楚,使用ck-launch-sessiondbus-launch 来加载 WM。但是我已经使用ck-launch-session来启动 WM 了。

随后我把怀疑的目光放到/usr/lib/polkit-gnome/polkit-gnome-authentication-agent-1这个程序给系统提供 PolicyKit 权限认证,请求时候会让用户输入密码,如下图:

PolicyKit Agent

可惜还是不行。

我甚至还参考Using gnome keyring in xmonad试图手工建立一个 Gnome Keyring。事实证明,Gnome Keyring 和这个问题无关。

最后,我用ck-list-sessions命令查看运行的用户 Session,发现同时运行着两个, 一个处于Active,一个不处于Active,这下真相大白了:GDM 启动时候会自己启动ck-launch-session,不用自己手动启动,否则会造成两个会话而无法正确授权。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
Session2:
  unix-user = '1000'
  realname = 'Jason Ti'
  seat = 'Seat1'
  session-type = ''
  active = TRUE
  x11-display = ':0'
  x11-display-device = '/dev/tty7'
  display-device = ''
  remote-host-name = ''
  is-local = TRUE
  on-since = '2012-05-17T00:54:31.706019Z'
  login-session-id = '2'
Session3:
  unix-user = '1000'
  realname = 'Jason Ti'
  seat = 'Seat1'
  session-type = ''
  active = False
  x11-display = ':0'
  x11-display-device = '/dev/tty7'
  display-device = ''
  remote-host-name = ''
  is-local = TRUE
  on-since = '2012-05-17T00:54:33.3465302Z'
  login-session-id = '2'

修正/usr/share/xsessions/awesome.desktop如下:

1
2
3
4
5
6
[Desktop Entry]
Name=Awesome
Comment=This session logs you into Awesome
Type=Application
Exec=$HOME/.start-session.sh awesome
TryExec=/usr/bin/awesome

事实上,在启动完 GDM 还没进入 WM 之前,Ctrl+Alt+F1切换到命令行下面,查看进程会发现

1
2
3
root       637     1  0 08:44 ?        00:00:00 /usr/lib/polkit-1/polkitd --no-debug
root      1072     1  0 08:44 ?        00:00:00 /usr/sbin/console-kit-daemon --no-daemon
rtkit     1260     1  0 08:45 ?        00:00:00 /usr/lib/rtkit-daemon

果不其然,PolicyKit 和 ConsoleKit 已经在运行了。

实测 Awesome / Xmonad 已经可以正常授权 NetworkManager 来编辑无线了。

]]>
0
<![CDATA[rsync 的核心算法]]> http://www.udpwork.com/item/7314.html http://www.udpwork.com/item/7314.html#reviews Thu, 17 May 2012 08:25:38 +0800 陈皓 http://www.udpwork.com/item/7314.html rsync是unix/linux下同步文件的一个高效算法,它能同步更新两处计算机的文件与目录,并适当利用查找文件中的不同块以减少数据传输。rsync中一项与其他大部分类似程序或协定中所未见的重要特性是镜像是只对有变更的部分进行传送。rsync可拷贝/显示目录属性,以及拷贝文件,并可选择性的压缩以及递归拷贝。rsync利用由Andrew Tridgell发明的算法。这里不介绍其使用方法,只介绍其核心算法。我们可以看到,Unix下的东西,一个命令,一个工具都有很多很精妙的东西,怎么学也学不完,这就是Unix的文化啊。

本来不想写这篇文章的,因为原先发现有很多中文blog都说了这个算法,但是看了一下,发现这些中文blog要么翻译国外文章翻译地非常烂,要么就是介绍这个算法介绍得很乱让人看不懂,还有错误,误人不浅,所以让我觉得有必要写篇rsync算法介绍的文章。(当然,我成文比较仓促,可能会有一些错误,请指正)

问题

首先, 我们先来想一下rsync要解决的问题,如果我们要同步的文件只想传不同的部分,我们就需要对两边的文件做diff,但是这两个问题在两台不同的机器上,无法做diff。如果我们做diff,就要把一个文件传到另一台机器上做diff,但这样一来,我们就传了整个文件,这与我们只想传输不同部的初衷相背。

于是我们就要想一个办法,让这两边的文件见不到面,但还能知道它们间有什么不同。这就出现了rsync的算法。

算法

rsync的算法如下:(假设我们同步源文件名为fileSrc,同步目的文件叫fileDst

1)分块Checksum算法 。首先,我们会把fileDst的文件平均切分成若干个小块,比如每块512个字节(最后一块会小于这个数),然后对每块计算两个checksum,

  • 一个叫rolling checksum,是弱checksum,32位的checksum,其使用的是Mark Adler发明的adler-32算法,
  • 另一个是强checksum,128位的,以前用md4,现在用md5 hash算法。

为什么要这样?因为若干年前的硬件上跑md4的算法太慢了,所以,我们需要一个快算法来鉴别文件块的不同,但是弱的adler32算法碰撞概率太高了,所以我们还要引入强的checksum算法以保证两文件块是相同的。也就是说,弱的checksum是用来区别不同,而强的是用来确认相同 。(checksum的具体公式可以参看这篇文章

2)传输算法。 同步目标端会把fileDst的一个checksum列表传给同步源,这个列表里包括了三个东西,rolling checksum(32bits)md5 checksume(128bits)文件块编号

我估计你猜到了同步源机器拿到了这个列表后,会对fileSrc做同样的checksum,然后和fileDst的checksum做对比,这样就知道哪些文件块改变了。

但是,聪明的你一定会有以下两个疑问:

  • 如果我fileSrc这边在文件中间加了一个字符,这样后面的文件块都会位移一个字符,这样就完全和fileDst这边的不一样了,但理论上来说,我应该只需要传一个字符就好了。这个怎么解决?
  • 如果这个checksum列表特别长,而我的两边的相同的文件块可能并不是一样的顺序,那就需要查找,线性的查找起来应该特别慢吧。这个怎么解决?

很好,让我们来看一下同步源端的算法。

3)checksum查找算法 。同步源端拿到fileDst的checksum数组后,会把这个数据存到一个hash table中,用rolling checksum做hash,以便获得O(1)时间复杂度的查找性能。这个hash table是16bits的,所以,hash table的尺寸是2的16次方,对rolling checksum的hash会被散列到0 到 2^16 – 1中的某个整数值。(对于hash table,如果你不清楚,建议回去看大学时的数据结构教科书)

顺便说一下,我在网上看到很多文章说,“要对rolling checksum做排序”(比如这篇这篇),这两篇文章都引用并翻译了原作者的这篇文章,但是他们都理解错了,不是排序,就只是把fileDst的checksum数据,按rolling checksum做存到2^16的hash table中,当然会发生碰撞,把碰撞的做成一个链表就好了。这就是原文中所说的第二步——搜索有碰撞的情况。

4)比对算法 。这是最关键的算法,细节如下:

4.1)取fileSrc的第一个文件块(我们假设的是512个长度),也就是从fileSrc的第1个字节到第512个字节,取出来后做rolling checksum计算。计算好的值到hash表中查。

4.2)如果查到了,说明发现在fileDst中有潜在相同的文件块,于是就再比较md5的checksum,因为rolling checksume太弱了,可能发生碰撞。于是还要算md5的128bits的checksum,这样一来,我们就有 2^-(32+128) = 2^-160的概率发生碰撞,这太小了可以忽略。如果rolling checksum和md5 checksum都相同,这说明在fileDst中有相同的块,我们需要记下这一块在fileDst下的文件编号

4.3)如果fileSrc的rolling checksum 没有在hash table中找到,那就不用算md5 checksum了。表示这一块中有不同的信息。总之,只要rolling checksum 或 md5 checksum 其中有一个在fileDst的checksum hash表中找不到匹配项,那么就会触发算法对fileSrc的rolling动作。于是,算法会住后step 1个字节,取fileSrc中字节2-513的文件块要做checksum,go to (4.1) - 现在你明白什么叫rolling checksum了吧。

4.4)这样,我们就可以找出fileSrc相邻两次匹配中的那些文本字符,这些就是我们要往同步目标端传的文件内容了。

图示

怎么,你没看懂? 好吧,我送佛送上西,画个示意图给你看看(对图中的东西我就不再解释了)。

这样,最终,在同步源这端,我们的rsync算法可能会得到下面这个样子的一个数据数组,图中,红色块表示在目标端已匹配上,不用传输(注:我专门在其中显示了两块chunk #5,相信你会懂的),而白色的地方就是需要传输的内容(注意:这些白色的块是不定长的),这样,同步源这端把这个数组(白色的就是实际内容,红色的就放一个标号)压缩传到目的端,在目的端的rsync会根据这个表重新生成文件,这样,同步完成。

最后想说一下,对于某些压缩文件使用rsync传输可能会传得更多,因为被压缩后的文件可能会非常的不同。对此,对于gzip和bzip2这样的命令,记得开启 “rsyncalbe” 模式。

(全文完,转载时请注明作者和出处

您可能也喜欢:

Linux/Unix 新手和专家教程

高级Unix命令

Unix 40年:昨天,今天和明天

用Unix的设计思想来应对多变的需求

Unix 40年:Unix年鉴
无觅

相关文章

]]>
rsync是unix/linux下同步文件的一个高效算法,它能同步更新两处计算机的文件与目录,并适当利用查找文件中的不同块以减少数据传输。rsync中一项与其他大部分类似程序或协定中所未见的重要特性是镜像是只对有变更的部分进行传送。rsync可拷贝/显示目录属性,以及拷贝文件,并可选择性的压缩以及递归拷贝。rsync利用由Andrew Tridgell发明的算法。这里不介绍其使用方法,只介绍其核心算法。我们可以看到,Unix下的东西,一个命令,一个工具都有很多很精妙的东西,怎么学也学不完,这就是Unix的文化啊。

本来不想写这篇文章的,因为原先发现有很多中文blog都说了这个算法,但是看了一下,发现这些中文blog要么翻译国外文章翻译地非常烂,要么就是介绍这个算法介绍得很乱让人看不懂,还有错误,误人不浅,所以让我觉得有必要写篇rsync算法介绍的文章。(当然,我成文比较仓促,可能会有一些错误,请指正)

问题

首先, 我们先来想一下rsync要解决的问题,如果我们要同步的文件只想传不同的部分,我们就需要对两边的文件做diff,但是这两个问题在两台不同的机器上,无法做diff。如果我们做diff,就要把一个文件传到另一台机器上做diff,但这样一来,我们就传了整个文件,这与我们只想传输不同部的初衷相背。

于是我们就要想一个办法,让这两边的文件见不到面,但还能知道它们间有什么不同。这就出现了rsync的算法。

算法

rsync的算法如下:(假设我们同步源文件名为fileSrc,同步目的文件叫fileDst

1)分块Checksum算法 。首先,我们会把fileDst的文件平均切分成若干个小块,比如每块512个字节(最后一块会小于这个数),然后对每块计算两个checksum,

  • 一个叫rolling checksum,是弱checksum,32位的checksum,其使用的是Mark Adler发明的adler-32算法,
  • 另一个是强checksum,128位的,以前用md4,现在用md5 hash算法。

为什么要这样?因为若干年前的硬件上跑md4的算法太慢了,所以,我们需要一个快算法来鉴别文件块的不同,但是弱的adler32算法碰撞概率太高了,所以我们还要引入强的checksum算法以保证两文件块是相同的。也就是说,弱的checksum是用来区别不同,而强的是用来确认相同 。(checksum的具体公式可以参看这篇文章

2)传输算法。 同步目标端会把fileDst的一个checksum列表传给同步源,这个列表里包括了三个东西,rolling checksum(32bits)md5 checksume(128bits)文件块编号

我估计你猜到了同步源机器拿到了这个列表后,会对fileSrc做同样的checksum,然后和fileDst的checksum做对比,这样就知道哪些文件块改变了。

但是,聪明的你一定会有以下两个疑问:

  • 如果我fileSrc这边在文件中间加了一个字符,这样后面的文件块都会位移一个字符,这样就完全和fileDst这边的不一样了,但理论上来说,我应该只需要传一个字符就好了。这个怎么解决?
  • 如果这个checksum列表特别长,而我的两边的相同的文件块可能并不是一样的顺序,那就需要查找,线性的查找起来应该特别慢吧。这个怎么解决?

很好,让我们来看一下同步源端的算法。

3)checksum查找算法 。同步源端拿到fileDst的checksum数组后,会把这个数据存到一个hash table中,用rolling checksum做hash,以便获得O(1)时间复杂度的查找性能。这个hash table是16bits的,所以,hash table的尺寸是2的16次方,对rolling checksum的hash会被散列到0 到 2^16 – 1中的某个整数值。(对于hash table,如果你不清楚,建议回去看大学时的数据结构教科书)

顺便说一下,我在网上看到很多文章说,“要对rolling checksum做排序”(比如这篇这篇),这两篇文章都引用并翻译了原作者的这篇文章,但是他们都理解错了,不是排序,就只是把fileDst的checksum数据,按rolling checksum做存到2^16的hash table中,当然会发生碰撞,把碰撞的做成一个链表就好了。这就是原文中所说的第二步——搜索有碰撞的情况。

4)比对算法 。这是最关键的算法,细节如下:

4.1)取fileSrc的第一个文件块(我们假设的是512个长度),也就是从fileSrc的第1个字节到第512个字节,取出来后做rolling checksum计算。计算好的值到hash表中查。

4.2)如果查到了,说明发现在fileDst中有潜在相同的文件块,于是就再比较md5的checksum,因为rolling checksume太弱了,可能发生碰撞。于是还要算md5的128bits的checksum,这样一来,我们就有 2^-(32+128) = 2^-160的概率发生碰撞,这太小了可以忽略。如果rolling checksum和md5 checksum都相同,这说明在fileDst中有相同的块,我们需要记下这一块在fileDst下的文件编号

4.3)如果fileSrc的rolling checksum 没有在hash table中找到,那就不用算md5 checksum了。表示这一块中有不同的信息。总之,只要rolling checksum 或 md5 checksum 其中有一个在fileDst的checksum hash表中找不到匹配项,那么就会触发算法对fileSrc的rolling动作。于是,算法会住后step 1个字节,取fileSrc中字节2-513的文件块要做checksum,go to (4.1) - 现在你明白什么叫rolling checksum了吧。

4.4)这样,我们就可以找出fileSrc相邻两次匹配中的那些文本字符,这些就是我们要往同步目标端传的文件内容了。

图示

怎么,你没看懂? 好吧,我送佛送上西,画个示意图给你看看(对图中的东西我就不再解释了)。

这样,最终,在同步源这端,我们的rsync算法可能会得到下面这个样子的一个数据数组,图中,红色块表示在目标端已匹配上,不用传输(注:我专门在其中显示了两块chunk #5,相信你会懂的),而白色的地方就是需要传输的内容(注意:这些白色的块是不定长的),这样,同步源这端把这个数组(白色的就是实际内容,红色的就放一个标号)压缩传到目的端,在目的端的rsync会根据这个表重新生成文件,这样,同步完成。

最后想说一下,对于某些压缩文件使用rsync传输可能会传得更多,因为被压缩后的文件可能会非常的不同。对此,对于gzip和bzip2这样的命令,记得开启 “rsyncalbe” 模式。

(全文完,转载时请注明作者和出处

您可能也喜欢:

Linux/Unix 新手和专家教程

高级Unix命令

Unix 40年:昨天,今天和明天

用Unix的设计思想来应对多变的需求

Unix 40年:Unix年鉴
无觅

相关文章

]]>
0
<![CDATA[微信架构的启示]]> http://www.udpwork.com/item/7313.html http://www.udpwork.com/item/7313.html#reviews Wed, 16 May 2012 15:12:26 +0800 Tim http://www.udpwork.com/item/7313.html 腾讯大讲堂中最近分享了周颢演讲的微信技术总监解读微信架构的秘密,看完视频的一些心得。

技术微创新

微信的技术设计上有很多微创新,看起来都很小,但是对于系统的稳定性、用户体验及开发敏捷都具有重要作用。

前轻后重
由于客户端升级不便,从技术设计上尽量利用后端的设计来减少依赖客户端升级的方法。如某个版本新增了群聊功能,按常规思路,需要所有客户端升级才能全部打通。微信采用服务器兼容的方法,在老客户端不升级情况下让其增加群聊的功能,通过在服务端将群聊协议转换成之前旧版兼容的协议返回给老的客户端。

客户端辅助设计
微信客户端做了很多非常规的功能,比如常规的客户端测速方法是登录阶段轮询测试多个IP来选择服务器,这样会带来流量及登录速度双方面的开销,因此微信选择的方法是服务端返回最佳的IP(可能是通过历史数据分析)。客户端另外实现了一些容灾能力的配合,当一个IDC访问出现异常自动选择另外一个IDC。

流量控制
由于大部分无线用户对流量非常敏感,为了防止由于客户端不可预知的bug如死循环导致“偷流量”,服务端增加用户流量实时分析的方法,可以在海量数据下找出流量异常的用户,并给这些用户强制下行终止连接信号。

基础研发的策略

从视频介绍来看,微信的基础研发与业务结合非常紧密,提到的有基础组件比如Client/Server框架,从原理上看类似TwitterFinagle,框架封装了大容量网络通讯及远程调用所需各种功能。此外介绍的一些监控与统计框架也较为先进,可以随时增加监控指标。

大量可复用的基础组件让业务开发非常敏捷,周颢总结的基础研发策略是“实现已有经验的固化”。这和其他一些公司中的基础研发团队思路有所区别。业界中基础研发脱离生产闭门造车的情况并不罕见,一方面业务部门重复低层次开发现象严重,另外一方面基础研发对业务理解欠缺,开发的组件模块与业务结合不紧密,无法被有效利用。因此类似微信这样增强业务团队的力量,在开发业务同时总结抽象更多的基础组件或许是一种更为实用的发展思路。

腾讯海量课程

视频中多次提到腾讯内部的一种海量模型的培训课程,其中的经验或设计模式包括
大系统小做
将一个复杂的大系统分解成多个独立的、小的、简单的任务去完成,“分而治之”。

柔性可用
服务端系统通常不是0与1之间的选择,可以在极端情况下做一定优雅降级,在服务端代码中需要体现这些设计。

Set模型
类似最近讨论的cell架构,按一个服务按用户范围分成不同的小单元,每个小单元(cell/set)具备全部业务服务能力,当一个set发生故障时候,只会影响这一小部分用户。微信架构中所做的补充是,在set之间增加了容错处理,当一个set发生故障时,使用类似一致性哈希的算法,调用方可以自动切换到下一个set来存储,并且将新的位置记录在index上(类似GFS master),周颢自称是一个简化版的GFS。

微信的协议

里面提到了XMPP和类Sync的自定义协议,里面提到XMPP的缺点是流量大和消息不可靠。但是流量大并非XMPP主要矛盾,可以很简单将其映射成二进制协议。消息ACK也可以添加简单的扩展协议来实现。较繁琐的还是兼容CMWAP网关的设计。

使用XMPP或者简化的XMPP标准协议有很多好处,类似的场景有业界广泛使用的open api基本都使用HTTP及JSON,并不是由于这两种协议优化或高效,而是其简洁并得到广泛的认知。一种标准协议的认知及扩展成本要比一个自定义协议小得多,XMPP流量大的问题可以通过转换协议来实现,比如用binary 1代表login等全部协商协议,2代表message,消息增量获取也可以通过自定义扩展协议来实现。标准协议可以让团队内部及新人的认知成本降低,每一个参与者都很容易想到代码及架构改进建议。而且微信目前也在构建开放平台,自定义协议在开放方面必然具备一些局限。

其他

分布式理论
从微信的分享也看到,指导业界不同背景的团队(不管大小)的分布式理论主要还是Google及Amazon系列论文,对互联网技术的发展具有深远影响。微信借鉴了Quorum及Merkle tree的理论,创造了一种自定义的做法,用于实现一种分布式递增发生器。
不过分布式递增算法其实有更简单的实现方法,twitter也有相关的公开博文,由于视频相关背景介绍比较简短,可能大家解决的需求具有差异,就不展开了。

监控
数千的监控项,可以在分钟发现系统的异常

敏捷
每天20个后台变更

技术传承
从视频和PPT来看,微信的技术体系是从头搭建的,可能有不少利用qqmail时代的基础代码,但与深圳团队并不存在太大技术沿袭或者传承关系。从另外一个角度也看到微信技术团队的战斗力。

新人力量
一位毕业生的创意:按SET分布,全量数据从2G减到200K(具体的情况待了解)
另外一个新特性,漂流瓶及摇一摇,据说也是2个月的本科毕业生一周完成,而且上线后运行稳定。

存储

上图中可扩展设计中字段配置表的做法感觉略显繁琐,目前大部分NoSQL产品的schema free方式可能更易于维护。

产品驱动

如图,其中“允许发布十分钟前的变更”这样做法通常在大型团队通常会引起广泛质疑,单纯学习这种形式并非正解,如何在互联网产品上实现敏捷值得产品和研发进一步思考。

Similar Posts: ]]>
腾讯大讲堂中最近分享了周颢演讲的微信技术总监解读微信架构的秘密,看完视频的一些心得。

技术微创新

微信的技术设计上有很多微创新,看起来都很小,但是对于系统的稳定性、用户体验及开发敏捷都具有重要作用。

前轻后重
由于客户端升级不便,从技术设计上尽量利用后端的设计来减少依赖客户端升级的方法。如某个版本新增了群聊功能,按常规思路,需要所有客户端升级才能全部打通。微信采用服务器兼容的方法,在老客户端不升级情况下让其增加群聊的功能,通过在服务端将群聊协议转换成之前旧版兼容的协议返回给老的客户端。

客户端辅助设计
微信客户端做了很多非常规的功能,比如常规的客户端测速方法是登录阶段轮询测试多个IP来选择服务器,这样会带来流量及登录速度双方面的开销,因此微信选择的方法是服务端返回最佳的IP(可能是通过历史数据分析)。客户端另外实现了一些容灾能力的配合,当一个IDC访问出现异常自动选择另外一个IDC。

流量控制
由于大部分无线用户对流量非常敏感,为了防止由于客户端不可预知的bug如死循环导致“偷流量”,服务端增加用户流量实时分析的方法,可以在海量数据下找出流量异常的用户,并给这些用户强制下行终止连接信号。

基础研发的策略

从视频介绍来看,微信的基础研发与业务结合非常紧密,提到的有基础组件比如Client/Server框架,从原理上看类似TwitterFinagle,框架封装了大容量网络通讯及远程调用所需各种功能。此外介绍的一些监控与统计框架也较为先进,可以随时增加监控指标。

大量可复用的基础组件让业务开发非常敏捷,周颢总结的基础研发策略是“实现已有经验的固化”。这和其他一些公司中的基础研发团队思路有所区别。业界中基础研发脱离生产闭门造车的情况并不罕见,一方面业务部门重复低层次开发现象严重,另外一方面基础研发对业务理解欠缺,开发的组件模块与业务结合不紧密,无法被有效利用。因此类似微信这样增强业务团队的力量,在开发业务同时总结抽象更多的基础组件或许是一种更为实用的发展思路。

腾讯海量课程

视频中多次提到腾讯内部的一种海量模型的培训课程,其中的经验或设计模式包括
大系统小做
将一个复杂的大系统分解成多个独立的、小的、简单的任务去完成,“分而治之”。

柔性可用
服务端系统通常不是0与1之间的选择,可以在极端情况下做一定优雅降级,在服务端代码中需要体现这些设计。

Set模型
类似最近讨论的cell架构,按一个服务按用户范围分成不同的小单元,每个小单元(cell/set)具备全部业务服务能力,当一个set发生故障时候,只会影响这一小部分用户。微信架构中所做的补充是,在set之间增加了容错处理,当一个set发生故障时,使用类似一致性哈希的算法,调用方可以自动切换到下一个set来存储,并且将新的位置记录在index上(类似GFS master),周颢自称是一个简化版的GFS。

微信的协议

里面提到了XMPP和类Sync的自定义协议,里面提到XMPP的缺点是流量大和消息不可靠。但是流量大并非XMPP主要矛盾,可以很简单将其映射成二进制协议。消息ACK也可以添加简单的扩展协议来实现。较繁琐的还是兼容CMWAP网关的设计。

使用XMPP或者简化的XMPP标准协议有很多好处,类似的场景有业界广泛使用的open api基本都使用HTTP及JSON,并不是由于这两种协议优化或高效,而是其简洁并得到广泛的认知。一种标准协议的认知及扩展成本要比一个自定义协议小得多,XMPP流量大的问题可以通过转换协议来实现,比如用binary 1代表login等全部协商协议,2代表message,消息增量获取也可以通过自定义扩展协议来实现。标准协议可以让团队内部及新人的认知成本降低,每一个参与者都很容易想到代码及架构改进建议。而且微信目前也在构建开放平台,自定义协议在开放方面必然具备一些局限。

其他

分布式理论
从微信的分享也看到,指导业界不同背景的团队(不管大小)的分布式理论主要还是Google及Amazon系列论文,对互联网技术的发展具有深远影响。微信借鉴了Quorum及Merkle tree的理论,创造了一种自定义的做法,用于实现一种分布式递增发生器。
不过分布式递增算法其实有更简单的实现方法,twitter也有相关的公开博文,由于视频相关背景介绍比较简短,可能大家解决的需求具有差异,就不展开了。

监控
数千的监控项,可以在分钟发现系统的异常

敏捷
每天20个后台变更

技术传承
从视频和PPT来看,微信的技术体系是从头搭建的,可能有不少利用qqmail时代的基础代码,但与深圳团队并不存在太大技术沿袭或者传承关系。从另外一个角度也看到微信技术团队的战斗力。

新人力量
一位毕业生的创意:按SET分布,全量数据从2G减到200K(具体的情况待了解)
另外一个新特性,漂流瓶及摇一摇,据说也是2个月的本科毕业生一周完成,而且上线后运行稳定。

存储

上图中可扩展设计中字段配置表的做法感觉略显繁琐,目前大部分NoSQL产品的schema free方式可能更易于维护。

产品驱动

如图,其中“允许发布十分钟前的变更”这样做法通常在大型团队通常会引起广泛质疑,单纯学习这种形式并非正解,如何在互联网产品上实现敏捷值得产品和研发进一步思考。

Similar Posts: ]]>
0
<![CDATA[关于《微博社区公约》这个事]]> http://www.udpwork.com/item/7312.html http://www.udpwork.com/item/7312.html#reviews Wed, 16 May 2012 14:31:38 +0800 魏武挥 http://www.udpwork.com/item/7312.html 微博公约开宗明义,我一点也不想掩饰自己对这个事的态度:滑稽。早些时候,看到几个大V在那里摇旗呐喊说要搞公约,就觉得他们着实吃饱了撑的。本来以为是这些大V们自己吃饱了撑的,后来事件转变为:原来是新浪自己的事儿,弄两个大V出来先造造势。新浪自己折腾,我倒不是以为完全是吃饱了撑的,我非常明白运营方所受到的压力,我只能说,某些人用了一个很滑稽的做法来达到让你自我阉割的目的。

新浪微博社区公约,不是所谓“自律”——新浪自己也没写成“自律公约”(但它在微博社区管理规定中的第29条这么写道:站方按照社区委员会判定结果所采取的处理措施,属于用户自律范畴,不代表新浪微博立场。)。这完全就是一个“使用条款”,严格意义上讲,就是使用者和运营者之间的合同 。还记得你注册的时候那个“新浪网络服务使用协议”么,那玩意儿就是个合同。理论上讲,注册即表明你同意这个合同,虽然霸王了点,但也是合同。在那个协议中,关于微博只有三个条款(第五部分),这份所谓“公约”,可视为对这个合同三个条款的扩充、解释和说明,但依然是合同,谈不上什么公约。

中国互联网搞过很多名堂的自律公约——线下传统媒体也干——比如我早年做博客的时候就有博客公约。但通常意义上,自律公约都是诸多运营商表示我们要自律,没有用户跳出来说我们要自律。一个很滑稽的比方是:一些报社凑在一起说要自律也就罢了,可一些报社合伙搞了个什么公约,让它们的读者要依据这个公约自律(比如说看完报纸不要随地乱扔),委实有点搞笑。

所以新浪微博社区公约不是自律公约,而是合同。合同是他律的:你违法合同,就得丧失某些权利。争执不下的,还要上仲裁,上法庭,官司输了要被强制执行某些惩罚措施。公约不是这样的。就拿现实生活中的小区业主公约,比如说不乱扔垃圾,不乱停车。你真要违反了,最多也就是被谴责。极端情况下,你得顶着左邻右舍鄙夷的眼光进进出出,但着实没有任何人可以跳出来说:滚,你被取缔住在这个小区的资格!但看看新浪微博这个社区,你违反了公约里的条款,你的下场就有可能是:滚!——这是典型的他律。

其实这事本来就是个新浪运营商修改(或者说扩充)了使用条款,有点像facebook成天在那里修改隐私条款——就是这么个事,非要搞成个大家都衷心拥护的“公约”干什么?另外的,还弄了所谓的社区委员会(普通型、专家型),搞的就像自治社区一样。大张旗鼓地颇有些西方文明社会的样子:公约、自治,社区委员会又有点像陪审员制度,真的是这样的么?

反正我是不信的。

以后删帖、删用户,就多了一件遮羞布了:根据公约,根据自治,根据委员会裁决,搞的好像真不是某些“官方意图”。明明是合同性质的事,非要搞成道德感实足的公约,干吗?避免打官司么?中国现实法律就极少受理这种被删帖被删用户的官司。

强奸就强奸吧,作为P民,也只好闭着眼去自寻快感。但问题是强奸还非要说成是两情相悦,这不是滑天下之大稽么?

最后补充说一下:这篇吐槽不是针对新浪运营方的,我善意地理解为:被迫为之。

关于作者
魏武挥, 上海交通大学媒体与设计学院, 教师
哥不做总好多年
Copyleft © 2010 知识共享署名-非商业性使用-禁止演绎 注意:转载勿改标题!
ItTalks -- 魏武挥的Blog (digitalfingerprint:fc4f8fc31f70097eea4b780b13146415)

欢迎 浏览我收集的信息图关注我的微博访问我的分享
无觅猜您也喜欢:

又有微创新

下一个微博的机会

微博:媒体?社交网络?

微博上的记者
无觅

与本日志可能相关的文章有:

]]>
微博公约开宗明义,我一点也不想掩饰自己对这个事的态度:滑稽。早些时候,看到几个大V在那里摇旗呐喊说要搞公约,就觉得他们着实吃饱了撑的。本来以为是这些大V们自己吃饱了撑的,后来事件转变为:原来是新浪自己的事儿,弄两个大V出来先造造势。新浪自己折腾,我倒不是以为完全是吃饱了撑的,我非常明白运营方所受到的压力,我只能说,某些人用了一个很滑稽的做法来达到让你自我阉割的目的。

新浪微博社区公约,不是所谓“自律”——新浪自己也没写成“自律公约”(但它在微博社区管理规定中的第29条这么写道:站方按照社区委员会判定结果所采取的处理措施,属于用户自律范畴,不代表新浪微博立场。)。这完全就是一个“使用条款”,严格意义上讲,就是使用者和运营者之间的合同 。还记得你注册的时候那个“新浪网络服务使用协议”么,那玩意儿就是个合同。理论上讲,注册即表明你同意这个合同,虽然霸王了点,但也是合同。在那个协议中,关于微博只有三个条款(第五部分),这份所谓“公约”,可视为对这个合同三个条款的扩充、解释和说明,但依然是合同,谈不上什么公约。

中国互联网搞过很多名堂的自律公约——线下传统媒体也干——比如我早年做博客的时候就有博客公约。但通常意义上,自律公约都是诸多运营商表示我们要自律,没有用户跳出来说我们要自律。一个很滑稽的比方是:一些报社凑在一起说要自律也就罢了,可一些报社合伙搞了个什么公约,让它们的读者要依据这个公约自律(比如说看完报纸不要随地乱扔),委实有点搞笑。

所以新浪微博社区公约不是自律公约,而是合同。合同是他律的:你违法合同,就得丧失某些权利。争执不下的,还要上仲裁,上法庭,官司输了要被强制执行某些惩罚措施。公约不是这样的。就拿现实生活中的小区业主公约,比如说不乱扔垃圾,不乱停车。你真要违反了,最多也就是被谴责。极端情况下,你得顶着左邻右舍鄙夷的眼光进进出出,但着实没有任何人可以跳出来说:滚,你被取缔住在这个小区的资格!但看看新浪微博这个社区,你违反了公约里的条款,你的下场就有可能是:滚!——这是典型的他律。

其实这事本来就是个新浪运营商修改(或者说扩充)了使用条款,有点像facebook成天在那里修改隐私条款——就是这么个事,非要搞成个大家都衷心拥护的“公约”干什么?另外的,还弄了所谓的社区委员会(普通型、专家型),搞的就像自治社区一样。大张旗鼓地颇有些西方文明社会的样子:公约、自治,社区委员会又有点像陪审员制度,真的是这样的么?

反正我是不信的。

以后删帖、删用户,就多了一件遮羞布了:根据公约,根据自治,根据委员会裁决,搞的好像真不是某些“官方意图”。明明是合同性质的事,非要搞成道德感实足的公约,干吗?避免打官司么?中国现实法律就极少受理这种被删帖被删用户的官司。

强奸就强奸吧,作为P民,也只好闭着眼去自寻快感。但问题是强奸还非要说成是两情相悦,这不是滑天下之大稽么?

最后补充说一下:这篇吐槽不是针对新浪运营方的,我善意地理解为:被迫为之。

关于作者
魏武挥, 上海交通大学媒体与设计学院, 教师
哥不做总好多年
Copyleft © 2010 知识共享署名-非商业性使用-禁止演绎 注意:转载勿改标题!
ItTalks -- 魏武挥的Blog (digitalfingerprint:fc4f8fc31f70097eea4b780b13146415)

欢迎 浏览我收集的信息图关注我的微博访问我的分享
无觅猜您也喜欢:

又有微创新

下一个微博的机会

微博:媒体?社交网络?

微博上的记者
无觅

与本日志可能相关的文章有:

]]>
0
<![CDATA[那些天一起刷过的Galaxy Note ICS ROM]]> http://www.udpwork.com/item/7311.html http://www.udpwork.com/item/7311.html#reviews Wed, 16 May 2012 11:36:33 +0800 gnawux http://www.udpwork.com/item/7311.html 似乎我用Milestone那么久都没有心思写篇关于手机的blog,用GN没几天就第二次想写了,我得说,这会儿总算对Android有些好感了,使用体验、界面流畅程度啥的都没什么问题了,也没什么冲动想换个个头那么小的 iPhone 了。我不是说 Android 比 iPhone 好了,只是,这些手机已经是各有特色了,iPhone 可能不再是每个人的理想智能手机了(对很多人从来没是过哈,对某些人永远都是)。

本文所指的ROM和内核,都来自 XDA( http://forum.xda-developers.com ),由于个人装逼需要,不喜欢安装国内论坛上的“大牛”们做的,比如机锋什么的下 ROM,如果能在官方市场找到的软件也不喜欢用其它来源的,如果是付费软件,又很想要,就想办法伪装成米国用户买下来,偶们码农,得带头尊重软件版权、反对盗版,这个不是因为我们工资已经高到每月能买得起一两刀、三五刀的软件了,而是因为我们自己就是这么活的,我们不能自己偷自己的钱,是吧。

目前的Galaxy Note ICS ROM和内核

Galaxy Note 目前的两大 ICS ROM 分支是:基于三星官方修订的,以及基于纯开源项目构建的;内核也有两类:三星放出来的和基于纯开源构建的。开源的ROM也可能会用三星放出来的内核,反之大概亦然。

5月10号,三星欧洲在德国放出了他们的第一个官方的Note ICS ROM,版本号为 LPY,之前,中国泄漏过 LP1, LP5, LP6 三个 ICS ROM(这些似乎最早都是在机锋泄漏的),下面称呼的时候,官方版本的ROM和内核都直接称为LPY,泄漏版的三个,如果不特殊指某一个的话,直接说中国泄漏版。

在出现这些三星ROM之后,有几个 Team 都对官方版本的ROM做出了自己的 MOD,主要包括:

  • 换用ApexLauncher 或 NovaLauncher,很多人都不喜欢三星的 TouchWiz ,呵呵
  • 删掉一些应用,换上另一些(中国泄漏版里有人人、新浪微博之类的一大堆,我看着都想删掉,老外们更不例外了)
  • 加一些启动的init脚本来做优化
  • 换主题
  • 增加一些通知栏 toggle 之类的功能(替换 SystemUI)

随后或同时,有一些人开始直接从开源的 AOSP (Android Open Source Project,这个是 google 直接放出的),以及在上面进行了一些修订的 AOKP 项目,这其中比较成熟的一般都使用了三星放出的内核——中国泄漏的或是更新的 LPY,它们的主要特点是:

  • 应用精简了不少,三星的一个都没有了,当然 S-Pen 应用也没有了(笔还能用,笔的按键不好用了,截屏之类的就不能用笔了)
  • 一般用 ApexLauncher 或 NovaLauncher,优化、toggle、主题之类的也是有的
  • 更多的可定制配置,包括锁屏
  • 可以修改为平板模式,安装平板才可以用的软件,比如 Papyrus 之类的
  • 早期AOSP官方有录像无法保存之类的 Bug,但后来已经修复了。

除了AOSP/AOKP之外,还有著名的CM9系列ROM,它们的mod更多,甚至使用了基于 i9100 内核源代码构建的纯开源内核,这个内核目前只是可用,还缺少一些功能(这个变化很快,可能blog发出来的时候已经修复了呢)

  • 拍照的预览是黑的
  • Speaker还有部分问题,这个似乎是有人的内核解决了,有人的没有,不同的修复
  • 其他不确定的问题

嗯,好了,总结就到这里,下面是重要的安全提示——

安全提示

根据XDA总结的用户的报告,所有三星放出的内核,LPY或是中国泄漏的,都存在一定的 eMMC IO 缺陷,有可能在大 IO 时导致硬变砖,也就是 hard brick,这对于我们这些质保比较差用户来说更严重一些哈。发生这种情况的风险依次为:

  • 使用Chainfire 打包的基于三星内核的 CF-root kernel 时,在 Recovery 下进行 Wipe 和 Flash,这种风险是最高的,当然,实际我也在没得到这个安全提示的时候 wipe 过好几次,很多其他人也是,大部分都没变砖,变砖这个事,概率不高,但是风险高就很吓人,是吧
  • 不使用 CF-Root的时候,也有可能 wipe 的时候出事
  • 删除大文件的时候据认为也有可能有风险

这个,说的是个可能性,但有很多用户不以为然,认为变砖不是这会才开始的,历史上也不是没出现过,不用看得这么重,那些手机可能是硬件本身有问题的,有很多变砖和新 kernel 根本没关系。不论如何,鉴于存在有问题的可能,因此XDA的开发者们给出了一个解决方案:

安全操作方法与免责声明

鉴于 2.3.6 的内核没有问题,于是建议这么操作:

  • 下 Abyss Kernel 4.2 (点这里: http://www.mediafire.com/?c65mndvpk6ocbaa ),放到手机里
  • 进 recovery 刷 Abyss 内核
  • 在 advanced 里选择重启到recovery
  • 如果想 wipe就wipe,想刷新 Rom 就刷新 Rom
  • 重启,搞定

当然,重复一下,刷机怎么都是有风险的,所以,即使你这么做了,赶上天灾人祸的可能性仍然是存在的,但是,要是啥风险都不承担,就表玩手机了,是吧。

 ICS使用体验

用ICS时间久了,2.3.6 的啥体验记不清了,嗯,总体评价一下ICS吧

  • 设置界面的流量显示、电量显示都不错,wifi、蓝牙的设置也更方便了,打开设置就有开关,也可以点进去设置
  • 流畅度没什么问题,原来有问题么,我不记得了啊,我觉得一直挺流畅的吧,当然,我毕竟是用老 milestone 过来的,对流畅啥的期待本来就不高,说实话,我承认我土鳖,玩 iPhone 4S 和 iPad、iPad 2 的时候也没觉得惊艳的流畅啊……
  • 电池啥的,跟 Coly 显摆过好几次,我觉得正常情况下,原电坚持一天应该没问题,我的坚持的意思是不以影响使用体验为代价的,不关 wifi、不关背景数据传输,该拍照拍照,该上传上传,该微博微博,该看 RSS 看 RSS……
  • 人脸解锁说起来拉风,但用一下就知道了,这东西对长得像我这么丑的屌丝完全是自取其辱啊,如果当天没刮胡子,或者干了一天活一脸油光的话,每次解锁都让你感到一阵恶心,嗯,当然了,对改善个人卫生有好处,用人脸解锁的几天,我会一天洗几次脸、刮胡子间隔绝对不会超过两天,嗯,即使这样,后来还是关掉人脸解锁了
  • 只要有 root,就可以安装 busy box 和 openvpn,你懂的,这个没有任何使用问题

嗯,再来说下基于三星ROM做的东西

  • 用 LPY 吧,毕竟是官方的,没有中文界面,也就是菜单啥的是英文的,中文程序没有任何问题
  • 如果觉得 instagram 之类的开的时候有点卡的话,disable 掉一片三星自带的程序,什么 weather、news、软件更新啥的,有 root 的话,可以直接移除 /system/app/ 下不需要的程序,当然,有些是不能拿走的,这个见仁见智吧,我移走了50多个,看起来没什么问题
  • mod啥的都可以手动做,比如 mod 个主题、装个软件啥的,有 root 都可以手工做了,基本不需要装个特殊的ROM版本了。

然后是 AOKP 的 ROM,我用 stunner 比较多,从 Beta4.1 一直用到 1.4.26.1,说说感受:

  • 流畅度没问题,内存占用少很多。当然,要我说,内存剩余 200MB 还是 500MB 都是浮云,只要应用不卡,内存不就是用来用的么;
  • 面板啥的可定制性更强,我喜欢这个,相机有全景相机功能,比免费应用的全景相机功能好用
  • 平板模式基本不用,字小啊,但支持 Papyrus 和其他一些 Note 软件,还是挺有吸引力的
  • 没有 S-Pen 按键的功能,心里小不爽,似乎笔的定位比三星 ROM 有偏移,这个是感觉,不是确实量出来的,但心情上确实是这样的

总结一下:

  • 只要有 root,流畅度不是问题,电池也没问题
  • 应用各有特色,我更倾向于官方的 S-Pen,虽然常常留恋 AOKP 的 ROM
  • 仅供参考,不承担责任哈
]]>
似乎我用Milestone那么久都没有心思写篇关于手机的blog,用GN没几天就第二次想写了,我得说,这会儿总算对Android有些好感了,使用体验、界面流畅程度啥的都没什么问题了,也没什么冲动想换个个头那么小的 iPhone 了。我不是说 Android 比 iPhone 好了,只是,这些手机已经是各有特色了,iPhone 可能不再是每个人的理想智能手机了(对很多人从来没是过哈,对某些人永远都是)。

本文所指的ROM和内核,都来自 XDA( http://forum.xda-developers.com ),由于个人装逼需要,不喜欢安装国内论坛上的“大牛”们做的,比如机锋什么的下 ROM,如果能在官方市场找到的软件也不喜欢用其它来源的,如果是付费软件,又很想要,就想办法伪装成米国用户买下来,偶们码农,得带头尊重软件版权、反对盗版,这个不是因为我们工资已经高到每月能买得起一两刀、三五刀的软件了,而是因为我们自己就是这么活的,我们不能自己偷自己的钱,是吧。

目前的Galaxy Note ICS ROM和内核

Galaxy Note 目前的两大 ICS ROM 分支是:基于三星官方修订的,以及基于纯开源项目构建的;内核也有两类:三星放出来的和基于纯开源构建的。开源的ROM也可能会用三星放出来的内核,反之大概亦然。

5月10号,三星欧洲在德国放出了他们的第一个官方的Note ICS ROM,版本号为 LPY,之前,中国泄漏过 LP1, LP5, LP6 三个 ICS ROM(这些似乎最早都是在机锋泄漏的),下面称呼的时候,官方版本的ROM和内核都直接称为LPY,泄漏版的三个,如果不特殊指某一个的话,直接说中国泄漏版。

在出现这些三星ROM之后,有几个 Team 都对官方版本的ROM做出了自己的 MOD,主要包括:

  • 换用ApexLauncher 或 NovaLauncher,很多人都不喜欢三星的 TouchWiz ,呵呵
  • 删掉一些应用,换上另一些(中国泄漏版里有人人、新浪微博之类的一大堆,我看着都想删掉,老外们更不例外了)
  • 加一些启动的init脚本来做优化
  • 换主题
  • 增加一些通知栏 toggle 之类的功能(替换 SystemUI)

随后或同时,有一些人开始直接从开源的 AOSP (Android Open Source Project,这个是 google 直接放出的),以及在上面进行了一些修订的 AOKP 项目,这其中比较成熟的一般都使用了三星放出的内核——中国泄漏的或是更新的 LPY,它们的主要特点是:

  • 应用精简了不少,三星的一个都没有了,当然 S-Pen 应用也没有了(笔还能用,笔的按键不好用了,截屏之类的就不能用笔了)
  • 一般用 ApexLauncher 或 NovaLauncher,优化、toggle、主题之类的也是有的
  • 更多的可定制配置,包括锁屏
  • 可以修改为平板模式,安装平板才可以用的软件,比如 Papyrus 之类的
  • 早期AOSP官方有录像无法保存之类的 Bug,但后来已经修复了。

除了AOSP/AOKP之外,还有著名的CM9系列ROM,它们的mod更多,甚至使用了基于 i9100 内核源代码构建的纯开源内核,这个内核目前只是可用,还缺少一些功能(这个变化很快,可能blog发出来的时候已经修复了呢)

  • 拍照的预览是黑的
  • Speaker还有部分问题,这个似乎是有人的内核解决了,有人的没有,不同的修复
  • 其他不确定的问题

嗯,好了,总结就到这里,下面是重要的安全提示——

安全提示

根据XDA总结的用户的报告,所有三星放出的内核,LPY或是中国泄漏的,都存在一定的 eMMC IO 缺陷,有可能在大 IO 时导致硬变砖,也就是 hard brick,这对于我们这些质保比较差用户来说更严重一些哈。发生这种情况的风险依次为:

  • 使用Chainfire 打包的基于三星内核的 CF-root kernel 时,在 Recovery 下进行 Wipe 和 Flash,这种风险是最高的,当然,实际我也在没得到这个安全提示的时候 wipe 过好几次,很多其他人也是,大部分都没变砖,变砖这个事,概率不高,但是风险高就很吓人,是吧
  • 不使用 CF-Root的时候,也有可能 wipe 的时候出事
  • 删除大文件的时候据认为也有可能有风险

这个,说的是个可能性,但有很多用户不以为然,认为变砖不是这会才开始的,历史上也不是没出现过,不用看得这么重,那些手机可能是硬件本身有问题的,有很多变砖和新 kernel 根本没关系。不论如何,鉴于存在有问题的可能,因此XDA的开发者们给出了一个解决方案:

安全操作方法与免责声明

鉴于 2.3.6 的内核没有问题,于是建议这么操作:

  • 下 Abyss Kernel 4.2 (点这里: http://www.mediafire.com/?c65mndvpk6ocbaa ),放到手机里
  • 进 recovery 刷 Abyss 内核
  • 在 advanced 里选择重启到recovery
  • 如果想 wipe就wipe,想刷新 Rom 就刷新 Rom
  • 重启,搞定

当然,重复一下,刷机怎么都是有风险的,所以,即使你这么做了,赶上天灾人祸的可能性仍然是存在的,但是,要是啥风险都不承担,就表玩手机了,是吧。

 ICS使用体验

用ICS时间久了,2.3.6 的啥体验记不清了,嗯,总体评价一下ICS吧

  • 设置界面的流量显示、电量显示都不错,wifi、蓝牙的设置也更方便了,打开设置就有开关,也可以点进去设置
  • 流畅度没什么问题,原来有问题么,我不记得了啊,我觉得一直挺流畅的吧,当然,我毕竟是用老 milestone 过来的,对流畅啥的期待本来就不高,说实话,我承认我土鳖,玩 iPhone 4S 和 iPad、iPad 2 的时候也没觉得惊艳的流畅啊……
  • 电池啥的,跟 Coly 显摆过好几次,我觉得正常情况下,原电坚持一天应该没问题,我的坚持的意思是不以影响使用体验为代价的,不关 wifi、不关背景数据传输,该拍照拍照,该上传上传,该微博微博,该看 RSS 看 RSS……
  • 人脸解锁说起来拉风,但用一下就知道了,这东西对长得像我这么丑的屌丝完全是自取其辱啊,如果当天没刮胡子,或者干了一天活一脸油光的话,每次解锁都让你感到一阵恶心,嗯,当然了,对改善个人卫生有好处,用人脸解锁的几天,我会一天洗几次脸、刮胡子间隔绝对不会超过两天,嗯,即使这样,后来还是关掉人脸解锁了
  • 只要有 root,就可以安装 busy box 和 openvpn,你懂的,这个没有任何使用问题

嗯,再来说下基于三星ROM做的东西

  • 用 LPY 吧,毕竟是官方的,没有中文界面,也就是菜单啥的是英文的,中文程序没有任何问题
  • 如果觉得 instagram 之类的开的时候有点卡的话,disable 掉一片三星自带的程序,什么 weather、news、软件更新啥的,有 root 的话,可以直接移除 /system/app/ 下不需要的程序,当然,有些是不能拿走的,这个见仁见智吧,我移走了50多个,看起来没什么问题
  • mod啥的都可以手动做,比如 mod 个主题、装个软件啥的,有 root 都可以手工做了,基本不需要装个特殊的ROM版本了。

然后是 AOKP 的 ROM,我用 stunner 比较多,从 Beta4.1 一直用到 1.4.26.1,说说感受:

  • 流畅度没问题,内存占用少很多。当然,要我说,内存剩余 200MB 还是 500MB 都是浮云,只要应用不卡,内存不就是用来用的么;
  • 面板啥的可定制性更强,我喜欢这个,相机有全景相机功能,比免费应用的全景相机功能好用
  • 平板模式基本不用,字小啊,但支持 Papyrus 和其他一些 Note 软件,还是挺有吸引力的
  • 没有 S-Pen 按键的功能,心里小不爽,似乎笔的定位比三星 ROM 有偏移,这个是感觉,不是确实量出来的,但心情上确实是这样的

总结一下:

  • 只要有 root,流畅度不是问题,电池也没问题
  • 应用各有特色,我更倾向于官方的 S-Pen,虽然常常留恋 AOKP 的 ROM
  • 仅供参考,不承担责任哈
]]>
0
<![CDATA[MySQL数据库优化的一些笔记]]> http://www.udpwork.com/item/7310.html http://www.udpwork.com/item/7310.html#reviews Wed, 16 May 2012 02:38:58 +0800 Xiaoxia http://www.udpwork.com/item/7310.html 0. 索引很重要

之前列举记录用了下面的语句。state字段为索引。

SELECT * FROM feed_urls WHERE state='ok' AND feed_url<>'' LIMIT N,10

当记录数量很大时,有几万之后,这句SQL就很慢了。主要是因为feed_url没有建立索引。后来的解决方法是,把feed_url为空的,设为一个ok以外的state值,就行了。

1、索引不是万能的

为了计算记录总数,下面的语句会很慢。

mysql> SELECT COUNT(*) FROM feed_urls WHERE state='error';
+----------+
| COUNT(*) |
+----------+
|    30715 |
+----------+
1 row in set (0.14 sec)

mysql> EXPLAIN SELECT COUNT(*) FROM feed_urls WHERE state='error'\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: feed_urls
         type: ref
possible_keys: state,page_index
          key: page_index
      key_len: 10
          ref: const
         rows: 25936
        Extra: Using where; Using index
1 row in set (0.00 sec)

state为索引,请求用时140ms。遍历了state='error'索引下的每一条记录。

mysql> SELECT state,COUNT(*) FROM feed_urls GROUP BY state;
+----------+----------+
| state    | COUNT(*) |
+----------+----------+
| error    |    30717 |
| fetching |        8 |
| nofeed   |    76461 |
| ok       |    74703 |
| queued   |   249681 |
+----------+----------+
5 rows in set (0.55 sec)

mysql> EXPLAIN SELECT state,COUNT(*) FROM feed_urls GROUP BY state\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: feed_urls
         type: index
possible_keys: NULL
          key: state
      key_len: 10
          ref: NULL
         rows: 431618
        Extra: Using index
1 row in set (0.00 sec)

请求用时550ms。遍历了每个state下的每一条记录。

改进方法:

独立一个表用来计数,使用MySQL的Trigger同步计数:

CREATE TRIGGER my_trigger AFTER UPDATE ON feed_urls
FOR EACH ROW BEGIN

IF OLD.state <> NEW.state THEN

IF NEW.state='ok' THEN
    UPDATE feed_stat SET count_feed = count_feed + 1;
END IF;

IF NEW.state IN ('ok', 'error', 'nofeed') THEN
    UPDATE feed_stat SET count_access = count_access + 1;
END IF;

END IF;

END

2. 当分页很大时

mysql> SELECT * FROM feed_urls LIMIT 230000, 1\G
*************************** 1. row ***************************
         id: 736841f82abb0bc87ccfec7c0fdbd09c30b5a24d
       link: http://mappemunde.typepad.com/
      title: Tim Peterson
   feed_url: NULL
update_time: 2012-05-12 11:01:56
      state: queued
http_server: NULL
   abstract: NULL
previous_id: ceea30e0ba609b69198c53ce71c44070d69038c5
  ref_count: 1
      error: NULL
        aid: 230001
1 row in set (0.50 sec)

mysql> EXPLAIN SELECT * FROM feed_urls LIMIT 230000, 1\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: feed_urls
         type: ALL
possible_keys: NULL
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 431751
        Extra:
1 row in set (0.00 sec)

读取一条记录,耗时500ms,因为表记录是变长的,所以MySQL不能算出目标位置,只能每一条记录的数过去。

改进方法:

通过索引定位,数索引比数记录要快,因为索引占用的空间比整条记录小很多。

mysql> SELECT * FROM (SELECT aid FROM feed_urls ORDER BY aid LIMIT 215000, 1) d JOIN feed_urls u ON d.aid=u.aid\G
*************************** 1. row ***************************
        aid: 215001
         id: 2e4b1a385c8aae40b3ec2af9153805ca446f2029
       link: http://ncse.com/
      title: NCSE
   feed_url: NULL
update_time: 2012-05-12 10:47:15
      state: queued
http_server: NULL
   abstract: NULL
previous_id: 819a6e3c5edc1624a9b8f171d8d3ae269843785f
  ref_count: 3
      error: NULL
        aid: 215001
1 row in set (0.06 sec)

mysql> EXPLAIN SELECT * FROM (SELECT aid FROM feed_urls ORDER BY aid LIMIT 215000, 1) d JOIN feed_urls u ON d.aid=u.aid\G
*************************** 1. row ***************************
           id: 1
  select_type: PRIMARY
        table: 
         type: system
possible_keys: NULL
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 1
        Extra:
*************************** 2. row ***************************
           id: 1
  select_type: PRIMARY
        table: u
         type: const
possible_keys: aid
          key: aid
      key_len: 4
          ref: const
         rows: 1
        Extra:
*************************** 3. row ***************************
           id: 2
  select_type: DERIVED
        table: feed_urls
         type: index
possible_keys: NULL
          key: aid
      key_len: 4
          ref: NULL
         rows: 211001
        Extra: Using index
3 rows in set (0.15 sec)

耗时60ms,比之前的方法快了将近10倍。如果LIMIT语句里还有WHERE a=1,应该建立一个(a,aid)的索引。

话说,MySQL好像还是不能直接算出第21500条索引的位置呀,这种方法还是数了索引了,能算出来就直接0ms了。不过这样的效率,对于百万级的,还能应付吧。如果是千万级的或者像我之前在KS创建的一张上亿条记录的表(120G),这种方法就肯定不行了。

经过上述优化,打开最后一页的速度已经很快了(之前需要800ms,现在则为300ms左右)。

膜拜下这Burst.NET最低档次的VPS (30RMB/month)。

root@xiaoxia-pc:~/# ping feed.readself.com -n
PING app.readself.com (184.82.185.32) 56(84) bytes of data.
64 bytes from 184.82.185.32: icmp_req=1 ttl=45 time=161 ms
64 bytes from 184.82.185.32: icmp_req=2 ttl=45 time=161 ms
64 bytes from 184.82.185.32: icmp_req=3 ttl=45 time=161 ms

用同样的方法,优化了搜索引擎的排名算法。即排名过程中选取尽量少的值出来排序,排序后再JOIN一次获取结果的信息。

排序过程如下:

SELECT u.*, count_level(u.id) lv
  FROM(
    SELECT f.id, f.ref_count, MATCH(i.link,i.title) AGAINST (keywords) score
    FROM feed_index i
    JOIN feed_urls f ON f.id=i.id
    WHERE MATCH(i.link,i.title) AGAINST (keywords)
    ORDER BY score*0.5 + score*0.5*(ref_count/max_ref_count_in_result) DESC
  LIMIT offset,10
) d JOIN feed_urls u ON u.id = d.id

目前处理10万记录的全文索引数据,MySQL还是可以满足的,就是不知道上百万之后,还能不能撑下去。撑不下去就依赖第三方的工具了,例如Sphinx:)

3. SELECT里的函数

给FeedDB增加了层次的显示。因为本人太懒,所以没有给数据库表增加一个记录深度的字段。所以,直接写了一个MySQL的自定义函数 count_level,用来统计通过parent_id一直找到顶层经过的路径长度(Level)。

CREATE DEFINER=`feeddb_rw`@`%` FUNCTION `count_level`(fid char(40)) RETURNS int(11)
BEGIN
     SET @levels = 0;
     SET @found = false;
     WHILE NOT @found DO
	     SELECT previous_id INTO @prev_id FROM feed_urls WHERE id=fid;
	     IF @prev_id is null OR @prev_id = '' THEN
		SET @found = true;
             ELSE
             	SET @levels = @levels + 1;
             	SET fid = @prev_id;
	     END IF;
     END WHILE;
     IF @prev_id is null THEN
         RETURN null;
     END IF;
     RETURN  @levels;
END

在网页显示的时候用了类似下面的SQL语句。

mysql> SELECT u.*, count_level(u.id) FROM feed_urls u ORDER BY ref_count DESC LIMIT 12000,1\G
*************************** 1. row ***************************
               id: e42f44b04dabbb9789ccb4709278e881c54c28a3
             link: http://tetellita.blogspot.com/
            title: le hamburger et le croissant
         feed_url: http://www.blogger.com/feeds/7360650/posts/default
      update_time: 2012-05-15 14:50:53
            state: ok
      http_server: GSE
         abstract: Lepekmezest un épais sirop bordeaux obtenu par réduction dumoût de raisin, une sorte de mélasse de raisin, en somme. Légèrement acidulé, il apporte du pep's aux yaourts et nappe avec bonheur les
      previous_id: 129cabd96e7099a53b78c7ddeff98658351082e9
        ref_count: 9
            error: NULL
              aid: 174262
count_level(u.id): 8
1 row in set (4.10 sec)

好吧,悲剧了!4100ms。一定对12000个条目都算了一次count_level,然后再进行排序。所以才用上了4秒那么漫长的时间!!!

改进方法:

先SELECT LIMIT,再在派生的临时表里,计算count_level。

mysql> SELECT u.*, count_level(u.id) FROM (
      SELECT id FROM feed_urls ORDER BY ref_count DESC LIMIT 27521,1
 ) d JOIN feed_urls u ON u.id=d.id\G
*************************** 1. row ***************************
               id: 61df288dda131ffd6125452d20ad0648f38abafd
             link: http://mynokiamobile.org/
            title: My Nokia Mobile
         feed_url: http://mynokiamobile.org/feed/
      update_time: 2012-05-14 14:06:57
            state: ok
      http_server: Apache/2.2.19 (Unix) mod_ssl/2.2.19 OpenSSL/1.0.0-fips mod_auth_passthrough/2.1 mod_bwlimited/1.4 FrontPage/5.0.2.2635
         abstract: ArchivesSelect MonthMay 2012April 2012March 2012February 2012January 2012December 2011November 2011October 2011September 2011August 2011July 2011June 2011May 2011April 2011March 2011February 2011Janua
      previous_id: f37af92bb89c08f6d4b69e72eab05d8ab1e2aca4
        ref_count: 5
            error: NULL
              aid: 154996
count_level(u.id): 8
1 row in set (0.09 sec)

如此,优化之后效果好很多了!但是还可以继续优化,例如建立一个字段存储Level的值应该是最好的办法了。

初次了解MySQL一些工作机制,欢迎一起探讨!

参考文献:

http://explainextended.com/2009/10/23/mysql-order-by-limit-performance-late-row-lookups/
http://www.mysqlperformanceblog.com/2006/09/01/order-by-limit-performance-optimization/

]]>
0. 索引很重要

之前列举记录用了下面的语句。state字段为索引。

SELECT * FROM feed_urls WHERE state='ok' AND feed_url<>'' LIMIT N,10

当记录数量很大时,有几万之后,这句SQL就很慢了。主要是因为feed_url没有建立索引。后来的解决方法是,把feed_url为空的,设为一个ok以外的state值,就行了。

1、索引不是万能的

为了计算记录总数,下面的语句会很慢。

mysql> SELECT COUNT(*) FROM feed_urls WHERE state='error';
+----------+
| COUNT(*) |
+----------+
|    30715 |
+----------+
1 row in set (0.14 sec)

mysql> EXPLAIN SELECT COUNT(*) FROM feed_urls WHERE state='error'\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: feed_urls
         type: ref
possible_keys: state,page_index
          key: page_index
      key_len: 10
          ref: const
         rows: 25936
        Extra: Using where; Using index
1 row in set (0.00 sec)

state为索引,请求用时140ms。遍历了state='error'索引下的每一条记录。

mysql> SELECT state,COUNT(*) FROM feed_urls GROUP BY state;
+----------+----------+
| state    | COUNT(*) |
+----------+----------+
| error    |    30717 |
| fetching |        8 |
| nofeed   |    76461 |
| ok       |    74703 |
| queued   |   249681 |
+----------+----------+
5 rows in set (0.55 sec)

mysql> EXPLAIN SELECT state,COUNT(*) FROM feed_urls GROUP BY state\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: feed_urls
         type: index
possible_keys: NULL
          key: state
      key_len: 10
          ref: NULL
         rows: 431618
        Extra: Using index
1 row in set (0.00 sec)

请求用时550ms。遍历了每个state下的每一条记录。

改进方法:

独立一个表用来计数,使用MySQL的Trigger同步计数:

CREATE TRIGGER my_trigger AFTER UPDATE ON feed_urls
FOR EACH ROW BEGIN

IF OLD.state <> NEW.state THEN

IF NEW.state='ok' THEN
    UPDATE feed_stat SET count_feed = count_feed + 1;
END IF;

IF NEW.state IN ('ok', 'error', 'nofeed') THEN
    UPDATE feed_stat SET count_access = count_access + 1;
END IF;

END IF;

END

2. 当分页很大时

mysql> SELECT * FROM feed_urls LIMIT 230000, 1\G
*************************** 1. row ***************************
         id: 736841f82abb0bc87ccfec7c0fdbd09c30b5a24d
       link: http://mappemunde.typepad.com/
      title: Tim Peterson
   feed_url: NULL
update_time: 2012-05-12 11:01:56
      state: queued
http_server: NULL
   abstract: NULL
previous_id: ceea30e0ba609b69198c53ce71c44070d69038c5
  ref_count: 1
      error: NULL
        aid: 230001
1 row in set (0.50 sec)

mysql> EXPLAIN SELECT * FROM feed_urls LIMIT 230000, 1\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: feed_urls
         type: ALL
possible_keys: NULL
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 431751
        Extra:
1 row in set (0.00 sec)

读取一条记录,耗时500ms,因为表记录是变长的,所以MySQL不能算出目标位置,只能每一条记录的数过去。

改进方法:

通过索引定位,数索引比数记录要快,因为索引占用的空间比整条记录小很多。

mysql> SELECT * FROM (SELECT aid FROM feed_urls ORDER BY aid LIMIT 215000, 1) d JOIN feed_urls u ON d.aid=u.aid\G
*************************** 1. row ***************************
        aid: 215001
         id: 2e4b1a385c8aae40b3ec2af9153805ca446f2029
       link: http://ncse.com/
      title: NCSE
   feed_url: NULL
update_time: 2012-05-12 10:47:15
      state: queued
http_server: NULL
   abstract: NULL
previous_id: 819a6e3c5edc1624a9b8f171d8d3ae269843785f
  ref_count: 3
      error: NULL
        aid: 215001
1 row in set (0.06 sec)

mysql> EXPLAIN SELECT * FROM (SELECT aid FROM feed_urls ORDER BY aid LIMIT 215000, 1) d JOIN feed_urls u ON d.aid=u.aid\G
*************************** 1. row ***************************
           id: 1
  select_type: PRIMARY
        table: 
         type: system
possible_keys: NULL
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 1
        Extra:
*************************** 2. row ***************************
           id: 1
  select_type: PRIMARY
        table: u
         type: const
possible_keys: aid
          key: aid
      key_len: 4
          ref: const
         rows: 1
        Extra:
*************************** 3. row ***************************
           id: 2
  select_type: DERIVED
        table: feed_urls
         type: index
possible_keys: NULL
          key: aid
      key_len: 4
          ref: NULL
         rows: 211001
        Extra: Using index
3 rows in set (0.15 sec)

耗时60ms,比之前的方法快了将近10倍。如果LIMIT语句里还有WHERE a=1,应该建立一个(a,aid)的索引。

话说,MySQL好像还是不能直接算出第21500条索引的位置呀,这种方法还是数了索引了,能算出来就直接0ms了。不过这样的效率,对于百万级的,还能应付吧。如果是千万级的或者像我之前在KS创建的一张上亿条记录的表(120G),这种方法就肯定不行了。

经过上述优化,打开最后一页的速度已经很快了(之前需要800ms,现在则为300ms左右)。

膜拜下这Burst.NET最低档次的VPS (30RMB/month)。

root@xiaoxia-pc:~/# ping feed.readself.com -n
PING app.readself.com (184.82.185.32) 56(84) bytes of data.
64 bytes from 184.82.185.32: icmp_req=1 ttl=45 time=161 ms
64 bytes from 184.82.185.32: icmp_req=2 ttl=45 time=161 ms
64 bytes from 184.82.185.32: icmp_req=3 ttl=45 time=161 ms

用同样的方法,优化了搜索引擎的排名算法。即排名过程中选取尽量少的值出来排序,排序后再JOIN一次获取结果的信息。

排序过程如下:

SELECT u.*, count_level(u.id) lv
  FROM(
    SELECT f.id, f.ref_count, MATCH(i.link,i.title) AGAINST (keywords) score
    FROM feed_index i
    JOIN feed_urls f ON f.id=i.id
    WHERE MATCH(i.link,i.title) AGAINST (keywords)
    ORDER BY score*0.5 + score*0.5*(ref_count/max_ref_count_in_result) DESC
  LIMIT offset,10
) d JOIN feed_urls u ON u.id = d.id

目前处理10万记录的全文索引数据,MySQL还是可以满足的,就是不知道上百万之后,还能不能撑下去。撑不下去就依赖第三方的工具了,例如Sphinx:)

3. SELECT里的函数

给FeedDB增加了层次的显示。因为本人太懒,所以没有给数据库表增加一个记录深度的字段。所以,直接写了一个MySQL的自定义函数 count_level,用来统计通过parent_id一直找到顶层经过的路径长度(Level)。

CREATE DEFINER=`feeddb_rw`@`%` FUNCTION `count_level`(fid char(40)) RETURNS int(11)
BEGIN
     SET @levels = 0;
     SET @found = false;
     WHILE NOT @found DO
	     SELECT previous_id INTO @prev_id FROM feed_urls WHERE id=fid;
	     IF @prev_id is null OR @prev_id = '' THEN
		SET @found = true;
             ELSE
             	SET @levels = @levels + 1;
             	SET fid = @prev_id;
	     END IF;
     END WHILE;
     IF @prev_id is null THEN
         RETURN null;
     END IF;
     RETURN  @levels;
END

在网页显示的时候用了类似下面的SQL语句。

mysql> SELECT u.*, count_level(u.id) FROM feed_urls u ORDER BY ref_count DESC LIMIT 12000,1\G
*************************** 1. row ***************************
               id: e42f44b04dabbb9789ccb4709278e881c54c28a3
             link: http://tetellita.blogspot.com/
            title: le hamburger et le croissant
         feed_url: http://www.blogger.com/feeds/7360650/posts/default
      update_time: 2012-05-15 14:50:53
            state: ok
      http_server: GSE
         abstract: Lepekmezest un épais sirop bordeaux obtenu par réduction dumoût de raisin, une sorte de mélasse de raisin, en somme. Légèrement acidulé, il apporte du pep's aux yaourts et nappe avec bonheur les
      previous_id: 129cabd96e7099a53b78c7ddeff98658351082e9
        ref_count: 9
            error: NULL
              aid: 174262
count_level(u.id): 8
1 row in set (4.10 sec)

好吧,悲剧了!4100ms。一定对12000个条目都算了一次count_level,然后再进行排序。所以才用上了4秒那么漫长的时间!!!

改进方法:

先SELECT LIMIT,再在派生的临时表里,计算count_level。

mysql> SELECT u.*, count_level(u.id) FROM (
      SELECT id FROM feed_urls ORDER BY ref_count DESC LIMIT 27521,1
 ) d JOIN feed_urls u ON u.id=d.id\G
*************************** 1. row ***************************
               id: 61df288dda131ffd6125452d20ad0648f38abafd
             link: http://mynokiamobile.org/
            title: My Nokia Mobile
         feed_url: http://mynokiamobile.org/feed/
      update_time: 2012-05-14 14:06:57
            state: ok
      http_server: Apache/2.2.19 (Unix) mod_ssl/2.2.19 OpenSSL/1.0.0-fips mod_auth_passthrough/2.1 mod_bwlimited/1.4 FrontPage/5.0.2.2635
         abstract: ArchivesSelect MonthMay 2012April 2012March 2012February 2012January 2012December 2011November 2011October 2011September 2011August 2011July 2011June 2011May 2011April 2011March 2011February 2011Janua
      previous_id: f37af92bb89c08f6d4b69e72eab05d8ab1e2aca4
        ref_count: 5
            error: NULL
              aid: 154996
count_level(u.id): 8
1 row in set (0.09 sec)

如此,优化之后效果好很多了!但是还可以继续优化,例如建立一个字段存储Level的值应该是最好的办法了。

初次了解MySQL一些工作机制,欢迎一起探讨!

参考文献:

http://explainextended.com/2009/10/23/mysql-order-by-limit-performance-late-row-lookups/
http://www.mysqlperformanceblog.com/2006/09/01/order-by-limit-performance-optimization/

]]>
0
<![CDATA[电商价格战]]> http://www.udpwork.com/item/7309.html http://www.udpwork.com/item/7309.html#reviews Tue, 15 May 2012 18:52:23 +0800 魏武挥 http://www.udpwork.com/item/7309.html 平台类电商近来,几个平台类电商的价格战愈演愈烈,无论是互联网出身的京东、天猫,还是传统行业涉足的苏宁、国美,都祭起了价格战这种“杀人一万自损八千”的法宝。虽然有论者认为,电商更应该注重自己的服务,而不是仅靠价格战,但恐怕电商这个业态,由于对消费者的吸引力很大一块建立在“便宜”上(相对于线下而言,理由是省略了大量的人工、场地、水电诸如此类的费用),价格对抗,大致是免不了的。

但其实电商的成本一点也不低——我有时候甚至会觉得,做一个电商怕是比线下开个店的成本低不到哪里去——有两部分的成本它高于线下店。其一是物流费用。消费者去线下店的成本是由消费者自己承担,买到了货也得自己想法子扛回去。但电商则以满多少多少包邮来吸引消费者,实质上就是将原来由消费者承担的成本转嫁到自己头上。第二部分费用在于吆喝。电商“全场3折”起的这条信息,要让足够多的人看到,是需要再次付出成本的。在对外广告上的投入,电商远远比线下店舍得花钱。

电商真正的优势在于“货架是无限的”——这也是安德森笔下的“长尾理论”。平台类这样的电商如果在线下开店,估计十层楼面都打不住(比如天猫就号称有6万个卖家)。每增加一个货品,只是增加一个页面。货品越多,最后所摊薄的宣传成本就越低。这也是线下店之所以不太会如此大规模投入广告的原因之一:摊薄的宣传成本有限。但是,光有货品没有交易显然是完成摊薄宣传成本的任务,电商必须刺激消费者来到自己的网站,并购买货品。最好的路,莫过于价格战了。

不过,中国电商的价格战使得他们的毛利率很低。有媒体近日援引一个电商人士的说法,京东的毛利率不过7-8%。虽然中国电商行业集体以亚马逊为师,但后者的毛利率一直在20%以上(哪怕是最艰难被万夫所指的亏损年代)。对于中国电商而言,追求的似乎更聚焦于“规模”上——也就是销量。而这个规模,直接和公司估值、未来上市有关。

一个公司上市之后,受到的公开市场的压力以及每季都必须发布财报,它动用价格战之前就必须谨慎异常。在中国市场上,稍大一点的上市电商(比如当当),对价格战属于防守性的。而文头所提及的若干平台类电商,无一上市,价格战就是进攻性的。我甚至可以这么说,在它们没有上市之前,价格战的对抗,将一直是常态,而不是间歇性的“促销战役”。

电商的价格战会不会让它们自身难以承受最终垮掉?我并不那么悲观。即便是打价格战最凶悍的京东,只要管理没有失控,就不会引发崩盘。几大平台类电商,事实上已经绑架了诸多投资者,已经到了“大而不死”的阶段。PPG全面溃败的原因在于品质失去控制,高管层集体出走,从目前的态势来看,平台类电商没有这类征兆。

价格战的后果就是加剧垄断的速度,也为后来者树立了一个极高的进入门槛:没有足够的实力(我以为都是亿当量级别的资金),就不要玩平台类。每一轮价格战都会指向这样一个结果:行业洗牌。从这个角度出发,如果哪一天爆出“凡客与某平台类电商合并”的新闻,我是一点不会奇怪的。

—— 《经济观察报》约稿 ——

附注说明一下:

1、报社约稿时,正处于从帝都回魔都的下午,身体且欠佳,有点浑浑噩噩,今日好些后,发现此文写得有些急就章了。

2、此文的重点在于电商(平台类)会出现并购。这是投资人的意志决定的,不是平时在媒体上经常出现的什么创始人什么首席执行官决定的。优土一案,已经足够明白地告诉了这一点:互联网实质是金融推动的。引申说一下,深得互联网喜欢的奥巴马信誓旦旦要打击华尔街,那是不可能的任务。

3、投资人在上市无望便无法退出的情况下,会推动公司之间的并购以达成换股。如果和某上市公司合并,这种换股就是变向退出。

4、要么上市退出,要么崩盘就认输。最怕吊在中间,而这种吊在中间只会是过渡性的。

关于作者
魏武挥, 上海交通大学媒体与设计学院, 教师
哥不做总好多年
Copyleft © 2010 知识共享署名-非商业性使用-禁止演绎 注意:转载勿改标题!
ItTalks -- 魏武挥的Blog (digitalfingerprint:fc4f8fc31f70097eea4b780b13146415)

欢迎 浏览我收集的信息图关注我的微博访问我的分享
无觅猜您也喜欢:
中国证券经纪业务百论之廿一:剖析佣金价格战
图书市场价格战的背后
谁是监管者?
电子阅读器:阅读器 版权 价格
无觅

与本日志可能相关的文章有:

]]>
平台类电商近来,几个平台类电商的价格战愈演愈烈,无论是互联网出身的京东、天猫,还是传统行业涉足的苏宁、国美,都祭起了价格战这种“杀人一万自损八千”的法宝。虽然有论者认为,电商更应该注重自己的服务,而不是仅靠价格战,但恐怕电商这个业态,由于对消费者的吸引力很大一块建立在“便宜”上(相对于线下而言,理由是省略了大量的人工、场地、水电诸如此类的费用),价格对抗,大致是免不了的。

但其实电商的成本一点也不低——我有时候甚至会觉得,做一个电商怕是比线下开个店的成本低不到哪里去——有两部分的成本它高于线下店。其一是物流费用。消费者去线下店的成本是由消费者自己承担,买到了货也得自己想法子扛回去。但电商则以满多少多少包邮来吸引消费者,实质上就是将原来由消费者承担的成本转嫁到自己头上。第二部分费用在于吆喝。电商“全场3折”起的这条信息,要让足够多的人看到,是需要再次付出成本的。在对外广告上的投入,电商远远比线下店舍得花钱。

电商真正的优势在于“货架是无限的”——这也是安德森笔下的“长尾理论”。平台类这样的电商如果在线下开店,估计十层楼面都打不住(比如天猫就号称有6万个卖家)。每增加一个货品,只是增加一个页面。货品越多,最后所摊薄的宣传成本就越低。这也是线下店之所以不太会如此大规模投入广告的原因之一:摊薄的宣传成本有限。但是,光有货品没有交易显然是完成摊薄宣传成本的任务,电商必须刺激消费者来到自己的网站,并购买货品。最好的路,莫过于价格战了。

不过,中国电商的价格战使得他们的毛利率很低。有媒体近日援引一个电商人士的说法,京东的毛利率不过7-8%。虽然中国电商行业集体以亚马逊为师,但后者的毛利率一直在20%以上(哪怕是最艰难被万夫所指的亏损年代)。对于中国电商而言,追求的似乎更聚焦于“规模”上——也就是销量。而这个规模,直接和公司估值、未来上市有关。

一个公司上市之后,受到的公开市场的压力以及每季都必须发布财报,它动用价格战之前就必须谨慎异常。在中国市场上,稍大一点的上市电商(比如当当),对价格战属于防守性的。而文头所提及的若干平台类电商,无一上市,价格战就是进攻性的。我甚至可以这么说,在它们没有上市之前,价格战的对抗,将一直是常态,而不是间歇性的“促销战役”。

电商的价格战会不会让它们自身难以承受最终垮掉?我并不那么悲观。即便是打价格战最凶悍的京东,只要管理没有失控,就不会引发崩盘。几大平台类电商,事实上已经绑架了诸多投资者,已经到了“大而不死”的阶段。PPG全面溃败的原因在于品质失去控制,高管层集体出走,从目前的态势来看,平台类电商没有这类征兆。

价格战的后果就是加剧垄断的速度,也为后来者树立了一个极高的进入门槛:没有足够的实力(我以为都是亿当量级别的资金),就不要玩平台类。每一轮价格战都会指向这样一个结果:行业洗牌。从这个角度出发,如果哪一天爆出“凡客与某平台类电商合并”的新闻,我是一点不会奇怪的。

—— 《经济观察报》约稿 ——

附注说明一下:

1、报社约稿时,正处于从帝都回魔都的下午,身体且欠佳,有点浑浑噩噩,今日好些后,发现此文写得有些急就章了。

2、此文的重点在于电商(平台类)会出现并购。这是投资人的意志决定的,不是平时在媒体上经常出现的什么创始人什么首席执行官决定的。优土一案,已经足够明白地告诉了这一点:互联网实质是金融推动的。引申说一下,深得互联网喜欢的奥巴马信誓旦旦要打击华尔街,那是不可能的任务。

3、投资人在上市无望便无法退出的情况下,会推动公司之间的并购以达成换股。如果和某上市公司合并,这种换股就是变向退出。

4、要么上市退出,要么崩盘就认输。最怕吊在中间,而这种吊在中间只会是过渡性的。

关于作者
魏武挥, 上海交通大学媒体与设计学院, 教师
哥不做总好多年
Copyleft © 2010 知识共享署名-非商业性使用-禁止演绎 注意:转载勿改标题!
ItTalks -- 魏武挥的Blog (digitalfingerprint:fc4f8fc31f70097eea4b780b13146415)

欢迎 浏览我收集的信息图关注我的微博访问我的分享
无觅猜您也喜欢:
中国证券经纪业务百论之廿一:剖析佣金价格战
图书市场价格战的背后
谁是监管者?
电子阅读器:阅读器 版权 价格
无觅

与本日志可能相关的文章有:

]]>
0
<![CDATA[开发笔记(19) : 怪物行走控制]]> http://www.udpwork.com/item/7308.html http://www.udpwork.com/item/7308.html#reviews Tue, 15 May 2012 17:18:58 +0800 云风 http://www.udpwork.com/item/7308.html 这段时间项目进展还算顺利,叮当同学在盯项目进度,我专心解决程序上的各种小问题。

最近我在协助解决 NPC (包括地图上的怪物)的行为控制以及 AI 的问题。

目前,我们的进度还处在玩家可以通过客户端登陆到服务器,可以在场景上漫游,以及做一些简单的战斗和技能动作的阶段。按最初的设计原则,我们的每个玩家是在服务器上有一个独立的agent服务的。目前写到现在,和中间想过的一些实现方法有些差异,但大体上还是按这个思路进行的。 关键是在于去除大部分的回调方式的异步调用;编写的控制流程自然完整,不需要太多的去考虑 agent 行为之外的交互性。

如果丝毫不考虑性能问题,我很想把每单个怪物和 NPC 都放在独立服务中。但是估算后,觉得不太现实。在这一篇的最后一段已经提过这个问题了。

今天展开来谈谈我的方案。

我想把怪物的移动行为独立出来做,以减少 AI 的压力。也就是说,地图上所有的怪,在设定的时候,都可以设定他们的巡逻路径,或是仅仅站立不动。我希望在没有外力干扰的时候,处理这些行为对系统压力最小。

我不想让怪在没有任何玩家看见的时候就让它静止不动,因为这样可能会增加实现的复杂性,并在怪物行为较为复杂时,无法贯彻策划的意图。

最好的方法还是把之隔离,使其对系统的负荷受控。同时也可以通过分离,减小实现的复杂性。

这个子系统是这样的:

它可以接收请求,在单张地图上创建出怪物来。它只关心怪物的坐标。通过ShareDB和别的服务分享怪物的坐标。因为它只关心和修改怪物的坐标字段,所以适用于任何结构不同的怪物。

在创建出怪物对象后,可以接受指令,给怪物附加上一个行为。这个行为目前可以是静止,巡逻,跟随别的对象。

这个子系统以一个较低的频率(比如一秒一次),按行为去重新计算所有对象的位置。更新位置后,通过组播服务通知地图上所有的玩家 agent 。

这个子系统如何和主系统协作呢?

这里所谓主系统就是地图服务器。我们会把怪物的 AI 模块加载进去运行。怪物 AI 模块会由玩家的 agent 去被动驱动。就是说,如果没有 agent 触发 AI 的处理流程,AI 是死的,不占用 CPU 时间的。每个怪物在生成时,同时通知上述子系统构建一个对象,使它可以在地图中游荡。

怪物由子系统驱动游荡时,通过 AOI 子系统,有可能引发相关的处理逻辑。(一般是进入 agent 的视野,进而触发怪物的 AI 处理)

当怪物 AI 模块接管怪物的控制后,通知子系统删除对应对象,然后进入 AI 控制环节。

这个子系统可以分处于独立进程,独立 CPU 中,并且可以调节控制频率。所以我们可以把这些游荡怪物对系统的负载影响减轻到最小。让系统负荷仅和地图上玩家数量正相关。

对于复杂的怪物逻辑,比如副本中的 BOSS 还是可以以 agent 等价的形式放在一个独立的服务中去处理,这和上面的系统并无矛盾。

]]>
这段时间项目进展还算顺利,叮当同学在盯项目进度,我专心解决程序上的各种小问题。

最近我在协助解决 NPC (包括地图上的怪物)的行为控制以及 AI 的问题。

目前,我们的进度还处在玩家可以通过客户端登陆到服务器,可以在场景上漫游,以及做一些简单的战斗和技能动作的阶段。按最初的设计原则,我们的每个玩家是在服务器上有一个独立的agent服务的。目前写到现在,和中间想过的一些实现方法有些差异,但大体上还是按这个思路进行的。 关键是在于去除大部分的回调方式的异步调用;编写的控制流程自然完整,不需要太多的去考虑 agent 行为之外的交互性。

如果丝毫不考虑性能问题,我很想把每单个怪物和 NPC 都放在独立服务中。但是估算后,觉得不太现实。在这一篇的最后一段已经提过这个问题了。

今天展开来谈谈我的方案。

我想把怪物的移动行为独立出来做,以减少 AI 的压力。也就是说,地图上所有的怪,在设定的时候,都可以设定他们的巡逻路径,或是仅仅站立不动。我希望在没有外力干扰的时候,处理这些行为对系统压力最小。

我不想让怪在没有任何玩家看见的时候就让它静止不动,因为这样可能会增加实现的复杂性,并在怪物行为较为复杂时,无法贯彻策划的意图。

最好的方法还是把之隔离,使其对系统的负荷受控。同时也可以通过分离,减小实现的复杂性。

这个子系统是这样的:

它可以接收请求,在单张地图上创建出怪物来。它只关心怪物的坐标。通过ShareDB和别的服务分享怪物的坐标。因为它只关心和修改怪物的坐标字段,所以适用于任何结构不同的怪物。

在创建出怪物对象后,可以接受指令,给怪物附加上一个行为。这个行为目前可以是静止,巡逻,跟随别的对象。

这个子系统以一个较低的频率(比如一秒一次),按行为去重新计算所有对象的位置。更新位置后,通过组播服务通知地图上所有的玩家 agent 。

这个子系统如何和主系统协作呢?

这里所谓主系统就是地图服务器。我们会把怪物的 AI 模块加载进去运行。怪物 AI 模块会由玩家的 agent 去被动驱动。就是说,如果没有 agent 触发 AI 的处理流程,AI 是死的,不占用 CPU 时间的。每个怪物在生成时,同时通知上述子系统构建一个对象,使它可以在地图中游荡。

怪物由子系统驱动游荡时,通过 AOI 子系统,有可能引发相关的处理逻辑。(一般是进入 agent 的视野,进而触发怪物的 AI 处理)

当怪物 AI 模块接管怪物的控制后,通知子系统删除对应对象,然后进入 AI 控制环节。

这个子系统可以分处于独立进程,独立 CPU 中,并且可以调节控制频率。所以我们可以把这些游荡怪物对系统的负载影响减轻到最小。让系统负荷仅和地图上玩家数量正相关。

对于复杂的怪物逻辑,比如副本中的 BOSS 还是可以以 agent 等价的形式放在一个独立的服务中去处理,这和上面的系统并无矛盾。

]]>
0
<![CDATA[Visual C++中的几种函数调用方式]]> http://www.udpwork.com/item/7307.html http://www.udpwork.com/item/7307.html#reviews Tue, 15 May 2012 13:54:54 +0800 admin http://www.udpwork.com/item/7307.html (本文中所有汇编代码均采用Intel语法,即dest在左边)

C++中的函数被编译成汇编代码的时候,必须遵循一定的规范,如参数怎么传递,栈指针怎么增减。Visual C++中,一共有5种情况:

  1. __cdecl
  2. __stdcall
  3. __fastcall
  4. __thiscall

默认情况下,是__cdecl。__cdecl 和__stdcall的区别是:__cdecl是调用者清理栈,而__stdcall是被调用者清理栈。所以,理论来说,__cdecl生成的代码体积会更大。但是,对于varargs函数,由于被调用者并不知道参数的具体长度,所以这样的函数只能采用__cdecl。

所有这四种方式,生成的函数都有固定的边界特征,

__cdecl 和__stdcall以这样的模式开始:

push ebp ;保存ebp
mov ebp,esp ;设置栈指针
sub esp,0C0h ;为局部变量保留栈空间
push ebx ;保存在这个函数中可能用到的寄存器
push esi ;保存在这个函数中可能用到的寄存器
push edi ;保存在这个函数中可能用到的寄存器

以这样的模式结束:

pop edi ;恢复寄存器原先的值
pop esi ;恢复寄存器原先的值
pop ebx ;恢复寄存器原先的值
add esp,0C0h ;与前面的sub esp,0C0h对应
mov esp,ebp ;恢复栈指针
pop ebp ;恢复ebp
ret

其中 “mov esp,ebp; pop ebp;”也可替换成一句“leave”指令。

如果是__stdcall,最后一行的ret会变成

ret 0Ch

这样。最后的那个数字代表从栈上弹出多少个字节,它应当等于函数参数的总大小。

类的成员函数默认是采用__thiscall。它与__stdcall非常相似,区别是this指针会通过ecx传递。所以,如果在一个函数中发现ecx未被赋值就开始读它,那么多半是__thiscall。如

push ebp ;保存ebp
mov ebp, esp ;设置栈指针
push ecx ;保存在这个函数中可能用到的寄存器
push ebx ;保存在这个函数中可能用到的寄存器
push esi ;保存在这个函数中可能用到的寄存器
mov esi, ecx ; 注意!!!ecx尚未被赋值就开始读了
mov ebx, [esi+344h] ; this指针一般存放在esi中,并且在整个函数体内,esi尽量保持不变。

另外再次强调,__thiscall末尾的ret语句要跟一个数字,来清理栈上的函数参数。

另外就是,如果类成员函数采用了变长参数列表,那么就不能用__thiscall,而必须用__cdecl,把this指针作为最后一个参数弹入。

__fastcall和__thiscall有时候很难区分开。__fastcall是把前2个DWORD类型的参数用ecx,edx传递,其它的继续push进栈里。

假设函数声明为:

void __fastcall testfunc(int x,int y);

那么调用这个函数的代码testfunc(3,4)就会被编译成

mov edx,4
mov ecx,3
call testfunc

"/GS" : Buffer Security Check

如果编译的时候加了"/GS"参数,并且开启了优化(如Release版本),那么对于某些可能会遭受缓存区溢出攻击的函数,编译器在生成代码的时候,会在函数局部变量的最末尾加一个4字节的cookie。如:

push ebp
mov ebp, esp
sub esp, 214h
mov eax, ___security_cookie ; random value, initialized at module startup
xor eax, ebp ; XOR it with the current base pointer
mov [ebp+var_4], eax ; store the cookie

___security_cookie是一个随机数,在程序启动的时候由CRT初始化,此处把当前的栈指针(ebp)和这个cookie作XOR运算,然后在return之前再检查一遍:

mov ecx, [ebp+var_4] ; get the cookie from the stack
xor ecx, ebp ; XOR the cookie with the current base pointer
call __security_check_cookie ; check the cookie
leave
retn 0Ch

__security_check_cookie是一个__fastcall,代码如下:

void __declspec(naked) __fastcall __security_check_cookie(UINT_PTR cookie)
{
    /* x86 version written in asm to preserve all regs */
    __asm {
        cmp ecx, __security_cookie
            jne failure
            rep ret /* REP to avoid AMD branch prediction penalty */
failure:
        jmp __report_gsfailure
    }
}

就是简单的做下比较,不正确则终止。

]]>
(本文中所有汇编代码均采用Intel语法,即dest在左边)

C++中的函数被编译成汇编代码的时候,必须遵循一定的规范,如参数怎么传递,栈指针怎么增减。Visual C++中,一共有5种情况:

  1. __cdecl
  2. __stdcall
  3. __fastcall
  4. __thiscall

默认情况下,是__cdecl。__cdecl 和__stdcall的区别是:__cdecl是调用者清理栈,而__stdcall是被调用者清理栈。所以,理论来说,__cdecl生成的代码体积会更大。但是,对于varargs函数,由于被调用者并不知道参数的具体长度,所以这样的函数只能采用__cdecl。

所有这四种方式,生成的函数都有固定的边界特征,

__cdecl 和__stdcall以这样的模式开始:

push ebp ;保存ebp
mov ebp,esp ;设置栈指针
sub esp,0C0h ;为局部变量保留栈空间
push ebx ;保存在这个函数中可能用到的寄存器
push esi ;保存在这个函数中可能用到的寄存器
push edi ;保存在这个函数中可能用到的寄存器

以这样的模式结束:

pop edi ;恢复寄存器原先的值
pop esi ;恢复寄存器原先的值
pop ebx ;恢复寄存器原先的值
add esp,0C0h ;与前面的sub esp,0C0h对应
mov esp,ebp ;恢复栈指针
pop ebp ;恢复ebp
ret

其中 “mov esp,ebp; pop ebp;”也可替换成一句“leave”指令。

如果是__stdcall,最后一行的ret会变成

ret 0Ch

这样。最后的那个数字代表从栈上弹出多少个字节,它应当等于函数参数的总大小。

类的成员函数默认是采用__thiscall。它与__stdcall非常相似,区别是this指针会通过ecx传递。所以,如果在一个函数中发现ecx未被赋值就开始读它,那么多半是__thiscall。如

push ebp ;保存ebp
mov ebp, esp ;设置栈指针
push ecx ;保存在这个函数中可能用到的寄存器
push ebx ;保存在这个函数中可能用到的寄存器
push esi ;保存在这个函数中可能用到的寄存器
mov esi, ecx ; 注意!!!ecx尚未被赋值就开始读了
mov ebx, [esi+344h] ; this指针一般存放在esi中,并且在整个函数体内,esi尽量保持不变。

另外再次强调,__thiscall末尾的ret语句要跟一个数字,来清理栈上的函数参数。

另外就是,如果类成员函数采用了变长参数列表,那么就不能用__thiscall,而必须用__cdecl,把this指针作为最后一个参数弹入。

__fastcall和__thiscall有时候很难区分开。__fastcall是把前2个DWORD类型的参数用ecx,edx传递,其它的继续push进栈里。

假设函数声明为:

void __fastcall testfunc(int x,int y);

那么调用这个函数的代码testfunc(3,4)就会被编译成

mov edx,4
mov ecx,3
call testfunc

"/GS" : Buffer Security Check

如果编译的时候加了"/GS"参数,并且开启了优化(如Release版本),那么对于某些可能会遭受缓存区溢出攻击的函数,编译器在生成代码的时候,会在函数局部变量的最末尾加一个4字节的cookie。如:

push ebp
mov ebp, esp
sub esp, 214h
mov eax, ___security_cookie ; random value, initialized at module startup
xor eax, ebp ; XOR it with the current base pointer
mov [ebp+var_4], eax ; store the cookie

___security_cookie是一个随机数,在程序启动的时候由CRT初始化,此处把当前的栈指针(ebp)和这个cookie作XOR运算,然后在return之前再检查一遍:

mov ecx, [ebp+var_4] ; get the cookie from the stack
xor ecx, ebp ; XOR the cookie with the current base pointer
call __security_check_cookie ; check the cookie
leave
retn 0Ch

__security_check_cookie是一个__fastcall,代码如下:

void __declspec(naked) __fastcall __security_check_cookie(UINT_PTR cookie)
{
    /* x86 version written in asm to preserve all regs */
    __asm {
        cmp ecx, __security_cookie
            jne failure
            rep ret /* REP to avoid AMD branch prediction penalty */
failure:
        jmp __report_gsfailure
    }
}

就是简单的做下比较,不正确则终止。

]]>
0
<![CDATA[核心版本——Programmers(37)]]> http://www.udpwork.com/item/7305.html http://www.udpwork.com/item/7305.html#reviews Tue, 15 May 2012 13:36:02 +0800 西乔 http://www.udpwork.com/item/7305.html 载于《程序员》杂志2012年第5期。

核心版本——《神秘的程序员们》系列漫画

这个系列的漫画讲述程序员——这种神秘人类的囧事,故事多来源于我身边的程序员朋友,且以互联网开发背景为主。

如果你有什么可乐的关于程序员的故事、对话、代码,愿意通过漫画的形式分享,请给我发邮件。

]]>
载于《程序员》杂志2012年第5期。

核心版本——《神秘的程序员们》系列漫画

这个系列的漫画讲述程序员——这种神秘人类的囧事,故事多来源于我身边的程序员朋友,且以互联网开发背景为主。

如果你有什么可乐的关于程序员的故事、对话、代码,愿意通过漫画的形式分享,请给我发邮件。

]]>
0
<![CDATA[移动开发者——Programmers(36)]]> http://www.udpwork.com/item/7306.html http://www.udpwork.com/item/7306.html#reviews Tue, 15 May 2012 13:33:02 +0800 西乔 http://www.udpwork.com/item/7306.html 载于《程序员》杂志2012年第4期。

移动开发者——《神秘的程序员们》系列漫画

感谢Stony Wang同学作为Android开发者的代表向我提供了各类悲剧list。

这个系列的漫画讲述程序员——这种神秘人类的囧事,故事多来源于我身边的程序员朋友,且以互联网开发背景为主。

如果你有什么可乐的关于程序员的故事、对话、代码,愿意通过漫画的形式分享,请给我发邮件。

]]>
载于《程序员》杂志2012年第4期。

移动开发者——《神秘的程序员们》系列漫画

感谢Stony Wang同学作为Android开发者的代表向我提供了各类悲剧list。

这个系列的漫画讲述程序员——这种神秘人类的囧事,故事多来源于我身边的程序员朋友,且以互联网开发背景为主。

如果你有什么可乐的关于程序员的故事、对话、代码,愿意通过漫画的形式分享,请给我发邮件。

]]>
1
<![CDATA[360为什么要做特供机?]]> http://www.udpwork.com/item/7284.html http://www.udpwork.com/item/7284.html#reviews Tue, 15 May 2012 10:41:20 +0800 周鸿祎 http://www.udpwork.com/item/7284.html 今天,无论你是乘坐地铁、公交车,走在大街上,或者坐在咖啡厅,都会看到很多人在玩手机。他们不是在打电话,不是在发短信,而是在上网、玩微博、看小说、玩游戏。手机成为一个小电脑,是一个永远在线的移动终端,这已经成为业界的一个共识。

手机作为移动终端,越来越紧密地与互联网服务商联系在一起。像亚马逊公司,本来是做零售的,就可以把Kindle做成零利润的移动终端,虽然从一次性卖硬件上没有获得收入,但可以在此基础上向用户提供一种长期的服务。从苹果的市场营销来看,苹果显然是通过产品快速更新,加快了产品大众化的步伐。虽然单品的利润空间在逐步减少,但为提供大规模的云服务奠定了基础。

智能手机的互联网化与传统的渠道营销模式发生了碰撞,既有火花,也有压力。很多手机厂商在面临着互联网冲击的时候,都在问这样一个问题:

到底什么是互联网化?

在我看来,智能手机的互联网化分为以下”四化”:

第一是商业模式互联网化。KK早就预言说,未来的硬件一定是免费的。当然,达到硬件免费需要一个过程,在中国更是如此。但硬件价格降低,向零利润方向发展,至少在美国这样的互联网发达国家,已经成为趋势。虽然移动终端的利润趋近于零,但通过内置的各种增值服务,同样可以建立起互联网化的商业模式。

第二是产品体验互联网化。过去的手机主要是用来打电话、发短信的。内置的游戏也非常简单。但现在,智能手机就是一部小电脑,用户频繁地下载软件,而且软件也像在PC上一样很快地进行更新。因此,智能手机像PC一样,越来越注重用户体验。与硬件厂商相比,互联网公司能更好地把握用户对产品体验的需求。

第三是市场推广的互联网化。传统的手机推广方式通过卖点策划和大量的广告投放,达到吸引用户、接触用户的目的。现在,进入互联网时代,产品的推广要基于好的产品体验,依靠口碑进行推广传播。作为新媒体,互联网的SNS特点打乱了传统广告对人群的划分方式,提供了一种低成本的推广方式。

第四,产品销售的互联网化。互联网既是媒体传播平台,也是电子商务平台。电子商务是扁平化的销售模式,压缩了中间渠道的沉淀成本。

360为什么要做智能手机开放平台?

手机的互联网化是个大趋势,但我自认为360既没有能力,也没有意愿去颠覆传统手机行业。360一直坚持两点的认知:第一,360始终是专注于互联网软件和服务,特别是互联网安全的公司;第二,360始终是坚持开放的原则。今天,许多传统的手机厂商迫切地想尝试互联网化的新模式,而360恰恰在互联网的产品体验和营销资源方面可以弥补它们的不足。所以,我们准备推出手机开放平台,和手机厂商合作,为360用户提供高性能、高配置、低价格、体验好的特供手机。

比如,利用理解用户需求方面的经验,我们可以帮助手机硬件厂商去打磨软件。在它们的观念里,手机软件一次提供,终身不变。但从我们的角度来看,软件必须要根据用户的需要时时升级更新。再比如,我们在互联网营销方面可以为手机厂商开拓思维,并利用360的互联网渠道帮助它们接触到用户,同样我们可以与电商伙伴合作提供手机的销售平台。另外,360拥有4亿用户,有多个平台产品,所接触的用户绝对不亚于无数线下卖场,这可以帮助手机厂商节约大量成本。

与手机厂商合作,一方面360的用户因为得到了配置高、体验好、价格低的智能手机,从而对360有更高的信任,创造更好的口碑,另一方面通过内置的互联网增值服务,我们可以与手机厂商形成长期的利益共享关系。这对于厂商、360和用户来说,是多赢的局面。我一直坚持这样的观点:帮助别人成功的生意才是一门好生意。无论是在PC互联网上,还是在智能手机的开放平台上,360都坚持“有所为,有所不为”的原则,让专业的人干专业的事,优势互补,利益共享,这样的生意才能是一门长久的生意。

360对手机厂商的质量要求是什么?

360的特供手机平台对所有手机硬件厂商开放,欢迎合作。但对于合作伙伴,我这里有几个要求:第一,这个厂商做手机必须要有若干年的历史,这样才能保证手机的硬件质量。对智能手机的“新军”,我可以帮着出主意,但是不会选这样的手机作为合作伙伴。第二,我们选择的手机厂商,每年的出货量必须足够大,比如最低不能少于500万只。为什么要有最低出货量?因为出货量越大,原料的采购价格就越低,让利于消费者的空间就越大。第三,在全国范围内要有线下的售后服务。售后服务跟不上,不仅损害原厂的品牌,而且也损害360的品牌。我们追求的是为360用户提供长期的价值,因此360的特供机必须要在质量、价格、售后服务方面过得硬。

360特供手机售价不超过1999元

我一直有个观点,就是除了镶钻镶黄金的,智能手机终将会变成一种大众消费品,一年一换,没有什么高端、低端之分。智能手机终将会像现在的笔记本一样,普及大众,人手一台。

360特供机要高配置、低价格。首先必须是4寸以上高清屏,这样看电影、看电子书、玩游戏才有视觉感;其次,CPU不低于1个G,这样才能要保证玩各种应用的速度;第三手机的摄像头必须是高清摄像头,这样拍出来的照片跟卡片式相机差不多。

360特供机售价不超过1999元。

开放、安全的软件环境

智能手机好不好,一个是靠硬件配置,一个是靠软件。现在,在智能手机行业有一个非常不好的现象,手机里预置的软件删除不掉,除非你把系统给刷了。我觉得预置软件无可厚非,但必须要尊重用户选择安装软件、卸载软件的权利。我这里可以保证,在360特供机里的软件都是可以删掉的,如果你不喜欢360的软件,你照样可以把360删掉。

我们一直强调开放,在PC上是如此,在智能手机上也是如此。微博上有人调侃,说360特供机不允许用户安装QQ,不允许用户使用百度搜索。这种说法真的是不负责任。凡是用户喜欢的软件,他都可以自由安装;凡是用户讨厌的软件,他都可以自由删除。360特供机就是一个中立的平台,用户选择用谁的软件,除非与360发生冲突,360一概不干涉。

安卓平台是开放平台,随着用户量的增加,其安全问题也会越来越突出。360是国内第一大手机安全厂商,360特供机更大的优点就是安全。

]]>
今天,无论你是乘坐地铁、公交车,走在大街上,或者坐在咖啡厅,都会看到很多人在玩手机。他们不是在打电话,不是在发短信,而是在上网、玩微博、看小说、玩游戏。手机成为一个小电脑,是一个永远在线的移动终端,这已经成为业界的一个共识。

手机作为移动终端,越来越紧密地与互联网服务商联系在一起。像亚马逊公司,本来是做零售的,就可以把Kindle做成零利润的移动终端,虽然从一次性卖硬件上没有获得收入,但可以在此基础上向用户提供一种长期的服务。从苹果的市场营销来看,苹果显然是通过产品快速更新,加快了产品大众化的步伐。虽然单品的利润空间在逐步减少,但为提供大规模的云服务奠定了基础。

智能手机的互联网化与传统的渠道营销模式发生了碰撞,既有火花,也有压力。很多手机厂商在面临着互联网冲击的时候,都在问这样一个问题:

到底什么是互联网化?

在我看来,智能手机的互联网化分为以下”四化”:

第一是商业模式互联网化。KK早就预言说,未来的硬件一定是免费的。当然,达到硬件免费需要一个过程,在中国更是如此。但硬件价格降低,向零利润方向发展,至少在美国这样的互联网发达国家,已经成为趋势。虽然移动终端的利润趋近于零,但通过内置的各种增值服务,同样可以建立起互联网化的商业模式。

第二是产品体验互联网化。过去的手机主要是用来打电话、发短信的。内置的游戏也非常简单。但现在,智能手机就是一部小电脑,用户频繁地下载软件,而且软件也像在PC上一样很快地进行更新。因此,智能手机像PC一样,越来越注重用户体验。与硬件厂商相比,互联网公司能更好地把握用户对产品体验的需求。

第三是市场推广的互联网化。传统的手机推广方式通过卖点策划和大量的广告投放,达到吸引用户、接触用户的目的。现在,进入互联网时代,产品的推广要基于好的产品体验,依靠口碑进行推广传播。作为新媒体,互联网的SNS特点打乱了传统广告对人群的划分方式,提供了一种低成本的推广方式。

第四,产品销售的互联网化。互联网既是媒体传播平台,也是电子商务平台。电子商务是扁平化的销售模式,压缩了中间渠道的沉淀成本。

360为什么要做智能手机开放平台?

手机的互联网化是个大趋势,但我自认为360既没有能力,也没有意愿去颠覆传统手机行业。360一直坚持两点的认知:第一,360始终是专注于互联网软件和服务,特别是互联网安全的公司;第二,360始终是坚持开放的原则。今天,许多传统的手机厂商迫切地想尝试互联网化的新模式,而360恰恰在互联网的产品体验和营销资源方面可以弥补它们的不足。所以,我们准备推出手机开放平台,和手机厂商合作,为360用户提供高性能、高配置、低价格、体验好的特供手机。

比如,利用理解用户需求方面的经验,我们可以帮助手机硬件厂商去打磨软件。在它们的观念里,手机软件一次提供,终身不变。但从我们的角度来看,软件必须要根据用户的需要时时升级更新。再比如,我们在互联网营销方面可以为手机厂商开拓思维,并利用360的互联网渠道帮助它们接触到用户,同样我们可以与电商伙伴合作提供手机的销售平台。另外,360拥有4亿用户,有多个平台产品,所接触的用户绝对不亚于无数线下卖场,这可以帮助手机厂商节约大量成本。

与手机厂商合作,一方面360的用户因为得到了配置高、体验好、价格低的智能手机,从而对360有更高的信任,创造更好的口碑,另一方面通过内置的互联网增值服务,我们可以与手机厂商形成长期的利益共享关系。这对于厂商、360和用户来说,是多赢的局面。我一直坚持这样的观点:帮助别人成功的生意才是一门好生意。无论是在PC互联网上,还是在智能手机的开放平台上,360都坚持“有所为,有所不为”的原则,让专业的人干专业的事,优势互补,利益共享,这样的生意才能是一门长久的生意。

360对手机厂商的质量要求是什么?

360的特供手机平台对所有手机硬件厂商开放,欢迎合作。但对于合作伙伴,我这里有几个要求:第一,这个厂商做手机必须要有若干年的历史,这样才能保证手机的硬件质量。对智能手机的“新军”,我可以帮着出主意,但是不会选这样的手机作为合作伙伴。第二,我们选择的手机厂商,每年的出货量必须足够大,比如最低不能少于500万只。为什么要有最低出货量?因为出货量越大,原料的采购价格就越低,让利于消费者的空间就越大。第三,在全国范围内要有线下的售后服务。售后服务跟不上,不仅损害原厂的品牌,而且也损害360的品牌。我们追求的是为360用户提供长期的价值,因此360的特供机必须要在质量、价格、售后服务方面过得硬。

360特供手机售价不超过1999元

我一直有个观点,就是除了镶钻镶黄金的,智能手机终将会变成一种大众消费品,一年一换,没有什么高端、低端之分。智能手机终将会像现在的笔记本一样,普及大众,人手一台。

360特供机要高配置、低价格。首先必须是4寸以上高清屏,这样看电影、看电子书、玩游戏才有视觉感;其次,CPU不低于1个G,这样才能要保证玩各种应用的速度;第三手机的摄像头必须是高清摄像头,这样拍出来的照片跟卡片式相机差不多。

360特供机售价不超过1999元。

开放、安全的软件环境

智能手机好不好,一个是靠硬件配置,一个是靠软件。现在,在智能手机行业有一个非常不好的现象,手机里预置的软件删除不掉,除非你把系统给刷了。我觉得预置软件无可厚非,但必须要尊重用户选择安装软件、卸载软件的权利。我这里可以保证,在360特供机里的软件都是可以删掉的,如果你不喜欢360的软件,你照样可以把360删掉。

我们一直强调开放,在PC上是如此,在智能手机上也是如此。微博上有人调侃,说360特供机不允许用户安装QQ,不允许用户使用百度搜索。这种说法真的是不负责任。凡是用户喜欢的软件,他都可以自由安装;凡是用户讨厌的软件,他都可以自由删除。360特供机就是一个中立的平台,用户选择用谁的软件,除非与360发生冲突,360一概不干涉。

安卓平台是开放平台,随着用户量的增加,其安全问题也会越来越突出。360是国内第一大手机安全厂商,360特供机更大的优点就是安全。

]]>
0
<![CDATA[NoSQL 数据建模技术]]> http://www.udpwork.com/item/7283.html http://www.udpwork.com/item/7283.html#reviews Tue, 15 May 2012 08:22:13 +0800 陈皓 http://www.udpwork.com/item/7283.html 全文译自墙外文章“NoSQL Data Modeling Techniques”,译得不好,还请见谅。这篇文章看完之后,你可能会对NoSQL的数据结构会有些感觉。我的感觉是,关系型数据库想把一致性,完整性,索引,CRUD都干好,NoSQL只干某一种事,但是牺牲了很多别的东西。总体来说,我觉得NoSQL更适合做Cache。下面是正文——

NoSQL 数据库经常被用作很多非功能性的地方,如,扩展性,性能和一致性的地方。这些NoSQL的特性在理论和实践中都正在被大众广泛地研究着,研究的热点正是那些和性能分布式相关的非功能性的东西,我们都知道CAP 理论被很好地应用于了 NoSQL 系统中(陈皓注:CAP即,一致性(Consistency), 可用性(Availability), 分区容忍性(Partition tolerance),在分布式系统中,这三个要素最多只能同时实现两个,而NoSQL一般放弃的是一致性)。但在另一方面,NoSQL的数据建模技术却因为缺乏像关系型数据库那样的基础理论没有被世人很好地研究。这篇文章从数据建模方面对NoSQL家族进行了比较,并讨论几个常见的数据建模技术。

要开始讨论数据建模技术,我们不得不或多或少地先系统地看一下NoSQL数据模型的成长的趋势,以此我们可以了解一些他们内在的联系。下图是NoSQL家族的进化图,我们可以看到这样的进化:Key-Value时代,BigTable时代,Document时代,全文搜索时代,和Graph数据库时代:(陈皓注:注意图中SQL说的那句话,NoSQL再这样发展下去就是SQL了,哈哈。)


NoSQL Data Models

首先,我们需要注意的是SQL和关系型数据模型已存在了很长的时间,这种面向用户的自然性意味着:

  • 最终用户一般更感兴趣于数据的聚合显示,而不是分离的数据,这主要通过SQL来完成。
  • 我们无法通过人手工控制数据的并发性,完整性,一致性,或是数据类型校验这些东西的。这就是为什么SQL需要在事务,二维表结构(schema)和外表联合上做很多事。

另一方面,SQL可以让软件应用程序在很多情况下不需要关心数据库的数据聚合,和数据完整性和有效性进行控制。而如果我们去除了数据一致性,完整性这些东西,会对性能和分布存储有着重的帮助。正因为如此,我们才有数据模型的进化:

  • Key-Value 键值对存储 是非常简单而强大的。下面的很多技术基本上都是基于这个技术开始发展的。但是,Key-Value有一个非常致命的问题,那就是如果我们需要查找一段范围内的key。(陈皓注:学过hash-table数据结构的人都应该知道,hash-table是非序列容器,其并不像数组,链接,队列这些有序容器,我们可以控制数据存储的顺序)。于是,有序键值 (Ordered Key-Value) 数据模型被设计出来解决这一限制,来从根本上提高数据集的问题。
  • Ordered Key-Value 有序键值 模型也非常强大,但是,其也没有对Value提供某种数据模型。通常来说,Value的模型可以由应用负责解析和存取。这种很不方便,于是出现了 BigTable类型的数据库,这个数据模型其实就是map里有map,map里再套map,一层一层套下去,也就是层层嵌套的key-value(value里又是一个key-value),这种数据库的Value主要通过“列族”(column families),列,和时间戳来控制版本。(陈皓注:关于时间戳来对数据的版本控制主要是解决数据存储并发问题,也就是所谓的乐观锁,详见《多版本并发控制(MVCC)在分布式系统中的应用》)
  • Document databases 文档数据库  改进了 BigTable 模型,并提供了两个有意义的改善。第一个是允许Value中有主观的模式(scheme),而不是map套map。第二个是索引。Full Text Search Engines 全文搜索引擎 可以被看作是文档数据库的一个变种,他们可以提供灵活的可变的数据模式(scheme)以及自动索引。他们之间的不同点主要是,文档数据库用字段名做索引,而全文搜索引擎用字段值做索引。
  • Graph data models 图式数据库  可以被认为是这个进化过程中从 Ordered Key-Value 数据库发展过来的一个分支。图式数据库允许构建议图结构的数据模型。它和文档数据库有关系的原因是,它的很多实现允许value可以是一个map或是一个document。

 NoSQL 数据模型摘要

本文剩下的章节将向你介绍数据建模的技术实现和相关模式。但是,在介绍这些技术之前,先来一段序言:

  • NoSQL 数据模型设计一般从业务应用的具体数据查询入手,而不是数据间的关系:
    • 关系型的数据模型基本上是分析数据间的结构和关系。其设计理念是: ”What answers do I have?”
    • NoSQL 数据模型基本上是从应用对数据的存取方式入手,如:我需要支持某种数据查询。其设计理念是 ”What questions do I have?”
  • NoSQL 数据模型设计比关系型数据库需要对数据结构和算法的更深的了解。在这篇文章中我会和大家说那些尽人皆知的数据结构,这些数据结构并不只是被NoSQL使用,但是对于NoSQL的数据模型却非常有帮助。
  • 数据冗余和反规格化是一等公民。
  • 关系型数据库对于处理层级数据和图式数据非常的不方便。NoSQL用来解决图式数据明显是一个非常好的解决方案,几乎所有的NoSQL数据库可以很强地解决此类问题。这就是为什么这篇文章专门拿出一章来说明层级数据模型。
下面是NoSQL的分类表,也是我用来写这篇文章时做实践的产品:
  • Key-Value 存储: Oracle Coherence, Redis, Kyoto Cabinet
  • 类BigTable存储: Apache HBase, Apache Cassandra
  • 文档数据库: MongoDB, CouchDB
  • 全文索引: Apache Lucene, Apache Solr
  • 图数据库: neo4j, FlockDB

概念技术 Conceptual Techniques

这一节主要介绍NoSQL数据模型的基本原则。

(1) 反规格化 Denormalization

反规格化 Denormalization 可以被认为是把相同的数据拷贝到不同的文档或是表中,这样就可以简化和优化查询,或是正好适合用户的某中特别的数据模型。这篇文章中所说的绝大多数技术都或多或少地导向了这一技术。

总体来说,反规格化需要权衡下面这些东西:

  • 查询数据量 /查询IO  VS  总数据量 。使用反规格化,一方面可以把一条查询语句所需要的所有数据组合起来放到一个地方存储。这意味着,其它不同不同查询所需要的相同的数据,需要放在别不同的地方。因此,这产生了很多冗余的数据,从而导致了数据量的增大。
  • 处理复杂度  VS总数据量 . 在符合范式的数据模式上进行表连接的查询,很显然会增加了查询处理的复杂度,尤其对于分布式系统来说更是。反规格化的数据模型允许我们以方便查询的方式来存构造数据结构以简化查询复杂度。

适用性 : Key-Value Store 键值对数据库, Document Databases文档数据库, BigTable风格的数据库。

(2) 聚合 Aggregates

所有类型的NoSQL数据库都会提供灵活的Schema(数据结构,对数据格式的限制):

  • Key-Value Stores 和 Graph Databases 基本上来说不会Value的形式,所以Value可以是任意格式。这样一来,这使得我们可以任意组合一个业务实体的keys。比如,我们有一个用户帐号的业务实体,其可以被如下这些key组合起来: UserID_name, UserID_email, UserID_messages 等等。如果一个用户没有email或message,那么相应也不会有这样的记录。
  • BigTable 模型通过列集合来支持灵活的Schema,我们称之为列族(column family)。BigTable还可以在同一记录上出现不同的版本(通过时间戳)。
  • Document databases 文档数据库是一种层级式的“去Schema”的存储,虽然有些这样的数据库允许检验需要保存的数据是否满足某种Schema。

灵活的Schema允许你可以用一种嵌套式的内部数据方式来存储一组有关联的业务实体(陈皓注:类似于JSON这样的数据封装格式)。这样可以为我们带来两个好处。

  • 最小化“一对多”关系——可以通过嵌套式的方式来存储实体,这样可以少一些表联结。
  • 可以让内部技术上的数据存储更接近于业务实体,特别是那种混合式的业务实体。可能存于一个文档集或是一张表中。
下图示意了这两种好处。图中描给了电子商务中的商品模型(陈皓注:我记得我在“挑战无处不在”一文中说到过电商中产品分类数据库设计的挑战)
  • 首先,所有的商品Product都会有一个ID,Price 和 Description。
  • 然后,我们可以知道不同的类型的商品会有不同的属性。比如,作者是书的属性,长度是牛仔裤的属性。其些属性可能是“一对多”或是“多对多”的关系,如:唱片中的曲目。
  • 接下来,我们知道,某些业务实体不可能使用固定的类型。如:牛仔裤的属性并不是所有的牌子都有的,而且,有些名牌还会搞非常特别的属性。

对于关系型数据库来说,要设计这样的数据模型并不简单,而且设计出来的绝对离优雅很远很远。而我们NoSQL中灵活的Schema允许你使用一个聚合 Aggregate (product) 可以建出所有不同种类的商品和他们的不同的属性:

Entity Aggregation

上图中我们可以比较关系型数据库和NoSQL的差别。但是我们可以看到在数据更新上,非规格化的数据存储在性能和一致性上会有很大的影响,这就是我们需要重点注意和不得不牺牲的地方

适用性 : Key-Value Store 键值对数据库, Document Databases文档数据库, BigTable风格的数据库。

(3) 应用层联结 Application Side Joins

表联结基本上不被NoSQL支持。正如我们前面所说的,NoSQL是“面向问题”而不是“面向答案”的,不支持表联结就是“面向问题”的后果。表的联结是在设计时被构造出来的,而不是在执行时建造出来的。所以,表联结在运行时是有很大开销的(陈皓注:搞过SQL表联结的都知道笛卡尔积是什么东西,大可以在参看以前酷壳的“图解数据库表Joins”),但是在使用了 Denormalization 和 Aggregates 技术后,我们基本不用进行表联结,如:你们使用嵌套式的数据实体。当然,如果你需要联结数据,你需要在应用层完成这个事。下面是几个主要的Use Case:

  • 多对多的数据实体关系——经常需要被连接或联结。
  • 聚合 Aggregates 并不适用于数据字段经常被改变的情况。对此,我们需要把那些经常被改变的字段分到另外的表中,而在查询时我们需要联结数据。例如,我们有个Message系统可以有一个User实体,其包括了一个内嵌的Message实体。但是,如果用户不断在附加 message,那么,最好把message拆分到另一个独立的实体,但在查询时联结这User和Message这两个实体。如下图:

适用性 : Key-Value Store 键值对数据库, Document Databases文档数据库, BigTable风格的数据库, Graph Databases 图数据库。

通用建模技术 General Modeling Techniques

在本书中,我们将讨论NoSQL中各种不同的通用的数据建模技术。

(4) 原子聚合 Atomic Aggregates

很多NoSQL的数据库(并不是所有)在事务处理上都是短板。在某些情况下,他们可以通过分布式锁技术或是应用层管理的MVCC技术来实现其事务性(陈皓注:可参看本站的“多版本并发控制(MVCC)在分布式系统中的应用”)但是,通常来说只能使用聚合Aggregates技术来保证一些ACID原则。

这就是为什么我们的关系型数据库需要有强大的事务处理机制——因为关系型数据库的数据是被规格化存放在了不同的地方。所以,Aggregates聚合允许我们把一个业务实体存成一个文档、存成一行,存成一个key-value,这样就可以原子式的更新了:


Atomic Aggregates

当然,原子聚合 Atomic Aggregates 这种数据模型并不能实现完全意义上的事务处理,但是如果支持原子性,锁,或 test-and-set 指令,那么, Atomic Aggregates 是可以适用的。

适用性 Key-Value Store 键值对数据库, Document Databases文档数据库, BigTable风格的数据库。

(5) 可枚举键 Enumerable Keys

也许,对于无顺序的Key-Value最大的好处是业务实体可以被容易地hash以分区在多个服务器上。而排序了的key会把事情搞复杂,但是有些时候,一个应用能从排序key中获得很多好处,就算是数据库本身不提供这个功能。让我们来思考下email消息的数据模型:

  1. 一些NoSQL的数据库提供原子计数器以允许生一些连续的ID。在这种情况下,我们可以使用 userID_messageID 来做为一个组合key。如果我们知道最新的message ID,就可以知道前一个message,也可能知道再前面和后面的Message。
  2. Messages可以被打包。比如,每天的邮件包。这样,我们就可以对邮件按指定的时间段来遍历。

适用性 Key-Value Store 键值对数据库

(6) 降维 Dimensionality Reduction

Dimensionality Reduction 降维是一种技术可以允许把一个多维的数据映射成一个Key-Value或是其它非多给的数据模型。

传统的地理位置信息系统使用一些如“四分树QuadTree” 或 “R-Tree” 来做地理位置索引。这些数据结构的内容需要被在适当的位置更新,并且,如果数据量很大的话,操作成本会很高。另一个方法是我们可以遍历一个二维的数据结构并把其扁平化成一个列表。一个众所周知的例子是Geohash(地理哈希)。一个Geohash使用“之字形”的路线扫描一个2维的空间,而且遍历中的移动可以被简单地用0和1来表示其方向,然后在移动的过程中产生0/1串。下图展示了这一算法:(陈皓注:先把地图分成四份,经度为第一位,纬度为第二位,于是左边的经度是0,右边的是1,纬度也一样,上面是为1,下面的为0,这样,经纬度就可以组合成01,11,00,10这四个值,其标识了四块区域,我们可以如此不断的递归地对每个区域进行四分,然后可以得到一串1和0组成的字串,然后使用0-9,b-z 去掉(去掉a, i, l, o)这32个字母进行base32编码得到一个8个长度的编码,这就是Geohash的算法)


Geohash Index

Geohash的最强大的功能是使用简单的位操作就可以知道两个区域间的距离,就像图中所示(陈皓:proximity框着的那两个,这个很像IP地址了)。Geohash把一个二维的坐标生生地变成了一个一维的数据模型,这就是降维技术。BigTable的降维技术参看到文章后面的 [6.1]。更多的关于Geohash和其它技术可以参看 [6.2] 和 [6.3]。

适用性 :  Key-Value Store 键值对数据库, Document Databases文档数据库, BigTable风格的数据库。

(7) 索引表 Index Table

Index Table 索引表是一个非常直白的技术,其可以你在不支持索引的数据库中得到索引的好处。BigTable是这类最重要的数据库。这需要我们维护一个有相应存取模式的特别表。例如,我们有一个主表存着用户帐号,其可以被UserID存取。某查询需要查出某个城市里所有的用户,于是我们可以加入一张表,这张表用城市做主键,所有和这个城市相关的UserID是其Value,如下所示:


Index Table Example

可见,城市索引表的需要和对主表用户表保持一致性,因此,主表的每一个更新可能需要对索引表进行更新,不然就是一个批处理更新。无论哪个方式,这都会损伤一些性能,因为需要保持一致性。

Index Table 索引表可以被认为是关系型数据库中的视图的等价物。

适用性 : BigTable 数据库。

(8) 键组合索引 Composite Key Index

Composite key 键组合是一个很常用的技术,对此,当我们的数据库支持键排序时能得到极大的好处。Composite key组合键的拼接成为第二排序字段可以让你构建出一种多维索引,这很像我们之前说过的 Dimensionality Reduction 降维技术。例如,我们需要存取用户统计。如果我们需要根据不同的地区来统计用户的分布情况,我们可以把Key设计成这样的格式 (State:City:UserID),这样一来,就使得我们可以通过State到City来按组遍历用户,特别是我们的NoSQL数据库支持在key上按区查询(如:BigTable类的系统):

SELECT Values WHERE state="CA:*"
SELECT Values WHERE city="CA:San Francisco*"


Composite Key Index

适用性 : BigTable 数据库。

(9) 键组合聚合 Aggregation with Composite Keys

Composite keys  键组合技术并不仅仅可以用来做索引,同样可以用来区分不用的类型的数据以支持数据分组。考虑一个例子,我们有一个海量的日志数组,这个日志记录了互联网上的用户的访问来源。我们需要计算从某一网站过来的独立访客的数量,在关系型数据库中,我们可能需要下面这样的SQL查询语句:

SELECT count(distinct(user_id)) FROM clicks GROUP BY site

我们可以在NoSQL中建立如下的数据模型:


Counting Unique Users using Composite Keys

这样,我们就可以把数据按UserID来排序,我们就可以很容易把同一个用户的数据(一个用户并不会产生太多的event)进行处理,去掉那些重复的站点(使用hash table或是别的什么)。另一个可选的技术是,我们可以对每一个用户建立一个数据实体,然后把其站点来源追加到这个数据实体中,当然,这样一来,数据的更新在性能相比之下会有一定损失。

适用性 :  Ordered Key-Value Store 排序键值对数据库, BigTable风格的数据库。


(10) 反转搜索 Inverted Search – 直接聚合 Direct Aggregation

这个技术更多的是数据处理技术,而不是数据建模技术。尽管如此,这个技术还是会影响数据模型。这个技术最主要的想法是使用一个索引来找到满足某条件的数据,但是把数据聚合起需要使用全文搜索。还是让我们来说一个示例。还是用上面那个例子,我们有很多的日志,其中包括互联网用户和他们的访问来源。让我们假定每条记录都有一个UserID,还有用户的种类 (Men, Women, Bloggers, 等),以及用户所在的城市,和访问过的站点。我们要干的事是,为每个用户种类找到满足某些条件(访问源,所在城市,等)的的独立用户。

很明显,我们需要搜索那些满足条件的用户,如果我们使用反转搜索,这会让我们把这事干得很容易,如: {Category -> [user IDs]} 或 {Site -> [user IDs]}。使用这样的索引, 我们可以取两个或多个UserID要的交集或并集(这个事很容易干,而且可以干得很快,如果这些UserID是排好序的)。但是,我们要按用户种类来生成报表会变得有点麻烦,因为我们用语句可能会像下面这样

SELECT count(distinct(user_id)) ... GROUP BY category

但这样的SQL很没有效率,因为category数据太多了。为了应对这个问题,我们可以建立一个直接索引 {UserID -> [Categories]} 然后我们用它来生成报表:


Counting Unique Users using Inverse and Direct Indexes

最后,我们需要明白,对每个UserID的随机查询是很没有效率的。我们可以通过批查询处理来解决这个问题。这意味着,对于一些用户集,我们可以进行预处理(不同的查询条件)。

适用性 : Key-Value Store 键值对数据库, Document Databases文档数据库, BigTable风格的数据库。

层级式模型 Hierarchy Modeling Techniques

(11) 树形聚合Tree Aggregation

树形或是任意的图(需反规格化)可以被直接打成一条记录或文档存放。

  • 当树形结构被一次性取出时这会非常有效率(如:我们需要展示一个blog的树形评论)
  • 搜索和任何存取这个实体都会存在问题。
  • 对于大多数NoSQL的实现来说,更新数据都是很不经济的(相比起独立结点来说)


Tree Aggregation

适用性 : Key-Value 键值对数据库, Document Databases 文档数据库

(12) 邻接列表 Adjacency Lists

Adjacency Lists 邻接列表是一种图 – 每一个结点都是一个独立的记录,其包含了 所有的父结点或子结点。这样,我们就可以通过给定的父或子结点来进行搜索。当然,我们需要通过hop查询遍历图。这个技术在广度和深度查询,以及得到某个结点的子树上没有效率。

适用性 : Key-Value 键值对数据库, Document Databases 文档数据库


(13) Materialized Paths

Materialized Paths 可以帮助避免递归遍历(如:树形结构)。这个技术也可以被认为是反规格化的一种变种。其想法是为每个结点加上父结点或子结点的标识属性,这样就可以不需要遍历就知道所有的后裔结点和祖先结点了:


Materialized Paths for eShop Category Hierarchy

这个技术对于全文搜索引擎来说非常有帮助,因为其可以允许把一个层级结构转成一个文档。上面的示图中我们可以看到所有的商品或Men’s Shoes下的子分类可以被一条很短的查询语句处理——只需要给定个分类名。

Materialized Paths 可以存储一个ID的集合,或是一堆ID拼出的字符串。后者允许你通过一个正则表达式来搜索一个特定的分支路径。下图展示了这个技术(分支的路径包括了结点本身):


Query Materialized Paths using RegExp

适用性 : Key-Value 键值对数据库, Document Databases 文档数据, Search Engines 搜索引擎

(14) 嵌套集 Nested Sets

Nested sets 嵌套集是树形结构的标准技术。它被广泛地用在了关系性数据库中,它完全地适用于 Key-Value 键值对数据库 和 Document Databases 文档数据库。这个技术的想法是把叶子结点存储成一个数组,并通过使用索引的开始和结束来映射每一个非叶子结点到一个叶子结点集,就如下图所示一样:


Modeling of eCommerce Catalog using Nested Sets

这样的数据结构对于immutable data不变的数据 有非常不错的效率,因为其点内存空间小,并且可以很快地找出所有的叶子结点而不需要树的遍历。尽管如此,在插入和更新上需要很高的性能成本,因为新的叶子结点需要大规模地更新索引。

适用性 : Key-Value Stores 键值数据库, Document Databases 文档数据库

(15) 嵌套文档扁平化:有限的字段名 Nested Documents Flattening: Numbered Field Names

搜索引擎基本上来说和扁平文档一同工作,如:每一个文档是一个扁平的字段和值的例表。这种数据模型的用来把业务实体映射到一个文本文档上,如果你的业务实体有很复杂的内部结构,这可能会变得很有挑战。一个典型的挑战是把一个有层级的文档映映射出来。例如,文档中嵌套另一个文档。让我们看看下面的示例:


Nested Documents Problem

上面的每一个业务实体代码一种简历。其包括了人名和一个技能列表。我把这个层级文档映射成一个文本文档,一种方法是创建 Skill 和 Level字段。这个模型可以通过技术或是等级来搜索一个人,而上图标注的那样的组合查询则会失败。(陈皓注:因为分不清Excellent是否是Math还是Poetry上的)

在引用中的 [4.6] 给出了一种解决方案。其为每个字段都标上数字 Skill_i 和 Level_i,这样就可以分开搜索每一个对(下图中使用了OR来遍历查找所有可能的字段):


Nested Document Modeling using Numbered Field Names

这样的方式根本没有扩展性,对于一些复杂的问题来说只会让代码复杂度和维护工作变大。

适用性 : Search Engines 全文搜索

(16)嵌套文档扁平化:邻近查询 Nested Documents Flattening: Proximity Queries

在附录 [4.6]中给出了这个技术用来解决扁平层次文档。它用邻近的查询来限制可被查询的单词的范围。下图中,所有的技能和等级被放在一个字段中,叫 SkillAndLevel,查询中出现的 “Excellent” 和 “Poetry” 必需一个紧跟另一个:


Nested Document Modeling using Proximity Queries

附录 [4.3] 中讲述了这个技术被用在Solr中的一个成功案例。

适用性 : Search Engines 全文搜索

(17) 图结构批处理 Batch Graph Processing

Graph databases 图数据库,如 neo4j 是一个出众的图数据库,尤其是使用一个结点来探索邻居结点,或是探索两个或少量结点前的关系。但是处理大量的图数据是很没有效率的,因为图数据库的性能和扩展性并不是其目的。分布式的图数据处理可以被 MapReduce 和 Message Passing pattern 来处理。如: 在我前一篇的文章中的那个示例。这个方法可以让 Key-Value stores, Document databases, 和 BigTable-style databases 适合于处理大图。

Applicability : Key-Value Stores, Document Databases, BigTable-style Databases

参考

Finally, I provide a list of useful links related to NoSQL data modeling:

  1. Key-Value Stores:
    1. http://www.devshed.com/c/a/MySQL/Database-Design-Using-KeyValue-Tables/
    2. http://antirez.com/post/Sorting-in-key-value-data-model.html
    3. http://stackoverflow.com/questions/3554169/difference-between-document-based-and-key-value-based-databases
    4. http://dbmsmusings.blogspot.com/2010/03/distinguishing-two-major-types-of_29.html
  2. BigTable-style Databases:
    1. http://www.slideshare.net/ebenhewitt/cassandra-datamodel-4985524
    2. http://www.slideshare.net/mattdennis/cassandra-data-modeling
    3. http://nosql.mypopescu.com/post/17419074362/cassandra-data-modeling-examples-with-matthew-f-dennis
    4. http://s-expressions.com/2009/03/08/hbase-on-designing-schemas-for-column-oriented-data-stores/
    5. http://jimbojw.com/wiki/index.php?title=Understanding_Hbase_and_BigTable
  3. Document Databases:
    1. http://www.slideshare.net/mongodb/mongodb-schema-design-richard-kreuters-mongo-berlin-preso
    2. http://www.michaelhamrah.com/blog/2011/08/data-modeling-at-scale-mongodb-mongoid-callbacks-and-denormalizing-data-for-efficiency/
    3. http://seancribbs.com/tech/2009/09/28/modeling-a-tree-in-a-document-database/
    4. http://www.mongodb.org/display/DOCS/Schema+Design
    5. http://www.mongodb.org/display/DOCS/Trees+in+MongoDB
    6. http://blog.fiesta.cc/post/11319522700/walkthrough-mongodb-data-modeling
  4. Full Text Search Engines:
    1. http://www.searchworkings.org/blog/-/blogs/query-time-joining-in-lucene
    2. http://www.lucidimagination.com/devzone/technical-articles/solr-and-rdbms-basics-designing-your-application-best-both
    3. http://blog.griddynamics.com/2011/07/solr-experience-search-parent-child.html
    4. http://www.lucidimagination.com/blog/2009/07/18/the-spanquery/
    5. http://blog.mgm-tp.com/2011/03/non-standard-ways-of-using-lucene/
    6. http://www.slideshare.net/MarkHarwood/proposal-for-nested-document-support-in-lucene
    7. http://mysolr.com/tips/denormalized-data-structure/
    8. http://sujitpal.blogspot.com/2010/10/denormalizing-maps-with-lucene-payloads.html
    9. http://java.dzone.com/articles/hibernate-search-mapping-entit
  5. Graph Databases:
    1. http://docs.neo4j.org/chunked/stable/tutorial-comparing-models.html
    2. http://blog.neo4j.org/2010/03/modeling-categories-in-graph-database.html
    3. http://skillsmatter.com/podcast/nosql/graph-modelling
    4. http://www.umiacs.umd.edu/~jimmylin/publications/Lin_Schatz_MLG2010.pdf
  6. Demensionality Reduction:
    1. http://www.slideshare.net/mmalone/scaling-gis-data-in-nonrelational-data-stores
    2. http://blog.notdot.net/2009/11/Damn-Cool-Algorithms-Spatial-indexing-with-Quadtrees-and-Hilbert-Curves
    3. http://www.trisis.co.uk/blog/?p=1287

(全文完)

您可能也喜欢:

SQL的Where语句

图解SQL的Join

【原创】SQL栏目树的代码

Web程序的最佳测试数据

几篇技术文章
无觅

相关文章

]]>
全文译自墙外文章“NoSQL Data Modeling Techniques”,译得不好,还请见谅。这篇文章看完之后,你可能会对NoSQL的数据结构会有些感觉。我的感觉是,关系型数据库想把一致性,完整性,索引,CRUD都干好,NoSQL只干某一种事,但是牺牲了很多别的东西。总体来说,我觉得NoSQL更适合做Cache。下面是正文——

NoSQL 数据库经常被用作很多非功能性的地方,如,扩展性,性能和一致性的地方。这些NoSQL的特性在理论和实践中都正在被大众广泛地研究着,研究的热点正是那些和性能分布式相关的非功能性的东西,我们都知道CAP 理论被很好地应用于了 NoSQL 系统中(陈皓注:CAP即,一致性(Consistency), 可用性(Availability), 分区容忍性(Partition tolerance),在分布式系统中,这三个要素最多只能同时实现两个,而NoSQL一般放弃的是一致性)。但在另一方面,NoSQL的数据建模技术却因为缺乏像关系型数据库那样的基础理论没有被世人很好地研究。这篇文章从数据建模方面对NoSQL家族进行了比较,并讨论几个常见的数据建模技术。

要开始讨论数据建模技术,我们不得不或多或少地先系统地看一下NoSQL数据模型的成长的趋势,以此我们可以了解一些他们内在的联系。下图是NoSQL家族的进化图,我们可以看到这样的进化:Key-Value时代,BigTable时代,Document时代,全文搜索时代,和Graph数据库时代:(陈皓注:注意图中SQL说的那句话,NoSQL再这样发展下去就是SQL了,哈哈。)


NoSQL Data Models

首先,我们需要注意的是SQL和关系型数据模型已存在了很长的时间,这种面向用户的自然性意味着:

  • 最终用户一般更感兴趣于数据的聚合显示,而不是分离的数据,这主要通过SQL来完成。
  • 我们无法通过人手工控制数据的并发性,完整性,一致性,或是数据类型校验这些东西的。这就是为什么SQL需要在事务,二维表结构(schema)和外表联合上做很多事。

另一方面,SQL可以让软件应用程序在很多情况下不需要关心数据库的数据聚合,和数据完整性和有效性进行控制。而如果我们去除了数据一致性,完整性这些东西,会对性能和分布存储有着重的帮助。正因为如此,我们才有数据模型的进化:

  • Key-Value 键值对存储 是非常简单而强大的。下面的很多技术基本上都是基于这个技术开始发展的。但是,Key-Value有一个非常致命的问题,那就是如果我们需要查找一段范围内的key。(陈皓注:学过hash-table数据结构的人都应该知道,hash-table是非序列容器,其并不像数组,链接,队列这些有序容器,我们可以控制数据存储的顺序)。于是,有序键值 (Ordered Key-Value) 数据模型被设计出来解决这一限制,来从根本上提高数据集的问题。
  • Ordered Key-Value 有序键值 模型也非常强大,但是,其也没有对Value提供某种数据模型。通常来说,Value的模型可以由应用负责解析和存取。这种很不方便,于是出现了 BigTable类型的数据库,这个数据模型其实就是map里有map,map里再套map,一层一层套下去,也就是层层嵌套的key-value(value里又是一个key-value),这种数据库的Value主要通过“列族”(column families),列,和时间戳来控制版本。(陈皓注:关于时间戳来对数据的版本控制主要是解决数据存储并发问题,也就是所谓的乐观锁,详见《多版本并发控制(MVCC)在分布式系统中的应用》)
  • Document databases 文档数据库  改进了 BigTable 模型,并提供了两个有意义的改善。第一个是允许Value中有主观的模式(scheme),而不是map套map。第二个是索引。Full Text Search Engines 全文搜索引擎 可以被看作是文档数据库的一个变种,他们可以提供灵活的可变的数据模式(scheme)以及自动索引。他们之间的不同点主要是,文档数据库用字段名做索引,而全文搜索引擎用字段值做索引。
  • Graph data models 图式数据库  可以被认为是这个进化过程中从 Ordered Key-Value 数据库发展过来的一个分支。图式数据库允许构建议图结构的数据模型。它和文档数据库有关系的原因是,它的很多实现允许value可以是一个map或是一个document。

 NoSQL 数据模型摘要

本文剩下的章节将向你介绍数据建模的技术实现和相关模式。但是,在介绍这些技术之前,先来一段序言:

  • NoSQL 数据模型设计一般从业务应用的具体数据查询入手,而不是数据间的关系:
    • 关系型的数据模型基本上是分析数据间的结构和关系。其设计理念是: ”What answers do I have?”
    • NoSQL 数据模型基本上是从应用对数据的存取方式入手,如:我需要支持某种数据查询。其设计理念是 ”What questions do I have?”
  • NoSQL 数据模型设计比关系型数据库需要对数据结构和算法的更深的了解。在这篇文章中我会和大家说那些尽人皆知的数据结构,这些数据结构并不只是被NoSQL使用,但是对于NoSQL的数据模型却非常有帮助。
  • 数据冗余和反规格化是一等公民。
  • 关系型数据库对于处理层级数据和图式数据非常的不方便。NoSQL用来解决图式数据明显是一个非常好的解决方案,几乎所有的NoSQL数据库可以很强地解决此类问题。这就是为什么这篇文章专门拿出一章来说明层级数据模型。
下面是NoSQL的分类表,也是我用来写这篇文章时做实践的产品:
  • Key-Value 存储: Oracle Coherence, Redis, Kyoto Cabinet
  • 类BigTable存储: Apache HBase, Apache Cassandra
  • 文档数据库: MongoDB, CouchDB
  • 全文索引: Apache Lucene, Apache Solr
  • 图数据库: neo4j, FlockDB

概念技术 Conceptual Techniques

这一节主要介绍NoSQL数据模型的基本原则。

(1) 反规格化 Denormalization

反规格化 Denormalization 可以被认为是把相同的数据拷贝到不同的文档或是表中,这样就可以简化和优化查询,或是正好适合用户的某中特别的数据模型。这篇文章中所说的绝大多数技术都或多或少地导向了这一技术。

总体来说,反规格化需要权衡下面这些东西:

  • 查询数据量 /查询IO  VS  总数据量 。使用反规格化,一方面可以把一条查询语句所需要的所有数据组合起来放到一个地方存储。这意味着,其它不同不同查询所需要的相同的数据,需要放在别不同的地方。因此,这产生了很多冗余的数据,从而导致了数据量的增大。
  • 处理复杂度  VS总数据量 . 在符合范式的数据模式上进行表连接的查询,很显然会增加了查询处理的复杂度,尤其对于分布式系统来说更是。反规格化的数据模型允许我们以方便查询的方式来存构造数据结构以简化查询复杂度。

适用性 : Key-Value Store 键值对数据库, Document Databases文档数据库, BigTable风格的数据库。

(2) 聚合 Aggregates

所有类型的NoSQL数据库都会提供灵活的Schema(数据结构,对数据格式的限制):

  • Key-Value Stores 和 Graph Databases 基本上来说不会Value的形式,所以Value可以是任意格式。这样一来,这使得我们可以任意组合一个业务实体的keys。比如,我们有一个用户帐号的业务实体,其可以被如下这些key组合起来: UserID_name, UserID_email, UserID_messages 等等。如果一个用户没有email或message,那么相应也不会有这样的记录。
  • BigTable 模型通过列集合来支持灵活的Schema,我们称之为列族(column family)。BigTable还可以在同一记录上出现不同的版本(通过时间戳)。
  • Document databases 文档数据库是一种层级式的“去Schema”的存储,虽然有些这样的数据库允许检验需要保存的数据是否满足某种Schema。

灵活的Schema允许你可以用一种嵌套式的内部数据方式来存储一组有关联的业务实体(陈皓注:类似于JSON这样的数据封装格式)。这样可以为我们带来两个好处。

  • 最小化“一对多”关系——可以通过嵌套式的方式来存储实体,这样可以少一些表联结。
  • 可以让内部技术上的数据存储更接近于业务实体,特别是那种混合式的业务实体。可能存于一个文档集或是一张表中。
下图示意了这两种好处。图中描给了电子商务中的商品模型(陈皓注:我记得我在“挑战无处不在”一文中说到过电商中产品分类数据库设计的挑战)
  • 首先,所有的商品Product都会有一个ID,Price 和 Description。
  • 然后,我们可以知道不同的类型的商品会有不同的属性。比如,作者是书的属性,长度是牛仔裤的属性。其些属性可能是“一对多”或是“多对多”的关系,如:唱片中的曲目。
  • 接下来,我们知道,某些业务实体不可能使用固定的类型。如:牛仔裤的属性并不是所有的牌子都有的,而且,有些名牌还会搞非常特别的属性。

对于关系型数据库来说,要设计这样的数据模型并不简单,而且设计出来的绝对离优雅很远很远。而我们NoSQL中灵活的Schema允许你使用一个聚合 Aggregate (product) 可以建出所有不同种类的商品和他们的不同的属性:

Entity Aggregation

上图中我们可以比较关系型数据库和NoSQL的差别。但是我们可以看到在数据更新上,非规格化的数据存储在性能和一致性上会有很大的影响,这就是我们需要重点注意和不得不牺牲的地方

适用性 : Key-Value Store 键值对数据库, Document Databases文档数据库, BigTable风格的数据库。

(3) 应用层联结 Application Side Joins

表联结基本上不被NoSQL支持。正如我们前面所说的,NoSQL是“面向问题”而不是“面向答案”的,不支持表联结就是“面向问题”的后果。表的联结是在设计时被构造出来的,而不是在执行时建造出来的。所以,表联结在运行时是有很大开销的(陈皓注:搞过SQL表联结的都知道笛卡尔积是什么东西,大可以在参看以前酷壳的“图解数据库表Joins”),但是在使用了 Denormalization 和 Aggregates 技术后,我们基本不用进行表联结,如:你们使用嵌套式的数据实体。当然,如果你需要联结数据,你需要在应用层完成这个事。下面是几个主要的Use Case:

  • 多对多的数据实体关系——经常需要被连接或联结。
  • 聚合 Aggregates 并不适用于数据字段经常被改变的情况。对此,我们需要把那些经常被改变的字段分到另外的表中,而在查询时我们需要联结数据。例如,我们有个Message系统可以有一个User实体,其包括了一个内嵌的Message实体。但是,如果用户不断在附加 message,那么,最好把message拆分到另一个独立的实体,但在查询时联结这User和Message这两个实体。如下图:

适用性 : Key-Value Store 键值对数据库, Document Databases文档数据库, BigTable风格的数据库, Graph Databases 图数据库。

通用建模技术 General Modeling Techniques

在本书中,我们将讨论NoSQL中各种不同的通用的数据建模技术。

(4) 原子聚合 Atomic Aggregates

很多NoSQL的数据库(并不是所有)在事务处理上都是短板。在某些情况下,他们可以通过分布式锁技术或是应用层管理的MVCC技术来实现其事务性(陈皓注:可参看本站的“多版本并发控制(MVCC)在分布式系统中的应用”)但是,通常来说只能使用聚合Aggregates技术来保证一些ACID原则。

这就是为什么我们的关系型数据库需要有强大的事务处理机制——因为关系型数据库的数据是被规格化存放在了不同的地方。所以,Aggregates聚合允许我们把一个业务实体存成一个文档、存成一行,存成一个key-value,这样就可以原子式的更新了:


Atomic Aggregates

当然,原子聚合 Atomic Aggregates 这种数据模型并不能实现完全意义上的事务处理,但是如果支持原子性,锁,或 test-and-set 指令,那么, Atomic Aggregates 是可以适用的。

适用性 Key-Value Store 键值对数据库, Document Databases文档数据库, BigTable风格的数据库。

(5) 可枚举键 Enumerable Keys

也许,对于无顺序的Key-Value最大的好处是业务实体可以被容易地hash以分区在多个服务器上。而排序了的key会把事情搞复杂,但是有些时候,一个应用能从排序key中获得很多好处,就算是数据库本身不提供这个功能。让我们来思考下email消息的数据模型:

  1. 一些NoSQL的数据库提供原子计数器以允许生一些连续的ID。在这种情况下,我们可以使用 userID_messageID 来做为一个组合key。如果我们知道最新的message ID,就可以知道前一个message,也可能知道再前面和后面的Message。
  2. Messages可以被打包。比如,每天的邮件包。这样,我们就可以对邮件按指定的时间段来遍历。

适用性 Key-Value Store 键值对数据库

(6) 降维 Dimensionality Reduction

Dimensionality Reduction 降维是一种技术可以允许把一个多维的数据映射成一个Key-Value或是其它非多给的数据模型。

传统的地理位置信息系统使用一些如“四分树QuadTree” 或 “R-Tree” 来做地理位置索引。这些数据结构的内容需要被在适当的位置更新,并且,如果数据量很大的话,操作成本会很高。另一个方法是我们可以遍历一个二维的数据结构并把其扁平化成一个列表。一个众所周知的例子是Geohash(地理哈希)。一个Geohash使用“之字形”的路线扫描一个2维的空间,而且遍历中的移动可以被简单地用0和1来表示其方向,然后在移动的过程中产生0/1串。下图展示了这一算法:(陈皓注:先把地图分成四份,经度为第一位,纬度为第二位,于是左边的经度是0,右边的是1,纬度也一样,上面是为1,下面的为0,这样,经纬度就可以组合成01,11,00,10这四个值,其标识了四块区域,我们可以如此不断的递归地对每个区域进行四分,然后可以得到一串1和0组成的字串,然后使用0-9,b-z 去掉(去掉a, i, l, o)这32个字母进行base32编码得到一个8个长度的编码,这就是Geohash的算法)


Geohash Index

Geohash的最强大的功能是使用简单的位操作就可以知道两个区域间的距离,就像图中所示(陈皓:proximity框着的那两个,这个很像IP地址了)。Geohash把一个二维的坐标生生地变成了一个一维的数据模型,这就是降维技术。BigTable的降维技术参看到文章后面的 [6.1]。更多的关于Geohash和其它技术可以参看 [6.2] 和 [6.3]。

适用性 :  Key-Value Store 键值对数据库, Document Databases文档数据库, BigTable风格的数据库。

(7) 索引表 Index Table

Index Table 索引表是一个非常直白的技术,其可以你在不支持索引的数据库中得到索引的好处。BigTable是这类最重要的数据库。这需要我们维护一个有相应存取模式的特别表。例如,我们有一个主表存着用户帐号,其可以被UserID存取。某查询需要查出某个城市里所有的用户,于是我们可以加入一张表,这张表用城市做主键,所有和这个城市相关的UserID是其Value,如下所示:


Index Table Example

可见,城市索引表的需要和对主表用户表保持一致性,因此,主表的每一个更新可能需要对索引表进行更新,不然就是一个批处理更新。无论哪个方式,这都会损伤一些性能,因为需要保持一致性。

Index Table 索引表可以被认为是关系型数据库中的视图的等价物。

适用性 : BigTable 数据库。

(8) 键组合索引 Composite Key Index

Composite key 键组合是一个很常用的技术,对此,当我们的数据库支持键排序时能得到极大的好处。Composite key组合键的拼接成为第二排序字段可以让你构建出一种多维索引,这很像我们之前说过的 Dimensionality Reduction 降维技术。例如,我们需要存取用户统计。如果我们需要根据不同的地区来统计用户的分布情况,我们可以把Key设计成这样的格式 (State:City:UserID),这样一来,就使得我们可以通过State到City来按组遍历用户,特别是我们的NoSQL数据库支持在key上按区查询(如:BigTable类的系统):

SELECT Values WHERE state="CA:*"
SELECT Values WHERE city="CA:San Francisco*"


Composite Key Index

适用性 : BigTable 数据库。

(9) 键组合聚合 Aggregation with Composite Keys

Composite keys  键组合技术并不仅仅可以用来做索引,同样可以用来区分不用的类型的数据以支持数据分组。考虑一个例子,我们有一个海量的日志数组,这个日志记录了互联网上的用户的访问来源。我们需要计算从某一网站过来的独立访客的数量,在关系型数据库中,我们可能需要下面这样的SQL查询语句:

SELECT count(distinct(user_id)) FROM clicks GROUP BY site

我们可以在NoSQL中建立如下的数据模型:


Counting Unique Users using Composite Keys

这样,我们就可以把数据按UserID来排序,我们就可以很容易把同一个用户的数据(一个用户并不会产生太多的event)进行处理,去掉那些重复的站点(使用hash table或是别的什么)。另一个可选的技术是,我们可以对每一个用户建立一个数据实体,然后把其站点来源追加到这个数据实体中,当然,这样一来,数据的更新在性能相比之下会有一定损失。

适用性 :  Ordered Key-Value Store 排序键值对数据库, BigTable风格的数据库。


(10) 反转搜索 Inverted Search – 直接聚合 Direct Aggregation

这个技术更多的是数据处理技术,而不是数据建模技术。尽管如此,这个技术还是会影响数据模型。这个技术最主要的想法是使用一个索引来找到满足某条件的数据,但是把数据聚合起需要使用全文搜索。还是让我们来说一个示例。还是用上面那个例子,我们有很多的日志,其中包括互联网用户和他们的访问来源。让我们假定每条记录都有一个UserID,还有用户的种类 (Men, Women, Bloggers, 等),以及用户所在的城市,和访问过的站点。我们要干的事是,为每个用户种类找到满足某些条件(访问源,所在城市,等)的的独立用户。

很明显,我们需要搜索那些满足条件的用户,如果我们使用反转搜索,这会让我们把这事干得很容易,如: {Category -> [user IDs]} 或 {Site -> [user IDs]}。使用这样的索引, 我们可以取两个或多个UserID要的交集或并集(这个事很容易干,而且可以干得很快,如果这些UserID是排好序的)。但是,我们要按用户种类来生成报表会变得有点麻烦,因为我们用语句可能会像下面这样

SELECT count(distinct(user_id)) ... GROUP BY category

但这样的SQL很没有效率,因为category数据太多了。为了应对这个问题,我们可以建立一个直接索引 {UserID -> [Categories]} 然后我们用它来生成报表:


Counting Unique Users using Inverse and Direct Indexes

最后,我们需要明白,对每个UserID的随机查询是很没有效率的。我们可以通过批查询处理来解决这个问题。这意味着,对于一些用户集,我们可以进行预处理(不同的查询条件)。

适用性 : Key-Value Store 键值对数据库, Document Databases文档数据库, BigTable风格的数据库。

层级式模型 Hierarchy Modeling Techniques

(11) 树形聚合Tree Aggregation

树形或是任意的图(需反规格化)可以被直接打成一条记录或文档存放。

  • 当树形结构被一次性取出时这会非常有效率(如:我们需要展示一个blog的树形评论)
  • 搜索和任何存取这个实体都会存在问题。
  • 对于大多数NoSQL的实现来说,更新数据都是很不经济的(相比起独立结点来说)


Tree Aggregation

适用性 : Key-Value 键值对数据库, Document Databases 文档数据库

(12) 邻接列表 Adjacency Lists

Adjacency Lists 邻接列表是一种图 – 每一个结点都是一个独立的记录,其包含了 所有的父结点或子结点。这样,我们就可以通过给定的父或子结点来进行搜索。当然,我们需要通过hop查询遍历图。这个技术在广度和深度查询,以及得到某个结点的子树上没有效率。

适用性 : Key-Value 键值对数据库, Document Databases 文档数据库


(13) Materialized Paths

Materialized Paths 可以帮助避免递归遍历(如:树形结构)。这个技术也可以被认为是反规格化的一种变种。其想法是为每个结点加上父结点或子结点的标识属性,这样就可以不需要遍历就知道所有的后裔结点和祖先结点了:


Materialized Paths for eShop Category Hierarchy

这个技术对于全文搜索引擎来说非常有帮助,因为其可以允许把一个层级结构转成一个文档。上面的示图中我们可以看到所有的商品或Men’s Shoes下的子分类可以被一条很短的查询语句处理——只需要给定个分类名。

Materialized Paths 可以存储一个ID的集合,或是一堆ID拼出的字符串。后者允许你通过一个正则表达式来搜索一个特定的分支路径。下图展示了这个技术(分支的路径包括了结点本身):


Query Materialized Paths using RegExp

适用性 : Key-Value 键值对数据库, Document Databases 文档数据, Search Engines 搜索引擎

(14) 嵌套集 Nested Sets

Nested sets 嵌套集是树形结构的标准技术。它被广泛地用在了关系性数据库中,它完全地适用于 Key-Value 键值对数据库 和 Document Databases 文档数据库。这个技术的想法是把叶子结点存储成一个数组,并通过使用索引的开始和结束来映射每一个非叶子结点到一个叶子结点集,就如下图所示一样:


Modeling of eCommerce Catalog using Nested Sets

这样的数据结构对于immutable data不变的数据 有非常不错的效率,因为其点内存空间小,并且可以很快地找出所有的叶子结点而不需要树的遍历。尽管如此,在插入和更新上需要很高的性能成本,因为新的叶子结点需要大规模地更新索引。

适用性 : Key-Value Stores 键值数据库, Document Databases 文档数据库

(15) 嵌套文档扁平化:有限的字段名 Nested Documents Flattening: Numbered Field Names

搜索引擎基本上来说和扁平文档一同工作,如:每一个文档是一个扁平的字段和值的例表。这种数据模型的用来把业务实体映射到一个文本文档上,如果你的业务实体有很复杂的内部结构,这可能会变得很有挑战。一个典型的挑战是把一个有层级的文档映映射出来。例如,文档中嵌套另一个文档。让我们看看下面的示例:


Nested Documents Problem

上面的每一个业务实体代码一种简历。其包括了人名和一个技能列表。我把这个层级文档映射成一个文本文档,一种方法是创建 Skill 和 Level字段。这个模型可以通过技术或是等级来搜索一个人,而上图标注的那样的组合查询则会失败。(陈皓注:因为分不清Excellent是否是Math还是Poetry上的)

在引用中的 [4.6] 给出了一种解决方案。其为每个字段都标上数字 Skill_i 和 Level_i,这样就可以分开搜索每一个对(下图中使用了OR来遍历查找所有可能的字段):


Nested Document Modeling using Numbered Field Names

这样的方式根本没有扩展性,对于一些复杂的问题来说只会让代码复杂度和维护工作变大。

适用性 : Search Engines 全文搜索

(16)嵌套文档扁平化:邻近查询 Nested Documents Flattening: Proximity Queries

在附录 [4.6]中给出了这个技术用来解决扁平层次文档。它用邻近的查询来限制可被查询的单词的范围。下图中,所有的技能和等级被放在一个字段中,叫 SkillAndLevel,查询中出现的 “Excellent” 和 “Poetry” 必需一个紧跟另一个:


Nested Document Modeling using Proximity Queries

附录 [4.3] 中讲述了这个技术被用在Solr中的一个成功案例。

适用性 : Search Engines 全文搜索

(17) 图结构批处理 Batch Graph Processing

Graph databases 图数据库,如 neo4j 是一个出众的图数据库,尤其是使用一个结点来探索邻居结点,或是探索两个或少量结点前的关系。但是处理大量的图数据是很没有效率的,因为图数据库的性能和扩展性并不是其目的。分布式的图数据处理可以被 MapReduce 和 Message Passing pattern 来处理。如: 在我前一篇的文章中的那个示例。这个方法可以让 Key-Value stores, Document databases, 和 BigTable-style databases 适合于处理大图。

Applicability : Key-Value Stores, Document Databases, BigTable-style Databases

参考

Finally, I provide a list of useful links related to NoSQL data modeling:

  1. Key-Value Stores:
    1. http://www.devshed.com/c/a/MySQL/Database-Design-Using-KeyValue-Tables/
    2. http://antirez.com/post/Sorting-in-key-value-data-model.html
    3. http://stackoverflow.com/questions/3554169/difference-between-document-based-and-key-value-based-databases
    4. http://dbmsmusings.blogspot.com/2010/03/distinguishing-two-major-types-of_29.html
  2. BigTable-style Databases:
    1. http://www.slideshare.net/ebenhewitt/cassandra-datamodel-4985524
    2. http://www.slideshare.net/mattdennis/cassandra-data-modeling
    3. http://nosql.mypopescu.com/post/17419074362/cassandra-data-modeling-examples-with-matthew-f-dennis
    4. http://s-expressions.com/2009/03/08/hbase-on-designing-schemas-for-column-oriented-data-stores/
    5. http://jimbojw.com/wiki/index.php?title=Understanding_Hbase_and_BigTable
  3. Document Databases:
    1. http://www.slideshare.net/mongodb/mongodb-schema-design-richard-kreuters-mongo-berlin-preso
    2. http://www.michaelhamrah.com/blog/2011/08/data-modeling-at-scale-mongodb-mongoid-callbacks-and-denormalizing-data-for-efficiency/
    3. http://seancribbs.com/tech/2009/09/28/modeling-a-tree-in-a-document-database/
    4. http://www.mongodb.org/display/DOCS/Schema+Design
    5. http://www.mongodb.org/display/DOCS/Trees+in+MongoDB
    6. http://blog.fiesta.cc/post/11319522700/walkthrough-mongodb-data-modeling
  4. Full Text Search Engines:
    1. http://www.searchworkings.org/blog/-/blogs/query-time-joining-in-lucene
    2. http://www.lucidimagination.com/devzone/technical-articles/solr-and-rdbms-basics-designing-your-application-best-both
    3. http://blog.griddynamics.com/2011/07/solr-experience-search-parent-child.html
    4. http://www.lucidimagination.com/blog/2009/07/18/the-spanquery/
    5. http://blog.mgm-tp.com/2011/03/non-standard-ways-of-using-lucene/
    6. http://www.slideshare.net/MarkHarwood/proposal-for-nested-document-support-in-lucene
    7. http://mysolr.com/tips/denormalized-data-structure/
    8. http://sujitpal.blogspot.com/2010/10/denormalizing-maps-with-lucene-payloads.html
    9. http://java.dzone.com/articles/hibernate-search-mapping-entit
  5. Graph Databases:
    1. http://docs.neo4j.org/chunked/stable/tutorial-comparing-models.html
    2. http://blog.neo4j.org/2010/03/modeling-categories-in-graph-database.html
    3. http://skillsmatter.com/podcast/nosql/graph-modelling
    4. http://www.umiacs.umd.edu/~jimmylin/publications/Lin_Schatz_MLG2010.pdf
  6. Demensionality Reduction:
    1. http://www.slideshare.net/mmalone/scaling-gis-data-in-nonrelational-data-stores
    2. http://blog.notdot.net/2009/11/Damn-Cool-Algorithms-Spatial-indexing-with-Quadtrees-and-Hilbert-Curves
    3. http://www.trisis.co.uk/blog/?p=1287

(全文完)

您可能也喜欢:

SQL的Where语句

图解SQL的Join

【原创】SQL栏目树的代码

Web程序的最佳测试数据

几篇技术文章
无觅

相关文章

]]>
0
<![CDATA[空间化界面]]> http://www.udpwork.com/item/7282.html http://www.udpwork.com/item/7282.html#reviews Mon, 14 May 2012 21:20:05 +0800 Singularity http://www.udpwork.com/item/7282.html 在论坛社区里有个问题每过段时间就会被提一次:是否有可能出现一种图形化编程方式能完成「传统」方式的所有任务,甚至取代后者的主流地位。知乎的 Rio 在回答中提出像 Lisp 这样语法超级简洁的语言也许可以通过图形化语法树的形式完成图形化编程。从更广的角度来说,自 Steve Jobs 访问 Xerox PARC 之后(甚至更早),软件设计者们一直在挑战一个难题:软件界面应该图形化到何种程度。Apple 在传统 Macintosh 中做到了图形化的极端,甚至去掉了键盘的方向键;在后期的系统以及 OS X 中则向相反方向回退:AppleScript 鼓励普通用户编写脚本,命令行的 Terminal 重新发挥作用。合适的边界在哪里,而编程又在边界的哪边? 问题维度 小学时学习实数用到数轴,中学时学习一元函数用到二维笛卡儿坐标的图形化。足够细心的人能用绘图法能够解决很多选择题。如果配合坐标纸,绘图甚至可以独立解答一部分平面解析几何的题目。更进一步,空间想象力和绘图功力不错的人可以用正交投影绘图来研究二元函数和立体几何。但投影绘图方式只能作为提供思路的辅助工具,无法起到一元函数和平面解析几何的绘图法那种独立解题的作用。作为研究问题的工具,图形化所能胜任的问题维度受限于工具介质的维度。而且这里的图形化严格说来应该称之为「空间化」。由于高维度的问题无法空间化,研究者必须直接操作逻辑符号。 计算机的显示器是二维的,即使它能用各种投影法来显示 3D 内容,指点设备 (pointing device,比如鼠标) 操作界面的方式仍是二维的。所以软件的界面受限于二维。当然,实际要更复杂一些。借助窗口,tab,分割线,甚至于更复杂的 dockable  palette 等等,软件界面是具有层次关系的一组二维空间。但是具有层次关系的二维空间组仍然不是三维空间。 适合图形化界面的问题,是在经过层次划分之后每个层次可以被自然地二维空间化的问题。比如文件管理,文字处理和排版。在 《The Mythical Man-Finger》 中,作者循序渐进的说明了简单的管理音乐文件的问题如何一步步复杂化到远远超越二维空间化的程度,最终必须由命令行来实现。比如「把 iTunes 中随机/最后播放/最常播放的 n 首歌曲同步到其它 app/device」。把这个问题拆借成单独的小问题,很容易分别图形化: 按照随机/最后播放/最常播放排序 —— 排序的空间化; 找到任意数量的歌曲 —— 数量的空间化; 同步到 iPhone —— 位移的空间化。 由于每个问题单独空间化的意义不同,它们的界面往往是分开的。组合到一起成为复合需求之后则难以图形化。这也是为什么一些图形界面应用总体设计的不错,一到了 Import/Export 界面却变成很凌乱的对话框,反而不如像 AppleScript [...]

]]>
在论坛社区里有个问题每过段时间就会被提一次:是否有可能出现一种图形化编程方式能完成「传统」方式的所有任务,甚至取代后者的主流地位。知乎的 Rio 在回答中提出像 Lisp 这样语法超级简洁的语言也许可以通过图形化语法树的形式完成图形化编程。从更广的角度来说,自 Steve Jobs 访问 Xerox PARC 之后(甚至更早),软件设计者们一直在挑战一个难题:软件界面应该图形化到何种程度。Apple 在传统 Macintosh 中做到了图形化的极端,甚至去掉了键盘的方向键;在后期的系统以及 OS X 中则向相反方向回退:AppleScript 鼓励普通用户编写脚本,命令行的 Terminal 重新发挥作用。合适的边界在哪里,而编程又在边界的哪边? 问题维度 小学时学习实数用到数轴,中学时学习一元函数用到二维笛卡儿坐标的图形化。足够细心的人能用绘图法能够解决很多选择题。如果配合坐标纸,绘图甚至可以独立解答一部分平面解析几何的题目。更进一步,空间想象力和绘图功力不错的人可以用正交投影绘图来研究二元函数和立体几何。但投影绘图方式只能作为提供思路的辅助工具,无法起到一元函数和平面解析几何的绘图法那种独立解题的作用。作为研究问题的工具,图形化所能胜任的问题维度受限于工具介质的维度。而且这里的图形化严格说来应该称之为「空间化」。由于高维度的问题无法空间化,研究者必须直接操作逻辑符号。 计算机的显示器是二维的,即使它能用各种投影法来显示 3D 内容,指点设备 (pointing device,比如鼠标) 操作界面的方式仍是二维的。所以软件的界面受限于二维。当然,实际要更复杂一些。借助窗口,tab,分割线,甚至于更复杂的 dockable  palette 等等,软件界面是具有层次关系的一组二维空间。但是具有层次关系的二维空间组仍然不是三维空间。 适合图形化界面的问题,是在经过层次划分之后每个层次可以被自然地二维空间化的问题。比如文件管理,文字处理和排版。在 《The Mythical Man-Finger》 中,作者循序渐进的说明了简单的管理音乐文件的问题如何一步步复杂化到远远超越二维空间化的程度,最终必须由命令行来实现。比如「把 iTunes 中随机/最后播放/最常播放的 n 首歌曲同步到其它 app/device」。把这个问题拆借成单独的小问题,很容易分别图形化: 按照随机/最后播放/最常播放排序 —— 排序的空间化; 找到任意数量的歌曲 —— 数量的空间化; 同步到 iPhone —— 位移的空间化。 由于每个问题单独空间化的意义不同,它们的界面往往是分开的。组合到一起成为复合需求之后则难以图形化。这也是为什么一些图形界面应用总体设计的不错,一到了 Import/Export 界面却变成很凌乱的对话框,反而不如像 AppleScript [...]

]]>
0