Untitled Post - 160
linux自动化运维,saltstack + zabbix?
linux自动化运维,saltstack + zabbix?
keepalived是一个路由软件,主要用于linux系统上的负载均衡(load balancing)和高可用(high availability)。
keepalived基于IPVS(IP Virtual Server)提供四层负载均衡功能,Keepalived提供一组checker根据服务器的健康状况来动态维护负载均衡资源池。
另一方面,keepalived基于VRRP协议提供高可用功能。可以由多台服务器组成一个热备组,一个热备组使用一个或一组虚拟ip对外提供服务。一个组内只有一台服务器接管虚拟ip对外提供服务,成为master,其余服务器为backup服务器。当master出现问题时,会执行一次选举(election)选出一台新的master服务器来接管虚拟ip对外提供服务。master服务器负责对虚拟ip请求的相应,并定时发出VRRP通告,backup服务器则待时而动。
keepalived的配置文件中由vrrp_sync_group和vrrp_instance提供高可用配置,由virtual_server_group和virtual_server提供负载均衡配置。
负载均衡配置提供HTTP_GET,SSL_GET,TCP_CHECK,SMTP_CHECK,MISC_CHECK,ICMP_CHECK等检查器,其中ICMP_CHECK工作在三层,TCP_CHECK工作在四层,而HTTP_GET则工作在七层。
高可用配置时,keepalive可以检测网络故障和自身运行状态,还可以设定用户脚本来检测服务器状态,从而当master出现故障时,可以通过重新选举来进行主备切换。
高可用配置
此处主要讲述高可用配置,下面是由两个服务器组成一个热备组用于PostgreSQL数据库高可用服务的配置:
1 | # Configuration File for keepalived |
MASTER和BACKUP节点的优先级如何调整?
首先,每个节点有一个初始优先级,由配置文件中的priority配置项指定,MASTER节点的priority应比BAKCUP高。运行过程中keepalived根据vrrp_script的weight设定,增加或减小节点优先级。
规则如下:
什么时候会发生主从切换?
当监测的网络接口发生故障、keepalived实例关闭或者主备优先级发生变化时,会重新选择新的master服务器来接管服务。
防止脑裂(brain split)
将主备服务器都设置为BACKUP状态,并且将master服务器(初始优先级高的服务器)配置为nopreempt,当master因为各种可能原因下线,然后重新恢复上线时,虽然恢复上线的master优先级高于当前master的优先级,但不会去抢夺控制权。
这样会造成一个问题,除非当前的master网络故障或keepalived实例停止,其优先级就算降低后低于原来的master服务器,因为设置了nopreempt,也不会切换到原来的master。所以原master恢复上线之前,应该降低其优先级,并且要低于当前master的优先级,然后去掉nopreempt,而当前master添加nopreempt。
如果没有设置nopreempt,当master因为网络原因短暂下线后,backup服务器接管vip,并且PostgreSQL备库升级为主库。当原来的master网络恢复,重新上线时,会重新成为master,而此时就有了两个主库,发生了分裂。
通知脚本
可以在通知脚本中处理PostgeSQL备库提升,主库停止,发送通知等各种事务。
查看VRRP通告
可以使用tcpdump命令监测VRRP通告,可以看到当前的master服务器为192.168.0.3
1 | $ sudo tcpdump -vvv -n -i eth0 host 224.0.0.18 |
如果热备组内的服务器跨越子网,则交换路由设备必须开启VRRP多播报文转发。
References:
[1]man keepalived.conf
[2]Keepalived在PostgreSQL高可用中的运用
[3]Linux集群实现–Keepalived-1.2.7
[4]PostgreSQL+pgpooll+Keepalived双机HA方案
[5]keepalived vip漂移基本原理及选举算法
[6]Note on using VRRP with Virtual MAC address
[7]Keepalived 集群软件高级使用(工作原理和状态通知)
[8]keepalived
===
[erq]
IE9及以下版本并不能正确处理application/json返回类型,会提示文件下载,下载之后的文件内容就是返回的json数据串。
出现此种症状,只需针对特定版本IE浏览器,将返回类型设置为text/html或者text/plain即可解决此问题。
据说IE10也有此问题,木有测试,也有人说木有问题,可能是早期版本与后期更新版本有不同的表现吧。
References:
[1]Jquery + JSON: IE8/IE9 treats response as downloadable file
===
[erq]
cassandra的native_transport使用与rpc_address同样的绑定地址,默认情况下只绑定到localhost,所以从外部是无法访问到cassandra的9042端口的,使用native协议的驱动也就无法访问节点了。因此,可以在不启用rpc的情况下,修改rpc_address地址为外部可访问接口,从而可以从外部访问native transport。
当standby备库启动时,首先会调用restore_command来恢复所有可用的归档日志。
如果没有配置restore_command或者恢复了所有的归档日志restore_command失败之后,stanby备库会尝试pg_xlog目录下所有可用的WAL日志。
pg_xlog目录下没有WAL日志或者已有的WAL日志全部恢复完毕后,如果配置了流复制,standby会尝试连接到主库,开始进行流式复制。
如果失败,或者没有配置流式复制,或者连接中断,standby会重新开始一个新的恢复循环。
从WAL归档日志,到pg_xlog,再到流式复制的恢复循环会一直持续到服务器停止或者退出standby模式。
可以使用pg_ctl promote命令或者找到触发文件时,备库退出standby模式并切换到正常操作模式,可以接受正常的读写请求。
在failover完成之前,所有restore_command可以访问的以及pg_xlog目录下的WAL日志会被恢复,但是不会连接到主库进行流式恢复。
References:
[1]25.2.2. Standby Server Operation
===
[erq]
前面讲了基于日志文件传输的warm/hot standby配置,但日志文件传输的最大问题在于延迟。
单个日志文件要空间满了或者到了归档超时时间才会传输然后应用到备库,每个日志文件有16MB大小。这会造成较大的延迟,如果主库当机,则数据损失会较大。如果缩小归档超时时间,又会造成大量的空间浪费。
基于流复制则解决了这些问题。备库会连接到主库,不用等待WAL日志文件填满就可以立即传输完成的WAL记录到备库。
流复制默认是异步的,这样主库和备库之间会有微小的延迟,极端情况下可能会有极少的数据丢失。
流复制不依赖于归档模式archive_mode和归档日志。但是部署流复制的同时,开启归档也是有必要的。不能把鸡蛋放到一个篮子里。基于日志文件传输或流复制的高可用warm/hot standby配置仍然很难防范主库误删除数据的问题。
基于流复制同样可以实现warm或者hot standby配置。
流复制hot standby配置步骤
1 | host replication postgres 192.168.0.0/24 md5 |
1 | wal_level = hot_standby |
wal_keep_segments这个参数只能根据实际情况来估算,并不会很精确。参数设置小了,有可能需要的日志会被覆盖,设置大了会占用主库大量的存储空间。
流复制槽可以解决WAL日志循环覆盖的问题,只要备库没有应用主库的WAL日志,则这些日志会一直保存,直到备库不再需要这些日志。设置流复制槽时,如果备库一直下线,则需要注意主库的存储空间是否充裕。
3. 使用基础备份搭建备库
详见前文所述。
4. 备库端配置
postgresql.conf文件:
1 | hot_standby = on |
recovery.conf文件:
1 | standby_mode = 'on' |
1 | LOG: started streaming WAL from primary at 1/B0000000 on timeline 1 |
1 | postgres=# select pg_current_xlog_location(); |
备库端:
1 | postgres=# select pg_last_xlog_receive_location(); |
配置复制槽
1 | postgres=# select pg_create_physical_replication_slot('slot_1'); |
所以要修改postgresql.conf文件:
1 | max_replication_slots = 5 |
重启后,重新创建复制槽即可。
1 | postgres=# select pg_create_physical_replication_slot('slot_1'); |
1 | primary_slot_name = 'slot_1' |
1 | postgres=# select * from pg_replication_slots; |
References:
[1]25.2.5. Streaming Replication
[2]25.2.2. Standby Server Operation
[3]PostgreSQL Hot Standby
[4]postgresql高可用性之备库(二)
[5]25.3. Failover
===
[erq]
传统的备份恢复问题在于恢复时间过长,恢复时间有时候是无法接受的。因此有了高可用(High Availability)的概念。
高可用的实现方式多种多样,PostgreSQL内置支持基于WAL日志文件传输或流复制的方式来实现warm/hot standby备库从而实现数据库的高可用性。
这一篇文章只讲基于日志文件传输方式的warm/hot standby配置。
hot standby与warm standby的区别在于,hot standby在日志恢复的同时还可以提供只读查询,而warm standby只能进行日志恢复。
先决条件
主备库硬件可以不同,但硬件架构必须相同,字长也必须相同。PostgreSQL的主版本号必须相同,小版本号可以不同。
但是推荐主备库使用完全相同的版本号。
主备库升级时,要先升级备库,因为新版本的程序会兼容旧版本传输过来的wal日志,但反过来却不一定。
搭建warm standby备库
首先参考”PostgreSQL使用连续归档备份恢复数据库“在主库上进行一次基础备份,然后将其在备机上恢复。
然后recovery.conf文件中除了restore_comman参数之外,再打开standby_mode参数:
1 | restore_command = 'cp /var/backups/postgresql/archive/%f %p' |
如果需要清理standby不再需要的归档日志,可以配置archive_cleanup_command。不过一般来讲,为了备份的目的,归档日志应该dump到永久存储介质之后再行删除。
可以看到,此处与前文恢复数据库的主要区别既在于在recovery.conf中打开了standby_mode参数。这样以来,备库就会一直处于WAL归档日志恢复循环之中,直到主库失败,备库通过failover升级为主库,或者通过switchover升级为主库。
还可以在recovery.conf文件通过trigger_file参数指定一个触发文件,当standby服务器检测到这个文件时,就会结束恢复模式进入正常操作模式。
1 | trigger_file = '/var/lib/postgresql/trigger' |
此参数在standby_mode为off时无效。即使设置了此参数,仍然可以使用pg_ctl promote命令来结束恢复模式,从而可以升级为master数据库。
提升为hot standby备库
warm standby是不可查询的:
1 | $ sudo -u postgres psql |
在warm standby备库的基础上,主备库只需做少许参数配置即可升级到hot standby模式。
主库端postgresql.conf文件中:
1 | wal_level = hot_standby |
然后重新启动主库,并切换归档日志,从而使下一个归档日志具有hot standby信息:
1 | $ sudo service postgresql restart |
备库端postgresql.conf文件中:
1 | hot_standby = on |
然后重新启动备库即可。
如果启动备库时有类似如下错误:
1 | FATAL: hot standby is not possible because max_connections = 100 is a lower setting than on the master server (its value was 500) |
需要将standby上的max_connections,max_prepared_transactions参数设置为大于或等于master上对应参数的值,然后再重新启动。
启动成功后日志中会有类似的输出:
1 | 2015-12-09 21:53:19 CST \[23100-3\] LOG: entering standby mode |
可用使用以下命令进一步确认备库处于日志恢复状态:
1 | sudo -u postgres psql -c "select pg_is_in_recovery()" |
此命令在主库上执行会返回false。
可以在主库上修改数据库并切换归档,然后查询备库,检查数据是否有一样的变化。因为备库是基于日志文件传输的,所以如果不强制切换归档,备库要等到主库日志切换之后才能看到修改。
流复制有更高的实时性,从而数据丢失的风险更低。
References:
[1]Chapter 26. Recovery Configuration
===
[erq]
当数据库因为各种原因损坏时,连续归档备份就派上用场了,不过这种恢复在对停机时间很苛刻的环境下并不是很合适。
如果数据库很大的话,恢复时间可能是不可接受的,这时候就应该配置高可用实时复制系统,比如配置warm/hot standby备用机。
此文中的$PG_VERISON代表postgresql的主次版本号,比如当前为9.4。
数据恢复
1 | $ sudo service postgresql stop |
1 | $ sudo rm -rf /var/lib/postgresql/$PG_VERSION/main/* |
1 | $ sudo -u postgres tar jxvf 20151207.tbz2 -C /var/lib/postgresql/$PG_VERSION/main/ |
1 | $ sudo -u postgres cp /usr/share/postgresql/$PG_VERSION/recovery.conf.sample /var/lib/postgresql/$PG_VERSION/main/ |
然后修改文件中的restore_command为适当的shell脚本以在恢复时可以读取到归档的WAL日志:
1 | restore_command = 'cp /var/backups/postgresql/archive/%f %p' |
因为此案例没有使用流复制,因此应该注释掉primary_conninfo参数。
恢复期间还应该修改pg_hba.conf文件或其他途径以阻止客户端连接。
6. 启动服务器,开始恢复
1 | $ sudo service postgresql start |
当所有的归档WAL恢复完毕,无法读取到其他更新的归档日志后,恢复就会自动结束,并且recovery.conf会被更名为recovery.done,防止意外重新进入restore过程。
恢复完毕后,可以允许客户端连接到服务器。
注意,恢复的最后阶段,日志中会出现No such file or directory字样的提示,这是正常的,因为恢复过程已经无法读取到其他的归档日志文件或时间线history文件。
1 | 2015-12-07 09:24:42 CST \[4906-5\] LOG: consistent recovery state reached at 1/86008798 |
时间点恢复Point-in-Time Recovery (PITR)
默认情况下,恢复过程会一直持续到最后一个可用的WAL归档日志。
但是也可以在recovery.conf中设置参数来控制恢复到的目标点,这四个参数recovery_target,recovery_target_name,recovery_target_time和recovery_target_xid可以用来指定恢复的目标点,但同时只能有一个生效,如果指定多个,则以最后一个为准。
这几个参数的含义如下:
1 | recovery_target_time = '2015-02-13 20:04:49.63197+08' |
还有几个参数会影响恢复目标的设定以及到达恢复目标时的动作:
没有指定恢复目标,或者没有处于hot_standby状态时,这个参数并不生效。
恢复时间线timeline
在做数据恢复时,如果能像时间旅行或者并行宇宙中那样来来回回随意穿梭就好了。比如,恢复一次之后,发现不满意,可以从头再来,直到找到满意的恢复点为止。
幸好,PostgreSQL支持时间线timeline,正好支持了这种“超能力”。如果没有时间线,每次恢复之后新产生的WAL日志极有可能会将部分之前的WAL日志覆盖,从而再也无法恢复到那些状态。
时间线是这样的,无论何时,一个恢复完成后,会创建一个新的时间线来标识此次恢复之后产生的WAL日志。时间线的id号是WAL日志文件名字的一部分,因此不会覆盖其他时间线上的WAL日志文件。
每次创建一个新的时间线时,PostgreSQL会创建一个新的时间线历史文件,后缀为.history。历史文件会标识此时间线是什么时候从那个时间线分支而来的。有了时间线历史文件,PostgreSQL就可以在含有多个时间线的归档文件中找到正确的WAL归档日志。
虽然时间线看起来的确很高能,但是无论如何也不可能恢复到制作基础备份之前的时间。
References:
[1]24.3. Continuous Archiving and Point-in-Time Recovery (PITR)
[2]26.2. Recovery Target Settings
[3]postgresql在线备份与恢复(三)
===
[erq]
pg_dump/pg_dumpall属于一致性逻辑备份,可以用其进行跨PostgreSQL版本,跨系统平台的数据迁移。用于常规备份则其速度和灵活性略显不足。
而连续归档模式则类似于oracle的rman备份方式,可用于大型数据库的增量备份和恢复,以及用于搭建高可用standby镜像备份。
设置归档
PostgreSQL默认处于非归档模式。开启归档模式,主要涉及到三个参数:wal_level,archive_mode和archive_command
wal_level参数默认为mininal,设置此参数为archive或者之上的级别都可以打开归档。
当postgresql需要传输归档日志时,会调用archive_command指定的shell命令。归档文件传输成功时,shell命令要返回0,此时,postgresql会认为归档文件已经传输成功,因此可以删除或者重新循环利用归档文件。当shell命令返回非0值时,postgresql会保留所有未成功传输的归档日志,并不断尝试重新传输,直到成功。如果归档命令一直不成功,pg_xlog目录会持续增长,有耗尽服务器存储空间的可能,此时postgresql会PANIC关闭,直到释放存储空间。
将归档WAL日志存储在本机上是风险极高,不被推荐的。postgresql通过archive_command提供了存储WAL日志的灵活性,可以将归档日志存储到挂装的NFS目录,磁带,刻录到光盘,也可以将WAL日志通过ssh/scp传输到异机保存。
要注意,archive_command将以运行PostgreSQL的系统用户的身份运行。debian系统里,这个系统用户是postgres。
修改/etc/postgresql/$PG_VERISON/main/postgresql.conf文件以启动归档:
1 | wal_level = archive |
arc_svr是用于存储WAL日志的ssh服务器别名
然后重新启动postgresql
1 | $ sudo service postgresql restart |
手动切换WAL日志,看配置是否正确,WAL是否正确传输了:
1 | $ sudo -u postgres psql -c 'select pg_switch_xlog()' |
查看归档目录下出现了归档WAL日志文件。
使用pg_start_backup进行基础备份
确保postgesql运行于归档模式
1 | postgres=# select name, setting from pg_catalog.pg_settings where name like 'archive%' or name = 'wal_level'; |
使用超级用户执行pg_start_backup
1 | postgres=# select pg_start_backup('basebackup-20151205'); |
basebackup-20151205是一个标签,用户自行指定用于标识本次基础备份。pg_start_backup会创建一个备份标签文件(backup label file),文件内保存有此次基本备份的相关信息。
使用文件系统备份工具备份整个集群的数据文件
1 | $ sudo -u postgres tar cjvf /var/backups/postgresql/base/20151205.tbz2 -P \\ |
备份时需要排除掉postmaster.pid和postmaster.opts文件,以及pg_xlog和pg_replslot目录。
生成的基础备份应该与归档WAL日志采用一样的存储策略,存储到异机保存,并可以进一步保存到永久介质保存,比如磁带或者CDROM。
4. 以超级用户身份执行pg_stop_backup
1 | postgres=# select pg_stop_backup(); |
pg_stop_backup会将备份期间活动的WAL日志文件归档,一旦这些日志完成归档,则整个备份过程就结束了。
pg_stop_backup会生成一个.backup文件标识出保证此次备份完整性所需要的最后一个WAL日志,使用此次基础备份恢复系统时,不再需要之前的WAL日志。
比如:
1 | -rw------- 1 admin admin 306 Dec 5 21:37 00000001000000010000006F.00000028.backup |
说明此次备份所需的归档WAL日志文件从00000001000000010000006F往后即可,包含此文件和对应的.backup文件。
backup文件的内容类似如下:
1 | START WAL LOCATION: 1/6F000028 (file 00000001000000010000006F) |
使用pg_basebackup进行基础备份
pg_basebackup使用复制协议,因此需要配置pg_hba.conf文件以允许replication连接,无论本地还是通过网络。
比如:
1 | local replication postgres peer |
还需要设置postgresql.conf文件中的max_wal_senders参数以允许至少一个session连接来进行备份。
修改两个参数文件后,重新启动postgresql。
然后执行以下命令:
1 | $ sudo -u postgres pg_basebackup -RPv -X fetch -D baseback20151205-1 |
这会生成一个备份目录,其目录结构与数据库集群的目录结构一致。如果要将数据打包到一个bz2文件,可以执行如下命令:
1 | $ sudo -u postgres sh -c 'pg_basebackup -RPv -Ft -D - -X fetch | bzip2 > baseback20151205-1.tbz2' |
请注意输出文件的写入权限
pg_basebackup命令同样会在备份中生成backup_label文件和.backup归档日志文件。
其.backup文件内容类似如下:
1 | START WAL LOCATION: 1/7C000028 (file 00000001000000010000007C) |
可以远程使用pg_basebackup来进行基础备份。
pg_basebackup的详细参数见man pg_basebackup或参考[2]。
References:
[1]24.3. Continuous Archiving and Point-in-Time Recovery (PITR)
[2]pg_basebackup
KVM qcow2格式镜像文件转换为VirtualBox VDI格式镜像文件,转换完毕后,可以使用VirtualBox直接启动虚拟机:
1 | $ qemu-img convert -f qcow2 foo.qcow2 -O vdi foo.vdi |