在Facebook应用程序和云计算时代,我正在重新思考大型多人游戏.
假设我要在现有的开放协议之上构建一些东西,我想为1,000,000个并发播放器提供服务,只是为了解决问题.
假设每个玩家都有一个传入的消息队列(用于聊天和诸如此类),平均有一个传入的消息队列(公会,区域,实例,拍卖......),因此我们有2,000,000个队列.玩家将一次收听1-10个队列.每个队列平均每秒可能有1条消息,但某些队列将具有更高的速率和更多的侦听器(例如,级别实例的"实体位置"队列).假设系统排队延迟不超过100毫秒,这对于温和的动作导向游戏来说是可以的(但不是像Quake或Unreal Tournament这样的游戏).
从其他系统,我知道在单个1U或刀片盒上为10,000个用户提供服务是一个合理的期望(假设没有其他任何昂贵的东西,比如物理模拟或诸如此类的东西).
因此,使用交叉开关集群系统,客户端连接到连接网关,然后连接到消息队列服务器,我们每个网关有100个用户,有100个网关机器,每个队列服务器有100个消息队列,有100个队列机器.再次,仅适用于一般范围.每台MQ机器上的连接数量很小:大约100,与每个网关通信.网关上的连接数量会更高:客户端为10,100,连接所有队列服务器.(除此之外,为游戏世界模拟服务器添加一些连接或诸如此类的东西,但我现在试图将它保持分离)
如果我不想从头开始构建这个,我必须使用一些存在的消息传递和/或排队基础结构.我能找到的两个开放协议是AMQP和XMPP.XMPP的预期用途更像是这个游戏系统所需要的,但开销非常明显(XML,加上冗长的状态数据,以及必须在顶部构建的各种其他通道).AMQP的实际数据模型更接近我上面描述的内容,但所有用户似乎都是大型企业级公司,工作负载似乎与工作流程相关,而不是与实时游戏更新相关.
有没有人可以分享这些技术或其实现的日常经验?
我有一个Django webapp.我已经安装了debug_toolbar中间件和模块.但是,我的webapps没有调试工具栏拉出.
我如何实际看到调试工具栏?还有什么我需要做的吗?我是否需要为我的webapp使用特定模板?我已经按照自述文件中的所有步骤进行了操作,但这还不够 - 似乎还有一些其他依赖项,或者其他我缺少的东西.
此外,望着URL模式集合了我的web应用程序时,将调试前缀不是公认的模式中找到.我在debug_toolbar中放入了一个urls.py日志,以确保激活的debug_toolbar应用程序正在加载模块.
这让我完全神秘,我找不到谷歌或自述文件来做这个实际显示,或者要求是什么,所以你能提供的任何指针都会很棒!
编辑:事实证明,我正在使用SSH隧道从运行浏览器的机器到运行Django/Apache的机器进行测试.在这种情况下,远程机器实际看到的IP地址不是我想象的那样,因此"好"IP列表不包含浏览器的明显远程机器.修复那个解决了问题!
考虑一个受CPU限制的应用程序,但也具有高性能I/O要求.
我正在将Linux文件I/O与Windows进行比较,我看不出epoll将如何帮助Linux程序.内核会告诉我文件描述符"准备好读取",但是我仍然需要调用阻塞read()来获取我的数据,如果我想读取兆字节,那么很明显它会阻塞.
在Windows上,我可以创建一个设置了OVERLAPPED的文件句柄,然后使用非阻塞I/O,并在I/O完成时收到通知,并使用该完成函数中的数据.我需要不花费应用程序级别的挂钟时间等待数据,这意味着我可以精确地将我的线程数调整为我的内核数量,并获得100%的高效CPU利用率.
如果我必须在Linux上模拟异步I/O,那么我必须分配一些线程来执行此操作,并且这些线程将花费一些时间来处理CPU事务,并且大量时间阻塞I/O,此外,在这些线程的消息传递中会有开销.因此,我将过度订阅或利用我的CPU核心.
我把mmap()+ madvise()(WILLNEED)视为"穷人的异步I/O",但它仍然没有完全通过那里,因为当它完成时我无法得到通知 - 我有"猜测",如果我猜"错误",我将最终阻止内存访问,等待数据来自磁盘.
Linux似乎在io_submit中启动了异步I/O,它似乎也有一个用户空间POSIX aio实现,但它已经有一段时间了,我知道没有人会担保这些系统的关键,高性能的应用程序.
Windows模型的工作方式大致如下:
步骤1/2通常作为单个事物完成.步骤3/4通常使用工作线程池完成,而不是(必要)与发出I/O相同的线程.这个模型有点类似于boost :: asio提供的模型,除了boost :: asio实际上不会给你异步的基于块的(磁盘)I/O.
Linux中epoll的不同之处在于,在步骤4中,还没有I/O发生 - 它会在步骤4之后提升第1步,如果你确切知道你需要的话,那就是"向后".
编写了大量的嵌入式,桌面和服务器操作系统之后,我可以说这种异步I/O模型对于某些类型的程序来说非常自然.它还具有非常高的吞吐量和低开销.我认为这是Linux I/O模型在API级别上仍然存在的真正缺点之一.
我在X86的x86 Linux上寻找C++(或C)的GLES2样本的良好来源.我可以找到的样本都是针对iOS的Objective C,或针对Android的Java,或针对WebGL的JavaScript.Kronos网站有一个"教程"部分,其中包含两行"我们的教程索引将在此处".鉴于GLES2已有5年历史,我对那里的内容突然激增并不抱太大希望.
我已经非常了解OpenGL了.我真的想要一些方便的复制粘贴上下文设置代码源.我在哪里可以找到类似的东西?
我分叉了一个项目.我研究了一下.我现在有十个不同的提交,每个提交都独立于其他提交.我想将每个单独的提交作为单独的pull请求发送,让上游的维护者选择他/她想要的那些.
我找不到一个简单的方法来做到这一点.我能找到的"最简单"是创建十个单独的分支,并将十个单独的提交中的每一个分别挑选到这些分支中,然后从每个分支发送一个pull请求.那是......不理智!(例如,参见如何在github上将一个拉取请求分成两个不同的拉取请求)
底层git request-pull函数支持这个工作流,这里的问题是GitHub没有一个好的接口吗?我注定要创建十个分支吗?
我正在尝试一些 Rust,但我的程序变得有点长。我现在想将我的程序分成许多文件 - 我如何最轻松地做到这一点?
当我尝试用 Google 搜索时,我得到的 Rust 书籍章节有很多关于包、板条箱和模块的页面,而且似乎永远没有说到重点——难道没有更简单的方法来做到这一点吗?
TL; DR:我有可能反应堆吞吐量有限吗?我怎么说?io_service的实现是多么昂贵和可扩展(跨线程)?
我有一个远程大规模并行应用程序,运行在超线程双四核Xeon机器上,具有大量RAM和快速SSD RAID.这是使用boost :: asio开发的.
此应用程序接受来自大约1,000台其他计算机的连接,读取数据,解码简单协议,并将数据混洗到使用mmap()映射的文件中.该应用程序还使用madvise(WILLNEED)预取"未来"mmap页面,因此它不太可能阻止页面错误,但只是为了确定,我已经尝试产生多达300个线程.
这是在Linux内核2.6.32-27-generic(Ubuntu Server x64 LTS 10.04)上运行的.Gcc版本是4.4.3,boost :: asio版本是1.40(都是Ubuntu LTS的股票).
运行vmstat,iostat和top,我看到磁盘吞吐量(在TPS和数据卷中)都是%的单个数字.同样,磁盘队列长度总是比线程数小很多,所以我不认为我是I/O绑定的.此外,RSS攀升,但然后稳定在几个演出(如预期)和vmstat显示没有分页,所以我想我不是内存限制.CPU恒定为0-1%用户,6-7%系统,其余为空闲.线索!一个完整的"核心"(记住超线程)是CPU的6.25%.
我知道系统落后了,因为当超过64kB未完成时,客户端机器阻止TCP发送,并报告事实; 他们都在报告这一事实,并且系统的吞吐量远远低于预期,预期和理论上的可能性.
我的猜测是我在争夺某种锁定.我使用应用程序级锁来保护可能会发生变异的查找表,因此我将其分为256个顶级锁/表来打破这种依赖.但是,这似乎没有任何帮助.
所有线程都通过一个全局io_service实例.在应用程序上运行strace表明它花费大部分时间来处理futex调用,我想这与io_service reactor的基于事件的实现有关.
我可能反应堆吞吐量有限吗?我怎么说?io_service的实现是多么昂贵和可扩展(跨线程)?
编辑:我最初没有找到这个其他线程,因为它使用了一组不与我重叠的标签: - /很可能我的问题是在执行boost :: asio reactor时使用的过度锁定.请参阅C++套接字服务器 - 无法使CPU饱和 然而,问题仍然存在:我如何证明这一点?我该如何解决?
我有许多类型需要提供与外部世界通信的自定义函数。例如,我可能有一个 Widget 和一个 Sprocket,当来自我无法控制的世界的数据到达并说“制作一个 Widget”时,我需要调用 Widget.Create() 函数。如果世界说“制作一个锤子”,那么我需要返回“锤子不存在”错误。然而,world-representation 和 type-name 之间的映射不是 1:1,所以我不能简单地使用反射来直接查找类型名称——我需要一个表。(事实上,“名称”可能是一个特定的整数值。)
我了解如何使用从世界表示映射到类名称的预定义表(或字典)。我还了解如果可能的类集发生更改,如何在运行时扩展/更改此表。(由于规则更改,或应用程序的动态加载部分,或其他原因。)
然而,所有这些都需要重复——我必须实现我的类,然后,在代码中的其他地方,记住添加一个“这个类在外部世界有这个名称”的实例。这有点代码味道,因为将来的某个时候我会编写一个新类(或删除一个旧类)并忘记更新表,然后花时间调试为什么它不能正常工作。
我想我可以在每个类中使用一个静态成员,该成员将自身注册到全局表中:
public static Registration Me = new Registration(typeid(MyClass), "My Name");
Run Code Online (Sandbox Code Playgroud)
不幸的是,静态字段在类中的某些函数被执行/访问之前不会被初始化,因此它不会在启动时运行。(静态构造函数也有类似的限制,而且运行时的开销甚至更大!)
下一个想法是用一个自定义属性来装饰该类,该属性表示“在表中注册该类”。
[Register("My Name")]
class MyClass : .... {
}
Run Code Online (Sandbox Code Playgroud)
不幸的是,“Register”属性不知道它附加到哪个类——只有 MyClass 类知道它具有 Register 属性。(这让我很生气,因为在很多很多情况下,如果属性知道它们附加在哪里,那就太方便了。但这是一个旁白!)
因此,我能想到的最不糟糕的实现是使用反射迭代所有程序集的所有类型,并检查它们是否具有此属性,如果有,则将它们注册到表中。我们可以说,这既不优雅也不高效。
有没有更好的方法来自动注册类,而无需使用中央注册表更新其他源文件?
我正在尝试HAProxy进行TCP负载平衡.连接在单个IP上进入端口X,然后HAProxy使用"leastconn"平衡方法将这些连接平衡到后端,以保持连接数均匀.这是在Ubuntu 10.04 x64上.
我已经将内核配置中的file-max调高到700,000.我已经将每个进程的ulimit调高到大约400,000.我已经将haproxy配置中的maxconn调到了200,000.它报告看到这个maxconn罚款:
show info
Name: HAProxy
Version: 1.3.22
Release_date: 2009/10/14
Nbproc: 1
Process_num: 1
Pid: 1355
Uptime: 0d 4h38m46s
Uptime_sec: 16726
Memmax_MB: 0
Ulimit-n: 400013
Maxsock: 400013
Maxconn: 200000
Maxpipes: 0
CurrConns: 1113
PipesUsed: 0
PipesFree: 0
Tasks: 1113
Run_queue: 1
node: XXXXX
Run Code Online (Sandbox Code Playgroud)
这个前端负载均衡5个后端系统.但是,当每个后端达到400个会话时,它只是平衡停止平衡,并且只是推迟了其他连接.我可以用"smax"统计数据看到这一点.您将注意到每个会话的最大会话数为400,并且最大会话总数为2000:
show stat
#
pxname,svname,qcur,qmax,scur,smax,slim,stot,bin,bout,dreq,dresp,ereq,econ,eresp,wretr,wredis,status,weight,act,bck,chkfail,chkdown,lastchg,downtime,qlimit,pid,iid,sid,throttle,lbtot,tracked,type,rate,rate_lim,rate_max,
protoa,FRONTEND,,,958,2000,2000,12624,6230219,6445523,0,0,0,,,,,OPEN,,,,,,,,,1,1,0,,,,0,0,0,406,
protoa,XXX1672,0,0,191,400,,3222,1249403,1286659,,0,,221,0,664,0,no check,1,1,0,,,,,,1,1,1,,2559,,2,0,,198,
protoa,XXX1674,0,0,192,400,,3106,1242103,1289247,,0,,178,0,535,0,no check,1,1,0,,,,,,1,1,2,,2572,,2,0,,171,
protoa,XXX1707,0,0,193,400,,3043,1266305,1305311,,0,,164,0,492,0,no check,1,1,0,,,,,,1,1,3,,2551,,2,0,,161,
protoa,XXX1782,0,0,189,400,,3046,1236790,1282690,,0,,204,0,619,0,no check,1,1,0,,,,,,1,1,4,,2429,,2,0,,190,
protoa,XXX1851,0,0,193,400,,3060,1235618,1281616,,0,,189,0,570,0,no check,1,1,0,,,,,,1,1,5,,2490,,2,0,,180,
protoa,BACKEND,0,0,958,2000,2000,12624,6230219,6445523,0,0,,956,0,2880,0,UP,5,5,0,,0,17645,0,,1,1,0,,12601,,1,0,,406,
protob,FRONTEND,,,4,6,2000,28,15204,15726,0,0,0,,,,,OPEN,,,,,,,,,1,2,0,,,,0,0,0,2,
protob,XXX1672,0,0,2,2,,5,2313,2322,,0,,0,0,0,0,no check,1,1,0,,,,,,1,2,1,,5,,2,0,,1,
protob,XXX1674,0,0,0,2,,5,3520,3803,,0,,0,0,0,0,no check,1,1,0,,,,,,1,2,2,,5,,2,0,,1,
protob,XXX1707,0,0,0,2,,8,3303,3214,,0,,0,0,0,0,no check,1,1,0,,,,,,1,2,3,,8,,2,0,,1,
protob,XXX1782,0,0,1,2,,5,3529,3745,,0,,0,0,0,0,no check,1,1,0,,,,,,1,2,4,,5,,2,0,,1,
protob,XXX1851,0,0,1,1,,5,2539,2642,,0,,0,0,0,0,no check,1,1,0,,,,,,1,2,5,,5,,2,0,,1,
protob,BACKEND,0,0,4,6,2000,28,15204,15726,0,0,,0,0,0,0,UP,5,5,0,,0,17645,0,,1,2,0,,28,,1,0,,2,
Run Code Online (Sandbox Code Playgroud)
这种限制来自哪里?我真的想把数十万个连接吸引到这个haproxy实例中.(机器有网络,CPU和RAM跟上)
我正在使用适用于Google App Engine的Windows Launcher开发环境.
我已经下载了Django 1.1.2源代码,并且取消了"django"子目录,以便在我的应用程序目录(app.yaml的同行)中生存
在每个.py源文件的顶部,我这样做:
import settings
import os
os.environ["DJANGO_SETTINGS_MODULE"] = 'settings'
Run Code Online (Sandbox Code Playgroud)
在我的文件settings.py中(也位于app目录的根目录下),我这样做:
DEBUG = True
TEMPLATE_DIRS = ('html')
INSTALLED_APPS = ('filters')
import os
os.environ["DJANGO_SETTINGS_MODULE"] = 'settings'
from google.appengine.dist import use_library
use_library('django', '1.1')
from django.template import loader
Run Code Online (Sandbox Code Playgroud)
是的,这看起来有点像矫枉过正,不是吗?
我只使用django.template.我没有明确使用django的任何其他部分.
但是,间歇性地我得到两个错误之一:
1)Django抱怨没有定义DJANGO_SETTINGS_MODULE.
2)Django抱怨common.html(我在其他模板中扩展的模板)不存在.
95%的情况下,没有遇到这些错误,而且它们随机开始发生.一旦进入该状态,本地服务器似乎"楔入"并重新启动它通常会修复它.
造成这种情况的原因是什么,我该怎么办呢?我怎么能调试呢?
以下是错误的回溯:
Traceback (most recent call last):
File "C:\code\kwbudget\edit_budget.py", line 34, in get
self.response.out.write(t.render(template.Context(values)))
File "C:\code\kwbudget\django\template\__init__.py", line 165, in render
return self.nodelist.render(context)
File "C:\code\kwbudget\django\template\__init__.py", line 784, in render
bits.append(self.render_node(node, context))
File "C:\code\kwbudget\django\template\__init__.py", line 797, in …Run Code Online (Sandbox Code Playgroud) linux ×3
django ×2
python ×2
amqp ×1
asynchronous ×1
attributes ×1
boost-asio ×1
branch ×1
c# ×1
debugging ×1
file ×1
git ×1
github ×1
haproxy ×1
intermittent ×1
module ×1
opengl-es ×1
optimization ×1
performance ×1
posix ×1
proxy ×1
pull ×1
pull-request ×1
reflection ×1
rust ×1
rust-crates ×1
scalability ×1
tcp ×1
throughput ×1
ubuntu-10.04 ×1
xmpp ×1
xorg ×1