SFEX (Shared Disk File EXclusiveness Control Program)

目的

SFEXはActive-Standbyのクラスタ構成で運用中、Heartbeat通信が切れた場合に両ノードがActiveとなる(スプリットブレイン状態)ことを防ぐために使用します。

ダウンロード

バイナリファイルはRHEL5用です。

基本的な考え方

シーケンス図

起動処理

SFEXはcib.xmlの中で高いスコアが付けられたノードで開始されます。そのため、複数のノードで、同時に共有ディスクにアクセスすることはありません。

Node A

  1. SFEXは共有ディスクからデータを読み、"status"を取得します。通常、共有ディスクはだれにも所有されていないので"status"は"NO_OWNED"となります。
  2. node=Node Aとstatus=OWNEDを含むデータを書き込みます。
  3. 再びデータを読み込み、node="Node A"のデータを取得します。
  4. 自身のノード名と比較します。ノード名が変更されていなければ、Node Aが所有権を獲得します。
  5. SFEXはその後、Heartbeatのモニタ処理によって共有ディスク上の"count"の値をインクリメントします。

この処理は所有権の更新を意味します。

Heartbeat通信断

Node A

  1. SFEXはHB更新処理によって所有権を更新します。

Node B

  1. heartbeat通信が失敗したとき、スタンバイノード(Node B)はリソースを起動します。
  2. SFEXは共有ディスク上のデータを読み込みます。
  3. しばらく処理を待ちます。(待ち時間はsfexのモニタ間隔より長くするべきです。この待ち時間により、Node Aによる定期的な更新を待ち、Node Aが所有権を持っていることを確認します。)
  4. 再びデータを読み込みます。
  5. 新しい"count"の値を確認します。二つの"count"の値が異なった場合、Node Aが動作中であると判断できます。
  6. Node Aが動作中であるため、SFEX起動処理は停止します。

アクティブノードのダウン

Node A

  1. 故障によってNode Aがダウン

Node B

このNode B起動処理はHB通信断と同じように行われます。

  1. しばらく待ちます。(Node Aの定期的な更新を待つが、Node Aが更新するこを確認できない)
  2. SFEXはデータを再び読みます。
  3. 新旧、二つの"count"の値を比較すると"count"の値が同じになります。これはNode Aがダウンしていると判断できます。
  4. node=Node B と stauts=OWNEDを含むデータをディスクに書き出します。
  5. データを再び読み込みます。
  6. 自身のノード名と比較します。ノード名が変更されていなければ、Node Bが所有権を獲得します。
  7. その後、他のリソースも起動します。

複数ノードからの同時のディスクアクセス

この事象はほとんど発生しません。しかしながら、heartbeat通信が切れた状態で同時に複数のノードが起動された場合などに発生します。

Node A / Node B 共有ディスクへの書き込みは最終的にシリアライズされます。書き込みできるエリアは"一つ"であるためです。その結果、最後に書き込まれたノード名が残ります。 この例では、Node Bが残ります。

  1. データを再び読み込みます。
  2. Node A:"owner"の値が変更になります。このノードは所有権を獲得できません。Node B:Node Bの名前が"owner"の値になります。Node Bが所有権を取得します。

SFEXを使う場合のcib.xml(サンプル)

 <cib admin_epoch="0" epoch="1" have_quorum="false" cib_feature_revision="1.3">
  <configuration>
    <crm_config>
      <cluster_property_set id="set01">
        <attributes>
          <nvpair id="symmetric-cluster"
            name="symmetric-cluster" value="true"/>
          <nvpair id="no-quorum-policy"
            name="no-quorum-policy" value="ignore"/>
          <nvpair id="stonith-enabled"
            name="stonith-enabled" value="false"/>
          <nvpair id="short-resource-names"
            name="short-resource-names" value="true"/>
          <nvpair id="is-managed-default"
            name="is-managed-default" value="true"/>
          <nvpair id="default-resource-stickiness"
            name="default-resource-stickiness" value="INFINITY"/>
          <nvpair id="stop-orphan-resources"
            name="stop-orphan-resources" value="true"/>
          <nvpair id="stop-orphan-actions"
            name="stop-orphan-actions" value="true"/>
          <nvpair id="remove-after-stop"
            name="remove-after-stop" value="false"/>
          <nvpair id="default-resource-failure-stickiness"
            name="default-resource-failure-stickiness" value="-INFINITY"/>
          <nvpair id="stonith-action"
            name="stonith-action" value="reboot"/>
          <nvpair id="default-action-timeout"
            name="default-action-timeout" value="120s"/>
          <nvpair id="dc-deadtime"
            name="dc-deadtime" value="10s"/>
          <nvpair id="cluster-recheck-interval"
            name="cluster-recheck-interval" value="0"/>
          <nvpair id="election-timeout"
            name="election-timeout" value="2min"/>
          <nvpair id="shutdown-escalation"
            name="shutdown-escalation" value="20min"/>
          <nvpair id="crmd-integration-timeout"
            name="crmd-integration-timeout" value="3min"/>
          <nvpair id="crmd-finalization-timeout"
            name="crmd-finalization-timeout" value="10min"/>
          <nvpair id="cluster-delay"
            name="cluster-delay" value="180s"/>
          <nvpair id="pe-error-series-max"
            name="pe-error-series-max" value="-1"/>
          <nvpair id="pe-warn-series-max"
            name="pe-warn-series-max" value="-1"/>
          <nvpair id="pe-input-series-max"
            name="pe-input-series-max" value="-1"/>
          <nvpair id="startup-fencing"
            name="startup-fencing" value="true"/>
        </attributes>
      </cluster_property_set>
    </crm_config>
    <nodes/>
    <resources>
      <group id="grpPostgreSQLDB">
        <primitive id="prmExPostgreSQLDB" class="ocf" type="sfex" provider="heartbeat">
          <operations>
            <op id="exPostgreSQLDB_start"
              name="start" timeout="180s" on_fail="fence"/>
            <op id="exPostgreSQLDB_monitor"
              name="monitor" interval="10s" timeout="60s" on_fail="fence"/>
            <op id="exPostgreSQLDB_stop"
              name="stop" timeout="60s" on_fail="fence"/>
          </operations>
          <instance_attributes id="atrExPostgreSQLDB">
            <attributes>
              <nvpair id="dskPostgreSQLDB"
                name="device" value="/dev/cciss/c1d0p1"/>
              <nvpair id="idxPostgreSQLDB"
                name="index" value="1"/>
              <nvpair id="cltPostgreSQLDB"
                name="collision_timeout" value="1"/>
              <nvpair id="lctPostgreSQLDB"
                name="lock_timeout" value="70"/>
              <nvpair id="mntPostgreSQLDB"
                name="monitor_interval" value="10"/>
              <nvpair id="fckPostgreSQLDB"
                name="fsck" value="/sbin/fsck -p /dev/cciss/c1d0p2"/>
              <nvpair id="fcmPostgreSQLDB"
                name="fsck_mode" value="check"/>
              <nvpair id="hltPostgreSQLDB"
                name="halt" value="/sbin/halt -f -n -p"/>
            </attributes>
          </instance_attributes>
        </primitive>
        <primitive id="prmFsPostgreSQLDB" class="ocf" type="Filesystem" provider="heartbeat">
          <operations>
            <op id="fsPostgreSQLDB_start"
              name="start" timeout="60s" on_fail="fence"/>
            <op id="fsPostgreSQLDB_monitor"
              name="monitor" interval="10s" timeout="60s" on_fail="fence"/>
            <op id="fsPostgreSQLDB_stop"
              name="stop" timeout="60s" on_fail="fence"/>
          </operations>
          <instance_attributes id="atrFsPostgreSQLDB">
            <attributes>
              <nvpair id="devPostgreSQLDB"
                name="device" value="/dev/cciss/c1d0p2"/>
              <nvpair id="dirPostgreSQLDB"
                name="directory" value="/mnt/shared-disk"/>
              <nvpair id="fstPostgreSQLDB"
                name="fstype" value="ext3"/>
            </attributes>
          </instance_attributes>
        </primitive>
        <primitive id="prmIpPostgreSQLDB" class="ocf" type="IPaddr" provider="heartbeat">
          <operations>
            <op id="ipPostgreSQLDB_start"
              name="start" timeout="60s" on_fail="fence"/>
            <op id="ipPostgreSQLDB_monitor"
              name="monitor" interval="10s" timeout="60s" on_fail="fence"/>
            <op id="ipPostgreSQLDB_stop"
              name="stop" timeout="60s" on_fail="fence"/>
            </operations>
          <instance_attributes id="atrIpPostgreSQLDB">
            <attributes>
              <!-- chenge ip address attribute -->
              <nvpair id="ipPostgreSQLDB" name="ip" value="aaa.bbb.ccc.ddd"/>
              <nvpair id="maskPostgreSQLDB" name="netmask" value="nn"/>
              <nvpair id="nicPostgreSQLDB" name="nic" value="bond0"/>
            </attributes>
          </instance_attributes>
        </primitive>
        <primitive id="prmApPostgreSQLDB" class="ocf" type="pgsql" provider="heartbeat">
          <operations>
            <op id="apPostgreSQLDB_start"
              name="start" timeout="60s" on_fail="fence"/>
            <op id="apPostgreSQLDB_monitor"
              name="monitor" interval="30s" timeout="60s" on_fail="fence"/>
            <op id="apPostgreSQLDB_stop"
              name="stop" timeout="60s" on_fail="fence"/>
          </operations>
          <instance_attributes id="atrApPostgreSQLDB">
            <attributes>
              <nvpair id="pgctl01"
                name="pgctl" value="/usr/local/pgsql/bin/pg_ctl"/>
              <nvpair id="psql01"
                name="psql" value="/usr/local/pgsql/bin/psql"/>
              <nvpair id="pgdata01"
                name="pgdata" value="/mnt/shared-disk/pgsql/data"/>
              <nvpair id="pgdba01"
                name="pgdba" value="postgres"/>
              <nvpair id="pgdb01"
                name="pgdb" value="template1"/>
              <nvpair id="logfile01"
                name="logfile" value="/var/log/pgsql.log"/>
            </attributes>
          </instance_attributes>
        </primitive>
      </group>
    </resources>
    <constraints>
      <rsc_location id="rlcPostgreSQLDB" rsc="grpPostgreSQLDB">
        <rule id="rulPostgreSQLDB_node01" score="200">
          <expression id="expPostgreSQLDB_node01"
            attribute="#uname" operation="eq" value="sfex01" />
        </rule>
        <rule id="rulPostgreSQLDB_node02" score="100">
          <expression id="expPostgreSQLDB_node02"
            attribute="#uname" operation="eq" value="sfex02"/>
        </rule>
      </rsc_location>
      <rsc_location id="ping1:disconn" rsc="grpPostgreSQLDB">
        <rule id="ping1:disconn:rule" score="-INFINITY" boolean_op="and">
          <expression id="ping1:disconn:expr:defined"
            attribute="default_ping_set" operation="defined"/>
          <expression id="ping1:disconn:expr:positive"
            attribute="default_ping_set" operation="lt" value="100"/>
        </rule>
      </rsc_location>
    </constraints>
  </configuration>
  <status/>
 </cib>

リリース情報

関連情報

Heartbeat用 追加パッケージ集 (contrib)

ja/sfex ja (last edited 2008-07-01 07:08:20 by TakayukiTanaka)