そろそろLDAPにしてみないか?

第19回OpenLDAPの冗長化対策【1】

はじめに

構築当初はアドレス帳データしか存在しなかったテスト用LDAPサーバでも、それを本格的に運用すると、⁠データの集中管理」だけでなく「サービスの安定性」を検討する必要があります。いわゆるサーバ、ネットワークの世界で「冗長化」「二重化」と呼ばれている部分です。

恐らく読者の皆さんの中にも、⁠集中管理で便利なのはわかるけど、センター側の障害を想像すると導入に踏み切れない」という方がいらっしゃるのではないでしょうか?

OpenLDAPに限らず、安定したサービスを提供するためには

  • 信頼性の高いハードウェアでサービスを構築する(RAID1、電源冗長化等含む)
  • 信頼性の高い(安定した)OSでサービスを提供する
  • 社内ではなくデータセンターなど安全な場所で運用を行う(停電、自然災害対策)
  • 万が一に備え、ハード、ソフト共に保守契約を結んでおく

などいくつかの要素が考えられます。これらは予算さえかければ簡単に実現できることです。しかし、ディスクだけでなくサーバ自身が故障した場合には、どうしてもサービス断が発生するため、規模やサービス内容によっては複数のLDAPサーバを利用し、サービスの冗長化を目指さなければなりません。

非常に重要な部分ですので、今回から何回かに分けてOpenLDAPの冗長化対策についてお話ししていきたいと思います。

OpenLDAPの持つ冗長化機能

OpenLDAPはご存じのように、サーバ機能を司るslapd、クライアント機能となる各種コマンドやライブラリで構成されており、それらはいくつかの冗長機能を備えています。

たとえば、サーバ側、つまりslapdが有する冗長機能のひとつがsyncreplです。この機能を活用することで、複数のサーバにデータをリアルタイムに複製することができます。

syncreplのデメリットとしては、複数ノードがマスタ兼スレーブとなるマルチマスタ機能がまだ完全には動作しないことでしょうか。最近のバージョンでは一応マルチマスタ機能がサポートされているのですが、実際に運用してみると、筆者の環境では負荷やエントリ数次第でサービスがストップしてしまいました。

さて、syncreplの具体的な設定に関しては次回以降詳しく解説するとして、これらの機能を利用してサーバの台数を増やしたところで、クライアントがその複数のサーバをうまく参照しない限り、データの複製に意味はありません。言い換えると、クライアントがうまく複数サーバを認識、参照することで、冗長機能はもちろんのこと、負荷分散による負荷の軽減、サービスの高速化を期待することができます。

C言語でLDAPサーバへの接続を行う場合、ldap_init関数やldap_open関数を使用します。

たとえば1番目のLDAPサーバが使用できなかった場合に別のサーバに接続するためには

リスト1
// 最初のサーバに接続
ld = ldap_open("localhost", 389); 
if (ld == NULL) { 
  // 次のサーバに接続
  ld = ldap_open("nexthost", 389); 
  ....
} 

のように記述することができます。しかしこれでは3台以上のサーバに接続する場合にコードが増えてしまいますし、ホスト名やポート番号を設定ファイルから読み込む場合はさらに処理が増えて大変です。また、細かいところをいえばldap_init関数とldap_open関数の挙動の違いについても考慮する必要があるでしょう。

ここで活躍するのがldap_initializeという関数です。ldap_initialize関数ではLDAP URIを引数として使用することができますので、上記の例は

リスト2
ldap_initialize(&ld, "ldap://localhost:389 ldap://nexthost:389"); 

と置き換えることができます。もしLDAPクライアントを開発される場合には、このように複数サーバを参照できるような親切設計を心がけてください。

さて、さまざまなLDAPクライアントがこのような複数サーバの定義をサポートしていればよいのですが、商用ソフトウェアの一部はそれをサポートしていません(涙⁠⁠。この場合、クライアント側でサーバの選択をすることが出来ないため、複数サーバに仮想IPとなるVIPを持たせ、複数台のサーバをあたかも1台のサービスのように見せる必要があります。この詳細も次回以降お伝えする予定です。

基本的な冗長化構成例

一言でOpenLDAPの冗長化構成といっても、予算や用途によって大きく変わりますが、まずは一般的な構成を次図に示します。

図1 syncreplによるデータの複製とクライアントからの参照(1)
図1 syncreplによるデータの複製とクライアントからの参照(1)
図2 syncreplによるデータの複製とクライアントからの参照(2)
図2 syncreplによるデータの複製とクライアントからの参照(2)

この構成では、OpenLDAPのsyncrepl機能を使ってデータを複製しています。マスターとなるサーバはサプライヤ、スレーブとなるサーバはコンシューマと呼ばれ、サプライヤで更新されたデータはすぐにコンシューマ側に反映される仕組みです。また、障害はクライアント側によって検知し切り替えが行われます。

データの更新はサプライヤ側で行われる必要がありますので、LDAP2側では

updateref ldap1

のように、LDAP2側に更新要求が発生した場合はLDAP1側へ要求をリダイレクトする設定が必要になります。このリダイレクト通知はサーバ間で処理されるわけではなく、LDAP2からクライアントに伝えられるため、リダイレクト通知を受け取ったクライアント自身が次の挙動を決めなければなりません。つまり、クライアントによっては更新時にうまくサーバの切り替えを行うことができないことになります。

参考までに、OpenLDAPクライアントライブラリの中には

ldap_set_option(ld, LDAP_OPT_REFERRALS, LDAP_OPT_ON); 

のようなREFERRALSの指定が出来るのですが、手元で試してみたところ、検索時にはうまくリダイレクト通知に従い実サーバからの検索を行うことが出来ましたが、追加、更新時にはマスターサーバのデータを更新することが出来ませんでした。設定次第で更新時にもREFERRALSを追えそうなものですが、今回は時間の都合でうまく検証できなかったため、以後余裕があれば追求してみたいと思います。

いずれにせよ、マルチマスタ機能を実装しない限り、サプライヤがダウンしてしまうと追加、更新作業が滞ってしまうことに違いはなく、これでは完全な対策とは言えません。

しかし、LDAPサーバに保存されるデータは頻繁には更新されないことがほとんどです。サーバポリシーにも依存しますが、もしデータの更新が数日に一度、という頻度であれば、サプライヤの障害を数時間で復旧させるだけで良いため、この構成でも十分に実用的と言えます。

さて、ページの都合上中途半端になってしまいましたが、今回はこの「基本形」を十分に理解していただくとともに、次回は「更新が頻繁に発生する場合」⁠クライアントが複数サーバに対応していない場合」などそれ以外のシチュエーションを想定した構成と具体的な設定について紹介する予定です。

おすすめ記事

記事・ニュース一覧