[oslo][oslo-messaging][nova] Stein nova-api AMQP issue running under uWSGI
iain.macdonnell at oracle.com
iain.macdonnell at oracle.com
Fri Apr 19 22:20:44 UTC 2019
Today I discovered that this problem appears to be caused by eventlet
monkey-patching. I've created a bug for it:
https://bugs.launchpad.net/nova/+bug/1825584
~iain
On 4/18/19 11:27 PM, iain.macdonnell at oracle.com wrote:
>
> Hi Damien,
>
> Thanks for the response! This definitely sounds similar enough that it
> has to be the same root problem.
>
> I didn't make too much progress today. Whilst using strace to try to
> compare Rocky and Stein, I noticed that TCP connections seem to be
> handled somewhat differently. This applies to mysql as well as AMQP. In
> the Rocky case, I see repeated fcntl() calls to F_SETFL O_RDWR between
> sendto() and recvfrom():
>
>
> [pid 32427] socket(AF_INET, SOCK_STREAM, IPPROTO_TCP) = 19
> [pid 32427] fcntl(19, F_GETFL) = 0x2 (flags O_RDWR)
> [pid 32427] fcntl(19, F_SETFL, O_RDWR|O_NONBLOCK) = 0
> [pid 32427] connect(19, {sa_family=AF_INET, sin_port=htons(3306),
> sin_addr=inet_addr("x.x.x.x")}, 16) = -1 EINPROGRESS (Operation now in
> progress)
> [pid 32427] poll([{fd=19, events=POLLOUT}], 1, 10000) = 1 ([{fd=19,
> revents=POLLOUT}])
> [pid 32427] getsockopt(19, SOL_SOCKET, SO_ERROR, [0], [4]) = 0
> [pid 32427] setsockopt(19, SOL_TCP, TCP_NODELAY, [1], 4) = 0
> [pid 32427] fcntl(19, F_GETFL) = 0x802 (flags O_RDWR|O_NONBLOCK)
> [pid 32427] fcntl(19, F_SETFL, O_RDWR) = 0
> [pid 32427] setsockopt(19, SOL_SOCKET, SO_KEEPALIVE, [1], 4) = 0
> [pid 32427] fcntl(19, F_GETFL) = 0x2 (flags O_RDWR)
> [pid 32427] fcntl(19, F_SETFL, O_RDWR) = 0
> [pid 32427] recvfrom(19,
> "J\0\0\0\n5.7.25\0\f\r\0\0#\4;;\n)\0309\0\377\377\10\2\0\377\301"...,
> 8192, 0, NULL, NULL) = 78
> [pid 32427] fcntl(19, F_GETFL) = 0x2 (flags O_RDWR)
> [pid 32427] fcntl(19, F_SETFL, O_RDWR) = 0
> [pid 32427] fcntl(19, F_GETFL) = 0x2 (flags O_RDWR)
> [pid 32427] fcntl(19, F_SETFL, O_RDWR) = 0
> [pid 32427] sendto(19,
> "\222\0\0\1\17\242:\0\377\377\377\0!\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"...,
> 150, 0, NULL, 0) = 150
> [pid 32427] fcntl(19, F_GETFL) = 0x2 (flags O_RDWR)
> [pid 32427] fcntl(19, F_SETFL, O_RDWR) = 0
> [pid 32427] recvfrom(19, ",\0\0\2\376mysql_native_password\0#\4;;\n"...,
> 8192, 0, NULL, NULL) = 48
>
>
> whereas in the Stein case, I see recvfrom() calls that get EAGAIN,
> followed by epoll before a successful recvfrom():
>
> [pid 17895] socket(AF_INET, SOCK_STREAM, IPPROTO_TCP) = 28
> [pid 17895] fcntl(28, F_GETFL) = 0x2 (flags O_RDWR)
> [pid 17895] fcntl(28, F_SETFL, O_RDWR|O_NONBLOCK) = 0
> [pid 17895] connect(28, {sa_family=AF_INET, sin_port=htons(3306),
> sin_addr=inet_addr("x.x.x.x")}, 16) = -1 EINPROGRESS (Operation now in
> progress)
> [pid 17895] epoll_ctl(26, EPOLL_CTL_ADD, 28,
> {EPOLLOUT|EPOLLERR|EPOLLHUP, {u32=28, u64=6398156018563416092}}) = 0
> [pid 17895] epoll_wait(26, [{EPOLLOUT, {u32=28,
> u64=6398156018563416092}}], 1023, 1992) = 1
> [pid 17895] epoll_ctl(26, EPOLL_CTL_DEL, 28, 0x7fb5ed1f7440) = 0
> [pid 17895] getsockopt(28, SOL_SOCKET, SO_ERROR, [0], [4]) = 0
> [pid 17895] connect(28, {sa_family=AF_INET, sin_port=htons(3306),
> sin_addr=inet_addr("10.241.154.33")}, 16) = 0
> [pid 17895] setsockopt(28, SOL_TCP, TCP_NODELAY, [1], 4) = 0
> [pid 17895] setsockopt(28, SOL_SOCKET, SO_KEEPALIVE, [1], 4) = 0
> [pid 17895] recvfrom(28,
> "J\0\0\0\n5.7.25\0(!\0\0\10w@\v-~)D\0\377\377\10\2\0\377\301"..., 8192,
> 0, NULL, NULL) = 78
> [pid 17895] sendto(28,
> "\222\0\0\1\17\242:\0\377\377\377\0!\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"...,
> 150, 0, NULL, 0) = 150
> [pid 17895] recvfrom(28, 0x7fb5d401e340, 8192, 0, NULL, NULL) = -1
> EAGAIN (Resource temporarily unavailable)
> [pid 17895] epoll_ctl(26, EPOLL_CTL_ADD, 28,
> {EPOLLIN|EPOLLPRI|EPOLLERR|EPOLLHUP, {u32=28, u64=6398156018563416092}})
> = 0
> [pid 17895] epoll_wait(26, [{EPOLLIN, {u32=28,
> u64=6398156018563416092}}], 1023, 1991) = 1
> [pid 17895] epoll_ctl(26, EPOLL_CTL_DEL, 28, 0x7fb5ed1f6530) = 0
> [pid 17895] recvfrom(28,
> ",\0\0\2\376mysql_native_password\0\10w@\v-"..., 8192, 0, NULL, NULL) = 48
>
>
> Not sure if this is related to the problem or not, but it's what jumped
> out first, and I wasn't able to figure out what's causing the change in
> behaviour before I ran out of enthusiasm today.
>
> Please let me know if you discover anything further or/and if there are
> any discussions (IRC?) that I should be participating in .. although I'm
> guessing that that's happening during the EU work day.
>
> Thanks!
>
> ~iain
>
>
>
>
>
> On 4/18/19 12:48 AM, Damien Ciabrini wrote:
>>
>>
>> On Thu, Apr 18, 2019 at 7:51 AM <iain.macdonnell at oracle.com
>> <mailto:iain.macdonnell at oracle.com>> wrote:
>>
>>
>> Is anyone running Stein nova-api under uWSGI? I'm trying to do
>> this, in
>> exactly the same way as I did with Rocky, but encountering a new
>> problem...
>>
>>
>> This sounds similar to a problem that we're currently debugging with John
>> Eckersberg and Michele Baldessari (in CC) in Stein, but when nova-api
>> runs
>> under Apache mod_wsgi.
>>
>> The symptoms for us seem similar: sometimes the scheduling of the AMQP
>> heartbeat greenlet seems heratic (no run for 75 seconds), RabbitMQ
>> drops the connection to the client during this idle period, and next time
>> nova-api needs to communicate over AMQP it logs a "connection reset
>> by peer" and reestablish a new connection.
>>
>> This is fresh news from yesterday so this is still to be
>> confirmed/disproved;
>> but currently we're investigating how eventlet schedules recurring tasks
>> such as the AMQP heartbeat greenlet under Apache mod_wsgi's execution
>> model.
>>
>> Once the AMQP heartbeat greenlet has sent its heartbeat, it sleeps for a
>> fixed amount of time; i.e. it suspends its execution, eventlet
>> registers a timer
>> for this greenlet, and continues scheduling other greenlets. Once the
>> timer
>> expires, eventlet marks the heartbeat greenlet as "eligible for
>> scheduling"
>> and eventually this greenlet resumes its execution.
>> For that mechanism to work, eventlet regularly watches for all the timers
>> that are registered in its event loop (with select/epoll/whatnot).
>>
>> Now, Apache mod_wsgi embeds its own Python interpreter, and calls it
>> whenever there's an API call to process. It seems that - the precise
>> course
>> of event is unclear to me yet - once the API call is processed, the
>> Python
>> Interpreter returns a result to mod_wsgi and stops its execution even if
>> some timers were still registered in eventlet.
>>
>> The state of the Python Interpreter is conserved though, and next time
>> mod_wsgi receives an API call, it resumes the execution of the Python
>> Interpreter: eventlet resumes its execution and process every timer
>> that were registered previously. So ultimately, the AMQP heartbeat
>> greenlet is rescheduled, but that might be a long time already since the
>> last AMQP heartbeat.
>>
>> So I have the feeling that when there's no traffic, mod_wsgi doesn't
>> execute
>> the Python interpreter, which prevents eventlet from running, watching
>> for
>> timers, and triggering the AMQP heartbeat greenlet. So far, the evidences
>> in favour of this theory are:
>> . When there's no traffic for nova-api running under mod_wsgi, and
>> I use
>> gdb to dump the call stack of the mod_wsgi process, I see no CPython
>> interpreter in the stack. Whereas when there's traffic, I see
>> many CPython
>> stack frames.
>> . When there's no traffic to nova-api and the AMQP heartbeat
>> greenlet seem
>> to be unscheduled for a long time, running a simple 'nova list'
>> command
>> seems to unblock everything and trigger a AMQP heartbeat.
>>
>> This would also explain why running the nova-api service in standalone
>> works
>> just fine as you said. because the Python interpreter is never stopped
>> in this
>> execution model.
>>
>> I'm still trying to figure out when the Python interpreter returns to
>> mod_wsgi
>> to make sure what I'm saying makes sense. And I also need to double check
>> that running in standalone works fine for me as well.
>>
>> The symptom is intermittent failure of API operations that involve
>> RPC
>> calls - notably getting the noVNC console URL for an instance. The
>> nova-api log shows RPC timeouts and "connection reset by peer" for
>> AMQP.
>> I've ruled out environmental issues, as a Rocky installation on the
>> same
>> hosts works fine. With oslo debug enabled, I see that the first API
>> call
>> causes a AMQP connections to be established, and the RPC call gets
>> its
>> reply, and all is well... but there are no heartbeats logged after
>> that.
>> 3 minutes later, rabbitmq-server reports that it has received no
>> heartbeats, and drops the connection. On a subsequent API call
>> (but not
>> before), nova-api logging "connection reset by peer" and the RPC call
>> times out. With the Rocky code, once the first API call causes the
>> AMQP
>> connections to be established, regular heartbeats start happening,
>> the
>> connections are maintained, and subsequent API calls work as
>> expected.
>>
>> It seems like a lockup in a thread that's supposed to maintain the
>> AMQP
>> connection, or something. I tried to use SIGUSR2 to trigger guru
>> meditation, but it seems that uWSGI has its own interpretation of
>> SIGUSR2, so nova-api never sees it (anyone know a way around this?).
>>
>> Running nova-api as a standalone service, instead of under uWSGI, the
>> problem does not occur (I see the heartbeats, and everything works
>> fine).
>>
>> I've tried updating oslo-messaging (and python-amqp) on a Rocky
>> installation to the Stein version, but the problem does not
>> reproduce.
>>
>> Ideas?
>>
>> ~iain
>>
>>
>>
>>
>>
>> --
>> Damien
>
More information about the openstack-discuss
mailing list