大家好,我第一次做服务器的程序,之前我一直做手机客户端,什么WEB框架啥的都没用过 ,遇到很多困难跟疑惑,请大家多多指教。 目前在做的一个社区页面网游,HTML页面,非FLASH的,所有的交互都是基于HTTP的。
这个游戏的逻辑比较常见,类似于SLG,玩家消耗时间采集资源(比如点一个按钮,等5分钟就可以采集了10个粮食),随后制造了5个士兵,接着玩家之间可以进行PK,双方损失N个士兵等等. 同时具有社区的常见功能,玩家之间也可以互相加好友,留言等等。 但是除了管理员,普通用户没有广播的功能。也没有专门的聊天频道。 这个系统的特点是: 1. 用户数可能会很多, 可能会有上百万在线(至少所用的架构要能扩展到支持那么多),并且不分区,大家都在同一个区。 也就是, 所有的玩家,都可以通过用户名查询到另外一个玩家的信息,然后可以加好友或者PK。 2. PV量很大,并且数据库操作频繁,玩家的每个点击,都可能生成新的对象.比如生成几个士兵,跟别人进行一场PK,会产生一条PK记录。
我现在的设计是
浏览器 ----> LOAD BALANCE -----> 动态页面服务器 TOMCAT集群 -----> Logic server -----> DB server
前端, 静态的图片,CSS什么的,都可以交给 NGIX 动态页面服务器,用JSP,可以用 N台 TOMCAT 集群
后端, 逻辑服务器 Logic server 数据库 DB server , 一台MYSQL
困惑之一: 页面服务器与逻辑服务器的通信问题
我现在的做法是,N台 TOMCAT 通过SOCKET 连接到 逻辑服务器, 然后发送自定义的消息格式;逻辑服务器用一个线程维护消息队列,然后逻辑服务器开启一个线程,不停地处理消息,并把结果返回对应的页面服务器。
然后页面服务器把逻辑服务器返回的结果,翻译成HTML返回给玩家
页面服务器
//
static Integer msgId = 0;
List
public String requestHandler(HttpServletRequest hsr) { // 一些检查 // 根据 request 生成 msg MyMsg msg = new MyMsg(); synchronized (msgId) { msg.setId(msgId++); } msg.startTime = System.currentTimeMillis(); msgQueue.add(msg); while (resultMap.get(msg.getMsgId()) == null) { Thread.yield(); if (System.currentTimeMillis() > msg.startTime + 10000) { break; // 超过 10 秒没响应, 算超时 } }
MyMsg result = resultMap.get(msg.getMsgId()); resultMap.remove(result); if (result != null) { return "翻译result"; } else { return "返回超时错误"; } } // 接收消息 , 逻辑服务器收到 MyMsg, 处理后, 会返回一个同样 msgId 的MyMsg 给页面服务器, 页面服务器直接保存 public void onReceiveMsg(MyMsg msg){ if (System.currentTimeMillis() > msg.startTime + 10000) { return; // 超过 10 秒才回来, 直接丢弃 } resultMap.put(msg.getMsgId(), msg); }
请问这样的设计,有没有问题? 很多线程在等待自己的结果的时候,会不会造成服务器出问题; 自己写这些,总感觉有些不可靠, 有没有现成的 服务器间通信框架,以及 消息队列什么的可以直接用的?
逻辑服务器中: 把所有收到的消息都加入到队列里面,然后进行 串行处理。 这样就省得同步什么的了。 但这种做法,会不会造成效率损失? 一般大家做 逻辑服务器与页面服务器的通信是怎么做的?
困惑之二 逻辑服务器上的数据库缓存问题, 因为数据库操作非常频繁,所以肯定需要缓存。 我现在的做法是 逻辑服务器起三个线程, 一个负责逻辑处理以及数据管理, 一个负责数据库读取, 一个负责数据库更新。 我没有用 hibernate , 直接用的JDBC。
比如玩家登陆 页面服务器创建玩家登陆消息 -> 逻辑服务器 -> DB读取线程读取数据 -> 读取到的数据,放入 数据管理进程 -> 返回玩家的信息给 页面服务器 然后数据管理线程,定时遍历 所有的账户数据(一个列表),判断该账户是不是有更新,如果有更新, 则放到DB更新线程去更新数据库。 我用的判断数据是不是有更新的方法是, 在该 object 上次被更新到数据库以后,就生成一个 saved = object.clone(), 把所有的成员对象都 clone一遍, 然后比较 当前object 与 saved 的所有成员, 看是否完全一致, 不一致,则说明有更新, 需要放到 数据库更新线程去更新。
现在这种做法, 1.我感觉很麻烦, 所有的entity,都要写 clone 方法 以及 saved与当前对象判断更新的方法, 2.非常担心的就是一旦服务器突然出故障退出, 则可能会有很多账户的数据是过期的。只能靠日志慢慢恢复。 3.所有的数据以及逻辑都放在一台电脑上, 如果用户数达到几十上百万以后, 会不会性能上有问题。
我后来看了一些数据库缓存的资料,比如memcache, redis ,都是类似于 hashMap 的功能, 好像是为了处理分布式系统,我的逻辑这块,完全就在一台机器上,所以我也不太懂怎么把这些缓存的工具应用到现在的系统中。 请大家多多指教。