0%

一、判断主备角色
有几个方法可以判断:
1、查看wal进程

1
$ ps aux grep wal

如果进程名有”postgres: 11/main: walwriter”字样,则为主库,walwriter为wal发送方。
如果进程名有”postgres: 11/main: walreceiver streaming 2A/ACAA1088”字样,则为备库,walreceiver为wal接收方。
2、pg_is_in_recovery函数

1
2
3
4
5
6
$ sudo -u postgres psql
postgres=# select pg_is_in_recovery();
pg_is_in_recovery
-------------------
f
(1 row)

显示f说明是主库,显示t说明为备库。
3、查看数据库控制信息

1
2
3
4
5
6
7
8
9
$ sudo -u postgres /usr/lib/postgresql/11/bin/pg_controldata -D /var/lib/postgresql/11/main/
g_control version number: 1100
Catalog version number: 201809051
Database system identifier: 6745356148899875633
Database cluster state: in production
pg_control last modified: Thu 09 Jul 2020 02:40:49 PM CST
Latest checkpoint location: 825/245660D8
Latest checkpoint's REDO location: 825/245660A0
...

Database cluster state这行为in production说明位主库,为in archive recovery说明为备库。
4、通过recovery.conf 文件判断
一般的,备库才有recovery.conf,主库一般没有或是改名为recovery.done

二、主备切换
1、使用trigger文件切换

a. 在备库启动时在 recovery.conf 文件中加入一个触发文件的路径(新加则需要重启备库)

1
trigger_file='/var/lib/postgresql/11/main/.postgresql.trigger'

b. 关闭主库:

1
$ sudo systemctl stop postgresql@11-main.service

或者
先查看postgresql集群信息

1
2
3
$ pg_lsclusters
Ver Cluster Port Status Owner Data directory Log file
11 main 5432 online postgres /var/lib/postgresql/11/main /var/log/postgresql/postgresql-11-main.log

然后执行:

1
$ sudo pg_ctlcluster 11 main stop

c.在备库上创建trigger文件

1
$ sudo touch /var/lib/postgresql/11/main/.postgresql.trigger

可以看到备库上的recovery文件已经成为done了,此时备库已经被激活为主库,可以直接做读写操作了
在新主库上创建复制槽

d. 原主库搭建为新备库
准备recovery.conf文件,primary_conninfo指向新主库,使用合适的复制槽,然后重新启动数据库即可。

1
2
3
4
recovery_target_timeline='latest'
standby_mode = 'on'
primary_conninfo = 'host=59.206.31.149 port=5432 user=xxxx password=xxxx'
primary_slot_name = 'repl_slot_2'

这里必须添加recovery_target_timeline=’latest’,因为主备切换时timeline更新了。
注意pg_hba_conf中对replication的权限设定

2、使用pg_ctlcluster命令切换
a. 停止应用程序,关闭主库
b. 备库提升为主库
备库端执行:

1
$ sudo pg_ctlcluster 11 main promote

c. 老主库上配置recovery.conf文件,启动原主库为新的备库

References:
[1]26.3. Failover
[2]PostgreSQL 流复制的主备切换
[3]PostgreSQL Switchover vs. Failover
[4]PostgreSQL主备切换

NFS通常情况下会使用动态端口,对于防火墙配置很不友好。
可以设置使用固定的几个端口。
修改以下配置文件:
/etc/default/nfs-common:

1
STATDOPTS="--port 3000 --outgoing-port 3001"

/etc/default/nfs-kernel-server:

1
RPCMOUNTDOPTS="--manage-gids --port 3002"

新添加配置文件:
/etc/sysctl.d/nfs-static-ports.conf:

1
2
fs.nfs.nlm_tcpport = 3003
fs.nfs.nlm_udpport = 3003

然后:

1
2
3
$ sudo sysctl -p /etc/sysctl.d/nfs-static-ports.conf
$ sudo systemctl restart nfs-utils.service
$ sudo systemctl restart nfs-kernel-server.service

然后打通防火墙的TCP和UDP端口:111,2049,3000-3003就可以了。

如果出现错误:

1
mount.nfs: access denied by server while mounting ...

可以检查/etc/exports设置的访问网段是否正确,如果通过防火墙NAT方式访问,端口号会大约1024,需要添加insecure访问选项,比如(insecure,rw)

修改/etc/exports后,可以使用

1
$ sudo exportfs -a

重新导出文件系统

References:
[1]SecuringNFS
[2]Setting Up iptables for NFS on Ubuntu

1、danted
安装

1
$ sudo apt install dante-server

配置/etc/danted.conf

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
logoutput: syslog /var/log/sockd.log stdout
internal: br0 port = 1080
external: 10.100.0.32
clientmethod: none
socksmethod: none
user.privileged: proxy
user.unprivileged: nobody
user.libwrap: nobody
client pass {
from: 0.0.0.0/0 port 1-65535 to: 0.0.0.0/0
}
socks pass {
from: 0.0.0.0/8 to: 0.0.0.0/0
command: bind connect udpassociate
log: error
}

References:
[1]

sshfs可以通过ssh和sftp协议来安全的在本地挂载远程文件系统,比NFS更方便的是无需更改防火墙设置,只要能使用ssh访问远程主机就可以了。

sshfs使用fuse在用户空间挂载远程文件系统,debian系统直接安装sshfs包,为了方便挂载,最好配置使用公私钥对来访问远程ssh主机,特别是fstab文件不支持ssh的密码访问方式。

挂载远程文件系统:

1
$ sshfs user@host:/mnt/data/reis_dump/ /mnt/hwy06_reisdb_bak/ -o reconnect,ServerAliveInterval=15,ServerAliveCountMax=3

也支持直接使用ssh别名

1
$ sshfs hwy-reisdb-3:/mnt/data/reis_dump/ /mnt/hwy06_reisdb_bak/ -o reconnect,ServerAliveInterval=15,ServerAliveCountMax=3

支持断线重连和心跳保持
具体的sshfs选项参见man

还有一个fuse文件系统挂载选项allow_other影响挂载的sshfs文件系统访问权限,如果允许除挂载用户之外的其他用户访问文件系统,需要指定此选项,并且需要修改fuse配置文件/etc/fuse.conf,打开user_allow_other选项

1
2
# Allow non-root users to specify the allow_other or allow_root mount options.
user_allow_other

还可以写入fstab,开机可以自动挂载sshfs
/etc/fstab

1
user@host:/var/www/ /var/www/ fuse.sshfs defaults,_netdev,allow_other,follow_symlinks,identityfile=/home/user/.ssh/id_rsa,reconnect,ServerAliveInterval=15,ServerAliveCountMax=3 0 0

在这里,_netdev挂载选项指定挂载sshfs需要有网络支持,follow_symlinks是sshfs的选项,支持符号链接,identityfile选项是ssh的选项,指定登录凭证,也可以通过.ssh/config配置别名来指定登录选项。

注意:
ssh长时间连接会超时,导致出现类似错误提示:

1
client_loop: send disconnect: Broken pipe

可以在ssh服务器/etc/ssh/sshd_config中打开客户端心跳探测:

1
2
ClientAliveInterval 30
ClientAliveCountMax 3

30秒发送一个心跳探测,超过3次没有回应断开连接。

References:
[1]SSHFS: Mounting a remote file system over SSH
[2]SSHFS

客户端连接失败,提示ORA-19815,alert.log有以下提示:
Errors in file /u01/app/oracle/admin/orcl/bdump/orcl_arc0_2734.trc:
ORA-19815: WARNING: db_recovery_file_dest_size of 2147483648 bytes is 100.00% used, and has 0 remaining bytes available.
Wed Jun 24 09:02:21 2020


You have following choices to free up space from flash recovery area:

  1. Consider changing RMAN RETENTION POLICY. If you are using Data Guard,
    then consider changing RMAN ARCHIVELOG DELETION POLICY.
  2. Back up files to tertiary device such as tape using RMAN
    BACKUP RECOVERY AREA command.
  3. Add disk space and increase db_recovery_file_dest_size parameter to
    reflect the new space.
  4. Delete unnecessary files using RMAN DELETE command. If an operating
    system command was used to delete files, then use RMAN CROSSCHECK and
    DELETE EXPIRED commands.

查看磁盘空间还有很多剩余空间,是因为默认的归档目标设置为USE_DB_RECOVERY_FILE_DEST,并且flash_recovery_area的最大尺寸设置为了2GB(db_recovery_file_dest_size= 2147483648),可以有多种方法来解决此问题,通过设置RMAN归档保持策略来自动删除过期的日志文件。也可以使用RMAN DELETE来删除日志文件。
比如删除系统时间1天以前的归档日志

1
RMAN>delete archivelog all completed before 'sysdate-1';

如果使用操作系统命令直接删除归档文件,并不能真正释放空间,还需要执行:

1
2
3
$ rman target /
rman> crosscheck archivelog all;
rman> delete expired archivelog all;

cassandra集群以前运行于本地机房,现在需要扩展到云端,云主机添加为集群的新数据中心。因为并不是公有云,所有没有启动SSL认证和加密。

本地机房与云机房通过专线连接,并且本地只有两个互联ip地址可用。本地机房原集群内节点只使用私有网络地址,无法被云端访问。云端主机使用私有地址,云平台将私有地址映射到专线可以访问的“公有地址”,这里并不是真正的“公有地址”,仍然是一个大的私有网络,不过本地机房和云机房通过这些地址可以互访,所有这里也叫做“公有地址”

因此集群的本地机房节点通过NAT映射,将私有地址的7000和9042端口映射到公有地址,从而可以被云主机访问,同时做了端口回流,保证本地机房其他机器也可以通过公有地址访问节点。
如果不做或不能做端口回流,应该也可以使用iptables/nftables在集群内节点以及需要访问集群的客户机器上添加nat转换规则,从公有ip转换到对应的私有ip,这个没试。

这样本地机房和云机房的节点都有私有地址和映射后的公有地址,cassandra集群节点需要使用公有地址进行互访,但cassandra都无法直接监听公有地址。这需要配置cassandra.yaml,设置listen_address和rpc_address为私有地址,设置broadcast_address和broadcast_rpc_address为公有ip地址,但是listen_on_broadcast_address设置为false,因为各个节点并不能在公有ip上监听。这样当跨数据中心时使用公有ip通讯,但在本地网络内部可以使用私有网络。

cassandra-rackdc.properties配置文件可以打开prefer_local选项,这样可以优先使用本地网络,降低网络延迟。

配置实例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
listen_address: 192.168.136.250
broadcast_address: 59.206.31.152
rpc_address: 192.168.136.250
broadcast_rpc_address: 59.206.31.152

seed_provider:
# Addresses of hosts that are deemed contact points.
# Cassandra nodes use this list of hosts to find each other and learn
# the topology of the ring. You must change this if you are running
# multiple nodes!
- class_name: org.apache.cassandra.locator.SimpleSeedProvider
parameters:
# seeds is actually a comma-delimited list of addresses.
# Ex: "<ip1>,<ip2>,<ip3>"
- seeds: "59.206.31.152,10.160.4.196,10.160.4.197"

这样本地数据中心和云数据中心就可以通过公有ip相互通讯了。
备注:rpc并不是必须的,只使用cql是可行的。

References:
[1]Using multiple network interfaces

brew upgrade升级了openssh以后,每次登录远程服务器都提示:

1
load pubkey "/Users/xxx/.ssh/id_rsa": invalid format

因为客户端根本就没存储公钥啊,为什么要读取公钥?公钥放在服务器端了啊

客户端重新生成对应的公钥,满足openssh的无理要求就可以了:

1
$ ssh-keygen -f ~/.ssh/id_rsa -y > ~/.ssh/id_rsa.pub

以前也没这问题。

因为某云在某个网络内没有debian安装源,所以只能使用本地源。
debian支持的软件包很多,amd64架构的dvd iso竟然有16张之多,bd格式iso则只有4张,这里使用dvd格式的iso。

首先,下载debian 10.1.0 amd64架构的dvd iso,http方式只能下载前三个iso,下载其他iso需要使用jigdo方式即时下载在线制作iso文件。

debian系统安装jigdo-file使用jigdo-lite命令,输入iso的jigdo文件url即可下载制作iso镜像。debian 10.1.0 dvd iso的jigdo下载地址在此
因为需要安装的包postgresql-11-postgis-2.5不在前三张dvd,所以使用jigdo下载了第四张dvd镜像。

然后,将四张dvd iso分别挂载到/media目录的挂载点:

1
2
3
4
# mount /path/to/debian-10.1.0-amd64-DVD-1.iso /media/cdrom1/
# mount /path/to/debian-10.1.0-amd64-DVD-2.iso /media/cdrom2/
# mount /path/to/debian-10.1.0-amd64-DVD-3.iso /media/cdrom3/
# mount /path/to/debian-10.1.0-amd64-DVD-4.iso /media/cdrom4/

也可以添加到/etc/fstab:

1
2
3
4
/srv/debsrcs/debian-10.1.0-amd64-DVD-1.iso/media/cdrom1udf,iso9660 loop 0 0
/srv/debsrcs/debian-10.1.0-amd64-DVD-2.iso/media/cdrom2udf,iso9660 loop 0 0
/srv/debsrcs/debian-10.1.0-amd64-DVD-3.iso/media/cdrom3udf,iso9660 loop 0 0
/srv/debsrcs/debian-10.1.0-amd64-DVD-4.iso/media/cdrom4udf,iso9660 loop 0 0

然后

1
# mount -a

编辑/etc/apt/sources.list文件,添加如下行:

1
2
3
4
deb \[ trusted=yes \] file:/media/cdrom1/ buster main contrib 
deb \[ trusted=yes \] file:/media/cdrom2/ buster main contrib
deb \[ trusted=yes \] file:/media/cdrom3/ buster main contrib
deb \[ trusted=yes \] file:/media/cdrom4/ buster main contrib

最后,apt update后正常安装软件即可,如果要安装的软件还是找不到,可能需要下载更多的dvd iso镜像。

使用rman convert database将oracle 10g 10.2.0.4 for windows x64环境下的数据库转换到oracle 10g 10.2.0.4 for linux x64环境下。

**注意:**无法使用standby备库来进行转换。

1、以只读方式打开数据库

1
2
3
SQL> shutdown immediate
SQL> startup mount
SQL> alter database open read only;

2、检查可转换性和标示外部对象。

使用DBMS_TDB.CHECK_DB检查数据库状态,是否可以顺利转换到目标平台:

1
2
3
4
5
6
7
8
9
SQL> set serveroutput on
SQL> declare
    db_ready boolean;
  begin
    /* db_ready is ignored, but with SERVEROUTPUT set to ON any 
     * conditions preventing transport will be output to console */
    db_ready := dbms_tdb.check_db('Linux x86 64-bit', dbms_tdb.skip_none);
  end;
/

DBMS_TDB.CHECK_DB返回TRUE表示可以转换到目标平台,返回FALSE则不可以,同时会输出不可已转换的原因。

使用DBMS_TDB.CHECK_EXTERNAL标识外部对象。

1
2
3
4
5
6
7
8
9
10
SQL> set serveroutput on
SQL> declare
     external boolean;
  begin
    /* value of external is ignored, but with SERVEROUTPUT set to ON
     * dbms_tdb.check_external displays report of external objects
     * on console */
    external := dbms_tdb.check_external;
  end;
/

如果有外部对象会在输出中显示出来。

3、转换数据库

可以在源数据库,也可以在目标数据库进行数据文件的转换。这里选择在目标数据库进行数据文件转换,这样可以减少源数据库的停止服务时间。

在源数据库执行rman convert database:

1
2
3
4
5
6
$ rman target sys/passwd@dbinst
RMAN> CONVERT DATABASE ON TARGET PLATFORM
CONVERT SCRIPT 'D:\\rman\\convertscript.rman'
TRANSPORT SCRIPT 'D:\\rman\\transportscript.sql'
new database 'orcl'
FORMAT 'D:\\rman\\%U';

命令执行完成会生成一个transport脚本用于在目标平台上创建数据库,一个pfile文件包含源数据库相同的参数配置,还生成一个convert脚本用于在目标平台上转换数据文件。

注意:在windows平台上只能使用windows系统路径名,包括FORMAT参数使用的路径,在linux平台上做数据库转换时,根据linux平台上oracle数据库的目录结构布局来相应修改生成的convertscript.rman,pfile和transportscript.sql。

3.1 convertscript.rman
生成的转换脚本类似如下:

1
2
3
4
5
6
7
8
9
10
11
RUN {

CONVERT DATAFILE 'E:\\ORACLE\\PRODUCT\\10.2.0\\DB_1\\DATABASE\\DIGITALSCANDATA.DAT'
FROM PLATFORM 'Microsoft Windows x86 64-bit'
FORMAT 'D:\\RMAN\\DATA_D-ORCL_I-1276927241_TS-DIGITALSCANDATA_FNO-38_HDV216EA';


CONVERT DATAFILE 'E:\\ORACLE\\PRODUCT\\10.2.0\\DB_1\\DATABASE\\DIGITALSCANDATA01.DAT'
FROM PLATFORM 'Microsoft Windows x86 64-bit'
FORMAT 'D:\\RMAN\\DATA_D-ORCL_I-1276927241_TS-DIGITALSCANDATA_FNO-39_HEV216EA';
...

根据目标平台文件系统布局,修改为:

1
2
3
4
5
6
7
8
9
10
11
RUN {

CONVERT DATAFILE '/mnt/data/database/DIGITALSCANDATA.DAT'
FROM PLATFORM 'Microsoft Windows x86 64-bit'
FORMAT '/u01/oradata/orcl/DATA_D-ORCL_I-1276927241_TS-DIGITALSCANDATA_FNO-38_HDV216EA';


CONVERT DATAFILE '/mnt/data/database/DIGITALSCANDATA01.DAT'
FROM PLATFORM 'Microsoft Windows x86 64-bit'
FORMAT '/u01/oradata/orcl/DATA_D-ORCL_I-1276927241_TS-DIGITALSCANDATA_FNO-39_HEV216EA';
...

/mnt/data/database目录下为从源库直接拷贝过来待转换的数据文件,转换完成的数据文件存储到/u01/oradata/orcl/目录下。

3.2 pfile
生成的INIT文件:

1
2
3
4
5
6
7
8
9
10
# Please change the values of the following parameters:

control_files = "D:\\RMAN\\CF_D-ORCL_ID-1276927241_00V216EA"

db_recovery_file_dest = "D:\\RMAN\\flash_recovery_area"

db_recovery_file_dest_size= 2147483648

audit_file_dest = "D:\\RMAN\\ADUMP"
...

相应修改为:

1
2
3
4
5
6
7
8
9
10
# Please change the values of the following parameters:

control_files = "/u01/oradata/orcl/CF_D-ORCL_ID-1276927241_00V216EA"

db_recovery_file_dest = "/u01/app/oracle/flash_recovery_area"

db_recovery_file_dest_size= 2147483648

audit_file_dest = "/u01/app/oracle/admin/orcl/adump"
...

3.3 transportscript.sql
生成的建库脚本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
-- The following commands will create a new control file and use it
-- to open the database.
-- Data used by Recovery Manager will be lost.
-- The contents of online logs will be lost and all backups will
-- be invalidated. Use this only if online logs are damaged.

-- After mounting the created controlfile, the following SQL
-- statement will place the database in the appropriate
-- protection mode:
-- ALTER DATABASE SET STANDBY DATABASE TO MAXIMIZE PERFORMANCE

STARTUP NOMOUNT PFILE='D:\\RMAN\\INIT_00V216EA_1_0.ORA'
CREATE CONTROLFILE REUSE SET DATABASE "ORCL" RESETLOGS FORCE LOGGING ARCHIVELOG
MAXLOGFILES 16
MAXLOGMEMBERS 3
MAXDATAFILES 100
MAXINSTANCES 8
MAXLOGHISTORY 14616
LOGFILE
GROUP 1 'D:\\RMAN\\ARCH_D-ORCL_ID-1276927241_S-517_T-1_A-1017328065_00V216EA' SIZE 50M,
GROUP 2 'D:\\RMAN\\ARCH_D-ORCL_ID-1276927241_S-515_T-1_A-1017328065_00V216EA' SIZE 50M,
GROUP 3 'D:\\RMAN\\ARCH_D-ORCL_ID-1276927241_S-516_T-1_A-1017328065_00V216EA' SIZE 50M
DATAFILE
'D:\\RMAN\\DATA_D-ORCL_I-1276927241_TS-SYSTEM_FNO-1_IKV216EF',
...

相应修改为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
STARTUP NOMOUNT PFILE='/u01/app/oracle/admin/orcl/pfile/INIT_00V216EA_1_0.ORA'
CREATE CONTROLFILE REUSE SET DATABASE "ORCL" RESETLOGS FORCE LOGGING ARCHIVELOG
MAXLOGFILES 16
MAXLOGMEMBERS 3
MAXDATAFILES 100
MAXINSTANCES 8
MAXLOGHISTORY 14616
LOGFILE
GROUP 1 '/u01/oradata/orcl/ARCH_D-ORCL_ID-1276927241_S-517_T-1_A-1017328065_00V216EA' SIZE 50M,
GROUP 2 '/u01/oradata/orcl/ARCH_D-ORCL_ID-1276927241_S-515_T-1_A-1017328065_00V216EA' SIZE 50M,
GROUP 3 '/u01/oradata/orcl/ARCH_D-ORCL_ID-1276927241_S-516_T-1_A-1017328065_00V216EA' SIZE 50M
DATAFILE
'/u01/oradata/orcl/DATA_D-ORCL_I-1276927241_TS-SYSTEM_FNO-1_IKV216EF',
...

3.4 实施转换

首先,将源数据库的数据文件全部拷贝到目标数据库(因为只拷贝数据文件,可以从standby备库拷贝),然后根据数据文件所在的路径相应的修改convert脚本,然后使用rman执行转换脚本,转换后的数据文件存储在format指定的位置。

目标平台必须要有一个已经存在的数据库,因为rman需要连接到target数据库才能工作:

1
2
$ rman target / nocatalog
RMAN> @CONVERTSCRIPT.RMAN

然后,根据目标平台环境修改生成的pfile文件参数
最后,执行transportscript.sql生成目标数据库。使用utlirp.sql和utlrp.sql脚本重新编译目标平台数据的PL/SQL模块。
先关闭已有的数据库,oracle实例每次只能启动一个数据库:

1
2
$ sqlplus / as sysdba;
SQL> @TRANSPORTSCRIPT.SQL

脚本最后最自动调用utlirp.sql和utlrp.sql编译模块。

其中遇到了错误:

1
2
ORA-27102: out of memory
Linux-x86_64 Error: 28: No space left on device

是因为内核参数kernel.shmall设置为了2097152,oracle最大只能使用2097152*4096=8GB的系统内存,而INIT文件中设置的SGA大小超过了10GB,重新设置kernel.shmall为4194304可以最大允许16GB,问题解决。

数据库的sys用户是由本地密码文件验证的,数据库转换时并没有涉及到sys用户,因此需要本地重新为sys用户新建一个密码文件:

1
$ orapwd file=$ORACLE_HOME/dbs/orapw$ORACLE_SID password=passwd_for_sys force=y

至此,数据库转换完成,最后以OPEN RESETLOGS方式打开新数据库。

References:
[1]15 RMAN Cross-Platform Transportable Databases and Tablespaces
[2]使用RMAN Convert Database命令实现跨平台的数据库迁移