NoSQL
基于位置的实时游戏MapAttack的技术实现
by Elton on 十.11, 2011, under NoSQL
MapAttack是一款实时的,基于地理位置的游戏,其通过Socket.io,node.js,和Redis实现了其实时性。下面文章对整个游戏及其技术实现进行了描述,推荐给大家。
这里我将向大家表述我们如何利用Socket.io、Redis、Node.js以及一路上我们所学的东西来规划、开发并测试一款实时的、基于位置的游戏。在过去的几个月中,我们将大部分的空闲时间都用在了开发一款实时游戏上,由于它是基于地图环境的,所以我们称之为“MapAttack!”,并把它作为我们LBS平台Geoloqi的一个测试程序。游戏中,两组队员互相竞争,尽可能多的攻占游戏界面上的小圆圈。而在这里,游戏界面其实就是城市中玩家周围的街道。

Geofence在这里指地图上带有数字的小圆圈,玩家进入这些小圆圈后,就会得到与圆圈中所标记数字相同的分数,它所在小组的总分数也会相应增加,同时圆圈的颜色会变成该玩家小组的颜色。
为什么要开发这么一款实时Geofencing游戏呢?
我们想要创造一款游戏,它能够让人们与真实世界物理交互,而不是像第一人称射击游戏或者即时战略游戏那样通过电脑控制台来交互。同时,我们也是受到了真人版吃豆人(PacManhattan)的启发。
技术挑战
处理用户进入区域的检测,同时留出200+的小圆圈。
处理一局游戏中所有手机位置信息的更新量(一局游戏有20或者更多用户)。
允许每台手机或者观看游戏的Web浏览器都能实时地看到玩家们的移动和圆圈颜色的改变。每台手机都会将它的位置发送给服务器,服务器会广播这些位置数据给其他手机以及观看游戏的浏览器。
处理GPS技术在不同智能手机模型间的错误和差异以保证游戏的公平体验。
GPS硬件的差异
众所周知,GPS信号反映了城市中高层建筑的情况。这就导致了在位置数据方面的不准确和不一致。这点在新手机上并不显著,但是在较老的手机上却十分明显。

MapAttack架构图

Socket.io
Socket.io是一个跨浏览器的Web套接字实现,它允许在浏览器上做实时数据更新,并且也支持老的浏览器。多亏了Socket.io我们可以利用最新的技术,同时不用要求所有我们的用户升级到最新的浏览器。这让我们实现了游戏中浏览器和手机间的即时更新。
Node.js
Node.js是谷歌浏览器的V8 Javascript引擎事件驱动的I/O实现,它由一个反应器实现,而这个反应器使得大量异步数据的传输得以实现。
当手机要发送数据时,我们用一个Node.js服务器将位置数据流从手机传输到Redis的发布频道或者订阅频道上。数据发布到Redis上,另一个Node服务器订阅该频道。我们的Node.js服务器接收手机通过一个类似Google’s Protocol Buffers的顾客协议发来的更新,实际上就是压缩的二进制的JSON。
当一个浏览器想要开始发送数据流时,它连接Socket.io服务器然后这个服务器订阅Redis的发布频道或订阅频道。这个Socket.io服务器通过Websockets向浏览器发送数据,如果Websockets不可用,闪回或者长轮询作为后备方式。
本质上讲,Socket.io允许我们使用Websockets规范,这是全新的,但同时也能工作在较老的浏览器上。
Redis
Redis是一个开源的、高级key-value存储系统,它支持消息队列使用发布/订阅模式。
从较高层次来说,Redis让我们所能做的事,是控制把数据实时发送到所有游戏中的手机和浏览器。游戏中的每一台手机把它的位置发送给服务器,服务器广播这些数据给其它手机和正在观看游戏的浏览器。
关于发布/订阅系统的一件吸引人的事:使用一个传统的系统你不得不维持许多连接,并且为了通过连接发送数据,你不得不重复发送,与发布/订阅系统不同,如果你有10,000个用户,你将不得不重复通过10,000个连接,发送回非常缓慢,并且容易出现死锁在套接字上的问题。
使用Redis的发布/订阅模式,就像启动一个广播电台。一旦把它打开了,人们(在这里指的是浏览器)就可以收听。这让我们能够把实时数据大规模地更新给客户端(浏览器和手机)。
Sinatra Synchrony
Sinatra::Synchrony是Sinatra的一个小扩展,它动态提升了Sinatra网络应用的并发性。由于EventMachine和EM-Synchrony的支持,当你有很多传输和低速IO请求时(如向外部APIs发送的HTTP请求),它增加了你的应用每个过程可服务的客户的数量。由于它内部使用Fibers处理堵塞的IO,所以没有回调的需要。这意味着我们可以像写一个正常的Sinatra网络应用那样进行开发。
Sinatra::Synchrony允许我们做异步程序,除了那些在Fibers中封装了回调操作的。这让我们能够实现同步程序的同时利用异步代码的优势。除了可以这样简单地变成,它也让我们根据需要可以转换一个不同的并发策略。
The MapAttack Game Server
最后,有一个MapAttack游戏的服务器,在这里,这个游戏服务器是一个简单的数据库,他负责存储玩家在地图上显示的所在点的数据,以及手机上玩家需要实时去抢夺的点的数据。
英文原文:blog.programmableweb.com
译文出处:www.lbsvision.com
让Redis使用TCMalloc,实现高性能NOSql服务器
by Elton on 七.28, 2011, under C/C++, Linux, NoSQL
TCMalloc(Thread-Caching Malloc)是google开发的开源工具──“google-perftools”中的成员。与标准的glibc库的malloc相比,TCMalloc在内存的分配上效率和速度要高得多,可以在很大程度上提高MySQL服务器在高并发情况下的性能,降低系统负载。
TCMalloc库的安装步骤(Linux环境):
Step 1. 64位操作系统请先安装libunwind库(32位操作系统不要安装)
libunwind库为基于64位CPU和操作系统的程序提供了基本的堆栈辗转开解功能,其中包括用于输出堆栈跟踪的API、用于以编程方式辗转开解堆栈的API以及支持C++异常处理机制的API。
1 2 3 4 5 6 | wget http://download.savannah.gnu.org/releases/libunwind/libunwind-0.99-alpha.tar.gz tar zxvf libunwind-0.99-alpha.tar.gz cd libunwind-0.99-alpha/ CFLAGS=-fPIC ./configure make CFLAGS=-fPIC make CFLAGS=-fPIC install |
Step 2、安装google-perftools:
1 2 3 4 5 6 7 8 | wget http://google-perftools.googlecode.com/files/google-perftools-1.8.1.tar.gz tar zxvf google-perftools-1.8.1.tar.gz cd google-perftools-1.8.1/ ./configure --disable-cpu-profiler --disable-heap-profiler --disable-heap-checker --disable-debugalloc --enable-minimal make && make install sudo echo "/usr/local/lib" > /etc/ld.so.conf.d/usr_local_lib.conf #如果没有这个文件,自己建一个 sudo /sbin/ldconfig |
Step 3. 安装Redis
1 2 3 4 5 | $ curl -O http://redis.googlecode.com/files/redis-2.2.12.tar.gz $ tar xzvf redis-2.2.12.tar.gz $ cd redis-2.2.12 $ make USE_TCMALLOC=yes $ sudo make install |
Step 4. 检查tcmalloc是否生效
1 2 | sudo lsof -n | grep tcmalloc redis-ser 31590 elton mem REG 8,3 1155539 4856411 /usr/local/lib/libtcmalloc_minimal.so.0.2.1 |
Step 5. 测试Redis
1 2 3 4 5 6 7 8 9 10 11 12 | # 修改配置文件: vim redis.conf # 找到 daemonize,将后面的no改为yes,让其可以以服务方式运行 # 然后启动 redis: $ ./redis-server ./redis.conf #连接数据库进行测试 $ src/redis-cli redis> set foo bar OK redis> get foo "bar" |
Staircar:Tumblr的Redis集群控制层
by Elton on 七.27, 2011, under NoSQL

Tumblr是世界上最流行的轻博客服务,其用户量在最近的一次统计中已经达到2090万,超过了全球最大的博客服务WordPress。而我们今天要介绍的是Tumblr通知系统的架构,其通知系统由一个叫Staircar的轻量级HTTP服务器和其下层的大规模Redis集群组成。
应用分析
在Tumblr初期,其通知系统是由MySQL+Memcached的传统架构组成,但是由于通知系统庞大的添加操作,导致MySQL负担非常大,经常搞得InnoDB global transaction max(1024)都超出了。于是他们打算重新构建消息系统。首先他们分析了消息系统的应用特点:
- 按时间排序
- 唯一性,每一条消息都是唯一的
- 读写比大概是 60%/30%
- 每个用户的消息条数一定
- 数据按用户划分,每个用户只能读自己的消息
架构
基于上面应用特点的考虑,Tumblr选择了Redis的sorted sets作为其数据存储。
他们的存储方式是:
- 给每个用户分配一个sorted sets,其中每一项保存一条通知
- 每条通知以时间戳为score在sorted sets中进行排序
- 超出100条通知后进行trim操作
Tumblr的数据量:2300万个BLOG,每个BLOG 100条消息,每条消息体大概160bytes。
响应速度:大概每秒提供7,500次请求,每次请求的响应时间小于5ms。
考虑到容灾性及可能快速增长的数据量,Tumblr打算采用preshard的方式来架构他们的Redis集群,于是他们开发了Staircar(一个提供HTTP服务的Redis集群调度管理组件)。下面是他们的通知系统架构图:

实际上在开发Staircar前,他们考查了一些其它的类似功能的产品,但都不能满足他们所有需求(或者说闲杂功能过多)。
性能
Staircar由C语言写成,以libevent为网络驱动层,提供JSON格式的RESTFul接口,其性能超出了Tumblr工程师们的想象,其在最高峰时的响应时间也在5ms以下,其性能测试结果是大概能处理每秒30,000次左右的请求。下面是其性能测试图,从图上可以看到,其绝大部分请求(红色区域)的响应时间在3-4ms之间:

来源:engineering.tumblr.com


