MySQL, Linux, and Thread Caching

와우, 바쁜 한 주였습니다. 나는 remember.yahoo.com MySQL 서버 및 관련 항목을 다루는 며칠 동안 완전히 늪에 빠졌습니다. 그리고 하루나 이틀을 회복하는 데 사용했습니다 (수면, 샤워 등).

어쨌든, 나는 그 과정에서 몇 가지 흥미로운 발견을 했다. 가장 놀라운 것은 바쁜 MySQL 서버가 있을 때 Linux에서 스레드 캐싱과 관련이 있습니다.

아시다시피, 우리는 누군가가 변경할 때마다 모든 웹 서버가 (PHP 사용) 연결할 수있는 단일 마스터 서버를 가지고있었습니다. 여기에는 타일 만들기(수십만 개의 타일이 생성됨), 타일을 승인하고, 타일을 “멋지다”로 표시하는 등의 작업이 포함됩니다. 주인은 꽤 바빴습니다.

그 기간 동안 20 개에서 45 개 사이의 프론트 엔드 웹 서버가 있었고 각 서버에는 연결에 필요한 최대 70 개의 아파치 프로세스가 있었을 수 있기 때문에 문제가 발생했습니다. 즉, 마스터는 최악의 경우 최대 3,150 개의 연결을 처리해야했습니다 (45 x 70). 대부분의 PHP 코드는 영구 연결을 유지하는 데 mysql_pconnect()사용됩니다.

그 방법에 대해 걱정하기보다는 wait_timeout매우 낮은 값인 15초로 설정했는지 확인했습니다. 즉, MySQL은 15초 이상 유휴 상태인 모든 연결을 닫습니다. 그러나 마스터가 연결을 거부하고 있다는 웹 서버에서 보고를 받기 전까지는 문제의 정도를 깨닫지 못했습니다. 왜? 마스터의 my.cnf 파일에서 최대 연결 수를 적절한 값으로 설정했기 때문에

set-variable = max_connections=180
set-variable = max_user_connections=140

그리고 그 때, wait_timeout600 초 (10 분)로 설정되어 있었습니다. 분명히 그것은 문제였습니다. 연결을 유지하고 새 클라이언트가 연결하고 실제 작업을 수행하는 것을 차단하는 유휴 클라이언트가 많았습니다.

해야 할 일은 무엇이었을까요?

mysql_pconnect()의 사용을 중단할 수도 있었지만 보시다시피 근본적인 문제는 해결되지 않았을 것입니다.

I needed to adjust the settings. But I wasn’t sure what values to use. And I really didn’t want to keep stopping and starting the master. That would just suck. Then I remembered that we were running MySQL 4.0.4. I’d has a new feature that allows you to change most of the server settings on on the fly without restarting! Read about here, it in the on-line manual.

Excellent!

All I needed to do was execute a few variations on this command:

SET GLOBAL wait_timeout=60;

(with different values in the place of “60”) to try and strike a balance between letting new clients in and kicking out already connected users too quickly.

Ultimately, I settled on a timeout of 15 seconds.

But that had an interesting and unanticipated side-effect. It meant that the Linux server was having to create new threads (MySQL is a multi-threaded server) at a very high rate. That sucks up a measurable amount of CPU time.

CPU 시간은 얼마입니까? 내가 SHOW STATUS출력을 보고 이것을 보았을 때

| Threads_cached           | 0          |
| Threads_created          | 270194     |
| Threads_connected        | 46         |
| Threads_running          | 28         |

상황이 꽤 나빴습니다. 컴퓨터의 유휴 CPU 시간은 거의 없었으며 기껏해야 5-10 % 정도였습니다. 그러나 실제로는 초당 40 개의 쿼리를 수행하는 것이 아닙니다. 나는 조금 당황했다. 그러나 Threads_created 숫자가 나에게 튀어 나왔다. 그것은 높았고 빠르게 증가했습니다.

운 좋게도 나는 thread_cache 설정을 기억했다. 그래서 조사하기로 결정했습니다 (서버 변수를 검사하기 위한 새 구문 사용).

mysql> SELECT @@global.thread_cache_size;
+---------------------+
| @@thread_cache_size |
+---------------------+
|                   0 |
+---------------------+
1 row in set (0.00 sec)

Uh oh. I never set the thread cache in my.cnf, so it has assumed the default. That’s bad. It’s like removing the pre-forking capabilities of Apache 1.3 and letting it get pounded on a busy web site. The “fork a new process for each new request” gets pretty expensive pretty quickly.

윽!

운 좋게도 스레드 캐시는 이제 즉석에서 조정할 수 있습니다. 그래서 내가 해야 할 일은 이것이었다.

SET GLOBAL thread_cache_size=40;

추측을 해보고 40 개의 스레드를 캐싱하면 많은 작업을 절약 할 수 있다고 생각했습니다. 그리고 소년은 내가 옳았다!

In the other window, where I was running vmstat 1 I noticed a dramatic change. The idle CPU on the machine immediately went from 5-10% to 35-40%

If only I had thought of that sooner!

따라서 이 이야기의 교훈은 이것입니다: 빠른 연결이 많은 사용량이 많은 서버가 있는 경우 SHOW STATUS로 Threads_created의 증가를 멈추게 할 스레드 캐시를 충분히 높게 설정하여 값이 증가하지 않도록 합니다. CPU가 고마워할 것입니다.

그래도 기분이 나쁘지는 않습니다. 우리는 모두 실행 중이고 잠을 거의 않는 동안 코드와 서버를 조정/최적화하기 위해 미쳐가고 있었습니다. 스레드 캐싱은 실제로 우리의 문제 중 최악이 아니 었습니다. 그러나 우리가 더 큰 것을 모두 고친 후에는 최악이되었습니다.

그것은 꽤 많은 학습 경험이었습니다.

Posted by jzawodn at September 14, 2002 04:42 PM

Leave a Comment