본문 바로가기
IT

우분투에서 Mariadb ODBC 드라이버 메모리 오류 분석하기

by developer's warehouse 2024. 3. 5.

mariadb를 python에서 테스트하기 위해서 pyodbc를 이용해서 tpcc 테스트를 진행중입니다. 그런데, mariadb odbc 드라이버에서 메모리 할당 오류가 발생합니다. 먼저 문제를 확인하기 위해서 두 가지 방법을 사용해서 메모리 문제를 확인해본 후 드라이버를 업데이트하게 되었습니다. 이 글에서는 dbms 라이브러리에서 발생하는 메모리 오류 문제를 분석하는 과정을 기록합니다.

우분투에서 Mariadb ODBC 드라이버 메모리 오류 분석하기 썸네일

1. ODBC driver를 사용하는 프로그램에 MALLOC_CHECK_ 확인하기

glibc 라이브러리에서 메모리 오류를 확인하고 처리하는 방법을 제어하는 주요 환경 변수는 MALLOC_CHECK_입니다. 이 환경 변수의 값에 따라 다음과 같은 동작이 수행됩니다.

MALLOC_CHECK_ 값동작
0 메모리 관리 함수는 오류를 더욱 허용하며 경고를 주지 않습니다.
1 메모리 관리 함수는 문제가 발견되면 표준 오류에 경고 메시지를 출력합니다.
2 메모리 관리 함수는 문제가 발견되면 abort()를 호출합니다.

그래서, 아래와 같이 MALLOC_CHECK_=2로 놓고 프로그램을 실행하여 테스트 해 본 결과 특이사항이 발견되지 않습니다.

export MALLOC_CHECK_=2
.... 
python3 tpcc.py --no-load --client 8 mariadb
File "/home/altibase/py-tpcc/pytpcc/drivers/mariadbdriver.py", line 513, in doPayment
    self.cursor.execute(q["updateBCCustomer"], [c_balance, c_ytd_payment, c_payment_cnt, c_data, c_w_id, c_d_id, c_id])
pyodbc.OperationalError: ('HY001', '[HY001] [ma-3.2.1][10.6.16-MariaDB-0ubuntu0.22.04.1]Memory allocation error (0) (SQLPutData)')
Aborting some transaction with some error PAYMENT ('HY001', '[HY001] [ma-3.2.1][10.6.16-MariaDB-0ubuntu0.22.04.1]Memory allocation error (0) (SQLPutData)')

 

2. valgrind 확인해보기

valgrind는 리눅스에서 메모리 오류와 누수(leak)를 검출하는데 사용되는 오픈소스 도구입니다. 이 툴은 바이너리를 수행할 때 이 툴을 통해서 실행시키면 메모리 누수와 오류등을 확인할 수 있습니다.

저의 경우 python에서 동작하는 mariadb의 odbc 프로그램에서 메모리 누수가 의심되는데, 다음과 같이 python 앞에 valgrind를 넣어주면 메모리 오류를 확인할 수 있습니다.

~/py-tpcc/pytpcc$ valgrind --leak-check=full --show-leak-kinds=all --error-limit=no python3 tpcc.py --no-load --client 8 mariadb

 

결과는 다음과 같이 나타납니다.

==601017==    by 0x24B26C: _PyEval_EvalFrameDefault (in /usr/bin/python3.10)
==601017==    by 0x2629FB: _PyFunction_Vectorcall (in /usr/bin/python3.10)
==601014== For lists of detected and suppressed errors, rerun with: -s
==601017==
==601014== ERROR SUMMARY: 67 errors from 67 contexts (suppressed: 0 from 0)
==601015== LEAK SUMMARY:
==601015==    definitely lost: 352 bytes in 11 blocks
==601015==    indirectly lost: 0 bytes in 0 blocks
==601015==      possibly lost: 56,493 bytes in 91 blocks
==601015==    still reachable: 3,548,257 bytes in 5,018 blocks
==601015==         suppressed: 0 bytes in 0 blocks
==601015== Reachable blocks (those to which a pointer was found) are not shown.
==601015== To see them, rerun with: --leak-check=full --show-leak-kinds=all
==601015==
==601015== For lists of detected and suppressed errors, rerun with: -s
==601015== ERROR SUMMARY: 67 errors from 67 contexts (suppressed: 0 from 0)
==601017== 9,608 bytes in 12 blocks are possibly lost in loss record 1,517 of 1,564
==601017==    at 0x4848899: malloc (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==601017==    by 0x224587: _PyObject_GC_NewVar (in /usr/bin/python3.10)
==601017==    by 0x24A2E6: ??? (in /usr/bin/python3.10)
==601017==    by 0x2629CD: _PyFunction_Vectorcall (in /usr/bin/python3.10)
==601017==    by 0x24B26C: _PyEval_EvalFrameDefault (in /usr/bin/python3.10)
==601017==    by 0x2629FB: _PyFunction_Vectorcall (in /usr/bin/python3.10)
==601017==    by 0x24B26C: _PyEval_EvalFrameDefault (in /usr/bin/python3.10)
==601017==    by 0x2629FB: _PyFunction_Vectorcall (in /usr/bin/python3.10)
==601017==    by 0x24B26C: _PyEval_EvalFrameDefault (in /usr/bin/python3.10)
==601017==    by 0x2629FB: _PyFunction_Vectorcall (in /usr/bin/python3.10)
==601017==    by 0x24B26C: _PyEval_EvalFrameDefault (in /usr/bin/python3.10)
==601017==    by 0x2629FB: _PyFunction_Vectorcall (in /usr/bin/python3.10)
==601017==
==601017== LEAK SUMMARY:
==601017==    definitely lost: 1,081 bytes in 13 blocks
==601017==    indirectly lost: 799 bytes in 1 blocks
==601017==      possibly lost: 59,253 bytes in 96 blocks
==601017==    still reachable: 3,558,337 bytes in 5,023 blocks
==601017==         suppressed: 0 bytes in 0 blocks
==601017== Reachable blocks (those to which a pointer was found) are not shown.
==601017== To see them, rerun with: --leak-check=full --show-leak-kinds=all
==601017==
==601017== For lists of detected and suppressed errors, rerun with: -s
==601017== ERROR SUMMARY: 74 errors from 74 contexts (suppressed: 0 from 0)

 

위에서 LEAK SUMMARY에서 보면 결론적으로 메모리 누수가 있을 수 있다고 나타나고 있기 때문에 드라이버를 업데이트 해보기로 하였습니다.

 

분석 결론

제가 사용한 mariadb 라이브러리는 아래와 같았습니다.

[ma-3.2.1][10.6.16-MariaDB-0ubuntu0.22.04.1

두 가지 증거를 이용해서 위의 버전에 메모리 누수가 있다고 생각하게 되었는데,

1. 동일한 소스로 mariadb 이외의 다른 db를 실행시에는 에러가 나타나지 않았다.

2. valgrind에서 메모리 leak 이 보고되었다.

때문에 mariadb의 odbc 드라이버를 업데이트해 보기로 하였습니다. mariadb의 odbc 드라이버 업데이트하고 사용하는 법은 다음 포스팅에서 계속하겠습니다.

 

 

 

 

facebook twitter kakaoTalk kakaostory naver band shareLink