带有mysql和redis的龙卷风websockets

时间:2018-04-26 08:40:41

标签: mysql asynchronous redis tornado

我有一个龙卷风服务器,它将与客户端建立Web套接字连接。每当客户端请求某些数据时,我需要从Redis或MySQL-DB获取它。除此之外,我需要收听来自龙卷风服务器的广播,接收网络数据包并在订阅数据时将它们发送给客户端。向客户端发送广播数据包取决于数据包中将存在的令牌。如果客户订阅了令牌,我们应该将包发送给他。

请求率:

  1. 5000个活动Web套接字连接(可以增加)
  2. 每秒插槽连接1-DB请求,因此总共5000个DB请求/秒
  3. 每秒每个套接字连接1次Redis请求,因此总共5000次Redis请求/秒。
  4. 在广播中,我应该收听1000个数据包/秒,并检查是否有任何用户订阅了该令牌。
  5. 我知道redis是单线程的并且是异步工作的(如果我错了,请纠正我)。对于我使用的MySQL-DB异步驱动程序是`tormysql`(我对DB的大多数调用是选择查询而没有复杂的数据库操作。)。

    我的问题:

    1. 对MySQL-DB的调用是否会阻塞?如果它们是阻塞调用,我可以为数据库查询运行不同的线程/进程吗?
    2. 龙卷风是否有可能在广播中丢包?
    3. 我可以在我的资源前面安装一个负载平衡器并为它们提供服务但是我可以使用一个带有2核8 GB RAM的单个CPU吗?
    4. 更新1
      我为MySQL编写了一个代码:
      Server.py

      import logging
      import tornado.escape
      import tornado.ioloop
      import tornado.options
      import tornado.web
      import tornado.websocket
      import os.path
      import uuid
      import sys
      from tornado import gen
      
      from tornado.options import define, options
      
      import tormysql ## MySQL async driver
      pool = tormysql.ConnectionPool(
          max_connections = 20, #max open connections
          idle_seconds = 7200, #conntion idle timeout time, 0 is not timeout
          wait_connection_timeout = 3, #wait connection timeout
          host = "127.0.0.1",
          user = "test",
          passwd = "",
          db = "testdb",
          charset = "utf8"
      )
      
      
      define("port", default=8000, help="run on the given port", type=int)
      
      class Application(tornado.web.Application):
          def __init__(self):
              handlers = [
                  (r"/", MainHandler),
                  (r"/dataSock", ChatSocketHandler),
              ]
              settings = dict(
                  cookie_secret="__TODO:_GENERATE_YOUR_OWN_RANDOM_VALUE_HERE__",
                  template_path=os.path.join(os.path.dirname(__file__), "templates"),
                  static_path=os.path.join(os.path.dirname(__file__), "static"),
                  xsrf_cookies=True,
              )
              super(Application, self).__init__(handlers, **settings)
      
      class MainHandler(tornado.web.RequestHandler):
          def get(self):
              self.render("indexWS.html")
      
      class ChatSocketHandler(tornado.websocket.WebSocketHandler):
          openConnCount = 0
          def get_compression_options(self):
              # Non-None enables compression with default options.
              return {}
      
          def open(self):
              # print("Socket open:%s"%(self))
              ChatSocketHandler.openConnCount += 1
              None
          def on_close(self):
              # print("Socket closed:%s"%(self))
              ChatSocketHandler.openConnCount -= 1
              None
      
          async def on_message(self, message):
              logging.info("open conn count %r", ChatSocketHandler.openConnCount)
              returnDB = await getDataFromDB()
              self.write_message("server got this from you:%s"%(str(returnDB)))
      
      @gen.coroutine
      def getDataFromDB():
          with (yield pool.Connection()) as conn:
              try:
                  with conn.cursor() as cursor:
                      yield cursor.execute("SHOW TABLES;")
                      # print(cursor.fetchall())
              except:
                  yield conn.rollback()
              else:
                  yield conn.commit()
      
              with conn.cursor() as cursor:
                  yield cursor.execute("SELECT * FROM theme;")
                  datas = cursor.fetchall()
      
          return datas
      
          # yield pool.close()
      def main():
          tornado.options.parse_command_line()
          app = Application()
          # print "options:", options
          # sys.exit()
          app.listen(options.port)
          print("PORT:%s"%(options.port))
          tornado.ioloop.IOLoop.current().start()
      
      if __name__ == "__main__":
          main()
      

      现在我用这个测试这段代码:
      Client.py

      import asyncio
      import websockets
      
      async def hello(i):
          async with websockets.connect('ws://localhost:8000/dataSock') as websocket:
              name = 'A'#input("What's your name? ")
              print("******************************%s******************************"%(i))
              for j in range(100):
                  await websocket.send(name)
                  # print("> {}".format(name))
      
                  greeting = await websocket.recv()
                  print("{}: {}".format(i, len(greeting)))
                  asyncio.sleep(10)
      
      async def start():
          for i in range(10):
              await hello(i)
          print("end")
          asyncio.sleep(20)
      asyncio.get_event_loop().run_until_complete(start())
      # asyncio.get_event_loop().run_forever()
      

      如果我运行代码的单个实例,那么每件事都运行良好。当我将客户端数量增加到70(客户端的70个实例)时,有一个 延迟我得到的回应。

      第二个问题解释:
      Tornado服务器必须侦听某个端口,在该端口中我将接收网络数据包,如果它们已订阅,我必须将其发送给客户端。那么这些数据包是否会被丢弃?

1 个答案:

答案 0 :(得分:1)

  
      
  1. 对MySQL-DB的调用是否会阻塞?如果它们是阻塞调用,我可以为数据库查询运行不同的线程/进程吗?
  2.   

正如您所提到的那样,您使用tormysql作为驱动程序,所以不会,因为tormysql是异步的,所以调用不会阻止。

  
      
  1. 龙卷风是否有可能在广播中丢包?
  2.   

我不太明白你的意思。但由于websocket协议是基于TCP构建的,因此可以保证所有数据包的传输。 TCP处理这个问题。

  
      
  1. 我可以在我的资源前面安装一个负载平衡器并为它们提供服务但是我可以使用一个带有2核8 GB RAM的单个CPU吗?
  2.   

是。

我认为你现在正在过度思考你的申请。过早优化是邪恶的。您尚未编写任何代码,而您正在考虑性能。这只是在浪费你的时间。

首先编写代码,然后对其进行压力测试以查看应用程序可以处理多少负载。然后进行分析,看看事情正在放缓的地方。 然后您优化代码,或更改您的设置,并可能升级您的硬件。

但只是考虑性能而不进行编写​​和压力测试代码只是浪费时间。