可插拔的儲存鎖定器
自 ActiveMQ Classic 5.7.0 版本起,儲存鎖定機制的選擇,如同持久化配接器所使用的,已變為可插拔。此功能僅對配置為共用儲存主/從拓撲的代理程式有意義。在 5.7.0 版本之前,儲存鎖定機制(以及主節點選舉)由持久化配接器的選擇決定。例如,對於 KahaDB 持久化配接器,儲存鎖定機制是基於共用檔案鎖定。類似地,JDBC 持久化配接器使用資料庫支援的儲存鎖定。
現在,儲存鎖定器的選擇與持久化配接器分開,可以混合搭配兩者的組合。儲存鎖定器的可插拔性由 Locker 介面實現,所有可插拔的鎖定器都必須實作此介面。這個介面使得實現符合本地需求的自訂儲存鎖定器變得容易。
然而,每個持久化配接器都有其自己的預設鎖定器,其工作方式與之前相同。
鎖定器
每個鎖定器都必須實作 Locker 介面。鎖定器介面具有以下屬性
屬性名稱 | 預設值 | 描述 |
---|---|---|
lockAcquireSleepInterval |
10000 |
在鎖定獲取嘗試之間輪詢的間隔(以毫秒為單位)。 |
failIfLocked |
false |
如果鎖定不是立即可用,是否應啟動代理程式失敗。當 true 時,從屬代理程式將不會啟動。 |
持久化配接器
每個持久化配接器(或任何希望使用鎖定的其他代理程式服務)都必須實作 Lockable 介面。這個介面具有以下屬性
屬性名稱 | 預設值 | 描述 |
---|---|---|
useLock |
true |
持久化配接器是否應使用已配置的鎖定器。主要用於開發期間,以暫時停用鎖定器的使用,而無需移除其配置。 |
lockKeepAlivePeriod |
0 |
保持鎖定活動的持續時間(以毫秒為單位),當大於 0 時。 |
現有的鎖定器
共用檔案鎖定器
共用檔案鎖定器是 KahaDB 持久化配接器的預設鎖定器。它鎖定一個檔案以確保只有持有鎖定的代理程式(主節點)被授予對訊息儲存的存取權。
範例
<persistenceAdapter>
<kahaDB directory="target/activemq-data" lockKeepAlivePeriod="10000">
<locker>
<shared-file-locker lockAcquireSleepInterval="5000"/>
</locker>
</kahaDB>
</persistenceAdapter>
lockKeepAlivePeriod
屬性不適用於舊於 5.9.0 的 ActiveMQ Classic 版本。
lockKeepAlivePeriod = 0 的後果
對於此鎖定器,
lockKeepAlivePeriod
應大於0
。此期間是主節點代理程式進行鎖定保持活動呼叫的頻率。當
lockKeepAlivePeriod = 0
時,從屬代理程式仍然無法獲得檔案鎖定。但是,如果某些第三方修改了鎖定檔案(修改或刪除),則主節點代理程式將不會偵測到該變更。因此,從屬代理程式下一次嘗試(根據其配置的lockAcquireSleepInterval
)獲取檔案鎖定將會成功。發生這種情況時,叢集中將有兩個主節點代理程式。這種情況將導致訊息儲存損壞!當
lockKeepAlivePeriod
大於0
時,主節點代理程式將每lockKeepAlivePeriod
毫秒進行一次鎖定保持活動呼叫。因此,主節點代理程式將在其下一次保持活動呼叫時偵測到任何鎖定檔案變更。在偵測到所述變更後,主節點代理程式會將其降級為從屬代理程式。
請注意,從 ActiveMQ Classic 5.9.0 開始,KahaDB 持久化配接器也可以使用租賃資料庫鎖定器(見下文)。
資料庫鎖定器
資料庫鎖定器是 JDBC 持久化配接器的預設鎖定器。它在交易中鎖定一個資料庫表,以確保僅使用單個資源。
範例
<persistenceAdapter>
<jdbcPersistenceAdapter dataDirectory="${activemq.data}" dataSource="#mysql-ds" lockKeepAlivePeriod="10000">
<locker>
<database-locker lockAcquireSleepInterval="5000"/>
</locker>
</jdbcPersistenceAdapter>
</persistenceAdapter>
資料庫鎖定器使用其 keepAlive
方法來確保代理程式仍然持有鎖定。您可以使用 lockKeepAlivePeriod
屬性來設定保持活動期間。預設期間為 30000 毫秒。如果代理程式無法在資料庫上獲取鎖定,它將每 lockAcquireSleepInterval
毫秒重試一次。
此鎖定器針對一個資料庫表 (activemq_lock
) 開啟一個 JDBC 交易,該交易的持續時間與代理程式保持活動的時間一樣長。這會鎖定整個表,並阻止另一個代理程式存取儲存。在大多數情況下,這將是一個相當長時間運行的 JDBC 交易,會在一段時間內佔用資料庫上的資源。
當主節點代理程式崩潰或失去與資料庫的連線時,可能會出現此鎖定器的問題,導致鎖定保留在資料庫中,直到資料庫透過 TCP 超時回應半關閉的套接字連線。資料庫鎖定過期要求可能會阻止從屬節點在一段時間後啟動。此外,如果資料庫支援故障轉移,並且在複本故障轉移事件中連線中斷,則該 JDBC 交易將被回滾。代理程式將此視為失敗。主節點和從屬節點代理程式將再次爭奪鎖定。
租賃資料庫鎖定器
建立租賃資料庫鎖定器是為了解決資料庫鎖定器的缺點。租賃資料庫鎖定器不會開啟長時間運行的 JDBC 交易。相反,它讓主節點代理程式獲取一個在固定(通常很短)持續時間後過期的鎖定。為了保留鎖定,主節點代理程式必須在鎖定過期之前定期延長鎖定的租賃。同時,從屬節點代理程式會定期檢查租賃是否已過期。如果由於任何原因,主節點代理程式未能更新其在鎖定上的租賃,則從屬節點將接管鎖定的所有權,從而成為新的主節點。租賃的鎖定可以從資料庫複本故障轉移中倖存下來。
範例
<persistenceAdapter>
<jdbcPersistenceAdapter dataDirectory="${activemq.data}" dataSource="#mysql-ds" lockKeepAlivePeriod="5000">
<locker>
<lease-database-locker lockAcquireSleepInterval="10000"/>
</locker>
</jdbcPersistenceAdapter>
</persistenceAdapter>
為了使此機制正常工作,主/從節點叢集中的每個代理程式都必須在 <broker/>
標籤上定義的 brokerName
屬性具有唯一值。或者,在 <lease-database-locker/>
標籤上使用 leaseHolderId
屬性的唯一值,因為此值用於建立租賃鎖定定義。
基於租賃的鎖定是在啟動時透過封鎖來獲取的。然後,它將保留一段時間,其持續時間(以毫秒為單位)由 lockKeepAlivePeriod
屬性給定。為了保留鎖定,主節點代理程式每次都會以 lockAcquireSleepInterval
毫秒為單位定期延長其租賃。因此,從理論上講,主節點代理程式在租賃方面始終比從屬節點代理程式提前 (lockAcquireSleepInterval - lockKeepAlivePeriod
)。必須確保 lockAcquireSleepInterval > lockKeepAlivePeriod
,以確保租賃始終為最新。從 ActiveMQ Classic 5.9.0 開始,如果未滿足此條件,則會記錄警告訊息。
在最簡單的情況下,主節點和從屬節點之間的時鐘必須同步,此解決方案才能正常工作。如果時鐘無法同步,鎖定器可以使用資料庫 CURRENT TIME 中的系統時間,並根據它們與資料庫系統時間的本地差異調整逾時。如果 maxAllowableDiffFromDBTime
大於零,則本地期間將根據任何超過 maxAllowableDiffFromDBTime
的增量進行調整。
了解 JDBC 驅動程式用於轉換
TIME
值的預設規則是否符合 JDBC 標準非常重要。例如,如果您使用的是 MySQL,則驅動程式的 JDBC URL 應包含useJDBCCompliantTimezoneShift=true
,以確保TIME
值轉換符合 JDBC 標準。否則,鎖定器在將擷取的租賃到期時間與目前的系統時間進行比較時,可能會報告較大的時間差異。請查閱 JDBC 驅動程式的文件以了解更多詳細資訊。
從 ActiveMQ Classic 5.9.0 開始,租賃資料庫鎖定器可以與 KahaDB 持久化配接器一起使用。但是,此特定組合要求租賃資料庫鎖定器元素包含一個 <statements/>
子元素。在下面的範例中,也配置了 lockTableName
,儘管這樣做不是強制性的。
<persistenceAdapter>
<kahaDB directory="target/activemq-data" lockKeepAlivePeriod="5000">
<locker>
<!\-\- When used with the KahaDB persistence adapter the 'dataSource' attribute must be defined on the locker itself: -->
<lease-database-locker lockAcquireSleepInterval="10000" dataSource="#mysql-ds">
<statements>
<!\-\- Default locker attributes and SQL statements may be overridden here
using one or more <statements attribute\_or\_statement="value"/> entries: -->
<statements lockTableName="activemq_lock"/>
</statements>
</lease-database-locker>
</locker>
</kahaDB>
</persistenceAdapter>
若要查看可以覆寫的屬性和 SQL 語句的完整清單,請參閱 Statements 類別。
當 KahaDB 持久化配接器配置為使用 lease-database-locker
時,您必須配置代理程式以使用您自己的 IO 例外處理程式,因為 DefaultIOExceptionHandler
和 JDBCIOExceptionHandler
都無法正確地與此組合一起使用。有關如何編寫處理程式的詳細資訊,請參閱 可配置的 IO 例外處理程式。
但是,從 ActiveMQ Classic 5.11 開始,
JDBCIOExceptionHandler
已被棄用。它已被org.apache.activemq.util.LeaseLockerIOExceptionHandler
取代,該處理程式將適用於任何支援可插拔儲存鎖定器的持久化配接器,無論是否配置。