• Oracle 主从切换脚本


    一、 切换前预检查

    1. dg_precheck_main_v1.4.sh

    1. #!/bin/bash
    2. #**********************************************************************************
    3. # Author: Hehuyi_In
    4. # Date: 2022年06月16日
    5. # FileName: dg_precheck_main_v1.4.sh
    6. #
    7. # For sys user, execute the script directly.
    8. # For other sysdba privileged users, you need to manually synchronize the password file to standby server in versions below 12.2.
    9. # The script cannot be executed on the Linux 5 os.
    10. #
    11. # Example:
    12. # ./dg_precheck_main_v1.4.sh &> dg_precheck.log
    13. # cat dg_precheck.log | grep --color=no -E "Warning|Error" ,or less -R dg_precheck.log
    14. #
    15. #
    16. # Description:
    17. # 2022-06-16 v_1.0 just get and print the infomation we want
    18. # 2022-06-17 v_1.1 auto check the database role
    19. # 2022-06-22 v_1.2 adjust the output format
    20. # 2022-06-28 v_1.3 add compare function, compare two nodes at a time
    21. # 2022-06-28 split to two scripts dg_precheck_main_v1.0.sh and dg_precheck_func_v1.0.sh
    22. # 2022-07-06 dg_precheck_main_v1.1 check os info
    23. # 2022-07-12 dg_precheck_main_v1.2 adjust the output format
    24. # 2022-07-13 dg_precheck_main_v1.3 adjust os info check function
    25. # 2022-10-19 dg_precheck_main_v1.4 add checking items: dblink,standby_file_management,flashback_on,db_flashback_retention_target,db_recovery_file_dest,db_recovery_file_dest_size
    26. #**********************************************************************************
    27. source ./dg_precheck_func_v1.4.sh
    28. # TNS列表
    29. TNS_LIST=(test_dg test)
    30. # 连接信息
    31. DBUSER='sys/"xxxxx"'
    32. # --------------------------- 检查并设置TNS_LIST中各tnsname对应数据库角色 ----------------------------------
    33. auto_check_db_role
    34. # 字典定义
    35. declare -A PRIMARY_TNS_DIC
    36. declare -A STANDBY_TNS_DIC
    37. echo -e "--------------------------------------------------------------------------------"
    38. echo -e "- 各节点主要参数检查 "
    39. echo -e "--------------------------------------------------------------------------------\n"
    40. # 内存参数 及 compatible 检查和对比
    41. PARAMS_LIST=(sga_max_size sga_target pga_aggregate_target shared_pool_size db_cache_size streams_pool_size compatible standby_file_management)
    42. for PARAM in ${PARAMS_LIST[@]};
    43. do
    44. PRIMARY_TNS_DIC+=([$PARAM]=`get_params_value $PRIMARY_TNS $PARAM`)
    45. STANDBY_TNS_DIC+=([$PARAM]=`get_params_value $STANDBY_TNS $PARAM`)
    46. # 主从库间对比参数是否相等
    47. compare_value ${PRIMARY_TNS_DIC[$PARAM]} ${STANDBY_TNS_DIC[$PARAM]} $PARAM
    48. done
    49. # 获取其他参数值
    50. PARAMS_LIST=(log_archive_max_processes db_create_file_dest db_file_name_convert log_file_name_convert fal_client fal_server log_archive_config db_recovery_file_dest db_recovery_file_dest_size db_flashback_retention_target)
    51. for PARAM in ${PARAMS_LIST[@]};
    52. do
    53. PRIMARY_TNS_DIC+=([$PARAM]=`get_params_value $PRIMARY_TNS $PARAM`)
    54. STANDBY_TNS_DIC+=([$PARAM]=`get_params_value $STANDBY_TNS $PARAM`)
    55. done
    56. echo -e "\n"
    57. echo -e "--------------------------------------------------------------------------------"
    58. echo -e "- 各节点主要文件数检查 "
    59. echo -e "--------------------------------------------------------------------------------\n"
    60. PRIMARY_TNS_DIC+=([redo_count]=`get_file_count $PRIMARY_TNS "LOG"`)
    61. PRIMARY_TNS_DIC+=([standby_count]=`get_file_count $PRIMARY_TNS "STANDBY_LOG"`)
    62. PRIMARY_TNS_DIC+=([tempfile_count]=`get_file_count $PRIMARY_TNS "TEMPFILE"`)
    63. STANDBY_TNS_DIC+=([redo_count]=`get_file_count $STANDBY_TNS "LOG"`)
    64. STANDBY_TNS_DIC+=([standby_count]=`get_file_count $STANDBY_TNS "STANDBY_LOG"`)
    65. STANDBY_TNS_DIC+=([tempfile_count]=`get_file_count $STANDBY_TNS "TEMPFILE"`)
    66. PRIMARY_TNS_DIC+=([datafile_online_count]=`get_datafile_online_count $PRIMARY_TNS`)
    67. STANDBY_TNS_DIC+=([datafile_online_count]=`get_datafile_online_count $STANDBY_TNS`)
    68. compare_value ${PRIMARY_TNS_DIC[redo_count]} ${STANDBY_TNS_DIC[redo_count]} "redo_count"
    69. compare_value ${PRIMARY_TNS_DIC[standby_count]} ${STANDBY_TNS_DIC[standby_count]} "standby_count"
    70. compare_value ${PRIMARY_TNS_DIC[tempfile_count]} ${STANDBY_TNS_DIC[tempfile_count]} "tempfile_count"
    71. compare_value ${PRIMARY_TNS_DIC[datafile_online_count]} ${STANDBY_TNS_DIC[datafile_online_count]} "datafile_online_count"
    72. echo -e "\n"
    73. echo -e "--------------------------------------------------------------------------------"
    74. echo -e "- 从节点redo日志状态检查 "
    75. echo -e "--------------------------------------------------------------------------------\n"
    76. # 只有从库需要检查
    77. STANDBY_TNS_DIC+=([redo_status_count]=`get_redo_status_count $STANDBY_TNS`)
    78. check_redo_status_count ${STANDBY_TNS_DIC[db_create_file_dest]} ${STANDBY_TNS_DIC[log_file_name_convert]} ${STANDBY_TNS_DIC[redo_status_count]}
    79. echo -e "\n"
    80. echo -e "--------------------------------------------------------------------------------"
    81. echo -e "- 闪回开启及保留时间检查 "
    82. echo -e "--------------------------------------------------------------------------------\n"
    83. # --------------------------- flashback_on 与 db_flashback_retention_target -------------------------------
    84. PRIMARY_TNS_DIC+=([flashback_on]=`get_flashback_on $PRIMARY_TNS`)
    85. echo -e "- primary database "
    86. compare_value ${PRIMARY_TNS_DIC[flashback_on]} "NO" "flashback_on"
    87. compare_value ${PRIMARY_TNS_DIC[db_flashback_retention_target]} "4320" "db_flashback_retention_target"
    88. STANDBY_TNS_DIC+=([flashback_on]=`get_flashback_on $STANDBY_TNS`)
    89. echo -e "- standby database "
    90. compare_value ${STANDBY_TNS_DIC[flashback_on]} "YES" "flashback_on"
    91. compare_value ${STANDBY_TNS_DIC[db_flashback_retention_target]} "4320" "db_flashback_retention_target"
    92. echo -e "\n"
    93. echo -e "--------------------------------------------------------------------------------"
    94. echo -e "- FRA区设置检查 "
    95. echo -e "--------------------------------------------------------------------------------\n"
    96. # --------------------------- db_recovery_file_dest 与 db_recovery_file_dest_size -------------------------------
    97. # 主从库设置是否相同
    98. compare_value ${PRIMARY_TNS_DIC[db_recovery_file_dest]} ${STANDBY_TNS_DIC[db_recovery_file_dest]} "db_recovery_file_dest"
    99. compare_value ${PRIMARY_TNS_DIC[db_recovery_file_dest_size]} ${STANDBY_TNS_DIC[db_recovery_file_dest_size]} "db_recovery_file_dest_size"
    100. echo -e "\n"
    101. echo -e "--------------------------------------------------------------------------------"
    102. echo -e "- 各节点主从相关参数检查 "
    103. echo -e "--------------------------------------------------------------------------------\n"
    104. # --------------------------- fal_client 与 fal_server ---------------------------
    105. # fal_server的值应该包括对方,因为${PRIMARY_TNS_DIC[fal_server]}返回值包含逗号,因此需要在传参时加"",避免参数传入函数后被截断
    106. # 主节点参数值
    107. include_value $PRIMARY_TNS "fal_server" "${PRIMARY_TNS_DIC[fal_server]}" $STANDBY_TNS
    108. # 从节点参数值
    109. include_value $STANDBY_TNS "fal_server" "${STANDBY_TNS_DIC[fal_server]}" $PRIMARY_TNS
    110. # fal_client的值应该包含自己
    111. # 主节点参数值
    112. include_value $PRIMARY_TNS "fal_client" "${PRIMARY_TNS_DIC[fal_client]}" $PRIMARY_TNS
    113. # 从节点参数值
    114. include_value $STANDBY_TNS "fal_client" "${STANDBY_TNS_DIC[fal_client]}" $STANDBY_TNS
    115. # --------------------------- log_archive_config -------------------------------
    116. # 主节点参数值
    117. include_value $PRIMARY_TNS "log_archive_config" ${PRIMARY_TNS_DIC[log_archive_config]} $STANDBY_TNS
    118. # 从节点参数值
    119. include_value $STANDBY_TNS "log_archive_config" ${STANDBY_TNS_DIC[log_archive_config]} $PRIMARY_TNS
    120. # --------------------------- log_archive_max_processes -------------------------------
    121. check_log_archive_max_processes $PRIMARY_TNS ${PRIMARY_TNS_DIC[log_archive_max_processes]}
    122. check_log_archive_max_processes $STANDBY_TNS ${STANDBY_TNS_DIC[log_archive_max_processes]}
    123. # --------------------------- log_archive_dest_n 与 log_archive_dest_state_n -------------------------------
    124. check_archive_dest $PRIMARY_TNS
    125. check_archive_dest $STANDBY_TNS
    126. check_archive_dest_state $PRIMARY_TNS
    127. check_archive_dest_state $STANDBY_TNS
    128. # --------------------------- OMF 与 db_file_name_convert,log_file_name_convert -------------------------------
    129. check_omf_and_convert_params $PRIMARY_TNS ${PRIMARY_TNS_DIC[db_create_file_dest]} ${PRIMARY_TNS_DIC[db_file_name_convert]} ${PRIMARY_TNS_DIC[log_file_name_convert]}
    130. check_omf_and_convert_params $STANDBY_TNS ${STANDBY_TNS_DIC[db_create_file_dest]} ${STANDBY_TNS_DIC[db_file_name_convert]} ${STANDBY_TNS_DIC[log_file_name_convert]}
    131. echo -e "\n"
    132. echo -e "--------------------------------------------------------------------------------"
    133. echo -e "- 从节点延迟 MRP进程与触发器检查 "
    134. echo -e "--------------------------------------------------------------------------------\n"
    135. check_db_lag $STANDBY_TNS "transport lag"
    136. check_db_lag $STANDBY_TNS "apply lag"
    137. check_mrp_process $STANDBY_TNS
    138. check_mrp_trigger $PRIMARY_TNS
    139. check_mrp_trigger $STANDBY_TNS
    140. echo -e "\n"
    141. echo -e "--------------------------------------------------------------------------------"
    142. echo -e "- dblink检查 "
    143. echo -e "--------------------------------------------------------------------------------\n"
    144. # --------------------------- dblink -------------------------------
    145. # 检查主库即可
    146. check_dblink $PRIMARY_TNS
    147. echo -e "\n"

    2. dg_precheck_func_v1.4.sh

    1. #!/bin/bash
    2. #**********************************************************************************
    3. # Author: Hehuyi_In
    4. # Date: 2022年06月16日
    5. # FileName: dg_precheck_func_v1.4.sh
    6. #
    7. # Description:
    8. # 2022-06-16 v_1.0 just get and print the infomation we want
    9. # 2022-06-17 v_1.1 auto check the database role
    10. # 2022-06-22 v_1.2 adjust the output format
    11. # 2022-06-28 v_1.3 add compare function, compare two nodes at a time
    12. # 2022-06-28 split to two scripts dg_precheck_main_v1.0.sh and dg_precheck_func_v1.0.sh
    13. # 2022-07-06 dg_precheck_func_v1.1 check os info
    14. # 2022-07-12 dg_precheck_func_v1.2 adjust the output format
    15. # 2022-07-13 dg_precheck_func_v1.3 adjust os info check function
    16. # 2022-10-19 dg_precheck_func_v1.4 add checking items: dblink,standby_file_management,flashback_on,db_flashback_retention_target,db_recovery_file_dest,db_recovery_file_dest_size
    17. #**********************************************************************************
    18. # 颜色定义
    19. # 红色
    20. ERROR_COLOR='\e[1;31m'
    21. # 绿色
    22. NARMAL_COLOR='\e[1;32m'
    23. # 黄色
    24. WARNING_COLOR='\e[1;33m'
    25. # 重置
    26. RESET_COLOR='\e[0m'
    27. # ------------------------------------------------------------------------
    28. # 检查TNS_LIST中各tnsname对应数据库角色
    29. auto_check_db_role() {
    30. for TNS in ${TNS_LIST[@]}; do
    31. DB_ROLE=$(
    32. sqlplus -s $DBUSER@$TNS as sysdba <<EOF
    33. set heading off feedback off pagesize 0 verify off echo off
    34. select database_role from v\$database;
    35. EOF
    36. )
    37. # 主库,则赋值给 PRIMARY_TNS
    38. if [[ "$DB_ROLE" = "PRIMARY" ]]; then
    39. PRIMARY_TNS=$TNS
    40. # 从库,则赋值给 STANDBY_TNS
    41. elif [[ "$DB_ROLE" = "PHYSICAL STANDBY" ]]; then
    42. STANDBY_TNS=$TNS
    43. fi
    44. done
    45. if [[ "$PRIMARY_TNS" = "" ]]; then
    46. echo -e "${ERROR_COLOR} $(date "+%Y-%m-%d %H:%M:%S") | Error! There is no primary database tns ${RESET_COLOR}"
    47. exit 1
    48. elif [[ "$STANDBY_TNS" = "" ]]; then
    49. echo -e "${ERROR_COLOR} $(date "+%Y-%m-%d %H:%M:%S") | Error! There is no standby database tns ${RESET_COLOR}"
    50. exit 1
    51. fi
    52. }
    53. # ----------------------------------获取操作系统信息--------------------------------------
    54. # 参数1:TNS连接串
    55. # get_cpu_info() {
    56. # sqlplus -s $DBUSER@$1 as sysdba <
    57. # !cat /proc/cpuinfo | grep "processor" | wc -l
    58. # EOF
    59. # }
    60. # get_memory_info() {
    61. # sqlplus -s $DBUSER@$1 as sysdba <
    62. # !free -h | grep 'Mem:' | awk '{print \$2}'
    63. # EOF
    64. # }
    65. # get_disk_info() {
    66. # sqlplus -s $DBUSER@$1 as sysdba <
    67. # !df -m | grep -v 'Filesystem' | awk '{sum+=\$2} END {print sum}'
    68. # EOF
    69. # }
    70. # 获取Oracle参数值
    71. # 参数1:TNS连接串,参数2:待检查参数名(不区分大小写)
    72. get_params_value() {
    73. if [[ "$1" != "" && "$2" != "" ]]; then
    74. sqlplus -s $DBUSER@$1 as sysdba <<EOF
    75. set heading off feedback off pagesize 0 verify off echo off
    76. select value from v\$parameter where upper(name)=upper('$2');
    77. EOF
    78. else
    79. echo -e "${ERROR_COLOR} $(date "+%Y-%m-%d %H:%M:%S") | Error! get_params_value() parameter 1 and 2 can't be null ${RESET_COLOR}"
    80. exit 1
    81. fi
    82. }
    83. # log_archive_max_processes 参数检查
    84. # 参数1:TNS连接串,参数2:待检查参数值
    85. check_log_archive_max_processes() {
    86. if [[ "$1" != "" && "$2" != "" ]]; then
    87. if [[ "$2" -ge 4 ]]; then
    88. printf "${NARMAL_COLOR}%-10s | Success | log_archive_max_processes >= 4${RESET_COLOR}\n" $1
    89. else
    90. printf "${WARNING_COLOR}%-10s | Warning | log_archive_max_processes < 4${RESET_COLOR}\n" $1
    91. fi
    92. else
    93. echo "${ERROR_COLOR} $(date "+%Y-%m-%d %H:%M:%S") | Error! check_log_archive_max_processes() parameter 1 and 2 can't be null ${RESET_COLOR}"
    94. exit 1
    95. fi
    96. }
    97. # 检查log_archive_dest_n参数,是否有设置DELAY关键字(延迟从库)
    98. # 参数1:TNS连接串
    99. check_archive_dest() {
    100. if [[ "$1" != "" ]]; then
    101. COUNT=$(
    102. sqlplus -s $DBUSER@$1 as sysdba <<EOF
    103. set heading off feedback off pagesize 0 verify off echo off
    104. select count(*) FROM v\$parameter where name like 'log_archive_dest%' and upper(value) like '%DELAY%';
    105. EOF
    106. )
    107. if [[ "$COUNT" -eq 0 ]]; then
    108. printf "${NARMAL_COLOR}%-10s | Success | There is no DELAY attribute in log_archive_dest_n${RESET_COLOR}\n" $1
    109. else
    110. printf "${WARNING_COLOR}%-10s | Warning | There is DELAY attribute in log_archive_dest_n${RESET_COLOR}\n" $1
    111. fi
    112. else
    113. echo -e "${ERROR_COLOR} $(date "+%Y-%m-%d %H:%M:%S") | Error! check_archive_dest() parameter 1 can't be null ${RESET_COLOR}"
    114. exit 1
    115. fi
    116. }
    117. # 检查log_archive_dest_state_n参数,是否有设置DEFER
    118. # 参数1:TNS连接串
    119. check_archive_dest_state() {
    120. if [[ "$1" != "" ]]; then
    121. COUNT=$(
    122. sqlplus -s $DBUSER@$1 as sysdba <<EOF
    123. set heading off feedback off pagesize 0 verify off echo off
    124. select count(*) FROM v\$parameter where name like 'log_archive_dest_state%' and upper(value)='DEFER';
    125. EOF
    126. )
    127. if [[ "$COUNT" -eq 0 ]]; then
    128. printf "${NARMAL_COLOR}%-10s | Success | There is no DEFER value in log_archive_dest_state_n${RESET_COLOR}\n" $1
    129. else
    130. printf "${WARNING_COLOR}%-10s | Warning | There is DEFER value in log_archive_dest_state_n${RESET_COLOR}\n" $1
    131. fi
    132. else
    133. echo -e "${ERROR_COLOR} $(date "+%Y-%m-%d %H:%M:%S") | Error! check_archive_dest_state() parameter 1 can't be null ${RESET_COLOR}"
    134. exit 1
    135. fi
    136. }
    137. # OMF与convert参数检查
    138. # 参数1:TNS连接串;参数2:db_create_file_dest参数值;参数3:db_file_name_convert参数值;参数4:log_file_name_convert参数值
    139. check_omf_and_convert_params() {
    140. if [[ "$2" != "" ]]; then
    141. printf "${NARMAL_COLOR}%-10s | Success | db_create_file_dest parameter was set${RESET_COLOR}\n" $1
    142. else
    143. if [[ "$3" != "" && "$4" != "" ]]; then
    144. printf "${NARMAL_COLOR}%-10s | Success | dbfile and logfile convert parameters were set${RESET_COLOR}\n" $1
    145. else
    146. printf "${WARNING_COLOR}%-10s | Warning | db_create_file_dest,dbfile and logfile convert parameters were set${RESET_COLOR}\n" $1
    147. fi
    148. fi
    149. }
    150. # 获取各类文件数
    151. # 参数1:TNS连接串,参数2:待查询视图名(V$LOG V$STANDBY_LOG V$TEMPFILE)
    152. get_file_count() {
    153. if [[ "$1" != "" ]]; then
    154. sqlplus -s $DBUSER@$1 as sysdba <<EOF
    155. set heading off feedback off pagesize 0 verify off echo off
    156. SELECT count(*) FROM V\$$2;
    157. EOF
    158. else
    159. echo -e "${ERROR_COLOR} $(date "+%Y-%m-%d %H:%M:%S") | Error! get_file_count() parameter 1 and 2 can't be null ${RESET_COLOR}"
    160. exit 1
    161. fi
    162. }
    163. # 获取指定状态的redo文件数
    164. # 参数1:TNS连接串
    165. get_redo_status_count() {
    166. if [[ "$1" != "" ]]; then
    167. sqlplus -s $DBUSER@$1 as sysdba <<EOF
    168. set heading off feedback off pagesize 0 verify off echo off
    169. SELECT count(*) FROM V\$LOG WHERE STATUS NOT IN ('UNUSED', 'CLEARING','CLEARING_CURRENT');
    170. EOF
    171. else
    172. echo -e "${ERROR_COLOR} $(date "+%Y-%m-%d %H:%M:%S") | Error! get_redo_status_count() parameter 1 can't be null ${RESET_COLOR}"
    173. exit 1
    174. fi
    175. }
    176. # 检查指定状态的redo文件数
    177. # 参数1:db_create_file_dest参数值;参数2:log_file_name_convert参数值;参数3:${STANDBY_TNS_DIC[redo_status_count]}
    178. check_redo_status_count() {
    179. # 如果设置了OMF或者LOG_FILE_NAME_CONVERT,则可以跳过此步骤
    180. if [[ "$1" != "" || "$2" != "" ]]; then
    181. printf "${NARMAL_COLOR}%-30s | %-8s | There is no need to check this item${RESET_COLOR}\n" redo_status_count Success
    182. else
    183. # 否则,指定状态的redo文件数应该为0
    184. if [[ "$3" -eq 0 ]]; then
    185. printf "${WARNING_COLOR}%-30s | %-8s | redo_status_count value is 0${RESET_COLOR}\n" redo_status_count Warning
    186. else
    187. # 否则,发出告警
    188. printf "${WARNING_COLOR}%-30s | %-8s | redo_status_count value is not 0${RESET_COLOR}\n" $1 Warning
    189. fi
    190. fi
    191. }
    192. # 获取online状态的数据文件数量
    193. # 参数1:TNS连接串
    194. get_datafile_online_count() {
    195. if [[ "$1" != "" ]]; then
    196. sqlplus -s $DBUSER@$1 as sysdba <<EOF
    197. set heading off feedback off pagesize 0 verify off echo off
    198. SELECT count(*) FROM V\$DATAFILE WHERE STATUS='ONLINE';
    199. EOF
    200. else
    201. echo -e "${ERROR_COLOR} $(date "+%Y-%m-%d %H:%M:%S") | Error! get_datafile_online_count() parameter 1 can't be null ${RESET_COLOR}"
    202. exit 1
    203. fi
    204. }
    205. # 获取数据库闪回功能开启状态
    206. # 参数1:TNS连接串
    207. get_flashback_on() {
    208. if [[ "$1" != "" ]]; then
    209. sqlplus -s $DBUSER@$1 as sysdba <<EOF
    210. set heading off feedback off pagesize 0 verify off echo off
    211. SELECT FLASHBACK_ON FROM V\$DATABASE;
    212. EOF
    213. else
    214. echo -e "${ERROR_COLOR} $(date "+%Y-%m-%d %H:%M:%S") | Error! get_flashback_on() parameter 1 can't be null ${RESET_COLOR}"
    215. exit 1
    216. fi
    217. }
    218. # mrp触发器检查
    219. # 参数1:TNS连接串
    220. check_mrp_trigger() {
    221. if [[ "$1" != "" ]]; then
    222. COUNT=$(
    223. sqlplus -s $DBUSER@$1 as sysdba <<EOF
    224. set heading off feedback off pagesize 0 verify off echo off
    225. select count(*) FROM dba_triggers where trigger_name in ('AUTO_START_STANDBY_MRP','AUTO_START_STANDBY_MRP_PDB');
    226. EOF
    227. )
    228. if [[ "$COUNT" -eq 0 ]]; then
    229. printf "${ERROR_COLOR}%-10s | %-8s | There is no MRP trigger${RESET_COLOR}\n" $1 Error
    230. else
    231. printf "${NARMAL_COLOR}%-10s | %-8s | MRP trigger was found${RESET_COLOR}\n" $1 Success
    232. fi
    233. else
    234. echo -e "${ERROR_COLOR}$(date "+%Y-%m-%d %H:%M:%S") | Error! check_mrp_trigger() parameter 1 can't be null ${RESET_COLOR}"
    235. exit 1
    236. fi
    237. }
    238. # mrp进程检查
    239. # 参数1:TNS连接串
    240. check_mrp_process() {
    241. if [[ "$1" != "" ]]; then
    242. COUNT=$(
    243. sqlplus -s $DBUSER@$1 as sysdba <<EOF
    244. set heading off feedback off pagesize 0 verify off echo off
    245. select count(*) FROM v\$managed_standby where process like 'MRP%';
    246. EOF
    247. )
    248. if [[ "$COUNT" -eq 0 ]]; then
    249. printf "${ERROR_COLOR}%-10s | %-8s | There is no MRP process${RESET_COLOR}\n" $1 Error
    250. else
    251. printf "${NARMAL_COLOR}%-10s | %-8s | MRP process was found${RESET_COLOR}\n" $1 Success
    252. fi
    253. else
    254. echo -e "${ERROR_COLOR} $(date "+%Y-%m-%d %H:%M:%S") | Error! check_mrp_process() parameter 1 can't be null ${RESET_COLOR}"
    255. exit 1
    256. fi
    257. }
    258. # 检查从库延迟(transport lag,apply lag )
    259. # 参数1:TNS连接串,参数2:待检查的lag类型
    260. check_db_lag(){
    261. if [[ "$1" != "" && "$2" != "" ]]
    262. then
    263. DB_LAG=`sqlplus -s $DBUSER@$1 as sysdba << EOF
    264. set heading off feedback off pagesize 0 verify off echo off
    265. select (extract(second from to_dsinterval(value)) +
    266. extract(minute from to_dsinterval(value)) * 60 +
    267. extract(hour from to_dsinterval(value)) * 60 * 60 +
    268. extract(day from to_dsinterval(value)) * 60 * 60 * 24) as retvalue
    269. from v\\$dataguard_stats
    270. where name = '$2';
    271. EOF`
    272. #去除左侧空格
    273. DB_LAG=`eval echo $DB_LAG`
    274. if [[ "$DB_LAG" -gt 30 ]]
    275. then
    276. printf "${WARNING_COLOR}%-10s | %-8s | the $2 is too large($DB_LAG seconds)${RESET_COLOR}\n" $1 Warning
    277. else
    278. printf "${NARMAL_COLOR}%-10s | %-8s | the $2 is $DB_LAG second(s)${RESET_COLOR}\n" $1 Success
    279. fi
    280. else
    281. echo -e "${ERROR_COLOR} $(date "+%Y-%m-%d %H:%M:%S") | Error! check_db_lag() parameter 1 and 2 can't be null ${RESET_COLOR}"
    282. exit 1
    283. fi
    284. }
    285. # dblink检查
    286. # 参数1:TNS连接串
    287. check_dblink() {
    288. if [[ "$1" != "" ]]; then
    289. COUNT=$(
    290. sqlplus -s $DBUSER@$1 as sysdba <<EOF
    291. set heading off feedback off pagesize 0 verify off echo off
    292. select count(*) FROM dba_db_links;
    293. EOF
    294. )
    295. if [[ "$COUNT" -eq 0 ]]; then
    296. printf "${NARMAL_COLOR}%-10s | %-8s | There is no dblink in our database${RESET_COLOR}\n" $1 Success
    297. else
    298. printf "${WARNING_COLOR}%-10s | %-8s | dblink was found,please check the tns file and firewall${RESET_COLOR}\n" $1 Warning
    299. fi
    300. else
    301. echo -e "${ERROR_COLOR}$(date "+%Y-%m-%d %H:%M:%S") | Error! check_mrp_trigger() parameter 1 can't be null ${RESET_COLOR}"
    302. exit 1
    303. fi
    304. }
    305. # 对比两个值是否相等
    306. # 参数1:待比较值1,参数2:待比较值2
    307. compare_value() {
    308. if [[ "$1" = "$2" ]]; then
    309. printf "${NARMAL_COLOR}%-30s | %-8s | The value is $1 ${RESET_COLOR}\n" $3 Success
    310. else
    311. printf "${WARNING_COLOR}%-30s | %-8s | The value 1 is: $1,but value 2 is: $2 ${RESET_COLOR}\n" $3 Warning
    312. fi
    313. }
    314. # 待判断参数值中是否包含给定的子字符串
    315. # 参数1:TNS连接串;参数2:待判断参数名;参数3:待判断参数值;参数3:子字符串
    316. # 例如:include_value $PRIMARY_TNS "fal_server" "${PRIMARY_TNS_DIC[fal_server]}" $STANDBY_TNS
    317. include_value(){
    318. # 过滤结果
    319. cnt=`echo $3 | grep $4 | wc -l`
    320. if [[ "$cnt" -gt 0 ]]; then
    321. printf "${NARMAL_COLOR}%-10s | %-8s| %-20s | The value is $3,include $4 ${RESET_COLOR}\n" $1 Success $2
    322. else
    323. printf "${WARNING_COLOR}%-10s | %-8s| %-20s | The value is $3,doesn't include $4 ${RESET_COLOR}\n" $1 Warning $2
    324. fi
    325. }

    3. 执行效果

    二、 执行切换

    1. dg_switchover_v1.4.sh

    1. #!/bin/bash
    2. #**********************************************************************************
    3. # Author: Hehuyi_In
    4. # Date: 2022年06月10日
    5. # FileName: dg_switchover_v1.4.sh
    6. #
    7. # For sys user, execute the script directly.
    8. # For other sysdba privileged users, you need to manually synchronize the password file to standby server and chown file mode to 640 in versions below 12.2.
    9. #
    10. # Example: ./dg_switchover_v1.4.sh or ./dg_switchover_v1.4.sh &>> dg_switchover.log
    11. # Description:
    12. # 2022-06-10 v_1.0 only oracle dataguard switchover
    13. # 2022-06-10 v_1.1 check instance status and db role after switchover.
    14. # 2022-06-10 v_1.2 check transport lag,apply lag,switchover_status before switchover.
    15. # 2022-06-13 v_1.3 add logging for main steps
    16. # 2022-06-14 v_1.4 auto check and select the target primary and standby database.
    17. #**********************************************************************************
    18. # 连接信息
    19. DBUSER='sys/xxxxx'
    20. # TNS列表,越靠前的被选为目标主库的概率较高
    21. TNS_LIST=(mrptest mrptest_dg mrpuat)
    22. # 列表元素个数检查,目前仅支持一主一从或一主两从
    23. if [[ ${#TNS_LIST[@]} -lt 2 || ${#TNS_LIST[@]} -gt 3 ]]
    24. then
    25. echo "`date "+%Y-%m-%d %H:%M:%S"` | Error! The number of standby db is less than 1 or greater than 2."
    26. fi
    27. # ------------------------------------------------------------------------
    28. # 判断 TNS_LIST 中每个连接串角色,并设置各切换目标参数
    29. # 若为主库,则作为TARGET_STANDBY_TNS
    30. # 若为从库,则检查lag。如果lag均为0,则作为TARGET_PRIMARY_TNS,剩余的从库作为OUTLOOKING_STANDBY_TNS
    31. # 如果所有从库lag都大于0,则报错退出。
    32. auto_set_target_db_tns(){
    33. for TNS in ${TNS_LIST[@]}
    34. do
    35. # 获取TNS对应db角色
    36. DB_ROLE=`check_db_role $TNS`
    37. # 若为主库,则赋值给TARGET_STANDBY_TNS
    38. if [[ "$DB_ROLE" = "PRIMARY" ]]
    39. then
    40. TARGET_STANDBY_TNS=$TNS
    41. # 若为从库
    42. elif [[ "$DB_ROLE" = "PHYSICAL STANDBY" ]]
    43. then
    44. # 如果TARGET_PRIMARY_TNS不为空,说明已经设置过了目标主库,直接设置旁观从库即可
    45. if [[ "$TARGET_PRIMARY_TNS" != "" ]]
    46. then
    47. OUTLOOKING_STANDBY_TNS=$TNS
    48. else
    49. # 若TARGET_PRIMARY_TNS为空,则需要再检查lag
    50. DB_TRAN_LAG=`check_db_lag $TNS "transport lag"`
    51. DB_APPLY_LAG=`check_db_lag $TNS "apply lag"`
    52. # 如果lag均为0,则赋值给TARGET_PRIMARY_TNS
    53. if [[ "$DB_TRAN_LAG" -eq 0 && "$DB_APPLY_LAG" -eq 0 ]]
    54. then
    55. TARGET_PRIMARY_TNS=$TNS
    56. fi
    57. fi
    58. fi
    59. done
    60. # 设置后检查,若TARGET_PRIMARY_TNS或TARGET_STANDBY_TNS为空,直接报错退出
    61. if [[ "$TARGET_PRIMARY_TNS" = "" || "$TARGET_STANDBY_TNS" = "" ]]
    62. then
    63. echo "`date "+%Y-%m-%d %H:%M:%S"` | Error! TARGET_PRIMARY_TNS and TARGET_STANDBY_TNS can't be null."
    64. exit 1
    65. fi
    66. }
    67. # ------------------------------------------------------------------------
    68. # 检查从库延迟(transport lag,apply lag )
    69. # 参数1为db对应的tnsname,参数2为待检查的lag
    70. check_db_lag(){
    71. if [[ "$1" != "" && "$2" != "" ]]
    72. then
    73. sqlplus -s $DBUSER@$1 as sysdba << EOF
    74. set heading off feedback off pagesize 0 verify off echo off
    75. select (extract(second from to_dsinterval(value)) +
    76. extract(minute from to_dsinterval(value)) * 60 +
    77. extract(hour from to_dsinterval(value)) * 60 * 60 +
    78. extract(day from to_dsinterval(value)) * 60 * 60 * 24) as retvalue
    79. from v\$dataguard_stats
    80. where name = '$2';
    81. EOF
    82. else
    83. echo "`date "+%Y-%m-%d %H:%M:%S"` | Error! parameter 1,2 can't be null."
    84. exit 1
    85. fi
    86. }
    87. # ------------------------------------------------------------------------
    88. # 检查切换前switchover_status
    89. # 参数1为db对应的tnsname,参数2为待检查的状态
    90. check_switchover_status(){
    91. if [[ "$1" != "" && "$2" != "" ]]
    92. then
    93. STATUS=`sqlplus -s $DBUSER@$1 as sysdba << EOF
    94. set heading off feedback off pagesize 0 verify off echo off
    95. select switchover_status from v\\$database;
    96. EOF`
    97. if [[ "$STATUS" = $2 || "$STATUS" = "SESSIONS ACTIVE" ]]
    98. then
    99. echo "`date "+%Y-%m-%d %H:%M:%S"` | Success! switchover_status of $1 is $STATUS."
    100. else
    101. echo "`date "+%Y-%m-%d %H:%M:%S"` | Error! switchover_status of $1 is $STATUS (should be $2 or SESSIONS ACTIVE)."
    102. exit 1
    103. fi
    104. else
    105. echo "`date "+%Y-%m-%d %H:%M:%S"` | Error! parameter 1 and 2 can't be null."
    106. exit 1
    107. fi
    108. }
    109. # ------------------------------------------------------------------------
    110. # 检查db角色,参数1为db对应的tnsname
    111. check_db_role(){
    112. if [[ "$1" != "" ]]
    113. then
    114. sqlplus -s $DBUSER@$1 as sysdba << EOF
    115. set heading off feedback off pagesize 0 verify off echo off
    116. select database_role from v\$database;
    117. EOF
    118. else
    119. echo "`date "+%Y-%m-%d %H:%M:%S"` | Error! parameter 1 should be tnsname."
    120. exit 1
    121. fi
    122. }
    123. # ------------------------------------------------------------------------
    124. # 检查切换后实例状态
    125. # 参数1为db对应的tnsname
    126. check_instance_status(){
    127. if [[ "$1" != "" ]]
    128. then
    129. STATUS=`sqlplus -s $DBUSER@$1 as sysdba << EOF
    130. set heading off feedback off pagesize 0 verify off echo off
    131. select status from v\\$instance;
    132. EOF`
    133. if [[ "$STATUS" != "OPEN" ]]
    134. then
    135. echo "`date "+%Y-%m-%d %H:%M:%S"` | Error! instance status of $1 is $STATUS after switchover."
    136. exit 1
    137. else
    138. echo "`date "+%Y-%m-%d %H:%M:%S"` | Success! instance status of $1 is $STATUS after switchover."
    139. fi
    140. else
    141. echo "`date "+%Y-%m-%d %H:%M:%S"` | Error! parameter 1 can't be null."
    142. exit 1
    143. fi
    144. }
    145. # ------------------------------- main() -----------------------------------------
    146. echo "------------------------------------------------------------------------"
    147. echo "`date "+%Y-%m-%d %H:%M:%S"` | Precheck before switchover..."
    148. # 判断 TNS_LIST 中每个连接串角色,并设置各切换目标参数
    149. auto_set_target_db_tns
    150. # 设置后各目标参数值
    151. echo "`date "+%Y-%m-%d %H:%M:%S"` | TARGET_PRIMARY_TNS: $TARGET_PRIMARY_TNS"
    152. echo "`date "+%Y-%m-%d %H:%M:%S"` | TARGET_STANDBY_TNS: $TARGET_STANDBY_TNS"
    153. echo "`date "+%Y-%m-%d %H:%M:%S"` | OUTLOOKING_STANDBY_TNS: $OUTLOOKING_STANDBY_TNS"
    154. # 切换前switchover_status检查
    155. check_switchover_status $TARGET_STANDBY_TNS "TO STANDBY"
    156. # 目标从库(原主库)执行:将原主库转切为从库
    157. echo "`date "+%Y-%m-%d %H:%M:%S"` | Begin switchover $TARGET_STANDBY_TNS to standby database..."
    158. sqlplus -s $DBUSER@$TARGET_STANDBY_TNS as sysdba << EOF
    159. alter database commit to switchover to standby with session shutdown;
    160. shutdown immediate
    161. EOF
    162. echo "`date "+%Y-%m-%d %H:%M:%S"` | Restarting $TARGET_STANDBY_TNS database..."
    163. # 重新启动目标从库
    164. sqlplus -s $DBUSER@$TARGET_STANDBY_TNS as sysdba << EOF
    165. startup
    166. EOF
    167. # 切换后角色检查
    168. DB_ROLE=`check_db_role $TARGET_STANDBY_TNS`
    169. if [[ "$DB_ROLE" != "PHYSICAL STANDBY" ]];
    170. then
    171. echo "`date "+%Y-%m-%d %H:%M:%S"` | Error! db role of $TARGET_STANDBY_TNS is $DB_ROLE(should be PHYSICAL STANDBY) after switchover."
    172. exit 1
    173. else
    174. echo "`date "+%Y-%m-%d %H:%M:%S"` | Success! db role of $TARGET_STANDBY_TNS is $DB_ROLE after switchover."
    175. fi
    176. # 切换后实例状态检查
    177. check_instance_status $TARGET_STANDBY_TNS
    178. echo "`date "+%Y-%m-%d %H:%M:%S"` | Finish switchover $TARGET_STANDBY_TNS to standby database."
    179. # ------------------------------------------------------------------------
    180. echo "`date "+%Y-%m-%d %H:%M:%S"` | Precheck before switchover $TARGET_PRIMARY_TNS to primary database..."
    181. # 切换前switchover_status检查
    182. check_switchover_status $TARGET_PRIMARY_TNS "TO PRIMARY"
    183. # 目标主库(原从库)执行
    184. # 将原从库切为主库
    185. echo "`date "+%Y-%m-%d %H:%M:%S"` | Begin switchover $TARGET_PRIMARY_TNS to primary database..."
    186. sqlplus -s $DBUSER@$TARGET_PRIMARY_TNS as sysdba << EOF
    187. alter database commit to switchover to primary with session shutdown;
    188. ALTER DATABASE OPEN;
    189. EOF
    190. # 切换后角色检查
    191. DB_ROLE=`check_db_role $TARGET_PRIMARY_TNS`
    192. if [[ "$DB_ROLE" != "PRIMARY" ]];
    193. then
    194. echo "`date "+%Y-%m-%d %H:%M:%S"` | Error! db role of $1 is $DB_ROLE(should be PRIMARY) after switchover."
    195. exit 1
    196. else
    197. echo "`date "+%Y-%m-%d %H:%M:%S"` | Success! db role of $1 is $DB_ROLE after switchover."
    198. fi
    199. # 切换后实例状态检查
    200. check_instance_status $TARGET_PRIMARY_TNS
    201. # 切换后从库lag检查
    202. DB_TRAN_LAG=`check_db_lag $TARGET_STANDBY_TNS "transport lag"`
    203. DB_APPLY_LAG=`check_db_lag $TARGET_STANDBY_TNS "apply lag"`
    204. echo "`date "+%Y-%m-%d %H:%M:%S"` | After switchover: DB_TRAN_LAG is $DB_TRAN_LAG second(s), DB_APPLY_LAG is $DB_APPLY_LAG second(s)"
    205. echo "`date "+%Y-%m-%d %H:%M:%S"` | Finish switchover $TARGET_PRIMARY_TNS to primary database."
    206. # ------------------------------------------------------------------------
    207. # 如果有旁观从库
    208. if [ "$OUTLOOKING_STANDBY_TNS" != "" ]; then
    209. echo "`date "+%Y-%m-%d %H:%M:%S"` | Begin onlooking standby database setting..."
    210. # 目标主库调整参数,指向旁观从库,先清空再设置,否则有可能报参数冲突
    211. sqlplus -s $DBUSER@$TARGET_PRIMARY_TNS as sysdba << EOF
    212. alter system set LOG_ARCHIVE_DEST_2='';
    213. alter system set LOG_ARCHIVE_DEST_3='';
    214. alter system set LOG_ARCHIVE_DEST_2='SERVICE=$TARGET_STANDBY_TNS ASYNC VALID_FOR=(ONLINE_LOGFILES,PRIMARY_ROLE) DB_UNIQUE_NAME=$TARGET_STANDBY_TNS';
    215. alter system set LOG_ARCHIVE_DEST_3='SERVICE=$OUTLOOKING_STANDBY_TNS ASYNC VALID_FOR=(ONLINE_LOGFILES,PRIMARY_ROLE) DB_UNIQUE_NAME=$OUTLOOKING_STANDBY_TNS';
    216. EOF
    217. # 目标从库调整参数,断开到旁观从库的连接
    218. sqlplus -s $DBUSER@$TARGET_STANDBY_TNS as sysdba << EOF
    219. alter system set LOG_ARCHIVE_DEST_3='';
    220. alter system set LOG_ARCHIVE_DEST_2='SERVICE=$TARGET_PRIMARY_TNS ASYNC VALID_FOR=(ONLINE_LOGFILES,PRIMARY_ROLE) DB_UNIQUE_NAME=$TARGET_PRIMARY_TNS';
    221. EOF
    222. # 旁观从库调整参数,指向新主库
    223. sqlplus -s $DBUSER@$OUTLOOKING_STANDBY_TNS as sysdba << EOF
    224. alter system set LOG_ARCHIVE_DEST_3='';
    225. alter system set LOG_ARCHIVE_DEST_2='SERVICE=$TARGET_PRIMARY_TNS ASYNC VALID_FOR=(ONLINE_LOGFILES,PRIMARY_ROLE) DB_UNIQUE_NAME=$TARGET_PRIMARY_TNS';
    226. EOF
    227. # 切换后旁观从库lag检查
    228. DB_TRAN_LAG=`check_db_lag $OUTLOOKING_STANDBY_TNS "transport lag"`
    229. DB_APPLY_LAG=`check_db_lag $OUTLOOKING_STANDBY_TNS "apply lag"`
    230. echo "`date "+%Y-%m-%d %H:%M:%S"` | After setting: DB_TRAN_LAG is $DB_TRAN_LAG second(s), DB_APPLY_LAG is $DB_APPLY_LAG second(s)"
    231. echo "`date "+%Y-%m-%d %H:%M:%S"` | Finish onlooking standby database setting."
    232. else # 没有旁观从库
    233. echo "`date "+%Y-%m-%d %H:%M:%S"` | There is no onlooking standby database."
    234. fi

  • 相关阅读:
    你还在凭感觉来优化性能?
    Redis Desktop Manager安装和使用
    读《DevOps实践指南》有感
    Activiti进阶
    如何优化百度搜索引擎?(10个技巧让你的网站更容易被搜索到)
    聊一聊作为高并发系统基石之一的缓存,会用很简单,用好才是技术活
    [CSS入门到进阶] 你真的了解 width height 吗?
    JAVA中常用序列化与反序列化合集
    windows2022远程桌面连接管理员已结束会话解决方法
    ai绘画部署教程
  • 原文地址:https://blog.csdn.net/Hehuyi_In/article/details/104712805