Chinaunix

标题: 一个python做的服务端软件的问题 [打印本页]

作者: gm3000    时间: 2009-07-12 16:47
标题: 一个python做的服务端软件的问题
小弟用python+twisted+sqlalchemy 写了一个类似于httpserver的服务端软件

这个软件干的事情是这样的:
主要分两步,由两个线程分别完成

1步 接受客户端的数据 放入线程公用队列(queue),线程1做(twisted主线程)
2步 从队列pop出数据 存入数据库,线程2做

现在一个很尴尬的问题是,第一步就收数据部分速度飞快 平均每次请求不到1ms就完成
但是第二部存数据库相比起来就超级慢了,处理一个请求的数据(存入数据库)平均要30ms,可能数据库本身需要一些优化,但是现在还不知道能提高多少

所以:线程公用队列就会一直堆积数据(两部分的性能差距太大),最终就只有撑满内存了........

我的问题是:不管DBA怎么搞数据库部分,但从软件层,有没有什么办法至少是缓解这个问题呢,因为我觉得不管怎么样,所有环节中,存取数据库应该永远是瓶颈大户,并且第2步基本上主要就是做存数据库,没什么其他的什么开销

哪位大哥有什么建议么?
作者: reiase    时间: 2009-07-12 20:05
怎么改都解决不了根本矛盾:访问量与数据处理能力的矛盾

所以只能限制访问,操作队列满的时候阻塞访问,让客户端去等
作者: gm3000    时间: 2009-07-12 22:43
哎....限制访问,可是需要限制访问到什么程度呢,当前两步骤性能差异在上百倍了...
作者: ziggler    时间: 2009-07-12 22:58
标题: 回复 #1 gm3000 的帖子
异步方式?存采取这样的方式如何?
作者: smallfish_xy    时间: 2009-07-13 08:18
原帖由 ziggler 于 2009-7-12 22:58 发表
异步方式?存采取这样的方式如何?

恩,可以试试。
作者: gm3000    时间: 2009-07-13 10:41
恩?激动
能否讲的详细点呢?我知道oracle有并发操作的能力,是否是你们说的异步呢?
作者: chrisyan    时间: 2009-07-13 13:23
使用twisted的defer,把 操作串起来
client会24小时不间断传数据吗?那样的话迟早也是不行的,不过这样的情况下twisted应该会帮你处理一部分东西,你测试一下吧
缓存几次查询一并向数据库请求会不会快一点呢?
作者: relvigour    时间: 2009-07-13 13:34
开多个线程2 ,并发写数据库会好些。
作者: ua    时间: 2009-07-13 16:30
把客户端数据先写入文本文件,再用数据库本身的导入导出工具放入到数据库中,这样能解决数据存储的问题
作者: cookis    时间: 2009-07-13 17:07
原帖由 smallfish_xy 于 2009-7-13 08:18 发表

恩,可以试试。


我觉得异步不是解决之道,因为你的瓶颈之处解决不了,数据就会堆积,同时会消耗内存,

我觉得你的接收消息的queue应该设置一个高水标,如果超出了阈值,就拒绝掉,

如果你的client不能拒绝,那么你可以先保存在内存中,等数据堆积到一定程度,再集中写到DB中,集中写比分散式的写效率要高一些,毕竟访问数据库(磁盘)的次数少了很多。

[ 本帖最后由 cookis 于 2009-7-13 17:09 编辑 ]
作者: gm3000    时间: 2009-07-13 19:11
原帖由 chrisyan 于 2009-7-13 13:23 发表
使用twisted的defer,把 操作串起来
client会24小时不间断传数据吗?那样的话迟早也是不行的,不过这样的情况下twisted应该会帮你处理一部分东西,你测试一下吧
缓存几次查询一并向数据库请求会不会快一点呢?


我尝试了再开几个线程,并且把数据库迁到另外一台机子上,并发写数据库,性能提高了一些,我只能说提高了一些,而且有不稳定的情况,有时候队列累积很快,有时候又基本没有累积...

不过数据库性能感觉提升了一些

另外,twisted只用来接受数据,写数据库是在另外一个线程里做,所以用不了defer,因为defer依赖于reactor来操作,所以...没办法这么做
作者: gm3000    时间: 2009-07-13 19:17
client端不是24小时都在大量请求,只是高峰期,根据之前的换算,高峰期1000个用户1分钟就会在内存积累超过2G的数据....
这肯定不行....
所以必须提高第二步的性能,关键应该在写数据库性能,和DBA商量后,觉得oracle在处理一次操作最快就在10ms上下,这样算来和接受数据部分的微秒级还是相差比较大啊...
作者: gm3000    时间: 2009-07-13 19:41
原帖由 ua 于 2009-7-13 16:30 发表
把客户端数据先写入文本文件,再用数据库本身的导入导出工具放入到数据库中,这样能解决数据存储的问题


sqlldr? 可是我的表有关联,行么?并且还有主键,需要插入时定好,sqlldr能做么?而且还有clob字段....

[ 本帖最后由 gm3000 于 2009-7-13 19:43 编辑 ]
作者: reiase    时间: 2009-07-13 22:07
参考tcp的设计,是接收端指定窗口(简单理解为发送速率),而不是发送端

既然不是24小时大量请求,就可以考虑设计异步处理了
作者: ua    时间: 2009-07-14 15:15
原帖由 gm3000 于 2009-7-13 19:41 发表


sqlldr? 可是我的表有关联,行么?并且还有主键,需要插入时定好,sqlldr能做么?而且还有clob字段....



你先把原始数据放进去,再起一个进程处理数据,这样数据库就能做一个简单的缓冲,如果按照你目前的设计来说,客户端不知道什么时刻就能把你的服务器给弄死了
作者: ua    时间: 2009-07-14 15:19
如果不想用你的业务数据库,可以用一个内存数据库,像sqllite那种,
作者: mseaspring    时间: 2009-07-19 15:45
我想可以这样不:配置多个队列,每个队列对应一个数据库操作线程,然后接收到数据,放到其中一个队列中去,
如果队列都满了,让client等吧,如果瓶颈还在后端,可以对一个队列多开几个线程处理。


不知道这样设计可行不拿?
作者: chrisyan    时间: 2009-07-20 10:00
原帖由 gm3000 于 2009-7-13 19:11 发表


我尝试了再开几个线程,并且把数据库迁到另外一台机子上,并发写数据库,性能提高了一些,我只能说提高了一些,而且有不稳定的情况,有时候队列累积很快,有时候又基本没有累积...

不过数据库性能感觉提 ...


defer怎么可能不能和thread配合使用呢?用queue啊
比如下面

def after_db_operation(return_value_from_db_operation):
     ....

def submit_to_db(data):
     #你必须能在这访问到queue,我们假设这个就是叫 data_queue
     d = defer.Deferred()
     d.addCallback(afer_db_operation) #可能你还需要一个errback,看需要来吧
     data_queuq.put(d.callback,data)

这样就串起来了,当thread拿到一个queue中的数据时,第一个是defer的callback方法(在传入thread处理函数时我们假设形参叫callback_fun),第二个就是client传来的数据,当处理完成后就调用
callback_fun(return_value_from_db_operation)
这样就行了

而且你还可以并发多个数据库线程来读这个queue,这样其实你有了一个内存中的请求缓冲区。不过如果你的请求真是太多的话,最后还是会由于内存不够而崩溃,所以你还是在factory中设置一个最大连接数吧,当protocol实例太多的话直接拒绝掉
作者: hawkli    时间: 2009-07-23 16:02
timeten
memcached
这二个基本上是你这种类型业务的唯一解决之道。

具体实现不要问我,我是眼高手低派的。




欢迎光临 Chinaunix (http://bbs.chinaunix.net/) Powered by Discuz! X3.2