【问题标题】:Python micro web service always hangPython微web服务总是挂起
【发布时间】:2017-03-24 02:02:37
【问题描述】:

我构建了一个微型 Web 服务,但我发现它挂了很多。挂起是指所有请求都会超时,当它挂起时,我可以看到该进程在服务器中运行良好,通常只使用大约 15MB 内存。我觉得这是一个非常有趣的问题,代码超级简单,请告诉我我做错了什么。

app = Bottle()
# static routing
@app.route('/')
def server_static_home():
    return static_file('index.html', root='client/')

@app.route('/<filename>')
def server_static(filename):
    return static_file(filename, root='client/')

@app.get('/api/data')
def getData():
    data = {}
    arrayToReturn = []
    with open("data.txt", "r") as dataFile:
        entryArray = json.load(dataFile)
        for entry in entryArray:
            if not entry['deleted']:
                arrayToReturn.append(entry)
        data["array"] = arrayToReturn

    return data

@app.put('/api/data')
def changeEntry():

    jsonObj = request.json
    with open("data.txt", "r+") as dataFile:
        entryArray = json.load(dataFile)
        for entry in entryArray:
            if entry['id'] == jsonObj['id']:
                entry['val'] = jsonObj['val']
        dataFile.seek(0)
        json.dump(entryArray, dataFile, indent=4)
        dataFile.truncate()

    return {"success":True}

run_simple('0.0.0.0', 80, app, use_reloader=True)

基本上mydomain.com 是路由到我的index.html 并加载必要的JS、CSS 文件,这就是静态路由部分正在做的事情。加载页面后,将向 /api/data 触发 ajax GET 请求以加载数据,当我修改数据时,它会向 /api/data 触发另一个 ajax Put 请求以修改数据。

如何重现

很容易重现挂起,我只需要访问mydomain.com并快速刷新页面10-30次,然后它就会停止响应。但是我永远无法在本地重现这个我刷新的速度有多快,data.txt 在我的本地机器上是一样的。

更新

事实证明,读/写文件不是问题,而是尝试写入损坏的管道时出现问题。发送请求的客户端在收到所有数据之前关闭连接。我正在寻找解决方案...

【问题讨论】:

  • 如果您使用的是包含在 Bottle 框架中的开发服务器,我注意到如果有足够的正常运行时间(毕竟它是一个开发服务器),损坏的管道错误实际上是不可避免的。如果这适用于您,我建议切换到在更适合生产的服务器上运行您的 Bottle 应用程序。我个人通过使用带有cherrypy的Bottle获得了非常好的结果。

标签: python web-services io wsgi bottle


【解决方案1】:

您似乎正在尝试使用每个 PUT 请求打开和读取相同的 data.txt 文件。最终,您将遇到此架构的并发问题,因为您将有多个请求尝试打开并写入同一个文件。

最好的解决方案是将数据持久化到数据库(例如 MySQL、Postgres、Mongodb)而不是写入磁盘上的平面文件。

但是,如果您必须写入一个平面文件,那么您应该在每个请求中写入一个不同的文件,其中文件的名称可以是jsonObj['id'],这样可以避免多个请求尝试读取/同时写入同一个文件。

【讨论】:

  • 因为服务真的很简单,我不想为它使用任何数据库。我正在读取和修改json格式文本文件中的条目,所以我认为我不能写入单独的文件,那么读取数据会很复杂。
  • 此外,我认为问题出在GET 请求而不是PUT 因为我不需要修改数据来重现问题,刷新只会触发读取的GET 请求数据。
【解决方案2】:

正如 Calvin 提到的,读取和写入 data.txt 文件将成为竞争条件的牺牲品。数据库在 python 中非常简单,尤其是使用 SqlAlchemy 之类的库。但是,如果您坚持,您也可以使用全局字典和锁,假设您的网络服务器没有作为多个进程运行。类似的东西

entryArray = {}
mylock = threading.Lock()
@app.put('/api/data')
def changeEntry():

    jsonObj = request.json
    with mylock.lock:
        for entry in entryArray:
           if entry['id'] == jsonObj['id']:
              entry['val'] = jsonObj['val']

【讨论】:

猜你喜欢
  • 1970-01-01
  • 2010-10-11
  • 1970-01-01
  • 1970-01-01
  • 2020-09-12
  • 2014-07-31
  • 1970-01-01
  • 2018-10-26
  • 1970-01-01
相关资源
最近更新 更多