» tagged pages
» logout

(Feed found, click Add Page to syndicate.) Error finding feed, please try again » Find feed title

A Blog Page allows you to add entries, for news or other time sensitive postings

(Login required to save to your tagged pages.)
(or Cancel)

Make further edits, (or Cancel)

(Login required to save to your tagged pages.)
(or Cancel)

(Editing anonymously: to be credited for your changes, login or register a new account)

Change Page Permissions? Changing these permissions will adjust who can modify this page.

sharkshark (change)
Swik Users (change)
(or Cancel)
Upload an image from your computer:
or Copy an image from a URL:
or Erase the current icon:
Icon Preview:

or Cancel

Erase Jabber-linux? The contents of Jabber-linux page and all pages directly attached to Jabber-linux will be erased.

or Cancel

(Editing anonymously: to be credited for your changes, login or register a new account)

other page actions:
Jabber-linux

Jabber-linux

Tags Applied to Jabber-linux

No one has tagged this page.

Jabber-linux Wiki Pages

Tag Cloud

To further filter what appears in the Things Tagged Jabber-linux list, select a tag from the Tag Cloud.

sorted by: recent | see : popular
Content Tagged Jabber-linux

在线好友列表与数据结构(3) - 平衡二叉树

Presence and Data Structure - Part III

关于在线好友场景的说明参看前文:在线好友状态列表与数据结构(1)-list

我们再评估一下平衡二叉树在前文场景中的性能。平衡二叉树(Self-balancing binary search tree)是一种将树的深度自动保持最小化的一种数据结构。

1) 红黑树 Red Black Tree
Red-Black Tree是如图所示一种数据结构,它最深的叶子最多是最短的叶子深度的2倍,是通过红色和黑色的控制来达到目的。 它的Insert/Delete/lookup算法复杂度是O(Log n)

Red-Black的插入/删除有非常直观的Applet动画演示
http://gauss.ececs.uc.edu/RedBlack/redblack.html

2) AVL tree
AVL tree也 是一种自平衡的二叉树,和Red-Black Tree非常相似。原理上AVL insert/delete比Red Black tree慢,lookup更快,因此AVL Tree在查找密集型操作中表现更好。由于我们考察的案例是insert/delete密集操作且set比较小,所以就不对AVL tree做性能比较了。

性能比较
我们仍然比较Red-Black Tree同Hash table的性能区别。Red-Black Tree使用Java的TreeMap来实现;Hash Table使用HashMap来实现。

5千万数据, 每50个为一组,插入50个8位长的随机数,在达到30个之后再每次删除一个元素。

测试结果
HashMap 20秒
TreeMap 18秒

这和平时理解有点区别,因为一般的Java教材都是说不要直接使用TreeMap,当需要排序时候再用构建好的HashMap传递进去,但在上述测试中,对于数字的key,TreeMap的性能和HashMap大致是一样的,甚至性能更好。

简单小结
对于前文的场景,就是比较各种数据结构之后,还是HashMap领先。对于数字类型的账号,也可考虑使用Red-Black Tree, 即TreeMap

补充说明
Java Collection Framework 其实用来进行各种数据结构原理的性能比较,可能结果不一定100%反应该数据结构原理的优劣,因为Java集合类不是完全照搬按教科书来实现,而是做了很 多实用性及性能的优化。而且Java集合类的开发者是Java界最优秀的两位高手Joshua BlochDoug Lea

HashMap 的作者
* @author Doug Lea
* @author Josh Bloch

TreeMap 的作者
* @author Josh Bloch and Doug Lea

另外还有一个多线程下性能更好的 ConcurrentHashMap
* @since 1.5
* @author Doug Lea

尽管这样,我们通常关注是实际环境下使用基于数据结构原理的JDK集合类的性能,所以上述测试对实际生产环境是有借鉴意义的。

参看:
在线好友列表与数据结构(2) - Radix Tree
在线好友状态列表与数据结构(1)-list
类别:编程 查看评论

Jabber-linux: Jabber XMPP resource

在线好友列表与数据结构(2) - Radix Tree

Presence and Data Structure - Part II

1) Hash table
在讨论Radix Tree之前先看下 hash table, 它是目前大家都很熟悉使用非常广泛的一种数据结构。它的算法复杂度是O(1)

/**
* Roster item cache - table: key jabberid string; value roster item.
*/
protected ConcurrentHashMap<String, RosterItem> rosterItems =
new ConcurrentHashMap<String, RosterItem>();

(Openfire class org.jivesoftware.openfire.roster.Roster)

2) Radix Tree

(图片来源:Wikipedia)

Radix Tree 是如图所示一种数据结构,对于小量范围有一定相似度的字符串具有较高的insert/delete/lookup性能。它的这几个操作算法复杂度是 O(k), k指key长度。与hash table相比,虽然O(k) > O(1)。但是 hash table的O(1)没有考虑计算hash所需时间及hash冲突的时间
。因此在某些情况下Radix Tree性能比hash table好也不足为奇。

性能比较

我们使用Google code中的 Radix Tree Java Library实现,
hash table使用Java Collection中的HashMap

1千万数据,每50个为一组,插入50个5位长的随机数,在达到30个之后再每次删除一个元素。考虑到实际应用中号码段可能会趋于集中,而且为了更好的测试Radix Tree,测试再在所有的号码前加上固定前缀1000。

执行时间:
HashMap 2秒
RadixTree 20秒

虽然构造的测试场景有利于Radix Tree, 但是测试结果是Radix Tree完全不适合此场景。而且还有不足的是上述Radix Tree库没有实现iterator()接口。

参看:
在线好友状态列表与数据结构(1)-list
在线好友列表与数据结构(3) - 平衡二叉树
类别:编程 查看评论

Jabber-linux: Jabber XMPP resource

Comet与Bayeux

任何一个想实现专业Comet产品都避免不了去了解Bayeux, 它定义了一个协议,通过一系列 json 的事件来实现 pubsub 模型进而实现Comet各种业务。它也致力让自己成为Comet的标准。小型的Comet应用通常会在Streaming里面返回一些自定义的 JavaScript来实现各种业务功能,但是Bayeux实现了一个full stack的体系,包括客户端服务器的交互,Event, Transport协商, Authentication, Security等。

Bayeux一些术语和概念包括

  • Pub/Sub,Bayeux的核心就是通过一个pub/sub模型来实现Comet各种业务。
  • ClientID, 通过客户端handshake之后服务器分配。
  • Channel,订阅的频道,可以理解成聊天的房间。
  • Messages: 所有的包都封装成一个message,里面包含各种字段。
  • data: message中的数据元素,应用可以根据业务再次定义细分的格式。

Bayeux的优势很明显,通过与Jetty配合可以几十行程序实现一个comet的聊天室demo

缺点
  • PubSub模型,点对点支持不佳,除了多人聊天的场合之外,其实大部分comet应用更适合点对点的模式。如果用PubSub套上去也可以实现,问题是对服务器的压力更高,而且通常comet应用的访问量都比较大。
  • 可靠性,一条信息publish了没法知道客户是否能收到了,也没法做进一步处理比如说保存或重发等业务逻辑。
  • 顺序,publisher顺序和接收显示的顺序
  • 多Tab浏览器打开同一个Comet应用,或者在IE里面Ctrl-N再次打开当前页面新窗口。

更详细的比较可参看 Battle of the Bayeux 系列

尽管Bayeux喜忧参半,但是对于希望实现一个专业Comet应用的开发者来说,Bayeux的诱惑是巨大的,它有开发者需要的完备的接口和成熟的体系架构。如果绕开它,不管是服务器还是客户端都需要一个漫长的摸索和自己定义规范的过程。如果看了这篇自己用C实现的comet http server,基于libevent以为就搞定Comet那可能就低估难度了。

Bayeux的例子可以通过下载Jetty6看到。
类别:Web Im 查看评论

Jabber-linux: Jabber XMPP resource

在线好友状态列表与数据结构(1)-list

Presence and Data Structure - Part I

在一个典型的IM Server上,每个登录的用户都需要维护一份自己在线用户列表,需要频繁进行以下操作

iterate
循环与遍历,很多操作需要调用iterator

insert/delete
由于在线的好友随时会产生上下线的变化,所以需要增加或删除列表的内容。

lookup

同时由于列表的元素需要保持唯一性,insert时候也需要查找已有的元素是否存在。

同时还具有以下一些特性

长度
在线的好友列表不会太长,通常都是几十个。

规律

假如系统使用的是基于号码的数字账号,这些数字通常有一定程度集中性,比如很多系统活跃用户集中在最新的号码段。


对于一个这样的需求,我尝试去了解一下需要知道在已有的数据结构中哪一种数据结构是最适合的。

在以下及后续的评估中,主要是考虑时间复杂度,即程序性能,对空间复杂度关注较少。

1) Array/List

对于这样一个列表,最简单的做法就是用数组或list实现。这就是往往现在大部分程序员不懂数据结构也能写出正常执行的程序。`

但是,Array/List都存在查找慢的问题,频繁的增删性能很慢。

2) Linked List
Linked List解决了增删性能问题,是一种最常采用的做法,如下代码片断。但仍然存在查找慢的问题。


/**
* remove a jid from a list, returning the new list
*
* @param id the JabberID that should be removed
* @param ids the list of JabberIDs
* @return the new list
*/
static jid _mod_presence_whack(jid id, jid ids) {
    jid curr;

    if (id == NULL || ids == NULL)
    return NULL;

    /* check first */
    if (jid_cmp(id,ids) == 0)
    return ids->next;

    /* check through the list, stopping at the previous list entry to a matching one */
    for (curr = ids; curr != NULL; curr = curr->next) {
    if (jid_cmp(curr->next, id) == 0)
        break;
    }

    /* clip it out if found */
    if(curr != NULL)
        curr->next = curr->next->next;

    return ids;
}
(Jabberd 1.4 更新好友列表的代码, mod_presence.cc)

(待续: 在线好友列表与数据结构(2) - Radix Tree)
类别:编程 查看评论

Jabber-linux: Jabber XMPP resource

构建大型的XMPP bot(即IM机器人)

最近看到一篇文章 Thoughts On Scalable XMPP Bots, 描述构建一个大型基于IM bot的一些思路。
  • Client Bot
就是Client 自己按照IM协议作为一个普通的客户连接到服务器。普通用户添加这个bot账号之后可以进一步进行相关的业务交互。Client Bot在实现各种专有IM系统中比较常见,比如MSN bot, GTalk Bot等。

Client Bot最大的问题就是能够添加的好友列表的长度限制。因为bot是一个普通的客户端,所以普通客户端最多只能添加数百个好友的问题就成了最大的障碍。

另外由于bot通常流量过大,而且会给服务器造成额外压力,很容易被服务器当做发广告信息或垃圾信息或其他业务竞争方面的原因遭受屏蔽。

综上所述,基于client bot构建一个大型业务系统不是最佳的选择。
  • Component Bot
这个只对XMPP系统而言,XMPP中Component使用专门的协议与服务器交互。实际上component有自己的domain, 如 rabbiter 使用 rabbiter@rabbiter.DOMAIN

在 ejabberd 上,component可以使用round robin负载均衡算法,将component请求分布到多个相同component name的服务上。以实现一个跨服务器的大型业务系统。
  • S2S Bot
Bot有自己专门的域名,如 tim-bot.com, 它可以在 DNS 设置轮询使服务定向到多个具体的服务器上。但是由于此方法需要单独申请域名并配置配置独立的服务,这个做法显得有点过于复杂。

Component和S2S bot适合构建自己的基于bot的服务。比如文章开头连接中所说的Chesspark(一个实现下棋游戏的bot),以及以前介绍的Rabbiter一个开源的XMPP微博客实现
类别:Xmpp 查看评论

Jabber-linux: Jabber XMPP resource

基于用户好友关系的分布式PubSub系统(2)

继续改进部分基于用户好友关系的分布式PubSub系统

本来的想法是把LocalSubList放到远端,好处是High availability即某个节点死了不会造成大面积故障,由另外一个节点可迅速接管。
但是如果放在远端, 那更新的开销会非常大, 1个改变需要修改n份远程数据,比如拿在线好友列表说事,一个用户改变状态,所有在线好友的列表需要同时update,在设计上人为制造了一个瓶颈。

因此今天把思路调整下,由发送方广播1个通知, 接收方各自维护更新自己的列表。那HA怎么办,每2个节点分成一组互相替对方存一份。反正发送方会广播通知的,即使增加一个专用的节点来做备份listener也不是什么大问题。在可靠性面前,硬件成本微不足道。

自己做一个网络模块的优点是风险可控,时间可控,但是原理通过之后就只剩下枯燥的开放了。按照don't re-invent the wheel的思想,或许将来更好的做法是底层(语言和框架)来做这些事情。比如网络间的通讯,节点迁移,HA, 数据共享等。

这个模块有点抽象,尽管我觉得不复杂,但跟别人口述的时候对方也是听得一头雾水,从软件项目管理的角度来说设计要尽量简单,至少要项目小组里面一半以上的人一看就明白,因此这个设计还有很大的简化空间。

做软件设计不能做得象编程之美的题目那样高深。对于一个网络服务端程序,我觉得
1. 性能优先
2. 简单优先
类别:高性能服务器 查看评论

Jabber-linux: Jabber XMPP resource

Java设计分布式网络架构的不足及与Erlang的比较

一. Java 的不足
如何构建一个分布式可扩展的Java服务器?首先我们要非常了解Java构建网络应用的优点及不足之处。
Java网络架构的基础是RMI远程调用。RMI是一种成熟稳定方便的应用,它的不足主要有

1) 没有安全隔离机制,一段代码的不稳定会造成整个node failure

2) 没有接管及远程监控机制,失败不能由另外一个程序或另外一个节点接管

3) RMI是C/S结构,通常是一对一, Client无法选择多个Server,无法切换Server,无法转移Server,如下一个典型的 Java RMI Spring配置
<bean id="timDemoService" class="org.springframework.remoting.rmi.RmiProxyFactoryBean">
    <property name="serviceUrl" value="rmi://server:1199/fooService"/>
    <property name="serviceInterface" value="com.foo.TimDemoService"/>
</bean>
上面的 timDemoService在JVM系统启动时候就加载,client/server就已经固定。

4) RMI是单向的,只能 client 调用 server, Server 调用 Client需要另外配置一套(即Server变成另外一个场景的client),不能共享同一个连接。

二. 传统的 RPC 都是错误的
因此最近有一种观点就说RPC都是错误的,下文中提到的RPC都可以理解成包含Java RMI

"but for normal languages, RPC creates more problems than it solves."
    -- Steve Vinoski

来源:(原文 中文版)
其主要论点就是说RPC最大的问题就是把远程调用做得象本地调用。但是,远程调用并不是本地调用,它的异常和错误及其他很多方面是截然不同的。传统的RPC调用忽略了local与remote的区别,因此在大型项目里面混淆了这两者调用区别的应用通常会造成性能问题。

三. Erlang的优势
跟传统的 RPC 相对比,Erlang 的主要优点包括

1) 2个process互为关联(link),一个crash,另外一个自动接管。

2) RPC就是message send/receive(严格的讲Erlang里面没有RPC), 可以很方便增加error handling, 而且 error handling 可以放在远程,这样更适合网络架构,因为local error handling在本机发生故障时候毫无意义。

3) message receive可以增加timeout,不会阻塞在某个地方

4) 其他场景,如Node X调用Node Y, Node Y执行业务之后把结果返回给Node Z, 传统RPC无法处理

四. Java中一些替代思路
1) RMI 也可以设置 timeout,因为底层无非都是基于Socket

2) RMI也可以实现无单点故障及负载均衡,参看 Clustered Remoting For Spring Framework Cluster4Spring 支持一对多调用,动态发现服务(dynamic services discovering)及远程错误监控, The Server Side 上有更多深入的讨论

3) 分布式内存共享 Coherence Data Grid, Openfire Cluster 就用了这个模块,不过这个框架不是开源的。

4) 分布式内存共享 Terracotta,这是一个开源的,Scala会采用这个

5) JGroups 可靠的组播服务,集群通讯首选的工具库,在其他语言无类似替代产品。JGroups介绍可参看前文 JGroups 简介、适用场合、配置、程序例子Demo等完全使用指南

6) Concurrent, Erlang中有轻量级的process, Java7中会有Doug Lea主导的fork/join

不过 Erlang里面还有Java中暂时无法替代的优势, 如Immutable变量, 无共享内存,Process交换数据通过消息传递实现等,这些特性在多核CPU下具有先天优势,相关资料也很多,就不这里重复了。
类别:服务器架构 查看评论

Jabber-linux: Jabber XMPP resource

基于用户好友关系的分布式PubSub系统

需要一个pubsub的功能,用在基于各种好友关系的场合。

* publish list 可能成千上万、十万、百万。
* publish topic 生命周期可能极短,调用一次就结束;也可能很长
* publish 数据实时广播即可,无需保存等待consumer到来
* subscribe list 可能很长,大的数千,也可能很小,只有1个
* subscribe list 相对固定(在线好友列表 or follow list)
* subscribe list 需要跨节点的,即一个topic在多个节点有local subscribe list
* 对性能要求极高,性能为王
* 无事务要求,特殊状况下,如某节点发生故障,丢失小量数据可容忍。
* 分布式,无中心节点
* 节点可动态切换

目前还没找到适合我的现成产品。前几天提到的rabbitmq和erlang或许是一个思路。

Erlang太高深了,周末的时候想了一个适合各种小白语言的思路,试画了一个简单的。


类别:高性能服务器 查看评论

Jabber-linux: Jabber XMPP resource

Rabbiter一个开源的XMPP微博客实现

最近听一个做类twitter系统的技术同行聊到 Rabbiter, 简单了解了一下,原理如下


1. Rabbiter 是一个xmpp bot,即 IM 机器人,基于 RabbitMQ 和 RabbitMQ XMPP Transport实现,即底层还是一个消息服务器

2. Rabbiter 采用 Erlang 开发,原理上具有良好的可扩展性,可支持非常大型的系统,通常跟 ejabberd 同时部署

3. Rabbiter 实现的原理上属于 XMPP PubSub

4. Rabbiter 实现的功能上目前主要是微博客(microblogging)的功能,支持的指令包括 follow, unfollow, following, followers 等。(微博客是twitter, 饭否之类系统)

5. Rabbiter 可以实现 MUC (多人聊天) 或群功能,比如用户A/B/C/D互相follow, 就成了一个多人群体

6. 所有 Client 订阅信息都是 PUSH 过去, 原理上可以避免 twitter 目前遇到的 API 负荷过大问题。

这个是我1年前关于 XMPP 与 Microblogging 不成熟的想法:Twitter中文版类似系统实现的技术构想。那现在 Rabbiter 则是可用的 XMPP/Microblogging 产品了。

Rabbiter的网站及下载地址为:http://github.com/tonyg/rabbiter/tree/master
类别:Xmpp 查看评论

Jabber-linux: Jabber XMPP resource

一种Java快速本地cache实现方法

前几个月曾经做个一次 比较Java中几种数据cache方式 的试验,最近看到 Openfire 中有一个非常小巧的本地 Cache实现, 在相同环境测试比流行的ehcache快大约5倍。简单介绍如下。

原理图

实现方法
* 用 HashMap 来存储和用来做 CacheKey 查找。
* 用一个LinkedList来存储访问顺序列表
* 用一个LinkedList来存储添加时间顺序列表,即过期时间。
* HashMap 中 Key 为 CacheKey, Value 包装成一个CacheObject
* CacheObject 包含:
1) object size
2) 指向 Access List 节点的指针
3) 指向 Age List 节点的指针

其中两个List的作用
1) AccessList
当添加新元素且 List 满时,删除列表最后的元素,即最长时间没有访问的元素。

2) AgeList
当调用 get cache 时候,判断 List 末尾有无过期元素,如有向前一直删除到最后一个没有过期的元素为止。

Performance 性能评测
写了个简单的测试,2线程写 Cache, 4 线程同时读Cache,每个Cache 100字节,平均速度大致为

写cache: 168,924 条/秒
读cache: 605,212 次/秒

结果在相同环境测试比流行的ehcache快大约5倍。

Resource资源下载
DefaultCache 源代码,稍修改去掉没用的引用即可独立使用。
类别:高性能服务器 查看评论

Jabber-linux: Jabber XMPP resource

未必有价值的《编程之美》及对开发人员能力的思考

记得我刚开始从事软件开发工作的时候,当时的领导曾经给我推荐过一本很薄很经典的90年代的书,书名我已经记不起来了,讲的是微软开发小组里面的一些优秀的开发实践,如TRACE, ASSERT, bound check 的一些美妙之处,看后对我的编程风格有很深的影响,有些习惯可能一直延续至今。微软亚洲研究院的《编程之美》给我第一印象应该是这样一本书,然而看了几个小时之后,稍微觉得有点失望。一般程序员看后可能会对有些应试的用途,但对提升自身价值没有任何帮助。

也顺便说说我对开发人员能力如何衡量。

1. 90%以上公司需要的都是知识型人才,比重占70%,
拿Java来说
a) 基础知识类:如jdk, collection, thread, jdbc, jsp, servlet
b) 专业技术类,如Struts, Spring, Hibernate
2) 综合知识类,如TCP/IP, socket, linux, web service, xml, sql, ajax

2. 协作能力/EQ, 比重占20%
比如协作,沟通,态度,责任心,积极心等

3. IQ(智力题,数学题) 10%
这个很难衡量需要多少,按应用类型来说
a) 以功能为主的应用, 国内大部分是这种情况,开发就是怎样用程序来完成业务系统,这种类型知识面更重要
b) 以性能为主的应用, 如 nginx
c) 两者兼顾,如 mysql
b/c可能是对智力方面要求稍高,但我觉得任何一个数学能打80分以上的在1,2达到要求之后都可以胜任。

在大部分软件开发中,纯算法占的比例很少,甚至没有。一个有趣的现象就是《数据结构》(严蔚敏的那本经典教材不怎样)这本书大部分程序员只是在面试前阶段有机会看看,工作中根本没需要查阅。
比如Java中
常用数据结构:ArrayList, LinkList, Queue, Hashtable, HashSet
常用排序:SortedSet, SortedMap, TreeMap
数据结构中描述的那些东西基本上JDK都有了,对于Java程序员只要理解这些工具库的使用场合,能够使用恰当就非常合格了。

再讲个纯数学算法优化是否重要的问题,书中有例子,如2.10 寻找1个数组中最大值和最小值。这个题通常的解法的时间复杂度是2*N,实际上可以很容易优化到1.5*N。如果从一个产品的角度来考虑,如果一个程序员提交的代码复杂度是2*N, 我觉得这样就足够了。因为
1) 大部分应用的电脑CPU占用5%都不到
2) 这样纯算法的问题在目前大部分Web系统通常不会成为瓶颈,瓶颈通常在IO, 网络及架构设计及语言本身上。比如你用Ruby写,某个算法再优化可能也只有C语言效率的1/100
3) 产品负责人更关心代码质量,可维护性,可扩展性等方面。
4) 产品负责人更关心更关注知识型/经验型的层面,比如程序员原来用Java IO实现的,可能用Java NIO更合适。

可能上面这个例子是此书里面离开发最近的,大部分题目比这个离实际开发更远,比如“数独”问题等,用来做做头脑游戏可能更适合。如果一个程序员花了1天,写出了一个构造数独的程序,他的能力就得到了提高吗?

后记中其中一个现任职于微软研究院的作者提到,“作为一个曾经的求职者,当时自己能够做的,就是搜集和整理能够在网络上搜刮到的所有题目。算法题、智力题以及各种面经。把各种题目做到让自己条件反射为止……(原文)”。如果真是这样,我对微软亚洲研究院的这种“高考式”的面试方法表示担心。擅长做数学题和智力题跟能否够给软件企业和社会创造价值未必能划上等号。
类别:编程 查看评论

Jabber-linux: Jabber XMPP resource

《构建可扩展的Web站点》一些观点

Building Scalable Web Sites一书大家基本上都是冲着Flickr和Cal Henderson首席架构师的名头去的,最近看到有中文版了就订了一本。书中全部代码用PHP为例,但其实跟PHP关系不大。书中实用的章节不多,先看了远程服务一章。

1. 使用远程服务的第一原则是不能依赖远程服务,另外一方面远程服务要考虑冗余性。
在我理解,远程服务有几类:
1) 远程API,如XML-RPC, HTTP接口, Message Queue。
这个是业务相关的,Failure怎样做要程序自身考虑了。
2) DB存储类,如MySQL, NFS。
MySQL可用主从或MySQL proxy, NFS不知道,不稳定,关键业务用的场合不多。
3) Cache, 如Memcached,
Memcache默认可以分布多个,Failure怎样处理?我觉得如果cache失效对系统影响比较大的话可以写2份,否则就立即启用备用cache。

书中还提到一个TCO的概念,在某个场合,靠人力去优化还是加硬件,哪个成本更低?

2. 异步系统。
异步系统也是我感兴趣的地方,任何一大型的系统,都会有不少异步的设计。
书中提到一种Ticket模型:

图片来源:(books.google.com)

Ticket异步模型除了书中介绍的用来转换图片服务的场景之外,我举一个我理解的例子。
用在IM里面比如在群中发送图片功能。
1) 发送方发送/粘贴图片,立即显示发送完毕
2) 群中所有接收方立即显示接收到图片(只是个Ticket)
3) 系统实际上处于发送方上传图片中
4) 同时群中用户拿ticket去要图片(轮询or通知)。
5) 发送方上传完毕
6) 接收方凭Ticket获取到图片最终资源显示。
这个场景理论上就是和Ticket模型相似,但在实际操作上群图片还有更多细节考虑。

3. 使用轻量级协议
HTTP和XML被过量使用,某些高访问场合未必是最好的选择。
这就是Flickr为什么要使用自己的存储服务和协议。
但这个问题是双面的,首先作者强调,“大多数场合,自行开发协议是糟糕的主意”。Flickr也尝试过NFS和scp。(这也是为什么gtalk选用XMPP)

另外翻译版源代码排版比较差,空行缩进行距等细节未注意,跟我们开发人员写的Word文档排版有得一比。
类别:服务器架构 查看评论

Jabber-linux: Jabber XMPP resource

HiveDB, 一个横向切分MySQL海量数据的框架

1. HiveDB是在2007年5月"Bay Area Community Meetup"首次出现,底层基于Hibernate shards基础实现。Hibernate shards 则是 Google 的开发工程师在"20%工作时间可以干别的有兴趣事情"环境下开发出来的一个 Hibernate extension,贡献给开源社区希望发扬光大;

2. HiveDB推出到现在也不算短,开发进度相对平缓。功能上已经处于一个相对稳定1.0状态,核心功能已经基本没大的问题。作者声称已经在一个每秒请求数达数千次的,包含海量数据的生产环境稳定运行;

3. HiveDB/Hibernate shards所适用的典型场合就是一个海量记录的表,可以根据某个规则分开存到多个相同表结构的数据库服务器上。和HSCALE功能差不多,但HSCALE当前版本实际上还不能跨服务器的;

4. 可以查询跨服务器数据,但不能做 order/join;

5. 具有类似mysql proxy之类多服务器容错功能,单独服务器发生故障不影响系统正常运行,通过类似ha-jdbc思想实现;

6. 目前只支持Java语言,有支持各种语言如php/python/perl/ruby hive client的计划,但是目前只有一个python hive client测试版可用。


图片:按字段(Partition Key)切分典型场合

(图片来源:hivedb.org)
类别:Mysql 查看评论

Jabber-linux: Jabber XMPP resource

google talk server 架构介绍

本文gtalk server架构介绍整理自视频 Seattle Conference on Scalability: Lessons In Building Scalable Systems 而得,加入Tim少量理解和补充。

演讲者 Reza Behforooz , 是 Google Talk servers的 team leader

1. Google talk server基于 java 平台实现,见视频23:50问答。

2. 关于系统设计与实现难点
和任何xmpp server一样,难点是处理Presence峰值流量,而不是用户数或并发用户数
峰值 total QPS > 10万
Presence = ConnectedUsers * BuddyListSize * OnlineStateChanges
系统在一夜之间通过 gmail/orkut用户突然增大,没有一个缓慢适应的过程。

3. 关于压力测试
1) 实验室式的压力测试只是一个开端;
2) 在正式上线之前,通过真实环境的试验平台,选取大约10%的用户,来做实际环境测试,在不显示UI的前提下,将google talk代码嵌入用户页面
这样在gtalk正式上线时候,所有功能已经是比较有把握的。

4. 数据和应用服务分布到多服务器
可以动态扩容,升级和更新,无须停机
但是 google talk server服务并不考虑跨 IDC, 因为作者认为在海量流量处理下,跨数据中心不利于系统处理。
分布包括数据分布,可参看以前文章MySQL 分表分数据库服务器的一种方案HSCALE, 基于MySQL proxy 另外还有请求和逻辑服务分布

5. abstraction, 抽象与分离
不将问题带入别的系统, gmail/gtalk单独出问题不影响另外一方使用。
gmail, orkut 与 google talk server 完全没有关系
如 gmail 无须关心 google talk 有哪些服务器,有多少,在哪里,怎样分布。
不同系统之间通过 gateway(logic name) 来访问, gateway 再映射到物理的服务器。

6. 避免客户端或服务器自动重连造成DoS问题,服务器瞬时访问过大而瘫痪

7. 在服务器增加profile/monitor机制,包括配置文件,资源状况, 日志, 可以做离线分析。
这样某个服务器发现问题,首先去看 monitor console
profile/monitor不是侵入式的,就是不是通过在服务器程序嵌入代码实现。

8. Google Talk Server其他一些开发经验
程序可以先前和向后兼容(协议/API兼容),可以逐个或批量升级,新老系统可以共存
有良好的平台来试验新功能,就是上文中提到可以用gmail来试验gtalk,这个是很多公司不具备的
开发人员可以直接访问真实生产环境(production environment),观察系统实际运行情况来调优和改进。
类别:高性能服务器 查看评论

Jabber-linux: Jabber XMPP resource

Openfire Server presence(在线状态)消息处理流程

Presence处理是IM Server的核心,也是一个IM Server最复杂的部分。一个用户的状态发生变化,需要通过服务器自动投递给他所有在线的好友,因此Presence模块实际上等同一个消息处理服务器,可参看以前消息服务器相关文章ActiveMQ性能研究及与memcacheq比较

Presence的复杂性体现在:

1. 由于每个用户都有1到多个好友,服务器的处理量被放大。
2. 分布式处理的复杂度,你的好友可能同时分布在n个服务器上,而且同时上线的好友没有规律。
3. 请求量不均衡,可能瞬时非常大。比如你服务器刚重启所有的客户几乎同时自动重连过来。比如Twitter宕机都是在一些热点事件时,大家活跃度突然同时增大。所以系统必须按峰值的处理量设计。
4. 缓存cache设计困难。每个用户的在线好友都不同,而且随时在变。
5. 隐身同黑名单的业务逻辑很难高效处理。

Openfire Server处理presence的流程如下,以3.6.0为准。


1. ConnectionHandler.messageReceived();
mina 层面处理。

2. StanzaHander.process() => processPresence
xmpp 层面。处理所有xmpp包的方法,实际上只有login相关包在这里处理。其他类型的包交由相关逻辑类来处理。 由于是个presence包,交由下面presence逻辑处理模块进行。(also add from to packet)

3. PacketRouteImpl.route() // route presence
4. PresenceRoute.route() => handle() // route presence
由于presence是一个需要路由的包,路由主要区分目标是本机还是远程,是component/server还是普通用户。

5. PresenceUpdateHandler.process() => broadcastUpdate
// process() update db and update cache,
calls PresenceManager.userAvaliable(); session.setPresence()...

6. Roster.boradcastPresence();
检查privacy list(隐身及黑名单用户)然后路由给所有在线好友。

7. RoutingTable.routePacket, routeTable.getRoutes()
真正的工作在这里,较慢。

8. session.process(), session.deliver
已经分发到相关用户了,调用该用户的session投递给此用户

9. nioconnection().deliver, deliver to the end users
再回到MINA

因此Presence投递工作的核心是在6~7,不过其他的步骤也有不少细节的处理。Openfire中6~7的实现比较精简和优雅,但如果想作为一个大型的高效消息投递系统还是有改进的空间。
类别:Openfire 查看评论

Jabber-linux: Jabber XMPP resource

MySQL 分表分数据库服务器的一种方案HSCALE, 基于MySQL proxy

在大型的应用中,我们经常碰到MySQL的表数据需要无限扩充的情形。我们通常有以下一些解决方案,但是现成的方案都不是完美的。

比如,
MySQL master/slave: 只适合大量读的情形,未必适合海量数据。
MySQL cluster: 提供的可能不是大家想要那种功能。
MySQL proxy: MySQL master/slave配合
MySQL 5.1 partition: 只是将一个表存储上逻辑分开,部分改善了性能,但是可扩展性仍然是问题。
MySQL 按应用逻辑分表和分数据库,通过程序来决定数据存放的表,目前很多公司都是这么做的。它的主要问题是跨区查询,可参考Tim以前的文章MySQL分表实现上百万上千万记录分布存储的批量查询设计模式

使用程序来分表分服务器最大的问题是比较繁琐,需要程序做很多特殊处理,需要程序员了解数据存放在哪个服务器哪个表,这样,几乎所有的程序员都牵涉了进来, 也容易出错。那如果我们把分表的逻辑放到中间层则上层的应用就简单很多,而且可以单点控制分表的逻辑,方便调整与扩展。

  • HSCALE分表分数据库的思路


    HSCALE就是这样一个产品,它是在MySQL proxy的 基础上,在MySQL proxy的层面将上层的请求分配到实际的表上。实际的原理是通过拦截SQL进行替换和服务器重定向再将SQL传递到目标服务器上。它的分表算法可以由自定义的Lua脚本来实现,非常灵活。目前已经能支持同数据库分表,跨数据库的实现也将增加,因为在MySQL proxy的框架下,这并不是很困难的事情。现在的版本或许不是很成熟,但是在原理上我觉得是基本上没多大障碍,发展下去将是一个不错的选择。

    HSCALE具体的性能测试简单介绍如下。
    • 测试
    使 用HSCALE有2个开销,一是网络层面的,下面的测试环境大约MySQL proxy对每个SQL会增加0.02ms的网络延迟,如果增加了HSCALE, 则会增加到0.3ms,第2个开销则是MySQL proxy, Lua, SQL解析,HSCALE算法等造成,可看下面数据。

    (图片来源:pero.blogs.aprilmayjune.org)

    结论是最极端的情况下,在10个线程的情况下,使用MySQL proxy会需要大约3倍时间,HSCALE则是10倍。
    注意结论是MySQL方面最优化的情况,查找一个三条记录的表。在实际环境中的latency和这个没有直接比例关系(比如1:3)。测试结果不太令人满意,幸好后面新版本MySQL proxy的测试数据得到了改善。

    使用了MySQL proxy 的 svn版本,性能提升很大。MySQL/MySQL proxy从1:3提升到1:2, HSCALE同样也提升比较大。具体结果见连接。但是仍然迫切希望作者再有提升。

    今天说到大部分技术Blog都以介绍国外技术与产品的文章为主,没有深度,当然我这篇也不例外。:)

  • 类别:Mysql 查看评论

    Jabber-linux: Jabber XMPP resource

    Page 1 | Next >>
    Username:
    Password:
    (or Cancel)