Greenplum 数据库按照指定 schema 恢复脚本




  • 前言

    Greenplum 作为OLAP 系统,通过在多个服务器或主机逐渐分配负载来存储和处理大规模业务数据。组成 Greenplum 数据库集群中的每一个计算节点是由独立的 PostgreSQL 实例构成。节点之间的通过 interconnect 相互通信来流转数据。Greenplum 数据库可以运行在多种 X86 架构的平台上,性能取决于安装平台的硬件。由于数据库数据分布在每一个 PostgreSQL 实例中,因此,单个 PostgreSQL 实例的配置性能会影响整个集群的性能。

    为什么要构建该脚本

    考虑到某些环境中的服务器配置可能采用的是虚拟机,而虚拟机的硬件由于虚拟化可能被多个其他系统中的环境共享,因此,尽管和物理环境的配置一样,但是性能却不能达到和物理环境的性能,因此,在恢复过程中,可能会碰到这样或那样的问题,所以对于一个可备份恢复的系统来说,如何将备份的数据恢复到整个集群中非常重要。当然,除了恢复数据以外, Greenplum 本身也提供数据同步工具,但是类似的这种工具需要不同集群中间的网络能够通信,否则,只能进行物理恢复的方式来将不同平台或者同平台数据库中的数据恢复到目标服务器上。

    备份脚本设计

    备份通过采用 gp_dump 命令来进行备份数据,尽管 gp_dump 已经在当前的所有版本中被丢弃,由 gpcrondump 来代替,而 gpcrondump 实际上是对 gp_dump 命令的封装重构,为了保证4.x 版本以前的兼容性,所以该命令依旧被保留。同时,gpbackup 和 gprestore 也是用来备份和恢复数据的工具,但是仅仅使用于非开发 5.0 以上的版本。

    gp_dump 如果对于数据备份到一个文件中,那么会面临两个问题,一是恢复时间长,另一个是如果在恢复期间出现问题,那么意味着需要重新恢复,浪费时间。那么采用 schema 备份的就可以处理该问题。

    当然,可能有同学会问, gp_dump 本身可以来备份 schema,写一个简单的备份脚本不就行了吗?答案却是如此,但是需要考略到一个问题,如果经过多次备份,那么恢复的时间戳需要独立去寻找,那么这个对于我们来说,就不是很方便了,而通过脚本,只需要在时间戳目录下找到指定的备份日期,就可以实现对任意时间段备份的数据进行恢复。而此脚本正是通过时间戳目录中记录的时间戳备份文件来进行备份数据,恢复的时候可以使用该时间戳目录。

    <code><code><span class="code-snippet_outer"><span class="code-snippet__meta">#!/bin/bash</span></span></code><code><span class="code-snippet_outer">  <span class="code-snippet__comment">####################################################</span></span></code><code><span class="code-snippet_outer">  <span class="code-snippet__comment">#Description: Backup schema for specifying database#</span></span></code><code><span class="code-snippet_outer">  <span class="code-snippet__comment">#Author:sungsasong                                 #</span></span></code><code><span class="code-snippet_outer">  <span class="code-snippet__comment">#Purpose:Backup database                           #</span></span></code><code><span class="code-snippet_outer">  <span class="code-snippet__comment">#Version: 1.0                                      #</span></span></code><code><span class="code-snippet_outer">  <span class="code-snippet__comment">#Date:2021-12-08                                   #</span></span></code><code><span class="code-snippet_outer">  <span class="code-snippet__comment">####################################################</span></span></code><code><span class="code-snippet_outer">
      #Defining relative directory
      #Current Directory   CURRENT_DIR=$(cd "$(dirname $0)";pwd)
      #Top Level Directory  TOP_DIR=$(cd ${CURRENT_DIR}/..;pwd)
      #Defining relative log files  LOG=${TOP_DIR}/log/log  SUCCESS_LOG=${TOP_DIR}/log/success_log  ERRLOG=${TOP_DIR}/log/error_log
      >${LOG}  >${ERRLOG}
      #Loading configuration file  source ${TOP_DIR}/conf/backup.conf  source ${TOP_DIR}/lib/funclib
      #Defining init Timestamp  TS=`date '+%Y%m%d%H%M%S'`
      #Defining timestamp file  TSFILE=${TOP_DIR}/tsdir/timestamp_${BAKDATE}
      #Defining save timstamp directory  TSDIR=${TOP_DIR}/tsdir
      #Define Database connection string  CONNINFO="psql -d ${DATABASE} -U ${USERNAME} -p ${DBPORT} -Atq -c"
    
      check_dir_valid()  {      if [ ! -d ${TSDIR} ];then          print_success_log "The ${TSDIR} will be created"          mkdir -p ${TSDIR}      else           print_log "The directory has been exists !"      fi  }
    
      #Defining fetch schema sql  FETCH_SCHEMA_SQL="  SELECT nspname  FROM pg_catalog.pg_namespace  WHERE nspname !~ '^pg|gp_toolkit|information_schema' "
      #Fetching schema from database  SCHEMALIST=`${CONNINFO} "${FETCH_SCHEMA_SQL}"`
    
      function backup_task()  {      for sname in ${SCHEMALIST};do          TS=`date '+%Y%m%d%H%M%S'`          #The file will be used to save timestamp and schema name when we start this scripts          echo "${TS} ${sname}" >>${TSFILE}          gp_dump --gp-c --gp-d=${BACKUPDIR} --gp-k=${TS} --gp-r=${REPORTDIR} -n ${sname} ${DATABASE} 1>>${SUCCESS_LOG} 2>&1      done      ERROR=$(grep -i -c -E 'ERROR' ${SUCCESS_LOG})      if [ ${ERROR} -ge 1 ];then          print_error_log "Backup data failed,please check error info  from ${SUCCESS_LOG}"          exit 88      fi       }
      print_log ">>>>>>>>>>>>>>>>>>>>>>>>Starting backup"
      check_dir_valid
      print_success_log ">>>>>>>>>>>>>>>>>>>>>>>>Schema `echo ${SCHEMALIST}` will be dump"
      backup_task
      print_success_log ">>>>>>>>>>>>>>>>>>>>>>>>Finished backup,Please checking the relative directory"
     

     

     

    恢复脚本

    默认恢复脚本使用最新的一个备份文件用来恢复数据。

    <code><code><span class="code-snippet_outer"><span class="code-snippet__meta">#!/bin/bash</span></span></code><code><span class="code-snippet_outer">  <span class="code-snippet__comment">####################################################</span></span></code><code><span class="code-snippet_outer">  <span class="code-snippet__comment">#Description: Restoring schema for specifying database#</span></span></code><code><span class="code-snippet_outer">  <span class="code-snippet__comment">#Author:sungsasong                                 #</span></span></code><code><span class="code-snippet_outer">  <span class="code-snippet__comment">#Purpose:Restoring data                            #</span></span></code><code><span class="code-snippet_outer">  <span class="code-snippet__comment">#Version: 1.0                                      #</span></span></code><code><span class="code-snippet_outer">  <span class="code-snippet__comment">#Date:2021-12-08                                   #</span></span></code><code><span class="code-snippet_outer">  <span class="code-snippet__comment">####################################################</span></span></code><code><span class="code-snippet_outer">
      #Defining relative directory
      #Current Directory   CURRENT_DIR=$(cd "$(dirname $0)";pwd)
      #Top Level Directory  TOP_DIR=$(cd ${CURRENT_DIR}/..;pwd)
      #Define Database connection string  CONNINFO="psql -d ${DATABASE} -U ${USERNAME} -p ${DBPORT} -Atq -c"
      #Defining relative log files  RESTORELOG=${TOP_DIR}/log/restore_log  RESTOREERRLOG=${TOP_DIR}/log/restore_error_log  TSDIR=${TOP_DIR}/tsdir  >${RESTORELOG}  >${RESTOREERRLOG}  #Loading configuration file  source ${TOP_DIR}/conf/backup.conf  source ${TOP_DIR}/lib/funclib
      #Getting restore timestamp  LASTESTFILE=`ls -rth ${TSDIR}/ | tail -1`
      #Loading restore timestamp and schema  RESTORETS=`cat ${TSDIR}/${LASTESTFILE} | awk '{print $1}'`  RESTORESCHEMA=(`cat ${TSDIR}/${LASTESTFILE} | awk '{print $2}'`)
      #Restoring data for every schema
      function restore_data()  {      print_success_log ">>>>>>Beginning restore data ^V^"      while read line ;do          fetch_schema=$(echo ${line} | awk '{print $2}')          fetch_ts=$(echo ${line} | awk '{print $1}')          print_log " >>>>>>${fetch_schema} schema will be restored,timestamp is:${fetch_ts}"          gp_restore -h ${HOST} -U ${USERNAME} -d ${DATABASE} -p ${DBPORT} --gp-c --gp-d=${BACKUPDIR} --gp-k=${fetch_ts} --gp-r=${REPORTDIR}  1>>${RESTORELOG} 2>&1          ERROR=$(grep -i -c -E 'ERROR' ${RESTORELOG})          if [ ${ERROR} -ge 1 ];then              print_error_log "Restoring data failed,please check error info  from ${RESTORLOG}"              exit 88          fi      done<${TSDIR}/${LASTESTFILE}      print_success_log ">>>>>>Restoring data finished ^_^"  }
      restore_data
     

     

    结语

    以上通过执行两个脚本可以实现按照 schema 来备份数据,同时也可以通过schema 恢复最新一次备份的数据,供大家参考。

     

    Speak Your Mind

    *