在可能的情況下,建議您使用 Apache Cassandra 原生功能,藉由設定 混合式叢集,將數據從現有的叢集遷移至適用於 Apache Cassandra 的 Azure 受控實例。 這項功能會使用 Apache Cassandra 的 Gossip 通訊協定,以順暢的方式,將資料從來源資料中心複寫到新的受控執行個體資料中心。
在某些情況下,您的源資料庫版本不相容,或混合式叢集設定否則不可行。 本教學課程說明如何使用雙重寫入 Proxy 和 Apache Spark,以即時方式將資料移轉至 Azure Managed Instance for Apache Cassandra。 雙重寫入 Proxy 用來捕捉即時變更,而 Apache Spark 則用來大量複製歷程記錄資料。 此方法的優點包括:
- 應用程式變更最少。 Proxy 可以接受來自應用程式程式碼的連線,而不需要變更任何設定。 它會將所有請求傳送至您的源資料庫,並以異步方式將寫入操作路由至次要目標資料庫。
- 用戶端連線通訊協定相依性。 由於此方法並不相依於後端資源或內部通訊協定,因此可以搭配任何實作 Apache Cassandra 有線通訊協定的來源或目標 Cassandra 系統使用。
下圖說明此方法。
先決條件
使用 Azure 入口網站或 Azure CLI 佈建 Azure Managed Instance for Apache Cassandra 叢集。 請確定您可以使用 CQLSH 連線到叢集。
在您的受控 Cassandra 虛擬網路內佈建 Azure Databricks 帳戶。 請確定帳戶具有來源 Cassandra 叢集的網路存取權。 此範例會在此帳戶中建立Spark叢集,以用於歷程記錄數據載入。
請確定您已將 keyspace/table 配置從來源 Cassandra 資料庫移轉至目標 Cassandra 受控實例資料庫。
佈建 Spark 叢集
建議您選取支援 Spark 3.0 的 Azure Databricks 運行時間 7.5 版。
新增 Spark 相依性
您必須將 Apache Spark Cassandra 連接器程式庫新增至叢集,以連線到任何與連線通訊協定相容的 Apache Cassandra 端點。 在您的叢集中,選取 [程式庫] > [安裝新的] > [Maven],然後在 Maven 座標中新增 com.datastax.spark:spark-cassandra-connector-assembly_2.12:3.0.0。
重要事項
如果您需要在移轉期間針對每個資料列保留 Apache Cassandra writetime,我們建議使用此範例。 此範例中的相依性 jar 不僅包含 Spark 連接器,因此請安裝此版本,而非安裝連接器總成。
如果您想要在記錄資料載入完成後在來源與目標之間執行資料列比較驗證,此範例也能幫上忙。 請參閱 執行歷程記錄數據載入 並 驗證來源和目標。
選取 [安裝],然後在安裝完成時重新啟動叢集。
附註
安裝 Cassandra 連接器程式庫之後,請務必重新啟動 Azure Databricks 叢集。
安裝雙重寫入 Proxy
為了在雙重寫入期間獲得最佳效能,建議您在來源 Cassandra 叢集中的所有節點上安裝 Proxy。
#assuming you do not have git already installed
sudo apt-get install git
#assuming you do not have maven already installed
sudo apt install maven
#clone repo for dual-write proxy
git clone https://github.com/Azure-Samples/cassandra-proxy.git
#change directory
cd cassandra-proxy
#compile the proxy
mvn package
啟動雙重寫入 Proxy
建議您在來源 Cassandra 叢集中的所有節點上安裝 Proxy。 至少要執行下列命令,以在每個節點上啟動 Proxy。 將 <target-server> 取代為目標叢集中其中一個節點的 IP 或伺服器位址。 <path to JKS file> 替換為本機 jks 檔案的路徑,<keystore password> 替換為對應的密碼。
java -jar target/cassandra-proxy-1.0-SNAPSHOT-fat.jar localhost <target-server> --proxy-jks-file <path to JKS file> --proxy-jks-password <keystore password>
以這種方式啟動 Proxy 便代表假設符合了下列條件:
- 來源和目標端點具有相同的使用者名稱和密碼。
- 來源和目標端點使用的是安全通訊端層 (SSL)。
如果您的來源和目標端點無法符合這些條件,請繼續閱讀以取得進一步的設定選項。
設定 SSL
針對 SSL,您可以實作現有的金鑰存放區,例如來源叢集所使用的 keytool金鑰存放區,或使用 建立自我簽署憑證:
keytool -genkey -keyalg RSA -alias selfsigned -keystore keystore.jks -storepass password -validity 360 -keysize 2048
如果來源或目標端點未使用 SSL,您也可以停用 SSL。 使用 --disable-source-tls 或 --disable-target-tls 旗標:
java -jar target/cassandra-proxy-1.0-SNAPSHOT-fat.jar localhost <target-server> \
--source-port 9042 --target-port 10350 --proxy-jks-file <path to JKS file> \
--proxy-jks-password <keystore password> --target-username <username> --target-password <password> \
--disable-source-tls true --disable-target-tls true
附註
當您建置 SSL 連線到使用 Proxy 的資料庫時,請確定您的用戶端應用程式所使用的金鑰儲存區和密碼,與用於雙重寫入 Proxy 的相同。
設定認證和連接埠
根據預設,來源認證會從用戶端應用程式傳遞。 Proxy 會使用認證來建立來源和目標叢集的連線。 如先前所述,此程式會假設來源的認證和目標的認證相同。 啟動 Proxy 時,您可視需要分別為目標 Cassandra 端點指定不同的使用者名稱和密碼:
java -jar target/cassandra-proxy-1.0-SNAPSHOT-fat.jar localhost <target-server> \
--proxy-jks-file <path to JKS file> --proxy-jks-password <keystore password> \
--target-username <username> --target-password <password>
未指定時的預設來源和目標埠為9042。 如果目標或來源 Cassandra 端點在不同的連接埠上執行,您可以使用 --source-port 或 --target-port 來指定不同的連接埠號碼:
java -jar target/cassandra-proxy-1.0-SNAPSHOT-fat.jar localhost <target-server> \
--source-port 9042 --target-port 10350 --proxy-jks-file <path to JKS file> \
--proxy-jks-password <keystore password> --target-username <username> --target-password <password>
遠端部署 Proxy
在某些情況下,您可能不想在叢集節點上安裝 Proxy。 您要將它安裝在個別的電腦上。 在該情境中,指定<source-server>的IP位址:
java -jar target/cassandra-proxy-1.0-SNAPSHOT-fat.jar <source-server> <destination-server>
警告
您可能想要在個別的計算機上遠端執行 Proxy,而不是在來源 Apache Cassandra 叢集中的所有節點上執行 Proxy。 若是如此,我們建議您將 Proxy 部署到叢集中有節點的相同數目機器。 在 system.peers 中設定其 IP 位址的替換。 在 Proxy 中使用此組態。 如果您未使用此方法,它可能會影響即時移轉時的效能,因為客戶端驅動程式無法開啟與叢集中所有節點的連線。
毫不允許應用程式程式碼變更
根據預設,Proxy 會在連接埠 29042 上接聽。 您必須將應用程式程式代碼變更為指向此埠。 或者,您可以變更 Proxy 接聽的埠。 如果您要藉由下列方式排除應用程式程式代碼變更,您可以使用此方法:
- 讓來源 Cassandra 伺服器在不同的連接埠上執行。
- 讓 Proxy 在標準 Cassandra 連接埠 9042 上執行。
java -jar target/cassandra-proxy-1.0-SNAPSHOT-fat.jar source-server destination-server --proxy-port 9042
附註
在叢集節點上安裝 Proxy 不需要重新啟動節點。 如果您有許多應用程式用戶端,而且想要在標準 Cassandra 連接埠 9042 上執行 Proxy,以消除任何應用程式碼變更,請變更 Apache Cassandra 預設埠。 您接著必須重新啟動叢集中的節點,並將來源連接埠設定為您為來源 Cassandra 叢集定義的新連接埠。
在下列範例中,我們將來源 Cassandra 叢集變更為在連接埠 3074 上執行,然後在連接埠 9042 上啟動叢集:
java -jar target/cassandra-proxy-1.0-SNAPSHOT-fat.jar source-server destination-server --proxy-port 9042 --source-port 3074
強制通訊協定
Proxy 具有強制通訊協定的功能,在來源端點比目標更先進或不受支援時將可能需要使用功能。 在這種情況下,您可以指定 --protocol-version 和 --cql-version 來強制通訊協定與目標相符:
java -jar target/cassandra-proxy-1.0-SNAPSHOT-fat.jar source-server destination-server --protocol-version 4 --cql-version 3.11
在雙重寫入 Proxy 執行之後,請變更應用程式用戶端上的連接埠,然後重新啟動。 或者,如果您選擇該方法,請變更 Cassandra 埠,然後重新啟動叢集。 Proxy 會開始將寫入轉送至目標端點。 您可以在此瞭解 Proxy 工具中可用的 監視和計量。
執行歷程資料載入
若要載入該資料,請在您的 Azure Databricks 帳戶中建立 Scala 筆記本。 將您的來源和目標 Cassandra 設定取代為對應的認證,以及來源和目標 keyspace 和資料表。 在下列範例中,視需要為每個資料表新增更多變數,然後執行。 在應用程式開始將要求傳送到雙重寫入 Proxy 之後,您即能開始轉移歷程記錄資料。
import com.datastax.spark.connector._
import com.datastax.spark.connector.cql._
import org.apache.spark.SparkContext
// source cassandra configs
val sourceCassandra = Map(
"spark.cassandra.connection.host" -> "<Source Cassandra Host>",
"spark.cassandra.connection.port" -> "9042",
"spark.cassandra.auth.username" -> "<USERNAME>",
"spark.cassandra.auth.password" -> "<PASSWORD>",
"spark.cassandra.connection.ssl.enabled" -> "true",
"keyspace" -> "<KEYSPACE>",
"table" -> "<TABLE>"
)
//target cassandra configs
val targetCassandra = Map(
"spark.cassandra.connection.host" -> "<Source Cassandra Host>",
"spark.cassandra.connection.port" -> "9042",
"spark.cassandra.auth.username" -> "<USERNAME>",
"spark.cassandra.auth.password" -> "<PASSWORD>",
"spark.cassandra.connection.ssl.enabled" -> "true",
"keyspace" -> "<KEYSPACE>",
"table" -> "<TABLE>",
//throughput related settings below - tweak these depending on data volumes.
"spark.cassandra.output.batch.size.rows"-> "1",
"spark.cassandra.output.concurrent.writes" -> "1000",
"spark.cassandra.connection.remoteConnectionsPerExecutor" -> "1",
"spark.cassandra.concurrent.reads" -> "512",
"spark.cassandra.output.batch.grouping.buffer.size" -> "1000",
"spark.cassandra.connection.keep_alive_ms" -> "600000000"
)
//set timestamp to ensure it is before read job starts
val timestamp: Long = System.currentTimeMillis / 1000
//Read from source Cassandra
val DFfromSourceCassandra = sqlContext
.read
.format("org.apache.spark.sql.cassandra")
.options(sourceCassandra)
.load
//Write to target Cassandra
DFfromSourceCassandra
.write
.format("org.apache.spark.sql.cassandra")
.options(targetCassandra)
.option("writetime", timestamp)
.mode(SaveMode.Append)
.save
附註
在上述 Scala 範例中,在讀取源數據表中的所有數據之前, timestamp 會先設定為目前的時間。 然後,writetime 會設定為追溯的時間戳記。 這方法能確保在讀取歷程資料的同時,從歷程資料負載寫入至目標端點的記錄,不會覆蓋具有較晚時間戳記、來自雙重寫入 Proxy 的更新。
重要事項
如果您基於任何原因而需要保留「確切」的時間戳記,您應該採用歷程資料移轉方法來保留時間戳記,例如此範例。 範例中的相依性 jar 也包含 Spark 連接器,因此您不需要安裝先前必要條件中所述的 Spark 連接器元件。 在您的Spark叢集中安裝這兩者會造成衝突。
驗證來源和目標
在歷程資料載入完成後,您的資料庫應該已同步完成並準備好進行完全移轉。 我們建議您在最終切換之前,先驗證來源和目標,以確保它們匹配。
附註
如果您使用先前章節所述的 Cassandra 移轉程式範例來保留 writetime,您就能夠根據特定容差比較來源和目標中的數據列來驗證移轉。