未来のいつか/hyoshiokの日記

hyoshiokの日々思うことをあれやこれや

スケーラビリティの向上

そもそも、スケーラビリティって何よ?という疑問はあるのだが、それはおいておいて、CPUの数が増えた時、それに比例して性能向上したらうれしいなあと言う程度のアバウトな事を考える。性能向上って何よ?という疑問はあるのだが、CPUの数が増えた時、処理できる量が増えたらうれしいなあという程度のアバウトな事を考える。処理時間が減るという方向もあるけど、ここでは処理量(スループット)を考える。

で、古典的な問題は、CPUに分散された処理の同期をどうとるかというやつである。素朴な方法はロックをして同期をする。別にロックだけが同期の方法じゃないのだけど、一番(?)素朴な方法なのでよく利用されている。

非常に素朴なロックの実装だと、一つのロックで全てのCPUの同期を取ろうとする。ロックの影響範囲がでかいのでジャイアントロックなんてよばれたりする。むかしのLinux Kernel 2.2あたりはそのような素朴なロックを利用していた。もちろん、賢明なる読者諸氏の指摘のとおり、そのような実装だとロックの競合は多発してスケーラビリティがでない。一つのCPUがロックを握ってしまうと他のCPUがそれをひたすら待つだけなので性能が出るわけないのだ。ぼーっと待つCPUは無駄な時間を費している。

ロックの範囲あるいは大きさをロックの粒度(granularity)などというが、上記の問題の素朴な解決策はその粒度を小さくすることである。CPU全体で一個のロックではなくて、別の小さい単位でロックをする。そうすると、ロックを競合する可能性が減るのでロックで待つ可能性が減ってスケーラビリティが向上する。

これはOSだけの話ではなくてRDBMSやその他のミドルウェア、アプリケーション等々共通のお話である。ロックの競合が発生してスケーラビリティ上の問題が発生したらロックの粒度を小さくしろと。Linuxカーネルは2.6になって、スケーラビリティが大変向上したのは、そのような改良を繰り返したからである。

PostgreSQLも8.1でそのような改良を施したようだ。MySQLはまだまだのようである。なので、MySQLのロック回りを改良すればMySQLのコミュニティに華々しくデビューすることができる。

ロックの粒度を小さくすることと、ロックをしている時間を短くすること。これをoprofileなどのプロファイリングツールを利用して、どのロックが頻繁に呼ばれているかを測定し、そのロックを回避する方法をソースコードレベルで分析する。そして、ロックの粒度を下げるアルゴリズムを考える。例えば、RDBMSのバッファーに対するロックが一つだけだったとする。そうしたら、そのロックの単位をページ単位や行単位に小さくできないか検討する。あるいはロック無しで同期を取る方法を考えたりする。

そのような中でいろいろ試行錯誤をして、有効性のある方法、ない方法、等々を検討していく。なかなか楽しそうなお話である。