unbit / uwsgi

uWSGI application server container
http://projects.unbit.it/uwsgi
Other
3.45k stars 686 forks source link

sharedarea calls hang process #1455

Open Lispython opened 7 years ago

Lispython commented 7 years ago

Hi. I testing sharedarea on simple flask application. This code increment 4 byte integer on every request. I added sharedarea_wlock, because another process can modify memory between uwsgi.sharedarea_read32 call and uwsgi.sharedarea_write32 call. First request work correctly, but second request hang process at this line https://github.com/unbit/uwsgi/blob/master/core/lock.c#L204

dev_flask_app_1  | 442631017 | -1025144027 ->>>> py_uwsgi_sharedarea_wlock
dev_flask_app_1  | 442631017 | -1025144026 ->>>> uwsgi_wlock_fast before pthread_rwlock_wrlock  pid=60 ->  lock_ptr=0x7fd8cd5f0000 lock_id=30397984 uli->pid=0 uli->rw=1 rw_refcount=0x7fd8cd5f0000
dev_flask_app_1  | Sat Jan 21 21:21:01 2017 - HARAKIRI triggered by worker 2 core 0 !!!
dev_flask_app_1  | Sat Jan 21 21:21:01 2017 - *** HARAKIRI ON WORKER 2 (pid: 60, try: 1) ***
dev_flask_app_1  | Sat Jan 21 21:21:01 2017 - HARAKIRI !!! worker 2 status !!!
dev_flask_app_1  | Sat Jan 21 21:21:01 2017 - HARAKIRI [core 0] 10.9.8.1 - GET / since 1485033540
dev_flask_app_1  | Sat Jan 21 21:21:01 2017 - HARAKIRI !!! end of worker 2 status !!!
dev_flask_app_1  | DAMN ! worker 2 (pid: 60) died, killed by signal 9 :( trying respawn ...
dev_flask_app_1  | Respawned uWSGI worker 2 (new pid: 64)

Code:

# Snippet 1
@app.route('/<path:path>')
@app.route('/')
def index(path='/'):
    uwsgi.sharedarea_wlock(0)
    counter = uwsgi.sharedarea_read32(0, 0)
    new_counter = counter + 1
    uwsgi.sharedarea_write32(0, 0, new_counter)
    counter = uwsgi.sharedarea_read32(0,0)
    uwsgi.sharedarea_unlock(0)

    if new_counter != counter:
        print("Invalid data: {0} - {1}".format(new_counter, counter))

    text = "# Process in {0}\nCounter: {1}\n\n".format(os.getpid(), new_counter)
    return Response(text, mimetype="text/plain")

I testing this code without locks, and get wrong results. 30 rps during 1 minute increase counter to 1787 (uwsgi processed 1800 requests). After I locks, process hang on

As I can understand, uwsgi lock functions can be used only with memoryview, because py_uwsgi_sharedarea_memoryview don't use uwsgi_wlock inside for sharedarea id?

This code works correclty.

# Snippet 2
    uwsgi.sharedarea_wlock(0)
    memoryview = uwsgi.sharedarea_memoryview(0)
    counter = struct.unpack(b'i', memoryview[0:4])[0]
    new_counter = counter + 1
    memoryview[0:4] = struct.pack(b'i', new_counter)
    uwsgi.sharedarea_unlock(0)
    counter = struct.unpack(b'i', memoryview[0:4])[0]

upd: I changed last code block.

xrmx commented 7 years ago

The last code block looks exactly the same as the one you report hanging. Please post your config please

Lispython commented 7 years ago
[uwsgi]
chdir=/usr/src/app/
env = APP_ROLE=dev_uwsgi
wsgi-file = /usr/src/app/flask_app.py
master=True
vacuum=True
max-requests=5000
harakiri=120
post-buffering=65536
workers=4
#enable-threads=True
#listen=4000
# socket=0.0.0.0:8997
stats=/tmp/uwsgi-app.stats
#logger=syslog:uwsgi_app_stage,local0
buffer-size=65536
http = 0.0.0.0:8051
thunder-lock=True

sharedarea=1
sharedarea=7
Lispython commented 7 years ago

@xrmx sorry, I make mistake and duplicate hanging code. I fix last snippet.

xrmx commented 7 years ago

@Lispython which version of python is this?

Lispython commented 7 years ago

python:2.7.8

Lispython commented 7 years ago

@xrmx snippet 1 is correct usage of locks?

Lispython commented 7 years ago

I added example project to github https://github.com/Lispython/uwsgi_sharedmemory_tests

Lispython commented 7 years ago

How I can make safe increment for float value without memoryview usage?

After some tests, I found that method used pthread_rwlock_rdlock and pthread_rwlock_rdlock return 35 code.