0%

因为网络故障或资源紧张,会使standby出现日志同步间隙(archive gap)。虽然设置好了FAL_CLIENT和FAL_SERVER参数,有时候仍然无法自动解决日志间隙问题。

比如由于CONTROL_FILE_RECORD_KEEP_TIME设置导致,较旧的主库归档日志记录被循环覆盖,standby无法自动获取相应的日志文件:

1
2
3
4
5
6
7
8
9
10
11
12
Fetching gap sequence in thread 1, gap sequence 19767-19866
Thu May 12 09:45:47 2016
FAL\[client\]: Failed to request gap sequence
GAP - thread 1 sequence 19767-19866
DBID 1276927241 branch 874659493
FAL\[client\]: All defined FAL servers have been attempted.
-------------------------------------------------------------
Check that the CONTROL_FILE_RECORD_KEEP_TIME initialization
parameter is defined to a value that is sufficiently large
enough to maintain adequate log switch information to resolve
archivelog gaps.
-------------------------------------------------------------

如果standby缺少的归档日志尚未删除,可以拷贝缺少的日志到备库,然后在备库上注册,备库会apply这些归档日志。
如果归档日志已经被删除,则需要从主库做增量备份,然后在备库进行恢复来修复日志间隙。

手工拷贝归档日志

首先查看日志间隙:

1
2
3
4
sql> select * from v$archive_gap;
THREAD# LOW_SEQUENCE# HIGH_SEQUENCE#
-------- ---------------- ----------------------
1 19767 19866

将对应的归档日志拷贝到备库端

最后在备库端注册这些归档日志:

1
sql> alter database register physical logfile '\\path\\to\\archive_log'

备库会立即应用这些归档日志。如果日志数量过多,也可以使用以下语句来自动恢复数据库:

1
SQL> ALTER DATABASE RECOVER AUTOMATIC STANDBY DATABASE;

创建备库导致的日志不同步问题

最近遇到的一个案例是这样的,rman dupicate创建完备库后,因为没有使用dorecovery恢复增量备份,主库上的部分归档日志又被清除掉了,导致主备库无法进行同步,备库有类似如下错误提示:

1
2
3
4
5
6
7
8
9
10
11
12
13
Media Recovery Waiting for thread 1 sequence 23943
Fetching gap sequence in thread 1, gap sequence 23943-24042
Sun Jul 24 13:02:27 2016
FAL\[client\]: Failed to request gap sequence
GAP - thread 1 sequence 23943-24042
DBID 1276927241 branch 874659493
FAL\[client\]: All defined FAL servers have been attempted.
-------------------------------------------------------------
Check that the CONTROL_FILE_RECORD_KEEP_TIME initialization
parameter is defined to a value that is sufficiently large
enough to maintain adequate log switch information to resolve
archivelog gaps.
-------------------------------------------------------------

主库有类似如下错误提示:

1
2
3
4
FAL Redo Shipping Client Established Network Login
Failed to queue the whole gap
GAP - thread 1 sequence 23943-24042
DBID 1276927241 branch 874659493

此时备库查询v$archive_gap表是没有任何记录的,幸好还有一个备库有完整的归档日志,将相应的归档日志完整拷贝到新建的物理备库上,然后执行以下语句自动恢复数据库:

1
SQL> ALTER DATABASE RECOVER AUTOMATIC STANDBY DATABASE;

所有可用日志全部恢复完毕后,会有如下提示:

1
2
3
4
5
6
7
8
9
10
11
ALTER DATABASE RECOVER AUTOMATIC STANDBY DATABASE
*
ERROR at line 1:
ORA-00279: change 7255663631 generated at 07/25/2016 08:51:20 needed for thread 1
ORA-00289: suggestion : D:\\ARCHIVED_LOG\\ARC24380_0874659493.001
ORA-00280: change 7255663631 for thread 1 is in sequence #24380
ORA-00278: log file 'D:\\ARCHIVED_LOG\\ARC24380_0874659493.001' no longer needed for this recovery
ORA-00308: cannot open archived log 'D:\\ARCHIVED_LOG\\ARC24380_0874659493.001'
ORA-27041: unable to open file
OSD-04002: unable to open file
O/S-Error: (OS 2) 系统找不到指定的文件。

这是因为已经没有日志可用于恢复了,此时重新打开实时日志应用就可以开始自动同步了:

1
SQL> alter database recover managed standby database disconnect from session;

如果归档日志已经找不到了,则可以采用以下增量备份方式修复备库。

增量备份修复备库

  1. 查找恢复点SCN
    备库端:
    首先查看日志间隙:
    1
    2
    3
    4
    sql> select * from v$archive_gap;
    THREAD# LOW_SEQUENCE# HIGH_SEQUENCE#
    -------- ---------------- ----------------------
    1 19767 19766

主库端:
然后主库上查找日志间隙中低端日志序号的上一个日志的first_change#

1
2
3
4
sql> select SEQUENCE#, FIRST_CHANGE# from v$archived_log where SEQUENCE#=19766;
SEQUENCE# FIRST_CHANGE#
--------- -------------
19766 7008518015
  1. 备库停止apply log
    备库端:
    1
    sql> alter database recover managed standby database cancel;
  2. 主库增量SCN备份
    主库端:
    1
    2
    $ rman target /
    RMAN> backup incremental from scn 7008518015 database format '/path/to/stdby_%U.bak';
  3. 生成备库控制文件
    主库端:
    1
    RMAN> backup current controlfile for standby format '/path/to/stdby_%U.ctl';
  4. 拷贝备份和控制文件到备库
  5. 备库使用新生成的控制文件启动
    备库端:
    1
    2
    3
    4
    rman> shutdown immediate;
    rman> startup nomount;
    rman> restore standby controlfile from '/path/to/stdby_xxx.ctl';
    rman> alter database mount
  6. 备库进行数据恢复
    备库端:
    1
    2
    RMAN> catalog start with '/path/to_bak';
    RMAN> recover database noredo;
  7. 备库恢复日志应用
    备库端:
    1
    SQL> alter database recover managed standby database disconnect from session;

References:
[1]DataGuard 中处理archive gap的方法
[2]Roll Forward Physical Standby Database using RMAN incremental backup
[3]Oracle Physical DataGuard使用RMAN增量备份修复GAP
[4]Using RMAN Incremental Backups to Refresh a Standby Database

===
[erq]

查询表空间状态:
[sql]
sql> select tablespace_name,status from dba_tablespaces;
[/sql]

修改表空间状态为READ ONLY:
[sql]
sql> alter tablespace tablespace_name read only;
[/sql]

表空间置为READ ONLY之后,不再发生任何变化,只需保存一份有效的备份即可,可以使用RMAN,也可以使用OS直接拷贝数据文件来备份只读表空间。

之后日常备份时就可以skip readonly来忽略掉只读表空间的备份,加速备份速度。

但恢复数据库时记得要check readonly,即使没有只读表空间,恢复仍然会成功,但open数据库会出现错误。

如果不使用check readonly,记得要将只读表空间的数据文件拷贝到相应的位置之后再recover数据库。

References:
[1]Oracle Read-only Tablespace(只读表空间)
[2](09)常被人遗忘的只读表空间
[3]Database Backup and Recovery Basics
[4]只读表空间的备份与恢复
[5]READ ONLY Tablespace Restore and Recovery
[6]Backing up, Restoring and Recovering Read Only tablespaces with RMAN
[7]Read Only Tablespaces and BACKUP OPTIMIZATION
[8]Rman管理命令

===
[erq]

python脚本在shell下运行的好好的,作为crontab任务运行就出错,import cx_Oracle的时候出错:

1
ImportError: libclntsh.so.12.1: cannot open shared object file: No such file or directory

明显是库路径的问题。

crontab运行程序时,其环境变量与用户的环境变量是不同的,有自己的变量环境,因此需要为crontab设置正确的环境变量,脚本才能正确运行。

python脚本中使用os.environ或者os.putenv来设置环境变量是没用的,反正在py脚本中正确设置了LD_LIBRARY_PATH变量,仍然无法解决问题。

有这么几个方法来设置crontab的环境变量:

第一种

可以在crontab配置文件中添加环境变量,但是不能用变量,类似$PATH这种,只能照实写。
类似如下:

1
2
3
4
5
6
ORACLE_HOME=/opt/oracle/instantclient_12_1
LD_LIBRARY_PATH=/opt/oracle/instantclient_12_1
PATH=/opt/oracle/instantclient_12_1
TNS_ADMIN=/opt/oracle/instantclient_12_1
SQLPATH=/opt/oracle/instantclient_12_1
NLS_LANG=AMERICAN_AMERICA.AL32UTF8

第二种

写一个bash脚本来中转一下,bash脚本中再调用py脚本,类似如下:

1
2
3
4
#!/bin/bash
export ORACLE_HOME=/opt/oracle/instantclient_12_1
source /home/xxx/.mybashrc
/home/xxx/py/business_notify.py "$@"

第三种

直接在crontab配置任务要执行的命令行上添加环境变量,类似如下:

1
*/10 * * * * LD_LIBRARY_PATH=/opt/oracle/instantclient_12_1 TNS_ADMIN=/opt/oracle/instantclient_12_1 /home/xxx/py/business_notify.py

推荐第一种

一般crontab运行的脚本中尽量不要依赖环境变量,使用绝对路径为佳。

===
[erq]

最近版本的即时客户端已经没有了tnsping这个命令,可以从相应版本的客户端或服务器bin目录中拷贝此文件,或者用脚本简单的替代:

1
2
3
4
tnsping >/dev/null 2>&1 
tnsping() {
sqlplus -L -S x/x@$1 </dev/null grep ORA- (grep -v ORA-01017 echo OK)
}

将此段脚本放入.profile或.bashrc即可。

又或者直接测试一下服务器的1521端口是否正常开放:

1
2
3
4
$ telnet a.b.c.d 1521
Trying a.b.c.d...
Connected to a.b.c.d.
Escape character is '^\]'.

这样就说明oracle监听是正常的。

===
[erq]

当ssh,vnc都不能访问客户机时,serial console可以提供另一种访问客户机的途径。

客户机serial console配置

/etc/inittab文件打开或添加如下行:

1
T0:23:respawn:/sbin/getty -L ttyS0 38400 vt100

/etc/securetty文件中确保列出了ttyS0:

1
ttyS0

/etc/default/grub文件添加:

1
2
3
GRUB_CMDLINE_LINUX='console=tty0 console=ttyS0,38400n8'
GRUB_TERMINAL=serial
GRUB_SERIAL_COMMAND="serial --speed=38400 --unit=0 --word=8 --parity=no --stop=1"

波特率是38400,没有奇偶校验,停止位是1

使用virsh来连接客户机串行控制台比较简单,应该也可以重定向客户机的串行端口到主机。

References:
[1]Debian Linux: Set a Serial Console
[2]Working with the serial console
[3]qemu(-kvm) monitor and serial console over sockets with minicom

===
[erq]

主机通过virtio上的9p文件系统以及文件系统设备,可以将主机上的文件系统导出给客户机来挂载使用

v9fs是plan 9 9p远程文件系统协议的实现

主机配置

在客户机启动命令上新添加fsdev和device选项

1
2
-fsdev local,security_model=passthrough,id=fsdev0,path=/mnt/share 
-device virtio-9p-pci,id=fs0,fsdev=fsdev0,mount_tag=hostshare

这样导出了主机的/mnt/share目录供客户机来存取

客户机配置

客户机需要在内核中开启9P文件系统相关选项,可以这样查看:

1
2
3
4
5
6
7
8
9
$ cat /boot/config-$(uname -r) grep 9P
CONFIG_NET_9P=m
CONFIG_NET_9P_VIRTIO=m
CONFIG_NET_9P_RDMA=m
# CONFIG_NET_9P_DEBUG is not set
CONFIG_9P_FS=m
CONFIG_9P_FSCACHE=y
CONFIG_9P_FS_POSIX_ACL=y
CONFIG_9P_FS_SECURITY=y

可以看到9P配置成了内核模块的形式,然后就可以挂载主机的目录来使用了:

1
# mount -t 9p -o trans=virtio\[,version=9p2000.L\] hostshare /mnt/point

hostshare就是主机导出的挂载点的名称,此处将其挂载到客户机的/mnt/point。
version选项是可选的。

References:
[1]Example Sharing Host files with the Guest
[2]Documentation/9psetup
[3]v9fs: Plan 9 Resource Sharing for Linux

===
[erq]

通过rlwrap可以使sqlplus具有具有命令历史回溯和命令行编辑功能,通过提供自动完成字典,可以更进一步使sqlplus具有tab自动补全/完成功能。

德国一个哥们写了rlwrap_ext for oralce可以使sqlplus自动补全sql关键字,oracle视图、表、包等等,比较全面。

下载

可以直接下载最新的版本

1
$ wget http://www.linuxification.at/download/rlwrap-extensions-V12-0.03.tar.gz

安装

1
2
$ sudo tar zxvf rlwrap-extensions-V12-0.03.tar.gz -C /usr/local/share/rlwrap/completions
$ sudo cp /usr/local/share/rlwrap/completions/sql+ /usr/local/bin/

然后使用sql+替代sqlplus就可以了。

References:
[1]rlwrap_ext for oracle

===
[erq]

最常见的原因是process和session数量设置过低。

查看修改process参数

1
2
3
4
5
6
7
8
9
10
> show parameter process

NAME TYPE VALUE
------------------------------------ --------------------------------- -------------------
aq_tm_processes integer 0
db_writer_processes integer 3
gcs_server_processes integer 0
job_queue_processes integer 20
log_archive_max_processes integer 2
processes integer 150

偏低,修改process参数

1
> alter system set processes=1000 scope = spfile;

这里无法直接修改内存值,也就是不能使用scope=both,否则会有提示:

1
ORA-02095: specified initialization parameter cannot be modified

查看修改session参数

查看

1
2
3
4
5
6
7
8
9
10
11
12
> show parameter session
NAME TYPE VALUE
------------------------------------ --------------------------------- --------------------
java_max_sessionspace_size integer 0
java_soft_sessionspace_limit integer 0
license_max_sessions integer 0
license_sessions_warning integer 0
logmnr_max_persistent_sessions integer 1
session_cached_cursors integer 20
session_max_open_files integer 10
sessions integer 170
shared_server_sessions integer

修改

1
> alter system set sessions=1105 scope = spfile;

sessions是个派生值,由processes的值决定,公式sessions=1.1*process + 5

因为修改的是spfile,所以并不会立即生效,只有重新启动oracle,设置才会生效。

===
[erq]

swift已经支持ubuntu,也可以在debian上安装

下载

下载ubuntu 15.10版本的安装包

1
$ wget https://swift.org/builds/swift-2.2-release/ubuntu1510/swift-2.2-RELEASE/swift-2.2-RELEASE-ubuntu15.10.tar.gz

解压重新打包

1
2
3
4
$ tar zxvf swift-2.2-RELEASE-ubuntu15.10.tar.gz
$ cd swift-2.2-RELEASE-ubuntu15.10
$ tar czvf swift-2.2.tar.gz usr
$ sudo alien -v swift-2.2.tar.gz

会生成deb安装包swift_2.2-2_all.deb

安装

1
$ sudo dpkg -i swift_2.2-2_all.deb

测试

新建main.swift文件

1
print("hello swift")

编译

1
$ swiftc main.swift -o main.s

查看

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
$ file main.s
main.s: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked,
interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32,
BuildID\[sha1\]=9ed9fa8e5accc18cd0a4482b465aecf814a2a114, not stripped

$ ldd main.s
linux-vdso.so.1 (0x00007ffe06af4000)
libswiftCore.so => /usr/lib/swift/linux/libswiftCore.so (0x00007fc4d764f000)
libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007fc4d72bc000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007fc4d6fbd000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007fc4d6da7000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fc4d6a03000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007fc4d67e5000)
libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007fc4d65e1000)
libicuuc.so.55 => /usr/lib/x86_64-linux-gnu/libicuuc.so.55 (0x00007fc4d624d000)
libicui18n.so.55 => /usr/lib/x86_64-linux-gnu/libicui18n.so.55 (0x00007fc4d5dea000)
libbsd.so.0 => /lib/x86_64-linux-gnu/libbsd.so.0 (0x00007fc4d5bd4000)
/lib64/ld-linux-x86-64.so.2 (0x0000557356b81000)
libicudata.so.55 => /usr/lib/x86_64-linux-gnu/libicudata.so.55 (0x00007fc4d411c000)

也可以动态解释执行

1
2
3
4
5
$ swift
Welcome to Swift version 2.2 (swift-2.2-RELEASE). Type :help for assistance.
1> print("hello, swift")
hello, swift
2> :q

===
[erq]

python有两个队列实现,分别是queue.Queue和mulitiprocess.Queue。

queue.Queue是线程安全的,用于线程间数据同步,而mulitiprocess.Queue是用于多进程间数据通讯的。如果在多进程间使用queue.Queue是无法共享数据的,每个进程会有一个单独的队列副本。

因为queue.Queue用于多线程数据同步,而mulitiprocess.Queue用于多进程数据同步。

python3中线程队列的名字为queue,而python2中其名字为Queue。

python中的list和dict不是线程安全的。

task_done与join

queue.Queue有一个join方法可以阻塞当前线程,直到队列中所有的item都处理完成了,所以需要每处理一个队列的item,调用一次队列的task_done方法,当队里的所有元素都标记为处理过了,join方法会从等待中返回。

如果不调用join方法,也就无需调用task_done方法了。

mulitiprocess.Queue并没有join特性,如需要此特性,应该使用multiprocessing.JoinableQueue队列

===
[erq]