將 MySQL(Percona Server)從 5.7 更新到 8.0

將 MySQL(Percona Server)從 5.7 更新到 8.0

進步不會停滯不前,因此升級到 MySQL 最新版本的理由變得越來越引人注目。 不久前,在我們的一個專案中,是時候將舒適的 Percona Server 5.7 叢集更新到版本 8。 這一切都發生在Ubuntu Linux 16.04平台上。 如何以最短的停機時間執行此類操作以及我們在更新過程中遇到的問題 - 請閱讀本文。

訓練

資料庫伺服器的任何更新很可能與資料庫重新配置相關:系統資源限制要求的變更以及需要清除過時指令的資料庫配置的更正。

在更新之前,我們一定會參考官方文件:

讓我們制定一個行動計劃:

  1. 透過刪除過時的指令來更正設定檔。
  2. 檢查與實用程式的相容性。
  3. 透過安裝包更新從資料庫 percona-server-server.
  4. 使用相同的包更新 master。

讓我們看看計劃的每一點,看看哪裡可能出問題。

重要! 基於 Galera 更新 MySQL 叢集的過程有其自身的微妙之處,本文未描述。 在這種情況下,您不應使用此指令。

第 1 部分:檢查配置

MySQL 在版本 8 中被刪除 query_cache。 其實他是 宣布過時 回到版本 5.7,但現在 完全刪除。 因此,有必要刪除相關指令。 為了快取請求,您現在可以使用外部工具 - 例如, 代理SQL.

此外,在配置中還有關於過時的指令 innodb_file_format。 如果在 MySQL 5.7 中可以選擇 InnoDB 格式,則第 8 版已經可以使用 僅限 Barracuda 格式.

我們的結果是刪除以下指令:

  • query_cache_type, query_cache_limit и query_cache_size;
  • innodb_file_format и innodb_file_format_max.

為了進行檢查,我們將使用 Percona Server 的 Docker 映像。 我們將伺服器配置放在目錄中 mysql_config_test,接下來我們將為資料和日誌建立目錄。 Percona-server 設定測試範例:

mkdir -p {mysql_config_test,mysql_data,mysql_logs}
cp -r /etc/mysql/conf.d/* mysql_config_test/
docker run  --name some-percona -v $(pwd)/mysql_config_test:/etc/my.cnf.d/  -v $(pwd)/mysql_data/:/var/lib/mysql/ -v $(pwd)/mysql_logs/:/var/log/mysql/ -e MYSQL_ROOT_PASSWORD=${MYSQL_PASSWORD} -d percona:8-centos

底線:無論是在 Docker 日誌中還是在包含日誌的目錄中(取決於您的配置),都會出現一個文件,其中將描述有問題的指令。

這是我們得到的:

2020-04-03T12:44:19.670831Z 0 [Warning] [MY-011068] [Server] The syntax 'expire-logs-days' is deprecated and will be removed in a future release. Please use binlog_expire_logs_seconds instead.
2020-04-03T12:44:19.671678Z 0 [Warning] [MY-013242] [Server] --character-set-server: 'utf8' is currently an alias for the character set UTF8MB3, but will be an alias for UTF8MB4 in a future release. Please consider using UTF8MB4 in order to be unambiguous.
2020-04-03T12:44:19.671682Z 0 [Warning] [MY-013244] [Server] --collation-server: 'utf8_general_ci' is a collation of the deprecated character set UTF8MB3. Please consider using UTF8MB4 with an appropriate collation instead.

因此,我們仍然需要找出編碼並替換過時的指令 expire-logs-days.

第 2 部分:檢查工作裝置

更新文件包含 2 個用於檢查資料庫相容性的實用程式。 它們的使用有助於管理員檢查現有資料結構的兼容性。

讓我們從經典的 mysqlcheck 實用程式開始。 只需運行:

mysqlcheck -u root -p --all-databases --check-upgrade

如果沒有發現問題,該實用程式將以代碼 0 退出:

將 MySQL(Percona Server)從 5.7 更新到 8.0

此外,在現代版本的 MySQL 中還提供了一個實用程序 mysql-shell (對 Percona 來說,這是包 percona-mysql-shell)。 它是經典 mysql 用戶端的替代品,結合了客戶端、SQL 程式碼編輯器和 MySQL 管理工具的功能。 要在更新之前檢查伺服器,您可以透過它執行以下命令:

mysqlsh -- util check-for-server-upgrade { --user=root --host=1.1.1.1 --port=3306 } --config-path=/etc/mysql/my.cnf

以下是我們收到的評論:

將 MySQL(Percona Server)從 5.7 更新到 8.0

一般來說,沒有什麼重要的 - 只有有關編碼的警告 (見下文)。 總體執行結果:

將 MySQL(Percona Server)從 5.7 更新到 8.0

我們決定更新應該不會有問題。

關於上述警告的註釋顯示編碼存在問題。 事實上,MySQL 中的 UTF-8 直到最近才出現 不是「真正的」UTF-8,因為它只儲存 3 個位元組而不是 4 個位元組。在 MySQL 8 中,這最終是 決定修復它: 別名 utf8 很快就會導致編碼 utf8mb4,表中的舊列將變為 utf8mb3。 進一步編碼 utf8mb3 將被刪除,但不會在此版本中刪除。 因此,我們決定在更新後更正正在執行的 DBMS 安裝上已有的編碼。

第 3 部分:伺服器更新

當有如此明智的計劃時,可能會出現什麼問題?…我們充分了解細微差別總是會發生,因此我們在 MySQL 開發叢集上進行了第一個實驗。

如前所述, 官方文檔 涵蓋了使用副本更新 MySQL 伺服器的問題。 最重要的是,您應該先更新所有副本(從屬),因為 MySQL 8 可以從主版本 5.7 複製。 一些困難在於我們使用該模式 大師 <-> 大師,當遠端主機處於模式時 唯讀。 也就是說,事實上,戰鬥流量流向一個資料中心,第二個資料中心是備份資料中心。

拓撲如下所示:

將 MySQL(Percona Server)從 5.7 更新到 8.0

更新必須從副本開始 mysql 副本 dc 2, mysql主控DC 2 и mysql replica dc 1,並以 mysql master dc 1 伺服器結束。為了更可靠,我們停止了虛擬機,拍攝了它們的快照,並在更新之前使用以下命令停止了複製 STOP SLAVE。 更新的其餘部分如下所示:

  1. 我們透過向配置添加 3 個選項來重新啟動每個副本: skip-networking, skip-slave-start, skip-log-bin。 事實上,更新資料庫會產生包含系統表更新的二進位日誌。 這些指令保證資料庫中的應用程式資料不會發生任何更改,並且有關更新系統表的資訊不會包含在二進位日誌中。 這將避免恢復複製時出現問題。
  2. 安裝包 percona-server-server。 需要注意的是,在 MySQL 版本 8 中 沒有 你需要運行命令 mysqlupgrade 伺服器更新後。
  3. 成功啟動後,我們再次重新啟動伺服器 - 不使用第一段中新增的參數。
  4. 我們確保複製成功:檢查 SHOW SLAVE STATUS 並看到應用程式資料庫中帶有計數器的表已更新。

一切看起來都很簡單:開發更新成功。 好的,您可以安全地安排每晚生產更新。

沒有悲傷 - 我們更新了產品

然而,將成功的開發經驗轉移到生產中並非沒有意外。

幸運的是,更新過程本身是從副本開始的,因此當我們遇到困難時,我們停止工作並從快照恢復副本。 對問題的調查被推遲到第二天早上。 日誌包含以下條目:

2020-01-14T21:43:21.500563Z 2 [ERROR] [MY-012069] [InnoDB] table: t1 has 19 columns but InnoDB dictionary has 20 columns
2020-01-14T21:43:21.500722Z 2 [ERROR] [MY-010767] [Server] Error in fixing SE data for db1.t1
2020-01-14T21:43:24.208365Z 0 [ERROR] [MY-010022] [Server] Failed to Populate DD tables.
2020-01-14T21:43:24.208658Z 0 [ERROR] [MY-010119] [Server] Aborting

研究了 Google 上各種郵件列表的檔案後發現,出現此問題的原因是 MySQL 錯誤。 雖然這更可能是實用程式錯誤 mysqlcheck и mysqlsh.

事實證明,MySQL 改變了十進位欄位(int、tinyint 等)的資料表示方式,因此 mysql-server 使用不同的方式來儲存它們。 如果你的資料庫 起初 先前版本為 5.5 或 5.1,然後您更新到 5.7,那麼您可能需要執行以下操作 OPTIMIZE 對於一些桌子。 然後MySQL將更新資料文件,將它們轉換為目前的儲存格式。

您還可以使用實用程式檢查這一點 mysqlfrm:

mysqlfrm --diagnostic -vv /var/lib/mysql/db/table.frm
...
 'field_length': 8,
  'field_type': 246, # формат поля
  'field_type_name': 'decimal',
  'flags': 3,
  'flags_extra': 67,
  'interval_nr': 0,
 'name': 'you_deciaml_column',
...

如果 field_type 如果它等於 0,則表中使用舊類型 - 您需要執行 OPTIMIZE。 但是,如果該值為 246,則您已經有了新類型。 有關類型的更多資訊可以在 程式碼.

此外,在 這個錯誤 我們正在考慮第二個可能的原因,它繞過了我們:系統表中缺少InnoDB表 INNODB_SYS_TABLESPACES,如果它們、表格是在版本 5.1 中建立的。 為了避免更新時出現問題,您可以使用 附上SQL腳本.

為什麼我們在開發時沒有遇到這樣的問題? 資料庫定期從生產環境複製 - 因此, 表格被重新創建.

不幸的是,在一個真正工作的大型資料庫上,您將無法僅獲取並執行通用的 OPTIMIZE。 percona-toolkit 將在這裡提供幫助:pt-online-schema-change 實用程式非常適合線上 OPTIMIZE 操作。

更新後的計劃如下圖所示:

  1. 優化所有表。
  2. 更新資料庫。

為了檢查它並同時找出更新時間,我們禁用了其中一個副本並對所有表運行以下命令:

pt-online-schema-change --critical-load Threads_running=150 --alter "ENGINE=InnoDB" --execute --chunk-size 100 --quiet --alter-foreign-keys-method auto h=127.0.0.1,u=root,p=${MYSQL_PASSWORD},D=db1,t=t1

由於實用程式會建立新的臨時表,並將資料從主表複製到其中,因此表的更新無需長時間鎖定。 當兩個表相同時,原始表被鎖定並替換為新表。 在我們的例子中,測試運行表明更新所有表大約需要一天的時間,但複製資料會導致磁碟負載過大。

為了避免這種情況,在生產中我們將參數添加到命令中 --sleep 值為10 - 此參數調整將一批資料傳輸到新表後的等待長度。 如果實際運行的應用程式對回應時間有要求,您可以透過這種方式減少負載。

執行優化後,更新成功。

……但不完全!

更新後半小時內,客戶端就出現了問題。 資料庫的工作方式非常奇怪:它們定期啟動 連線重置。 這是監控中的樣子:

將 MySQL(Percona Server)從 5.7 更新到 8.0

由於某些 MySQL 伺服器執行緒定期因錯誤而崩潰,因此螢幕截圖顯示了鋸齒圖。 應用程式中出現錯誤:

[PDOException] SQLSTATE[HY000] [2002] Connection refused

快速檢查日誌發現 mysqld 守護程序無法從作業系統取得所需的資源。 在整理錯誤的過程中,我們發現系統中 「孤兒」apparmor 策略文件:

# dpkg -S /etc/apparmor.d/cache/usr.sbin.mysqld
dpkg-query: no path found matching pattern /etc/apparmor.d/cache/usr.sbin.mysqld
# dpkg -S /etc/apparmor.d/local/usr.sbin.mysqld
dpkg-query: no path found matching pattern /etc/apparmor.d/local/usr.sbin.mysqld
# dpkg -S /etc/apparmor.d/usr.sbin.mysqld
mysql-server-5.7: /etc/apparmor.d/usr.sbin.mysqld
# dpkg -l mysql-server-5.7
rc  mysql-server-5.7 5.7.23-0ubuntu0.16.04.1      amd64

這些檔案是幾年前升級到 MySQL 5.7 時所建立的,屬於已刪除的套件。 刪除檔案並重新啟動 apparmor 服務解決了問題:

systemctl stop apparmor
rm /etc/apparmor.d/cache/usr.sbin.mysqld
rm /etc/apparmor.d/local/usr.sbin.mysqld
rm /etc/apparmor.d/usr.sbin.mysqld
systemctl start apparmor

總之

任何操作,即使是最簡單的操作,都可能導致意想不到的問題。 即使有一個深思熟慮的計劃也不總是保證達到預期的結果。 現在,我們團隊的任何更新計劃還包括強制清理可能因最近的操作而出現的不必要的文件。

而用這種不太專業的平面創意,我要對Percona的優秀產品表示衷心的感謝!

將 MySQL(Percona Server)從 5.7 更新到 8.0

聚苯乙烯

另請閱讀我們的博客:

來源: www.habr.com

添加評論