본문 바로가기

Advanced MySQL

27. InnoDB now supports native AIO on Linux

원문 : http://blogs.innodb.com/wp/2010/04/innodb-performance-aio-linux/


InnoDB now supports native AIO on Linux

InnoDB가 이제 리눅스에서 native AIO를 지원한다.

 

With the exception of Windows InnoDB has used ’simulated AIO’ on all other platforms to perform certain IO operations. The IO requests that have been performed in a ’simulated AIO’ way are the write requests and the readahead requests for the datafile pages. Let us first look at what does ’simulated AIO’ mean in this context.

윈도우를 제외하고 InnoDB는 지금까지 모든 플랫폼에서 확실한 IO 수행을 위해 가상 AIO’를 사용해왔다. ‘가상 AIO’에서 수행되어온 IO 요청들은 데이터파일 페이지들에 대한 요청을 쓰는 것과 미리 읽어오는 것이었다. 우선 가상 AIO’가 무엇인지 알아보자.

 

We call it ’simulated AIO’ because it appears asynchronous from the context of a query thread but from the OS perspective the IO calls are still synchronous. The query thread simply queues the request in an array and then returns to the normal working. One of the IO helper thread, which is a background thread, then takes the request from the queue and issues a synchronous IO call (pread/pwrite) meaning it blocks on the IO call. Once it returns from the pread/pwrite call, this helper thread then calls the IO completion routine on the block in question which includes doing a merge of buffered operations, if any, in case of a read. In case of a write, the block is marked as ‘clean’ and is removed from the flush_list. Some other book keeping stuff also happens in IO completion routine.

우리가 이것을 가상 AIO’라고 부르는 이유는 쿼리 쓰레드는 비동기식인 것으로 보이지만 실제로 OS 관점에서 IO 요청은 여전히 동기식이기 때문이다. 쿼리 쓰레드는 단순히 요청을 큐에 쌓고 일반적인 작업으로 돌아온다. 백그라운드 쓰레드인 IO helper 쓰레드는 큐에서 요청을 꺼내 동기식 IO 요청(pread/pwrite)를 실행하며 이는 IO 요청동안 블록됨을 의미한다. pread/pwrite 요청이 반환되면, 읽기 작업인 경우 이 helper 쓰레드는 해당 블록에 대해 쌓였던 요청들을 합치는 작업이 포함된 IO 완료 루틴을 호출한다. 쓰기 작업인 경우, 해당 블록은 ‘clean’ 상태로 표시되고 flush_list 에서 제거된다. 몇몇 다른 예약된 작업들도 IO 완료 루틴에서 발생한다.

 

What we have changed in the InnoDB Plugin 1.1 is to use the native AIO interface on Linux. Note that this feature requires that your system has libaio installed on it. libaio is a thin wrapper around the kernelized AIO on Linux. It is different from Posix AIO which requires user level threads to service AIO requests. There is a new boolean switch, innodb_use_native_aio, to choose between simulated or native AIO, the default being to use native AIO.

InnoDB Plugin 1.1 에서 우리가 변경한 것은 리눅스의 native AIO를 이용하도록 한 것이다. 이 기능은 당신의 시스템에 libaio가 설치되어있어야 함을 잊지 말자. libaio는 리눅스 커널에서의 AIO를 처리하기 위한 thin wrapper 이다. 이것은 AIO 요청을 제공하기 위해 사용자 레벨의 쓰레드를 요구하는 표준(Posix) AIO 와는 다른 것이다. 가상 AIO native AIO를 선택하기 위해 innodb_use_native_aio 라는 boolean 스위치가 있으며, 기본값은 native AIO를 사용하는 것이다.

 

How does this change the design of the InnoDB IO subsystem? Now the query thread instead of enqueueing the IO request actually dispatches the request to the kernel and returns to the normal working. The IO helper thread, instead of picking up enqueued requests, waits on the IO wait events for any completed IO requests. As soon as it is notified by the kernel that a certain request has been completed it calls the IO completion routine on that request and then returns back to wait on the IO wait events. In this new design the IO requesting thread becomes kind of a dispatcher while the background IO thread takes on the role of a collector.

이는 InnoDB IO 시스템에 어떠한 영향을 주었을까? 이제 쿼리 쓰레드는 IO 요청을 큐에 쌓는 대신 바로 커널에 요청을 한 뒤 일반 작업으로 복귀한다. IO helper 쓰레드는 큐에서 요청을 꺼내는 대신 IO 처리 완료를 뜻하는 IO wait 이벤트를 기다린다. 커널로부터 요청이 완료되었다는 알림을 받으면 요청에 대한 IO 완료 루틴을 호출하고 다시 IO wait 이벤트를 기다린다. 이러한 새로운 구조에서 백그라운드 IO 쓰레드는 수집역할을 하는 반면, IO 요청 쓰레드는 발송만을 담당하게 된다.

 

What will this buy us? The answer is simple – scalability. For example, consider a system which is heavily IO bound. In InnoDB one IO helper thread works on a maximum of 256 IO requests at one time. Assume that the heavy workload results in the queue being filled up. In simulated AIO the IO helper thread will go through these requests one by one making a synchronous call for each request. This means serialization forcing the request that is serviced last to wait for the other 255 requests before it gets a chance. What this implies is that with simulated AIO there can be at most ‘n’ IO requests in parallel inside the kernel where ‘n’ is the total number of IO helper threads (this is not entirely true because query threads are also allowed to issue synchronous requests as well, but I’ll gloss over that detail for now). In case of native AIO all 256 requests are dispatched to the kernel and if the underlying OS can service more requests in parallel then we’ll take advantage of that.

이것이 우리에게 무슨 도움이 될 것인가? 답은 간단하다 확장성. 예를 들어, IO 작업이 많은 시스템을 고려해보자. InnoDB에서 하나의 IO helper 쓰레드는 한 번에 최대 256개의 IO 요청을 처리한다. 엄청난 작업이 큐를 채우고 있다고 가정하자. 가상 AIO에서 IO helper 쓰레드는 하나의 요청에 대해서 동기(synchronous)작업을 해야 하므로 요청을 하나씩 처리하게 된다. 이는 순차적으로 요청이 처리되고, 처리가 완료되기 전에는 나머지 255개의 요청은 기다려야만 한다는 것을 의미한다. 이는 가상 AIO에서는 IO helper 쓰레드가 총 n개 동작 중 이면, 최대 n개의 IO 요청이 커널에서 병행처리가 가능하다는 것을 의미한다(이는 쿼리 쓰레드들도 동기적 요청을 수행할 수 있기 때문에 완전히 사실은 아니다). native AIO 에서는 모든 256개의 요청들은 커널로 보내지고 OS가 요청을 더 받을 수 있다면 우리는 그 이득을 더 얻을 수 있다.

 

The idea of coalescing contiguous requests is now off loaded to the kernel/IO scheduler. What this means is that which IO scheduler you are using or the properties of your RAID/disk controller may now have more affect on the overall IO performance. This is also true because now many more IO requests will be inside the kernel than before. Though we have not run tests to specifically certify any particular IO scheduler the conventional wisdom has been that for database engine workloads perhaps no-op or deadline scheduler would give optimal performance. I have heard that lately a lots of improvements have gone in cfq as well. It is for you to try and as always YMMV. And we look forward to hear your story.

인접한 요청을 합치는 아이디어는 커널 IO 스케줄러의 부하를 낮추어준다. 이는 당신이 사용하는 IO 스케줄러나 당신의 RAID/disk 컨트롤러의 속성이 IO 성능에 더 큰 영향을 줄 수도 있음을 의미한다. 요즈음은 전에 비해 더 많은 IO 요청이 커널안에 있기 때문에 사실이다. 우리가 비록 각각의 IO 스케줄러에 대해 테스트를 해본 것은 아니지만, 전통적으로 데이터베이스 엔진에는 no-op 또는 deadline 스케줄러가 최적의 성능을 낸다고 한다. 또한 최근에는 cfs 에서도 성능이 좋다는 이야기를 많이 들었다. 시도해보는 것은 당신 몫이며, 결과 또한 경우마다 다르다(YMMV – your mileage may vary). 우리는 당신의 결과를 들어보는 것을 기대한다.

 

NOTE:InnoDB has always used native AIO on Windows and it continues to do so in Plugin 1.1. innodb_use_native_aio will have no affect on Windows.

참고 : InnoDB Windows에서 native AIO 를 계속 사용해 왔으며, 이는 Plugin 1.1에도 지속되고 있다. Innodb_use_native_aio Windows 에서 아무런 영향을 주지 못한다.

 

# 참고자료

Synchronous and Asynchronous I/O

In synchronous file I/O, a thread starts an I/O operation and immediately enters a wait state until the I/O request has completed. A thread performing asynchronous file I/O sends an I/O request to the kernel by calling an appropriate function. If the request is accepted by the kernel, the calling thread continues processing another job until the kernel signals to the thread that the I/O operation is complete. It then interrupts its current job and processes the data from the I/O operation as necessary.


Figure 1 – The two synchronization types

In situations where an I/O request is expected to take a large amount of time, such as a refresh or backup of a large database or a slow communications link, asynchronous I/O is generally a good way to optimize processing efficiency. However, for relatively fast I/O operations, the overhead of processing kernel I/O requests and kernel signals may make asynchronous I/O less beneficial, particularly if many fast I/O operations need to be made. In this case, synchronous I/O would be better. The mechanisms and implementation details of how to accomplish these tasks vary depending on the type of device handle that is used and the particular needs of the application. In other words, there are usually multiple ways to solve the problem.

http://msdn.microsoft.com/en-us/library/aa365683(v=vs.85).aspx