之前用swoole(1.7.19)写的一段程序在数据量大的时候存在内存泄漏,改为twisted(15.4)实现,自测无误,记录如下(两者cpu占用率90%时吞吐rps能从120提升到1000)。
#!/usr/bin/env python from twisted.internet import task, reactor from twisted.python import log from twisted.web import static, server, resource import MySQLdb import json class RotateMap(object): def __init__(self): self.using = 0 self.unuse = 1 self.map = [{},{}] def find(self, key): if self.map[self.using].has_key(key): return self.map[self.using][key] return False def set(self, nmap): self.map[self.unuse] = nmap self._swap() def get(self): return self.map[self.using] def _swap(self): self.using,self.unuse = self.unuse,self.using check = RotateMap() allow = RotateMap() start = RotateMap() log.startLogging(open("/tmp/tserver.log",'w')) class TServer(resource.Resource): isLeaf = True def getChild(self, name, request): if name == '': return self return Resource.getChild(self, name, request) def render_GET(self, request): if request.requestHeaders.hasHeader("x-forwarded-for"): log.msg("%s %s %s" % (request.requestHeaders.getRawHeaders("x-forwarded-for"), request.path, json.dumps(request.args))) else: log.msg("%s %s %s" % ("127.0.0.1", request.path, json.dumps(request.args))) if "/api1" == request.path: if request.args.has_key("version"): version = request.args["version"][0] if version != "": global start info = start.get() result = {} if info["version"] != version: result["needUp"] = True result["version"] = info else: result["needUp"] = False return json.dumps(result) elif "/api2" == request.path: host = "" if request.args.has_key("host"): host = request.args["host"][0] global check if host != "": v1 = check.find(host) if v1 == False: v1 = "0" return "%s" % (v1) elif "/api3" == request.path: host = "" if request.args.has_key("host"): host = request.args["host"][0] v1 = v2 = 1 global allow if host != "" and allow.find(host) != False: v1 = 0 return "%d|%d" % (v1,v2) elif "/reload" == request.path: cmd = "file" if request.args.has_key("cmd"): cmd = request.args["cmd"][0] helper = ReloadHelper() helper.reload(cmd) return "done" else: request.setResponseCode(404) return "404 not found" request.setResponseCode(400) return "400 bad request" class ReloadHelper(object): def reload(self, cmd): log.msg("reload %s start" % (cmd)) if cmd == "db": self._reloadDB() elif cmd == "file": self._reloadFile() log.msg("reload %s end" % (cmd)) def _reloadFile(self): data = {} f = open("check.data") line = f.readline() while line: domain, levelid = line.strip().split("|") data[domain] = levelid line = f.readline() f.close() global check check.set(data) data = {} f = open("allow.data") line = f.readline() while line: domain = line.strip() data[domain] = "0" line = f.readline() f.close() global allow allow.set(data) def _reloadDB(self): try: conn=MySQLdb.connect(host='hostname',user='username',passwd='passwd',port=3306) conn.select_db("dbname") cur = conn.cursor() cur.execute("set names utf8") cur.execute("SELECT id, version, name FROM table ORDER BY id DESC LIMIT 1") row = cur.fetchone() if len(row) == 3: data = {} data["id"] = row[0] data["version"] = row[1] data["name"] = row[2] global start start.set(data) cur.close() conn.close() except MySQLdb.Error, e: log.err("mysql error %d, %s" %(e.args[0], e.args[1])) helper = ReloadHelper() l = task.LoopingCall(helper.reload, "db") l.start(600) l = task.LoopingCall(helper.reload, "file") l.start(3600000) def main(): tserver = static.File("/usr/local/nginx/html") tserver.putChild("service", TServer()) tserver.putChild("html", static.File("/usr/nginx/html")) reactor.listenTCP(8080, server.Site(tserver), 50, "127.0.0.1") reactor.run() if __name__ == '__main__': main()