Stale connections when VIP is moved
Affects | Status | Importance | Assigned to | Milestone | |
---|---|---|---|---|---|
tripleo |
Fix Released
|
High
|
Jan Provaznik |
Bug Description
API services connect to mysql through VIP+haproxy. DB connection is kept open for next requests (IOW no new DB connection is done for each request coming to an API service). When API service and VIP is running on same machine and API service opens connection through haproxy to DB, then if VIP is moved to different machine (e.g. because of short network outage), then this "stale" connection from API service to DB (haproxy) remains open. If API service writes something to the socket of this connection it doesn't get expected "socket closed" error, but connection is presented as alive, but it doesn't get any response after writing to this socket so request times out.
Sockets of he connection API<->haproxy(DB) are visible in /proc/PID/fd of both API and haproxy processes, so this is probably why socket is still alive and writeable - I guess this is system feature, not bug.
If VIP is running on different machine than API service and VIP is moved, then API service gets expected "socket closed" error when trying to write again to the opened socket. IOW if connection API<->haproxy is not on same machine, then socket is not writeable. What looks like a bug is the fact that I get different behavior depending wheter connection is on local machine or to different machine.
Anyway the result is that because TripleO deploys API+haproxy on all controller nodes by default, then there is significant chance that after VIP failover APi service will stop responding.
How to reproduce:
1) set public_workers = 1 in keystone.conf (this is not necessary but makes debugging easier)
2) make sure VIP is on the same machine which will handle API request (we use "source" strategy in haproxy, so it's typically ctrl0 -> you can bump priority in keepalived.conf on ctrl0 and restart keepalived)
3) run "nova --debug list" - this request passes, important is that keystone creates DB connection and leaves it open
4) stop keepalived on ctrl0 - VIP is moved
5) run "nova --debug list" - this request times out on doing keystone auth
Here are details important bits from my reproducer + strace (file descriptor 7 in strace ouput is the opened connection to DB - socket 13484432):
[tripleo@
[root@overcloud
root 4744 0.0 0.0 6188 2036 pts/0 S+ 11:06 0:00 | \_ grep --color=auto keyst
keystone 4507 2.4 1.2 56336 38192 ? Ss 11:05 0:01 /opt/stack/
[root@overcloud
keystone- 4507 keystone 7u IPv4 13484432 0t0 TCP overcloud-
[root@overcloud
[tripleo@
***** strace -p 4507 *****
{{EPOLLIN, {u32=5, u64=13803923081
epoll_ctl(4, EPOLL_CTL_DEL, 5, bf9162d0) = 0
accept(5, {sa_family=AF_INET, sin_port=
fcntl64(8, F_GETFL) = 0x2 (flags O_RDWR)
fcntl64(8, F_SETFL, O_RDWR|O_NONBLOCK) = 0
fcntl64(8, F_GETFL) = 0x802 (flags O_RDWR|O_NONBLOCK)
fcntl64(8, F_SETFL, O_RDWR|O_NONBLOCK) = 0
gettimeofday(
accept(5, 0xbf91658c, [16]) = -1 EAGAIN (Resource temporarily unavailable)
epoll_ctl(4, EPOLL_CTL_ADD, 5, {EPOLLIN|
gettimeofday(
recv(8, "POST /v2.0/tokens HTTP/1.
getsockname(8, {sa_family=AF_INET, sin_port=
gettimeofday(
gettimeofday(
poll([{fd=7, events=
write(7, "$\1\0\0\3SELECT user.id AS user_id, "..., 296) = 296
read(7,
**** strace when keystone connects to VIP on different machine and this VIP is moved ****
[root@overcloud
Process 4507 attached
gettimeofday(
epoll_wait(4, {{EPOLLIN, {u32=5, u64=13807746495
epoll_ctl(4, EPOLL_CTL_DEL, 5, bf9ef830) = 0
accept(5, {sa_family=AF_INET, sin_port=
fcntl64(6, F_GETFL) = 0x2 (flags O_RDWR)
fcntl64(6, F_SETFL, O_RDWR|O_NONBLOCK) = 0
fcntl64(6, F_GETFL) = 0x802 (flags O_RDWR|O_NONBLOCK)
fcntl64(6, F_SETFL, O_RDWR|O_NONBLOCK) = 0
gettimeofday(
accept(5, 0xbf9efaec, [16]) = -1 EAGAIN (Resource temporarily unavailable)
epoll_ctl(4, EPOLL_CTL_ADD, 5, {EPOLLIN|
gettimeofday(
recv(6, "POST /v2.0/tokens HTTP/1.
getsockname(6, {sa_family=AF_INET, sin_port=
gettimeofday(
gettimeofday(
poll([{fd=7, events=
write(7, "$\1\0\0\3SELECT user.id AS user_id, "..., 296) = 296
read(7, 0xabe1b68, 16384) = -1 ECONNRESET (Connection reset by peer)
shutdown(7, SHUT_RDWR) = -1 ENOTCONN (Transport endpoint is not connected)
close(7) = 0
gettimeofday(
gettimeofday(
gettimeofday(
epoll_wait(4, {}, 1023, 0) = 0
gettimeofday(
gettimeofday(
stat64(
open("/
...
Changed in tripleo: | |
importance: | Undecided → High |
Changed in tripleo: | |
assignee: | nobody → Jan Provaznik (jan-provaznik) |
Changed in tripleo: | |
status: | Fix Committed → Fix Released |
I wonder if we can just get haproxy to shutdown all connections when the VIP moves away.