Postgresql, and ODBC handles

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Summary: I am facing a contention problem with ODBC on the client side. strace and perf top show we are serializing over what appears to be accesses to the ODBC statement handle. Contention goes down if I use multiple processes instead of multiple threads within a process. Also, all the threads get the same connection handle number and the same statement handle number. Is there a way to force different connection and statement handles? I have asked this question on the ODBC mailing list, and they suggested it could be something in the postgresql driver.

 

Details: Running the TPCx-V benchmark, we hit a performance bottleneck as the load increases. We have plenty of CPU and disk resources available in our driver VM, client VM, and database backend VM (all with high vCPU counts) on a dedicated server. When we increase the number of threads of execution, not only doesn’t throughput go up, it actually degrades. I am running with 80 threads in one process. When I divide these threads into 5 processes, performance nearly doubles. So, the problem is not in the database backend. Each thread has its own database connection and its own statement handle.

 

Looking more closely at the client, this is what I see in the strace output when everything flows through one process:

 

17:52:52.762491 futex(0x7fae351c5100, FUTEX_WAIT_PRIVATE, 2, NULL)                                  = -1 EAGAIN (Resource temporarily unavailable) <0.000102>

17:52:52.762635 futex(0x7fae351c5100, FUTEX_WAIT_PRIVATE, 2, NULL)                                  = 0 <0.000664>

17:52:52.763540 futex(0x7fae351c5100, FUTEX_WAIT_PRIVATE, 2, NULL)                                  = -1 EAGAIN (Resource temporarily unavailable) <0.000027>

17:52:52.763616 futex(0x7fae351c5100, FUTEX_WAKE_PRIVATE, 1)                                        = 1 <0.000076>

17:52:52.763738 futex(0x7fae463a9f00, FUTEX_WAIT_PRIVATE, 2, NULL)                                  = -1 EAGAIN (Resource temporarily unavailable) <0.000016>

17:52:52.763793 futex(0x7fae463a9f00, FUTEX_WAKE_PRIVATE, 1)                                        = 1 <0.000010>

17:52:52.763867 futex(0x7fae351c5100, FUTEX_WAIT_PRIVATE, 2, NULL)                                  = -1 EAGAIN (Resource temporarily unavailable) <0.000038>

17:52:52.763982 futex(0x7fae351c5100, FUTEX_WAKE_PRIVATE, 1)                                        = 1 <0.000037>

17:52:52.764078 futex(0x7fae18000020, FUTEX_WAKE_PRIVATE, 1)                                        = 0 <0.000010>

17:52:52.764182 futex(0x7fae351c5100, FUTEX_WAIT_PRIVATE, 2, NULL)                                  = -1 EAGAIN (Resource temporarily unavailable) <0.000030>

17:52:52.764264 futex(0x7fae351c5100, FUTEX_WAKE_PRIVATE, 1)                                        = 1 <0.000075>

17:52:52.764401 futex(0x7fae351c5100, FUTEX_WAKE_PRIVATE, 1)                                        = 1 <0.000014>

17:52:52.764455 futex(0x7fae351c5100, FUTEX_WAIT_PRIVATE, 2, NULL)                                  = -1 EAGAIN (Resource temporarily unavailable) <0.000011>

17:52:52.764507 futex(0x7fae351c5100, FUTEX_WAKE_PRIVATE, 1)                                        = 1 <0.000025>

17:52:52.764579 futex(0x7fae351c5100, FUTEX_WAKE_PRIVATE, 1)                                        = 1 <0.000010>

17:52:52.764821 sendto(227, "\x51\x00\x00\x00\x0b\x43\x4f\x4d\x4d\x49\x54\x00", 12, MSG_NOSIGNAL, NULL, 0) = 12 <0.000029>

17:52:52.764911 recvfrom(227, 0x7fae18058760, 4096, 16384, 0, 0)                                    = -1 EAGAIN (Resource temporarily unavailable) <0.000107>

17:52:52.765065 poll([{fd=227, events=POLLIN}], 1, 4294967295)                                      = 1 ([{fd=227, revents=POLLIN}]) <0.000017>

17:52:52.765185 recvfrom(227, "\x43\x00\x00\x00\x0b\x43\x4f\x4d\x4d\x49\x54\x00\x5a\x00\x00\x00\x05\x49", 4096, MSG_NOSIGNAL, NULL, NULL) = 18 <0.000018>

17:52:52.765258 futex(0x7fae351c5100, FUTEX_WAIT_PRIVATE, 2, NULL)                                  = 0 <0.000470>

17:52:52.765764 futex(0x7fae351c5100, FUTEX_WAIT_PRIVATE, 2, NULL)                                  = -1 EAGAIN (Resource temporarily unavailable) <0.000052>

17:52:52.765908 futex(0x7fae351c5100, FUTEX_WAKE_PRIVATE, 1)                                        = 1 <0.000073>

17:52:52.766045 futex(0x7fae351c5100, FUTEX_WAKE_PRIVATE, 1)                                        = 1 <0.000040>

17:52:52.766246 futex(0x7fae351c5100, FUTEX_WAIT_PRIVATE, 2, NULL)                                  = -1 EAGAIN (Resource temporarily unavailable) <0.000026>

 

 

And perf top shows:

 

  9.89%  [kernel]                         [k] _raw_spin_unlock_irqrestore

  4.86%  [kernel]                         [k] finish_task_switch

  3.53%  [kernel]                         [k] _raw_spin_lock

  3.00%  libodbc.so.2.0.0                 [.] __check_stmt_from_dbc_v

  2.80%  [kernel]                         [k] __do_softirq

  2.43%  psqlodbcw.so                     [.] 0x000000000003b146

  1.95%  libodbc.so.2.0.0                 [.] __validate_stmt

  1.93%  libc-2.17.so                     [.] _IO_vfscanf

  1.91%  libodbc.so.2.0.0                 [.] __validate_dbc

  1.90%  psqlodbcw.so                     [.] copy_and_convert_field

  1.80%  libc-2.17.so                     [.] _int_malloc

  1.58%  libc-2.17.so                     [.] malloc

  1.42%  libc-2.17.so                     [.] _int_free

  1.36%  libodbc.so.2.0.0                 [.] __release_desc

  1.26%  libc-2.17.so                     [.] __strncpy_sse2_unaligned

  1.25%  psqlodbcw.so                     [.] mylog

  1.17%  libc-2.17.so                     [.] __offtime

  1.05%  [kernel]                         [k] vmxnet3_xmit_frame

  1.03%  psqlodbcw.so                     [.] SC_fetch

  0.91%  libc-2.17.so                     [.] __memcpy_ssse3_back

  0.89%  libc-2.17.so                     [.] __strcpy_sse2_unaligned

  0.87%  libc-2.17.so                     [.] __GI_____strtod_l_internal

  0.86%  libc-2.17.so                     [.] __tz_convert

  0.76%  libc-2.17.so                     [.] __tzfile_compute

  0.76%  psqlodbcw.so                     [.] convert_linefeeds

  0.71%  libpthread-2.17.so               [.] pthread_mutex_lock

  0.69%  [kernel]                         [k] vmxnet3_poll_rx_only

  0.66%  [kernel]                         [k] tick_nohz_idle_enter

  0.64%  libc-2.17.so                     [.] __strcmp_sse2

  0.63%  libc-2.17.so                     [.] malloc_consolidate

  0.63%  libodbc.so.2.0.0                 [.] __set_stmt_state

  0.62%  [kernel]                         [k] __audit_syscall_exit

  0.60%  libc-2.17.so                     [.] __GI_____strtoll_l_internal

  0.59%  libc-2.17.so                     [.] __memset_sse2

  0.56%  libpthread-2.17.so               [.] pthread_mutex_unlock

  0.54%  psqlodbcw.so                     [.] PGAPI_ExtendedFetch

  0.53%  [kernel]                         [k] ipt_do_table

 

So, we have severe contention, but not over actual database accesses. If I look at the PGSQL backend, I see many transactions in flight; i.e., transactions aren’t serialized. The contention appears to be over accesses to data structures:

-          With 5 processes and 80 threads of execution, the response time of the TRADE_STATUS transaction is 6.3ms @ 2718 total transactions/sec

-          With 1 process and 80 threads of execution, TRADE_STATUS response time is 44ms @ 1376 total transactions/sec

-          TRADE_STATUS has a number of function calls that reference the “stmt” handle returned by SQLAllocStmt:

o    6 to allocate the statement handle, run the query, bind input parameter, free the handle, …

o    13 SQLBindCol()

o    50 SQLFetch()

-          If I replace the 50 SQLFetch() calls with a single SQLExtendedFetch() call, response time drops to 20ms

-          If I comment out the 13 SQLBindCol() calls (which means the benchmark isn’t working right but the query still runs), it drops to 13.9ms

-          If by dropping these calls we were simply saving the execution time of their pathlength, we would have saved at most the 6.3ms we measured with 5 processes. So, the improvements we saw by avoiding the SQLBindCol() and SQLFetch() calls weren’t simply due to doing less work. They were due to avoiding contention inside those routines

                                                                                                                                                                                                                                           

Something that puzzles me is that all the calls to SQLAllocHandle(SQL_HANDLE_DBC, env_handle, &dbc_handle) set the dbc_handle to 19290 for all the threads within the process, and all the calls to SQLAllocHandle(SQL_HANDLE_STMT, dbc_handle, &stmt_handle) set the stmt_handle to 19291. Even if I call SQLAllocHandle(SQL_HANDLE_STMT, , ) multiple times to get multiple statement handles, all the handles get set to the same 19291 (and furthermore, performance gets worse even if I don’t use the new statement handles; just creating them impacts performance).

 

Is there a way to avoid all this contention, and allow multiple threads to behave like multiple processes?  The threads do not share connections, statements, etc. There should be no contention between them, and as far as I can tell, there isn’t any contention over actual resources. The contention appears to be over just accessing the ODBC data structures

 

We have unixODBC-2.3.4, built with:

./configure --prefix=/usr --sysconfdir=/etc --enable-threads=yes --enable-drivers=yes --enable-driver-conf=yes --enable-stats=no --enable-fastvalidate=yes

make

make install

My config files look like:

# cat /etc/odbcinst.ini 

# Example driver definitions

# Driver from the postgresql-odbc package

# Setup from the unixODBC package

[PostgreSQL]

Description = ODBC for PostgreSQL

Driver = /usr/lib/psqlodbcw.so

Setup = /usr/lib/libodbcpsqlS.so

Driver64 = /usr/pgsql-9.3/lib/psqlodbcw.so

Setup64 = /usr/lib64/libodbcpsqlS.so

FileUsage = 1

Threading = 0

#

# cat /etc/odbc.ini 

[PSQL2]

Description = PostgreSQL

Driver = PostgreSQL

Database = tpcv

ServerName = w1-tpcv-vm-50

UserName = tpcv

Password = tpcv

Port = 5432

[PSQL5]

Description = PostgreSQL

Driver = PostgreSQL

Database = tpcv1

ServerName = w1-tpcv-vm-60

UserName = tpcv

Password = tpcv

Port = 5432

 


[Postgresql General]     [Postgresql PHP]     [PHP Users]     [PHP Home]     [PHP on Windows]     [Kernel Newbies]     [PHP Classes]     [PHP Books]     [PHP Databases]     [Yosemite]

  Powered by Linux