- 浏览: 335289 次
- 性别:
- 来自: 北京
文章分类
最新评论
web game里经常出现这样的需求:
1.建造一个房子,等待n秒后建好
2.种植一个植物,等待n秒后完成
3.生产一个汽车,等待n秒后完成
4.升级一个基地,等待n秒后完成
..................
无论是汽车还是房子,建造或升级这个动作很简单,只需要更新一下数据库里的某个字段。
关键是如何处理等待n秒这个操作。
cron + rake
最简单的做法就是后台定时rake,每隔一段时间扫描一下整个表,根据结束时间去改变状态字段。
但是这样作的缺陷很明显,即使扫描的时间间隔再短也达不到准确,还有就是rake每次执行都要加载一次rails环境,然后再释放,这样效率很低。
Delay Job:
看了各种delay job插件,这些插件主要解决的问题是异步的问题,同样达不到精确的计划。
异步线程or进程+sleep n
这种方案看起来不错,但是无论线程还是进程,一直sleep都会占很多资源.
EventMachine
好了,神器在手,,看代码:
Delay Server:
Rails Server:
其实rails server与delay server之间通讯可以有多种选择,比如drb
本着简单高效的原则,选择了http协议..
虽然eventmachine是非阻塞io,但是单个进程的吞吐量有限,利用http协议很容易在前面加个nginx,变成一个小集群....
如果系统使用了二级缓存,像cache_money..在数据库上做trigger,就会出现数据库数据与缓存不同步的现象。。
是用户在线时利用前端的timer,不在线时在登录时候同步吗?
这样有一个问题:
比如建造一个房子
如果玩家A在未建造完成之前下线,
虽然玩家A再次上线的时候会得到建造完成的房子,
但是在其他玩家在查看玩家A的建筑的时候是看不到玩家A的房子的...
在其他玩家view你的地理坐标也可以同时触发这个事件吧。。。事实上
currenttime > start_time+duration 可以作为判断标记,来决定显示不显示这个房子。
说得更具体的:假设有个城 (破三国),城里有各种设施,比如厕所、停尸房之类的^_^,城和设施是个一对多的关系:
----- 设施----------------------------------------------
id, city_id, name,type,setup_duration,start_time,level,X-cordinator,Y-Cordinator
--------------------------------------------------------
每次有人(包括自己或者别人)来看这个城的时候,先根据current_time >start_time + duration 来update一下table, 简单的说就是把level+1,start_time清空,再一句select * from 设施 where start_time is empty 就搞定了。
这里用start_time+duration,是因为好像还可以盖某些设施来缩短duration,是个可变量,你也可以用expected_completet_time来代替之。
其实由于前端timer的不可靠性,后台再加上你说的这个同步机制是可以解决问题的。
但是,这样就会检查更新逻辑(可能不止一种这样的场景)混到了其他逻辑(你这个例子里的查看坐标)。。。
这样最终会使很多action里面充斥着各种同步状态的逻辑...很难维护。
我们只是把数据库更新延迟再延迟到有人来查看、改变城的状态(比如敌我查看城市、攻打城市等等),而这个操作可以完全写成一个SP,独立于所有的action,这样就解决了这个问题。。
是用户在线时利用前端的timer,不在线时在登录时候同步吗?
这样有一个问题:
比如建造一个房子
如果玩家A在未建造完成之前下线,
虽然玩家A再次上线的时候会得到建造完成的房子,
但是在其他玩家在查看玩家A的建筑的时候是看不到玩家A的房子的...
在其他玩家view你的地理坐标也可以同时触发这个事件吧。。。事实上
currenttime > start_time+duration 可以作为判断标记,来决定显示不显示这个房子。
说得更具体的:假设有个城 (破三国),城里有各种设施,比如厕所、停尸房之类的^_^,城和设施是个一对多的关系:
----- 设施----------------------------------------------
id, city_id, name,type,setup_duration,start_time,level,X-cordinator,Y-Cordinator
--------------------------------------------------------
每次有人(包括自己或者别人)来看这个城的时候,先根据current_time >start_time + duration 来update一下table, 简单的说就是把level+1,start_time清空,再一句select * from 设施 where start_time is empty 就搞定了。
这里用start_time+duration,是因为好像还可以盖某些设施来缩短duration,是个可变量,你也可以用expected_completet_time来代替之。
其实由于前端timer的不可靠性,后台再加上你说的这个同步机制是可以解决问题的。
但是,这样就会检查更新逻辑(可能不止一种这样的场景)混到了其他逻辑(你这个例子里的查看坐标)。。。
这样最终会使很多action里面充斥着各种同步状态的逻辑...很难维护。
是用户在线时利用前端的timer,不在线时在登录时候同步吗?
这样有一个问题:
比如建造一个房子
如果玩家A在未建造完成之前下线,
虽然玩家A再次上线的时候会得到建造完成的房子,
但是在其他玩家在查看玩家A的建筑的时候是看不到玩家A的房子的...
在其他玩家view你的地理坐标也可以同时触发这个事件吧。。。事实上
currenttime > start_time+duration 可以作为判断标记,来决定显示不显示这个房子。
说得更具体的:假设有个城 (破三国),城里有各种设施,比如厕所、停尸房之类的^_^,城和设施是个一对多的关系:
----- 设施----------------------------------------------
id, city_id, name,type,setup_duration,start_time,level,X-cordinator,Y-Cordinator
--------------------------------------------------------
每次有人(包括自己或者别人)来看这个城的时候,先根据current_time >start_time + duration 来update一下table, 简单的说就是把level+1,start_time清空,再一句select * from 设施 where start_time is empty 就搞定了。
这里用start_time+duration,是因为好像还可以盖某些设施来缩短duration,是个可变量,你也可以用expected_completet_time来代替之。
是用户在线时利用前端的timer,不在线时在登录时候同步吗?
这样有一个问题:
比如建造一个房子
如果玩家A在未建造完成之前下线,
虽然玩家A再次上线的时候会得到建造完成的房子,
但是在其他玩家在查看玩家A的建筑的时候是看不到玩家A的房子的...
可以,node里有setTimeout
http://nodejs.org/api.html#timers-84
如果出现你说的覆盖的情况,那么每秒处理一个也是必然会卡机的。而且会越卡越多。。
add_timer方式也可以通过增加进程数量方式避免这个问题。而添加多个job server势必又增加了数据库查询。
add_timer方式如果出现你说的情况,还可以加一个定时任务,每隔一段时间把覆盖调的处理掉。
不是每秒处理一个,而是每一秒查询一次,有几个早于当前时间需要完成的任务,就处理几个。玩家说的“卡机”是指原定于12:00:00会完成的任务,由于11:59:59的任务太多,导致处理任务的时间过长,可能到12:00:10才会执行查询,进行处理。
eventmachine用处很多,但是用他的add_timer不合适用在web game这种定时完成任务,你可以拿真实的项目数据做对比压力测试看看,你会发现这个架构和数据库查询相比是没有硬件成本和开发成本优势的,你说的加进程或者定时任务更会让这个架构复杂和不稳定。
如果出现你说的覆盖的情况,那么每秒处理一个也是必然会卡机的。而且会越卡越多。。
add_timer方式也可以通过增加进程数量方式避免这个问题。而添加多个job server势必又增加了数据库查询。
add_timer方式如果出现你说的情况,还可以加一个定时任务,每隔一段时间把覆盖调的处理掉。
1.建造一个房子,等待n秒后建好
2.种植一个植物,等待n秒后完成
3.生产一个汽车,等待n秒后完成
4.升级一个基地,等待n秒后完成
..................
无论是汽车还是房子,建造或升级这个动作很简单,只需要更新一下数据库里的某个字段。
关键是如何处理等待n秒这个操作。
cron + rake
最简单的做法就是后台定时rake,每隔一段时间扫描一下整个表,根据结束时间去改变状态字段。
但是这样作的缺陷很明显,即使扫描的时间间隔再短也达不到准确,还有就是rake每次执行都要加载一次rails环境,然后再释放,这样效率很低。
Delay Job:
看了各种delay job插件,这些插件主要解决的问题是异步的问题,同样达不到精确的计划。
异步线程or进程+sleep n
这种方案看起来不错,但是无论线程还是进程,一直sleep都会占很多资源.
EventMachine
引用
EventMachine是一个基于Reactor设计模式的、用于网络编程和并发编程的框架。Reactor模式描述了一种服务处理器,它接受事件并将其分发给已注册的事件处理。这种模式的好处就是清晰的分离了时间分发和处理事件的应用程序逻辑,而不需引入多线程来把代码复杂化。
好了,神器在手,,看代码:
Delay Server:
#!/usr/bin/env ruby require 'rubygems' require 'optparse' require 'eventmachine' require 'evma_httpserver' require 'rack' options = { :Port => 3000, :Host => "0.0.0.0", :environment => (ENV['RAILS_ENV'] || "development").dup } ARGV.clone.options do |opts| opts.on("-p", "--port=port", Integer, "Runs Delay Server on the specified port.", "Default: 3000") { |v| options[:Port] = v } opts.on("-b", "--binding=ip", String, "Binds Delay Server to the specified ip.", "Default: 0.0.0.0") { |v| options[:Host] = v } opts.on("-e", "--environment=name", String, "Specifies the environment to run this server under (test/development/production).", "Default: development") { |v| options[:environment] = v } opts.separator "" opts.on("-h", "--help", "Show this help message.") { puts opts; exit } opts.parse! end puts "=> Delay Server starting on http://#{options[:Host]}:#{options[:Port]}" ENV["RAILS_ENV"] = options[:environment] require(File.join(File.dirname(__FILE__), 'config', 'boot')) require(File.join(File.dirname(__FILE__), 'config', 'environment')) class DelayServer < EM::Connection include EM::HttpServer def post_init super end def process_http_request params = Rack::Utils.parse_query(@http_query_string) response = EM::DelegatedHttpResponse.new(self) response.status = 200 response.content_type 'text/html' current_time = Time.now response.content = "request time -> #{current_time.to_s(:db)} / delay time -> #{params['delay']}s\n" EM::add_timer(params["delay"]) do p params["operate"] puts Time.now.to_s(:db) end response.send_response end end trap(:INT) { exit } puts "=> Ctrl-C to shutdown server" EM.run{ EM.start_server options[:Host], options[:Port], DelayServer }
Rails Server:
class XxxController < ApplicationController def build #................. system('%Q{curl "http://0.0.0.0:3000?delay=10&operate=build" > ./log/delay_server.log 2>&1 &}) #................. end end
其实rails server与delay server之间通讯可以有多种选择,比如drb
本着简单高效的原则,选择了http协议..
虽然eventmachine是非阻塞io,但是单个进程的吞吐量有限,利用http协议很容易在前面加个nginx,变成一个小集群....
评论
18 楼
paranoid945
2010-09-16
不存在数据库中可以吗
17 楼
Hooopo
2010-09-12
xds2000 写道
可以在数据库上做一个trigger,不扫表更方便.在做一个UDF发送你的请求.
如果系统使用了二级缓存,像cache_money..在数据库上做trigger,就会出现数据库数据与缓存不同步的现象。。
16 楼
dualface
2010-09-12
我靠,高射炮打蚊子啊。。。。
假设建造一个房屋需要100秒,玩家点击确认后开始计时。
不需要搞什么后台任务,只需要把这个任务写入数据库。当客户端有请求时,才取出数据进行计算。如果时间未到,服务端直接忽略就行了。
所有其他工作都由客户端进行,比如“还剩下xx秒”都在客户端进行,说白了就是一个模拟计算的过程。
假设建造一个房屋需要100秒,玩家点击确认后开始计时。
不需要搞什么后台任务,只需要把这个任务写入数据库。当客户端有请求时,才取出数据进行计算。如果时间未到,服务端直接忽略就行了。
所有其他工作都由客户端进行,比如“还剩下xx秒”都在客户端进行,说白了就是一个模拟计算的过程。
15 楼
xds2000
2010-09-12
可以在数据库上做一个trigger,不扫表更方便.在做一个UDF发送你的请求.
14 楼
全冠清
2010-09-09
很显然是第一种
13 楼
Saito
2010-09-09
hooooopo这个需求让我想到了各种邪恶的网盘. .
由于各种门的存在.网盘的需求量很高.但是网盘不能让你无限制的下载.
然后每次下载都要有delay时间. 类似freakshare这个网盘会记录你的下载记录. 第一次一般等待60秒. 第二次就会变成10分钟.
这个其实也是一个delay server. 有些类似的功能. 不过他不需要保证 建造中断问题.如果离线他会重读60秒.
60秒/10分钟结束会发起一次请求.获得一个下载地址.跟update数据库其实是一样的.
或许可以参考.也是两次请求.
况且现在EM模式并没有解决delay的问题.大家实际上还是在排队..
还有空间啊.
由于各种门的存在.网盘的需求量很高.但是网盘不能让你无限制的下载.
然后每次下载都要有delay时间. 类似freakshare这个网盘会记录你的下载记录. 第一次一般等待60秒. 第二次就会变成10分钟.
这个其实也是一个delay server. 有些类似的功能. 不过他不需要保证 建造中断问题.如果离线他会重读60秒.
60秒/10分钟结束会发起一次请求.获得一个下载地址.跟update数据库其实是一样的.
或许可以参考.也是两次请求.
况且现在EM模式并没有解决delay的问题.大家实际上还是在排队..
还有空间啊.
12 楼
ray_linn
2010-09-09
Hooopo 写道
ray_linn 写道
Hooopo 写道
ray_linn 写道
记录下duration和start time在数据库里
duration,start_time
5, 12:30:52
客户端的javascript access服务器端(比如login,或者客户端计时器到期)的时候,一条select,一条update.
duration,start_time
5, 12:30:52
客户端的javascript access服务器端(比如login,或者客户端计时器到期)的时候,一条select,一条update.
是用户在线时利用前端的timer,不在线时在登录时候同步吗?
这样有一个问题:
比如建造一个房子
如果玩家A在未建造完成之前下线,
虽然玩家A再次上线的时候会得到建造完成的房子,
但是在其他玩家在查看玩家A的建筑的时候是看不到玩家A的房子的...
在其他玩家view你的地理坐标也可以同时触发这个事件吧。。。事实上
currenttime > start_time+duration 可以作为判断标记,来决定显示不显示这个房子。
说得更具体的:假设有个城 (破三国),城里有各种设施,比如厕所、停尸房之类的^_^,城和设施是个一对多的关系:
----- 设施----------------------------------------------
id, city_id, name,type,setup_duration,start_time,level,X-cordinator,Y-Cordinator
--------------------------------------------------------
每次有人(包括自己或者别人)来看这个城的时候,先根据current_time >start_time + duration 来update一下table, 简单的说就是把level+1,start_time清空,再一句select * from 设施 where start_time is empty 就搞定了。
这里用start_time+duration,是因为好像还可以盖某些设施来缩短duration,是个可变量,你也可以用expected_completet_time来代替之。
其实由于前端timer的不可靠性,后台再加上你说的这个同步机制是可以解决问题的。
但是,这样就会检查更新逻辑(可能不止一种这样的场景)混到了其他逻辑(你这个例子里的查看坐标)。。。
这样最终会使很多action里面充斥着各种同步状态的逻辑...很难维护。
我们只是把数据库更新延迟再延迟到有人来查看、改变城的状态(比如敌我查看城市、攻打城市等等),而这个操作可以完全写成一个SP,独立于所有的action,这样就解决了这个问题。。
11 楼
Hooopo
2010-09-09
ray_linn 写道
Hooopo 写道
ray_linn 写道
记录下duration和start time在数据库里
duration,start_time
5, 12:30:52
客户端的javascript access服务器端(比如login,或者客户端计时器到期)的时候,一条select,一条update.
duration,start_time
5, 12:30:52
客户端的javascript access服务器端(比如login,或者客户端计时器到期)的时候,一条select,一条update.
是用户在线时利用前端的timer,不在线时在登录时候同步吗?
这样有一个问题:
比如建造一个房子
如果玩家A在未建造完成之前下线,
虽然玩家A再次上线的时候会得到建造完成的房子,
但是在其他玩家在查看玩家A的建筑的时候是看不到玩家A的房子的...
在其他玩家view你的地理坐标也可以同时触发这个事件吧。。。事实上
currenttime > start_time+duration 可以作为判断标记,来决定显示不显示这个房子。
说得更具体的:假设有个城 (破三国),城里有各种设施,比如厕所、停尸房之类的^_^,城和设施是个一对多的关系:
----- 设施----------------------------------------------
id, city_id, name,type,setup_duration,start_time,level,X-cordinator,Y-Cordinator
--------------------------------------------------------
每次有人(包括自己或者别人)来看这个城的时候,先根据current_time >start_time + duration 来update一下table, 简单的说就是把level+1,start_time清空,再一句select * from 设施 where start_time is empty 就搞定了。
这里用start_time+duration,是因为好像还可以盖某些设施来缩短duration,是个可变量,你也可以用expected_completet_time来代替之。
其实由于前端timer的不可靠性,后台再加上你说的这个同步机制是可以解决问题的。
但是,这样就会检查更新逻辑(可能不止一种这样的场景)混到了其他逻辑(你这个例子里的查看坐标)。。。
这样最终会使很多action里面充斥着各种同步状态的逻辑...很难维护。
10 楼
ray_linn
2010-09-08
Hooopo 写道
ray_linn 写道
记录下duration和start time在数据库里
duration,start_time
5, 12:30:52
客户端的javascript access服务器端(比如login,或者客户端计时器到期)的时候,一条select,一条update.
duration,start_time
5, 12:30:52
客户端的javascript access服务器端(比如login,或者客户端计时器到期)的时候,一条select,一条update.
是用户在线时利用前端的timer,不在线时在登录时候同步吗?
这样有一个问题:
比如建造一个房子
如果玩家A在未建造完成之前下线,
虽然玩家A再次上线的时候会得到建造完成的房子,
但是在其他玩家在查看玩家A的建筑的时候是看不到玩家A的房子的...
在其他玩家view你的地理坐标也可以同时触发这个事件吧。。。事实上
currenttime > start_time+duration 可以作为判断标记,来决定显示不显示这个房子。
说得更具体的:假设有个城 (破三国),城里有各种设施,比如厕所、停尸房之类的^_^,城和设施是个一对多的关系:
----- 设施----------------------------------------------
id, city_id, name,type,setup_duration,start_time,level,X-cordinator,Y-Cordinator
--------------------------------------------------------
每次有人(包括自己或者别人)来看这个城的时候,先根据current_time >start_time + duration 来update一下table, 简单的说就是把level+1,start_time清空,再一句select * from 设施 where start_time is empty 就搞定了。
这里用start_time+duration,是因为好像还可以盖某些设施来缩短duration,是个可变量,你也可以用expected_completet_time来代替之。
9 楼
Hooopo
2010-09-08
ray_linn 写道
记录下duration和start time在数据库里
duration,start_time
5, 12:30:52
客户端的javascript access服务器端(比如login,或者客户端计时器到期)的时候,一条select,一条update.
duration,start_time
5, 12:30:52
客户端的javascript access服务器端(比如login,或者客户端计时器到期)的时候,一条select,一条update.
是用户在线时利用前端的timer,不在线时在登录时候同步吗?
这样有一个问题:
比如建造一个房子
如果玩家A在未建造完成之前下线,
虽然玩家A再次上线的时候会得到建造完成的房子,
但是在其他玩家在查看玩家A的建筑的时候是看不到玩家A的房子的...
8 楼
Hooopo
2010-09-08
g.zhen.ning 写道
离题问个问题,这个eventmachine做的功能能被node.js取代么?
可以,node里有setTimeout
http://nodejs.org/api.html#timers-84
7 楼
Hooopo
2010-09-08
刚才简单测试了一下,add_timer方式在并发情况不会出现覆盖现象,在同一时间如果出现处理不了的操作,前一个操作会阻塞后一个,但是每个操作最终还会执行,也就是quakewang说的卡机.
简单测试代码:
控制台输出:
=> Ctrl-C to shutdown server
"2010-09-09 14:51:11--->1"
"2010-09-09 14:51:11--->2"
"2010-09-09 14:51:12--->3"
"2010-09-09 14:51:12--->4"
"2010-09-09 14:51:13--->5"
"2010-09-09 14:51:13--->6"
"2010-09-09 14:51:14--->7"
"2010-09-09 14:51:14--->8"
"2010-09-09 14:51:15--->9"
"2010-09-09 14:51:15--->10"
"2010-09-09 14:51:16--->11"
"2010-09-09 14:51:16--->12"
"2010-09-09 14:51:17--->13"
"2010-09-09 14:51:17--->14"
"2010-09-09 14:51:18--->15"
"2010-09-09 14:51:18--->16"
"2010-09-09 14:51:19--->17"
"2010-09-09 14:51:19--->18"
"2010-09-09 14:51:20--->19"
"2010-09-09 14:51:20--->20"
"2010-09-09 14:51:21--->21"
"2010-09-09 14:51:21--->22"
"2010-09-09 14:51:22--->23"
"2010-09-09 14:51:22--->24"
"2010-09-09 14:51:23--->25"
"2010-09-09 14:51:23--->26"
"2010-09-09 14:51:24--->27"
"2010-09-09 14:51:24--->28"
"2010-09-09 14:51:25--->29"
"2010-09-09 14:51:25--->30"
"2010-09-09 14:51:26--->31"
"2010-09-09 14:51:26--->32"
"2010-09-09 14:51:27--->33"
"2010-09-09 14:51:27--->34"
"2010-09-09 14:51:28--->35"
"2010-09-09 14:51:28--->36"
"2010-09-09 14:51:29--->37"
"2010-09-09 14:51:29--->38"
"2010-09-09 14:51:30--->39"
"2010-09-09 14:51:30--->40"
"2010-09-09 14:51:31--->41"
"2010-09-09 14:51:31--->42"
"2010-09-09 14:51:32--->43"
"2010-09-09 14:51:32--->44"
"2010-09-09 14:51:33--->45"
"2010-09-09 14:51:33--->46"
"2010-09-09 14:51:34--->47"
"2010-09-09 14:51:34--->48"
"2010-09-09 14:51:35--->49"
"2010-09-09 14:51:35--->50"
"2010-09-09 14:51:36--->51"
"2010-09-09 14:51:36--->52"
"2010-09-09 14:51:37--->53"
"2010-09-09 14:51:37--->54"
"2010-09-09 14:51:38--->55"
"2010-09-09 14:51:38--->56"
"2010-09-09 14:51:39--->57"
"2010-09-09 14:51:39--->58"
"2010-09-09 14:51:40--->59"
"2010-09-09 14:51:40--->60"
"2010-09-09 14:51:41--->61"
"2010-09-09 14:51:41--->62"
"2010-09-09 14:51:42--->63"
"2010-09-09 14:51:42--->64"
"2010-09-09 14:51:43--->65"
"2010-09-09 14:51:43--->66"
"2010-09-09 14:51:44--->67"
"2010-09-09 14:51:44--->68"
"2010-09-09 14:51:45--->69"
"2010-09-09 14:51:45--->70"
"2010-09-09 14:51:46--->71"
"2010-09-09 14:51:46--->72"
"2010-09-09 14:51:47--->73"
"2010-09-09 14:51:47--->74"
"2010-09-09 14:51:48--->75"
"2010-09-09 14:51:48--->76"
"2010-09-09 14:51:49--->77"
"2010-09-09 14:51:49--->78"
"2010-09-09 14:51:50--->79"
"2010-09-09 14:51:50--->80"
"2010-09-09 14:51:51--->81"
"2010-09-09 14:51:51--->82"
"2010-09-09 14:51:52--->83"
"2010-09-09 14:51:52--->84"
"2010-09-09 14:51:53--->85"
"2010-09-09 14:51:53--->86"
"2010-09-09 14:51:54--->87"
"2010-09-09 14:51:54--->88"
"2010-09-09 14:51:55--->89"
"2010-09-09 14:51:55--->90"
"2010-09-09 14:51:56--->91"
"2010-09-09 14:51:56--->92"
"2010-09-09 14:51:57--->93"
"2010-09-09 14:51:57--->94"
"2010-09-09 14:51:58--->95"
"2010-09-09 14:51:58--->96"
"2010-09-09 14:51:59--->97"
"2010-09-09 14:51:59--->98"
"2010-09-09 14:52:00--->99"
"2010-09-09 14:52:00--->100"
简单测试代码:
#!/usr/bin/env ruby require 'rubygems' require 'optparse' require 'eventmachine' require 'evma_httpserver' require 'rack' options = { :Port => 3000, :Host => "0.0.0.0", :environment => (ENV['RAILS_ENV'] || "development").dup } ARGV.clone.options do |opts| opts.on("-p", "--port=port", Integer, "Runs Delay Server on the specified port.", "Default: 3000") { |v| options[:Port] = v } opts.on("-b", "--binding=ip", String, "Binds Delay Server to the specified ip.", "Default: 0.0.0.0") { |v| options[:Host] = v } opts.on("-e", "--environment=name", String, "Specifies the environment to run this server under (test/development/production).", "Default: development") { |v| options[:environment] = v } opts.separator "" opts.on("-h", "--help", "Show this help message.") { puts opts; exit } opts.parse! end puts "=> Delay Server starting on http://#{options[:Host]}:#{options[:Port]}" ENV["RAILS_ENV"] = options[:environment] require(File.join(File.dirname(__FILE__), 'config', 'boot')) require(File.join(File.dirname(__FILE__), 'config', 'environment')) class DelayServer < EM::Connection include EM::HttpServer def post_init super end def process_http_request #params = Rack::Utils.parse_query(@http_query_string) response = EM::DelegatedHttpResponse.new(self) response.status = 200 response.content_type 'text/html' response.content = "ok" EM::add_timer(10) do sleep 0.5 $count += 1 p Time.now.to_s(:db) + "--->#{$count}" end response.send_response end end trap(:INT) { exit } puts "=> Ctrl-C to shutdown server" EM.run{ $count = 0 EM.start_server options[:Host], options[:Port], DelayServer }
ab -c50 -n100 http://0.0.0.0:3000/
控制台输出:
引用
=> Ctrl-C to shutdown server
"2010-09-09 14:51:11--->1"
"2010-09-09 14:51:11--->2"
"2010-09-09 14:51:12--->3"
"2010-09-09 14:51:12--->4"
"2010-09-09 14:51:13--->5"
"2010-09-09 14:51:13--->6"
"2010-09-09 14:51:14--->7"
"2010-09-09 14:51:14--->8"
"2010-09-09 14:51:15--->9"
"2010-09-09 14:51:15--->10"
"2010-09-09 14:51:16--->11"
"2010-09-09 14:51:16--->12"
"2010-09-09 14:51:17--->13"
"2010-09-09 14:51:17--->14"
"2010-09-09 14:51:18--->15"
"2010-09-09 14:51:18--->16"
"2010-09-09 14:51:19--->17"
"2010-09-09 14:51:19--->18"
"2010-09-09 14:51:20--->19"
"2010-09-09 14:51:20--->20"
"2010-09-09 14:51:21--->21"
"2010-09-09 14:51:21--->22"
"2010-09-09 14:51:22--->23"
"2010-09-09 14:51:22--->24"
"2010-09-09 14:51:23--->25"
"2010-09-09 14:51:23--->26"
"2010-09-09 14:51:24--->27"
"2010-09-09 14:51:24--->28"
"2010-09-09 14:51:25--->29"
"2010-09-09 14:51:25--->30"
"2010-09-09 14:51:26--->31"
"2010-09-09 14:51:26--->32"
"2010-09-09 14:51:27--->33"
"2010-09-09 14:51:27--->34"
"2010-09-09 14:51:28--->35"
"2010-09-09 14:51:28--->36"
"2010-09-09 14:51:29--->37"
"2010-09-09 14:51:29--->38"
"2010-09-09 14:51:30--->39"
"2010-09-09 14:51:30--->40"
"2010-09-09 14:51:31--->41"
"2010-09-09 14:51:31--->42"
"2010-09-09 14:51:32--->43"
"2010-09-09 14:51:32--->44"
"2010-09-09 14:51:33--->45"
"2010-09-09 14:51:33--->46"
"2010-09-09 14:51:34--->47"
"2010-09-09 14:51:34--->48"
"2010-09-09 14:51:35--->49"
"2010-09-09 14:51:35--->50"
"2010-09-09 14:51:36--->51"
"2010-09-09 14:51:36--->52"
"2010-09-09 14:51:37--->53"
"2010-09-09 14:51:37--->54"
"2010-09-09 14:51:38--->55"
"2010-09-09 14:51:38--->56"
"2010-09-09 14:51:39--->57"
"2010-09-09 14:51:39--->58"
"2010-09-09 14:51:40--->59"
"2010-09-09 14:51:40--->60"
"2010-09-09 14:51:41--->61"
"2010-09-09 14:51:41--->62"
"2010-09-09 14:51:42--->63"
"2010-09-09 14:51:42--->64"
"2010-09-09 14:51:43--->65"
"2010-09-09 14:51:43--->66"
"2010-09-09 14:51:44--->67"
"2010-09-09 14:51:44--->68"
"2010-09-09 14:51:45--->69"
"2010-09-09 14:51:45--->70"
"2010-09-09 14:51:46--->71"
"2010-09-09 14:51:46--->72"
"2010-09-09 14:51:47--->73"
"2010-09-09 14:51:47--->74"
"2010-09-09 14:51:48--->75"
"2010-09-09 14:51:48--->76"
"2010-09-09 14:51:49--->77"
"2010-09-09 14:51:49--->78"
"2010-09-09 14:51:50--->79"
"2010-09-09 14:51:50--->80"
"2010-09-09 14:51:51--->81"
"2010-09-09 14:51:51--->82"
"2010-09-09 14:51:52--->83"
"2010-09-09 14:51:52--->84"
"2010-09-09 14:51:53--->85"
"2010-09-09 14:51:53--->86"
"2010-09-09 14:51:54--->87"
"2010-09-09 14:51:54--->88"
"2010-09-09 14:51:55--->89"
"2010-09-09 14:51:55--->90"
"2010-09-09 14:51:56--->91"
"2010-09-09 14:51:56--->92"
"2010-09-09 14:51:57--->93"
"2010-09-09 14:51:57--->94"
"2010-09-09 14:51:58--->95"
"2010-09-09 14:51:58--->96"
"2010-09-09 14:51:59--->97"
"2010-09-09 14:51:59--->98"
"2010-09-09 14:52:00--->99"
"2010-09-09 14:52:00--->100"
6 楼
ray_linn
2010-09-08
记录下duration和start time在数据库里
duration,start_time
5, 12:30:52
客户端的javascript access服务器端(比如login,或者客户端计时器到期)的时候,一条select,一条update.
duration,start_time
5, 12:30:52
客户端的javascript access服务器端(比如login,或者客户端计时器到期)的时候,一条select,一条update.
5 楼
g.zhen.ning
2010-09-08
离题问个问题,这个eventmachine做的功能能被node.js取代么?
4 楼
QuakeWang
2010-09-08
Hooopo 写道
QuakeWang 写道
eventmachine的add_timer不合适用来作这个需求,而且他在高并发下如果有相同的delay time会出现后者覆盖前者的情况。
webgame的delay job通常都是在数据库里面直接插入一条什么时间需要作什么事情的记录,后台一个job server每1秒都进行查询看是否有小于当前时间还未完成的job,然后处理掉,如果每秒要处理的事情太多,就会出现所谓的"卡机"。数据库1秒查询一次的代价其实是很小的。
webgame的delay job通常都是在数据库里面直接插入一条什么时间需要作什么事情的记录,后台一个job server每1秒都进行查询看是否有小于当前时间还未完成的job,然后处理掉,如果每秒要处理的事情太多,就会出现所谓的"卡机"。数据库1秒查询一次的代价其实是很小的。
如果出现你说的覆盖的情况,那么每秒处理一个也是必然会卡机的。而且会越卡越多。。
add_timer方式也可以通过增加进程数量方式避免这个问题。而添加多个job server势必又增加了数据库查询。
add_timer方式如果出现你说的情况,还可以加一个定时任务,每隔一段时间把覆盖调的处理掉。
不是每秒处理一个,而是每一秒查询一次,有几个早于当前时间需要完成的任务,就处理几个。玩家说的“卡机”是指原定于12:00:00会完成的任务,由于11:59:59的任务太多,导致处理任务的时间过长,可能到12:00:10才会执行查询,进行处理。
eventmachine用处很多,但是用他的add_timer不合适用在web game这种定时完成任务,你可以拿真实的项目数据做对比压力测试看看,你会发现这个架构和数据库查询相比是没有硬件成本和开发成本优势的,你说的加进程或者定时任务更会让这个架构复杂和不稳定。
3 楼
beneo
2010-09-08
event actor真是越来越多啊
如果这种delay job的场景更清除一些就好了。。
web game种花种草的,长时间的,我觉得job server来做比较合适
如果是射击,法术即时的,你这个思路也许不错哦
如果这种delay job的场景更清除一些就好了。。
web game种花种草的,长时间的,我觉得job server来做比较合适
如果是射击,法术即时的,你这个思路也许不错哦
2 楼
Hooopo
2010-09-07
QuakeWang 写道
eventmachine的add_timer不合适用来作这个需求,而且他在高并发下如果有相同的delay time会出现后者覆盖前者的情况。
webgame的delay job通常都是在数据库里面直接插入一条什么时间需要作什么事情的记录,后台一个job server每1秒都进行查询看是否有小于当前时间还未完成的job,然后处理掉,如果每秒要处理的事情太多,就会出现所谓的"卡机"。数据库1秒查询一次的代价其实是很小的。
webgame的delay job通常都是在数据库里面直接插入一条什么时间需要作什么事情的记录,后台一个job server每1秒都进行查询看是否有小于当前时间还未完成的job,然后处理掉,如果每秒要处理的事情太多,就会出现所谓的"卡机"。数据库1秒查询一次的代价其实是很小的。
如果出现你说的覆盖的情况,那么每秒处理一个也是必然会卡机的。而且会越卡越多。。
add_timer方式也可以通过增加进程数量方式避免这个问题。而添加多个job server势必又增加了数据库查询。
add_timer方式如果出现你说的情况,还可以加一个定时任务,每隔一段时间把覆盖调的处理掉。
1 楼
QuakeWang
2010-09-07
eventmachine的add_timer不合适用来作这个需求,而且他在高并发下如果有相同的delay time会出现后者覆盖前者的情况。
webgame的delay job通常都是在数据库里面直接插入一条什么时间需要作什么事情的记录,后台一个job server每1秒都进行查询看是否有小于当前时间还未完成的job,然后处理掉,如果每秒要处理的事情太多,就会出现所谓的"卡机"。数据库1秒查询一次的代价其实是很小的。
webgame的delay job通常都是在数据库里面直接插入一条什么时间需要作什么事情的记录,后台一个job server每1秒都进行查询看是否有小于当前时间还未完成的job,然后处理掉,如果每秒要处理的事情太多,就会出现所谓的"卡机"。数据库1秒查询一次的代价其实是很小的。
发表评论
-
新博客
2012-04-23 20:47 1734https://db-china.org -
Ruby Verbose Warning Mode
2011-10-16 14:48 2051Ruby在很多方面是一个更优雅的Perl,从Perl社区继承了 ... -
Pattern Match In Ruby
2011-10-07 01:17 2006最近看了一些Erlang,模式匹配是个好东西,简单的sum函数 ... -
Draper: View Models for Rails
2011-10-07 01:19 2268Draper是一个Ruby gem,它让Rails model ... -
Active Record batch processing in parallel processes
2011-10-07 01:20 2270Active Record 提供 find_each来分批处理 ... -
最轻量级的Ruby后台任务
2011-08-04 16:47 3860普通情况下ruby调用系统命令行的过程是堵塞的,无论是用sys ... -
test
2011-07-15 19:59 0test -
fiber
2011-06-17 09:37 0挖坑,待填。。 1.用到fiber.alive?、fiber ... -
Identity Map in Rails3.1
2011-06-12 18:29 2737Identity Map是Rails3.1的又 ... -
xx00
2011-06-06 03:40 0https://github.com/ngmoco/cache ... -
挖坑1
2011-06-06 02:17 0cache money 源码 替换memcache为redis ... -
websocket demo
2011-06-04 20:44 2054地址:https://github.com/hooopo/we ... -
ruby GC
2011-06-02 04:24 0http://blog.csdn.net/lijun84/a ... -
reduce method missing call stack with dynamic define method
2011-04-22 22:54 1592method_missing是ruby里面一个非常cool的h ... -
Autocompete with Trie
2011-04-09 04:04 1674像微薄里面用户输入一 ... -
用imagemagick和tesseract-ocr破解简单验证码
2011-04-09 01:31 18926工具:imagemagick + tesseract-ocr ... -
OAuth gem for rails,支持豆瓣,新浪微薄,腾讯微博,搜狐微博,网易微博
2011-03-26 03:13 4480地址:https://github.com/hooopo/oa ... -
用jmeter模拟amf请求进行压力测试
2010-12-16 16:56 30231.获取amf二进制包: 在本地建立proxy,端口为888 ... -
Memoization in Ruby
2010-11-14 11:42 1210这里的Memoization就是将ruby的方法或lambda ... -
整理了一下2008-2010的RubyHeroes博客列表
2010-10-07 02:26 2827Bryan Helmkamp(webrat作者)https:/ ...
相关推荐
SQL Server是一个流行的关系型数据库管理系统(RDBMS),由Microsoft开发。它广泛用于企业级应用,具有完善的数据管理、事务处理和存储过程等功能。SQL Server使用结构化查询语言(SQL)来管理数据,执行各种数据库...
这个例子展示了如何创建一个简单的TCP服务器,它将接收到的数据转发回客户端。 通过理解这些基本概念和实践,你可以利用ESP8266构建自己的TCP服务器,实现远程控制、数据传输等功能。在实际应用中,还可以结合MQTT...
`devserver`就是这样一个轻量级的开发服务器,它提供了基本的功能,如延迟支持、静态文件服务以及对JSONP的支持,虽然在描述中提到JSONP和镜像JS脚本功能尚未实现。 ### 延迟支持 延迟支持(Delay Support)是一项...
Snap7 Express服务器一个简单的node.js表示REST服务器即可写入siemens徽标。用法一个端点打开大门。 $ curl --location --request GET ' ...
在SQL Server 2008中,`WAITFOR`是一个非常有用的T-SQL语句,它允许你控制SQL Server执行的流程,使程序在执行特定操作之前暂停一段时间或等待特定事件发生。`WAITFOR`语句主要包含三个部分:`DELAY`、`TIME`和`( ...
9. **延迟执行**:第十题要求SQL Server等待15秒后再执行,使用WAITFOR DELAY语句实现,正确选项是B,但书写格式有误,正确的写法是`WAITFOR DELAY '00:00:15'`。 通过以上解析,我们可以看出试卷主要测试了SQL ...
以下是一个简单的示例,展示如何在C#中实现TCP客户端的自动重连: ```csharp using System; using System.Net; using System.Net.Sockets; using System.Threading.Tasks; class TcpAutoReconnectClient { ...
`Delay()`函数作为ASP开发中的一个小工具,虽然简单却十分实用。它可以帮助开发者更好地控制脚本的执行流程,提高程序的灵活性和可用性。然而,在实际应用中还需注意其对服务器性能的影响,并采取相应的优化措施。
为了解决这个问题,可以使用json-server这个轻量级的工具来快速搭建一个RESTful API接口,用以模拟后端数据。 json-server是一个零配置、轻量级的REST API服务器,它可以让开发者用JSON文件来模拟数据库,并提供...
在本主题中,我们将探讨如何使用ESP8266创建一个简单的Web服务器,以控制LED灯。这个项目可以帮助初学者理解Web服务器的基本工作原理,并学习如何通过HTTP请求与硬件交互。 **Web请求过程** 当我们在浏览器中输入一...
尤其是在SQL Server这样的关系型数据库管理系统中,如何有效地进行数据恢复成为了一个不可忽视的问题。本文将通过一次实际的数据恢复案例来详细介绍SQL Server的日志恢复方法,特别是针对`DROP`和`TRUNCATE`操作后的...
以一个简单的例子来说,假设我们有如下配置: - **VIP**:10.0.0.1 - **DIP**:192.168.0.200 - **RIP**:192.168.0.201 - **DGW**:192.168.0.200 在这种情况下,客户端发送的请求会首先到达DIP,即192.168.0.200...
它提供了一个 REST 接口来处理存储的数据。 什么是诺姆斯特? Nomster 是一种简化“午餐时间吃什么?”的简单方法。 过程。 它提供了同事现有建议的列表。 重要信息 此版本使用 H2 内存数据库。 要使其与您的 ...
【单片机计算器简易程序】是一个基于C51语言编写的计算器应用,它实现了基本的四则运算(加、减、乘、除)。这个程序利用单片机的资源,通过键盘输入数字和运算符,然后在LCD显示屏上显示计算结果。 在程序中,可以...
下面是一个简单的例子,展示了如何使用 `Timer` 类来每隔一秒打印一条消息: ```python from threading import Timer import time def delay_run(): print('running') t = Timer(1, delay_run) # 创建一个新的 ...
2. **配置灵活**:LVS支持多种负载调度算法和转发模式,可以根据不同的场景选择最适合的策略,同时Keepalived的配置也相对简单,只需要一个配置文件即可完成复杂的高可用设置。 3. **高可用性**:Keepalived通过实时...
该项目的目标是创建一个简易但功能完整的温度监测系统,该系统能够自动读取环境温度并通过Wi-Fi网络将数据上传至远程服务器或云平台。 #### 二、项目准备 ##### 1. 硬件需求 - **Arduino Uno**:作为主控单元,...
1. 注册中心(Eureka Server):创建一个 Eureka Server,只需要在主函数上添加 @EnableEurekaServer 注解,并在 properties 文件进行简单配置即可。 2. Zuul: Zuul 需要注册到 Eureka Server 上,并添加 @...