谈谈我对数据同步的理解

We性质b和网游最大的不同也许就在于数据同步。 Web的工作流程(这里不包括页游)虽然也有很多变化,但是一般都大致分为三步。 1. 在浏览器输入网址, 浏览器通过HTTP协议请求服务器加载数据,服务器在收到HTTP请求之后,从数据库加载相应的数据(有可能是HTML,JS等一些用于浏览器渲染的数据)并返回给客户端。这一步我称之为查询。 2. 浏览器收到服务器返回的数据之后,将数据渲染并呈现给用户。这一步我称之为渲染。 3. 用户在看到浏览器呈现的内容之后,根据需要去执行不同的操作……

实现了一个AOI模块

在场景服务中,如果有一个人A的行为想要被其他人看得到,就必须将A的数据包进行转发给其他人。 最KISS的办法,就是直接把A的数据包直接在场景服务内组播。 但是在一个场景服务中可能有成百上千个人,如果直接在服务进程内进行广播,数据流量会大到一个很夸张的地步,至少以目前的网速来讲是不现实的。 因此,往往场景服务都为人物设计一个视野半径,即只将数据包转发给在我视野内的人,这样可以极大的降低数据的转发流量。 而AOI(Area Of Interest)正这样一个可以帮我们快速确定视野……

一个高可伸缩的游戏服务器架构

设计完socket通讯协议后,就面临着服务器架构设计了。我希望他是一个去中心化且具有高可伸缩性的集群架构。 水平扩展是高可伸缩的首要条件,因此,在设计之初就必须考虑好水平扩展考方案。事实上这一部分几乎花了我1整个月的时间来设计,在此期间我重写了3版才总算确定下来我认为可用的方案。 第一版设计方案如下: 将服务器分为3类,分别是GateServer, LoginServer, LogicServer。 GateServer管理客户端链接,数据包的加密、解密、广播、转发等与业务逻辑无关的操作。当压力过大时……

关于网络协议封装的一些新想法

最近业余时间在写一个小游戏。在为客户端封装socket层时头脑一热,有了一些新的想法, 在这里记录一下。 客户端使用的是Unity3d引擎。而在Unity3d中,基础的socket库只提供两种模式,一种是阻塞模式,一种是异步callback模式。 一般都需要基于这两种模式下进一步封装,才可以更方便的使用。 咨询了几个做客户端的并搜了一下,发现大家的惯用手法都是开一个线程去使用socket阻塞去读,然后把读到的数据通过队列传回主线程进行处理。 但是也许是单线程的思维模式已经深入我心了,所以我……

如何恢复全局INDEX

一般来说,当需要分配全局惟一id时,一般都会有一个变量来记录当前最新的id值,比如叫INDEX变量。 每次需要分配id时,只要简单的自增一下INDEX变量,然后INDEX的值即为当前分配出去的ID的值。 为了最大可能的延迟复用已经分配过的id,一般来说不会去特殊处理INDEX变量,即每次自增INDEX,并允许回绕情况的发生。 但是最近碰到问题就是,我有一堆分配过的id,如何重新恢复出INDEX的值。具体场景如下: [c] struct obj { unsigned int id; time_t createtime; ……

谈谈协议的设计

闲来无事,最近接了个公众号玩玩,当然肯定是基于silly的:) 最初的打算是开一个daemon,在收到微信sdk callback后根据好友发送的消息来做出不同的处理。比如根据输入关键字然后去我的blog上去爬取相关信息,每天定时把最新的blog文章做群发。 在实现http client过程中,需要解析dns。虽然gethostbyname可以用来解析域名,但是整个silly底层是基于异步来实现的,而gethostbyname则是以阻塞方式解析的,因此使用gethostbyname会极大地降低整个框架的吞吐量。 向dns服务器请求解析域名……

解耦

事情起源于昨天的一次讨论。模块A如何在不同的时期返回不一样的数据类型的值,供其他不同的模块使用。 我自行脑补了一下,其实这类问题可以归结为对数据类型的解耦。 考虑一种特殊情况,有moduleA,moduleB,moduleC1,moduleC2等四个模块。moduleA在不同的时期产出不同的数据供moduleC1和moduleC2处理。moduleB用于将moduleA产出的数据根据具体情况情况分别调用moduleCx来处理。moduleCx的接口类似moduleC1::doSomething(type1 data);moduleC2::doSomething(type2 data);  最l……

使用多态来做到open-close

自从看了设计模式了解到open-close原则后, 我在写代码时都是尽量遵循着open-close原则来进行编码。 而面向对象中的多态在做到open-close原则中起到不可忽略的作用。 一般在设计之初会先抽象出一个interface(也就是C++中的纯虚类), 这个interface中的函数接口一定是要仔细考量的,因为这关系到所有子类的实现。 然后根据具体情况去继承并实现interface,当我们新增功能时,仅仅重新继承一下interface生成一个新的类即可, 在一般情况下并不需要动到之前运行良好的类。当然不论你inte……

服务器的分布式部署

两周前使用redis-benchmark测了一下silly的并发请求响应速度, 开1000个客户端, 平均大概每秒能响应6W个请求。 但是这些请求仅仅是PING/PONG协议,也就是说这基本上就是纯网络I/O的性能,如果考虑到逻辑处理、数据压缩、加密、解密等时间, 可能一个silly都不一定能够撑得起5000人的访问量。 所以最近两周除了在研究redis之外, 就是在研究怎么给silly增加cluster支持,以便可以将计算分摊到不同的计算机上来降低客户端的请求的响应延迟,silly应该怎么增加对cluster的支持。 直到……

silly的socket模块重构

最初, 我仅仅最只想将silly实现成一个socket异步框架, 每一个socket有数据或事件过来直接将注册的处理函数异步回调即可。 然后, 随着三国杀的一步步实现, 我发现我之前考虑处理时漏掉了数据库环节。 由于所有socket事件均为异步, 当一个client发过来一个请求, 而这个请求需要使用到数据库数据时, 可能就会写出类似下面这样的代码: socket.recv(fd,function(fd, data) --process segment1 db.get(key, function(value) --process segment……