
目录1.简介2.运行环境3.软件安装4.功能介绍4.1.IP漂移4.2.执行管理4.3.文件同步4.4.Mysql主从同步4.5.Mysql/Sqlserver/PostgreSQL数据同步4.6.邮件提醒5.关于开机自启动6.清除配置1.简介PanguHA是Windows平台的双机热备集群系统是提供系统高可用性的纯软件解决方案一般由两个节点构成分为活动节点及备用节点。通常把正在执行业务的称为活动节点而作为活动节点的一个备份的则称为备用节点。当活动节点出现问题导致正在运行的业务不能正常运行时备用节点此时就会侦测到并立即接续活动节点来执行业务。从而实现业务的不中断或短暂中断。双机热备软件下载https://gitee.com/AaronE_2890620459/pangu-ha2.运行环境环境 .NET Framework 4.6.1 及以上3.软件安装无需安装解压后点击运行4.功能介绍4.1.IP漂移IP漂移的作用是实现Web应用、WebApi/Webservice、数据库等的故障转移除了服务器本机的IP地址外该软件可以对服务器额外设置一个虚拟IP然后使用虚拟IP作为代理来访问Web应用或数据库当双机热备配置完成后虚拟IP挂载于主节点当主节点宕机以后该虚拟IP会漂移到备节点继续提供服务对Web应用和数据库来说这个切换是没有感知的因为它们还是使用虚拟IP作为代理访问。主节点出现以下情况将进行IP漂移宕机网卡异常Web服务Url异常需要配置Windows服务异常需要配置那么该如何操作呢我们先选一台服务器A作为主节点在该节点上打开软件切换到【IP漂移】标签页然后选择网络(请确保该网卡设置的是静态IP而非自动获取)如下图所示如果有多个网卡也没事选一个你需要做虚拟IP的那个网段的网卡然后设置本机IP(假设IP为192.168.56.101)和集群IP(也就是浮动IP,假设为192.168.56.103,路由器或三层交换机严禁设置浮动IP与Mac绑定)如下图所示这里需要注意虚拟IP要和本机IP在同一网段并且无机器在使用然后添加对方IP如下图所示注意事项如果有条件【对方IP】最好选择另外一个网段的IP避免某些隔离的网络环境允许浮动IP同时设置在不同机器上我这里为了简单演示就直接设置该网段的IP(192.168.56.102)了对于正常的网络环境是没有问题的然后点击运行右下角显示失败重试无需管它等待稍许时间可发现左下角显示主节点这个时候就表明主节点设置成功虚拟IP已经挂载在当前节点可通过ipconfig命令查看对方节点红色是因为对方节点还没运行热备软件如下图所示心跳间隔和断联重试设置可以调整主备切换的速度但也不宜设置得过小否则会因为一点点网络抖动而切换频繁切换不是一件好事。【切换】按钮提供了手动切换主备的功能。【停止】按钮将停止心跳检测不进行主备切换。配置对方IP后检测对方热备软件在线情况异常时发送邮件提醒防火墙需要开放ICMP和默认端口9999如下图所示需要注意使用telnet命令检测时请在两端打开PanguHA软件 如果发现端口已开软件已开但是telnet不通需要检查防火墙是否把HA应用给禁掉了如下图所示对方IP颜色对应的含义绿色正常红色断联灰色不监测正常情况如下图所示添加本机Url可以对本机的Web服务进行检测如果发现Web服务的状态码不是200的时候即服务出现异常时30s内重试3次如果在主节点上则进行切换并邮件提醒。如果在备节点上则进行邮件提醒防止主节点服务异常没有可用的备节点。如下图所示配置windows服务后主节点发现Windows服务异常会先进行重启30s内重试3次重启失败则进行故障转移。如果是备节点重启失败发送邮件提醒如下图所示接着我们来设置备节点服务器B,假设IP为192.168.56.102大部分操作都和上面类似我讲一下需要注意的点首先两台服务器要能互相ping通然后两边的集群IP设置是相同的两台服务器处在同一网段如下图所示至此IP漂移设置告一段落然后我们来测试一下我们将主节点服务器关闭观察备节点是否升级为主节点也就是虚拟IP是否漂移过来如下图所示可以发现B服务器从备节点变成了主节点这个时候访问代理IP将会访问B服务器节点这样就完成了故障转移的功能。那么该如何设置Web应用呢如果使用的是IIS那么先在两台服务器上部署相同的应用然后将两边的绑定IP都设置为虚拟IP如下图所示其他Tomcat等web服务器也是类似的道理如果绑定虚拟IP导致服务启动失败绑定0.0.0.0即可。4.2.执行管理执行管理功能是在IP漂移的基础上对可执行文件exe或Windows服务做切换配置配置的进程和windows服务只会在主节点上运行备节点将会关闭配置的进程和windows服务那么该如何操作呢假设我们已经配置完成了IP漂移然后我们要控制WindowsFormsApp1.exe这个程序的切换我们只要在A,B两台服务器上都对这个程序进行配置即可如下图所示可以看到配置的进程会在主节点上运行不小心手动关闭了也会自动启动在备节点上关闭不小心启动了也会自动关闭当主节点A宕机后备节点B升级为主节点就会将配置的进程自动开启这样就实现了进程的切换windows服务也是同样的配置方法。4.3.文件同步注意事项数据库文件的同步谨慎使用该功能文件同步功能是在IP漂移功能基础上进行的因为该软件的定位并非单纯地做文件同步而是作为文件服务器来使用的所以也要搭配虚拟IP来使用。在配置之前需要先设置共享文件夹如下图所示保证IP路径可以访问即A可以访问B的文件夹IP路径B可以访问A的文件夹IP路径如下图所示然后我们将软件切换到【文件同步标签页】,在A服务器上做A-B的同步设置如下图所示在B服务器上做B-A的同步设置如下图所示然后两边都点击启动虽然两边都配置了同步路径并启动但同步任务只会在主节点上运行当主节点A宕机备节点B升级为主节点然后会开启同步任务。文件同步是实时的右上角的镜像周期是为了防止备节点不小心修改、删除文件是为了保持备节点的文件始终和主节点一模一样并非指同步文件需要5分钟延迟。4.4.Mysql主从同步注意事项部署之前请确保两个节点结构和数据完全一致详见视频教程Mysql主从同步https://www.bilibili.com/video/BV1Mi421R7FP/?vd_source8db0f4c511ee648e595718cb636c8df7软件可以快速地部署Mysql双主复制配合IP漂移功能即可搭建Mysql高可用架构。那么该如何操作呢我们将软件切换到【Mysql主从】根据上面的文字提醒先在A,B两台服务器做相应配置如下图所示然后A,B都重启Mysql服务。然后在A服务器输入相关信息做A主B从的设置然后点击部署按钮如下图所示右下角会提示部署成功接着在B服务器上输入相关信息做B主A从的设置与上面类似点击部署按钮有如下成功提示如下图所示至此Mysql双主复制搭建完成除此之外需要保证mysql.user表内有%账号这样才能保证虚拟IP可以访问mysql。结合IP漂移功能可以做服务器级别宕机的双机切换即主节点A服务器宕机后备节点B升级为主节点虚拟IP指向B节点继续提供mysql服务。如果在下面填写本机Mysql服务名称并开启健康检测则可以做数据库应用级别的宕机切换即主节点A的mysql服务挂了则备节点B可以检测到然后做虚拟IP的转移B升级为主节点继续提供mysql服务。同时如果备节点的mysql服务挂了则会发送邮件提醒。如下图所示4.5.Mysql/Sqlserver/PostgreSQL数据同步详见视频教程Mysql/Sqlserver/PostgreSQL数据同步https://www.bilibili.com/video/BV1VSjbz8EwN/?vd_source8db0f4c511ee648e595718cb636c8df7视频要点说明假设初始状态X为主节点Y为备节点。在主备节点准备好数据库表结构需要完全一致(数据不需要一致) 然后在备节点Y使用【清空备节点数据脚本】或truncate语句(不要使用delete)清空数据在Y节点切换到【数据同步】标签页添加任务选库不选表批量配置Y-X方向的任务启动任务如遇到主键问题使用【批量主键创建脚本】或自行创建主键待所有任务启动成功。然后在X主节点上切换到【数据同步】标签页添加任务选库不选表批量配置X-Y方向的任务启动任务如遇到主键问题使用【批量主键创建脚本】或自行创建主键待所有任务启动成功这个时候一开始会做X-Y方向的初始数据全量同步在全量同步阶段请在Y备节点【IP漂移】界面停止避免不小心切换全量同步完成后会做增量同步这个时候再在Y备节点【IP漂移】界面运行。Sqlserver清空备节点数据脚本【参考视频】-- 替换为实际数据库名称 Use B; DECLARE DatabaseName NVARCHAR(128) NB; -- 验证数据库是否存在 IF NOT EXISTS (SELECT 1 FROM sys.databases WHERE name DatabaseName) BEGIN RAISERROR(N错误数据库 %s 不存在, 16, 1, DatabaseName); RETURN; END; -- 声明变量 DECLARE SchemaName NVARCHAR(128), TableName NVARCHAR(128), FullTableName NVARCHAR(255), SqlStatement NVARCHAR(MAX); -- 创建游标获取所有用户表 DECLARE tableCursor CURSOR LOCAL FAST_FORWARD FOR SELECT s.name AS SchemaName, t.name AS TableName FROM sys.databases db INNER JOIN sys.tables t ON db.name DatabaseName INNER JOIN sys.schemas s ON t.schema_id s.schema_id WHERE db.name DatabaseName AND t.type U; -- 只获取用户表 -- 开始处理 OPEN tableCursor; FETCH NEXT FROM tableCursor INTO SchemaName, TableName; WHILE FETCH_STATUS 0 BEGIN BEGIN TRY -- 构造完整表名和SQL语句 SET FullTableName QUOTENAME(SchemaName) . QUOTENAME(TableName); SET SqlStatement NUSE QUOTENAME(DatabaseName) N; TRUNCATE TABLE FullTableName; -- 执行截断操作 EXEC sp_executesql SqlStatement; PRINT N成功截断表: FullTableName; END TRY BEGIN CATCH PRINT N错误截断表: FullTableName N | 错误信息: ERROR_MESSAGE(); END CATCH FETCH NEXT FROM tableCursor INTO SchemaName, TableName; END; -- 清理资源 CLOSE tableCursor; DEALLOCATE tableCursor; PRINT N操作完成请检查输出信息确认结果。;PostgreSQL清空备节点数据脚本【参考视频】DO $$ DECLARE table_name TEXT; BEGIN -- 获取所有用户表 FOR table_name IN SELECT tablename FROM pg_tables WHERE schemaname public LOOP -- 清空表并重置序列 EXECUTE TRUNCATE TABLE || quote_ident(table_name) || RESTART IDENTITY CASCADE; RAISE NOTICE 已清空表: %, table_name; END LOOP; END $$;Mysql清空备节点数据脚本【参考视频】SET SESSION group_concat_max_len 10000000; -- 生成 TRUNCATE 语句 SELECT GROUP_CONCAT( CONCAT(TRUNCATE TABLE , table_name, ) SEPARATOR ; ) INTO truncate_sql FROM information_schema.tables WHERE table_schema DATABASE() AND table_type BASE TABLE; -- 显示将要执行的语句 SELECT truncate_sql AS 将要执行的语句;1.查询出结果后复制语句---------------------------------------------------------------------------------------- 禁用外键检查SET FOREIGN_KEY_CHECKS 0;2.刚才查询出来的语句SET FOREIGN_KEY_CHECKS 1;【Sqlserver批量主键创建脚本】(遍历某个库所有表1.如果有主键则跳过。2.如果有自增列却没有主键则将自增列设置为主键。3.如果没有自增列也没有主键则自动创建名为_PanguId_类型为Bigint的自增主键)DECLARE DatabaseName NVARCHAR(128) NA -- 替换为你的数据库名称 USE [A] -- 这里也需要替换为实际的数据库名称 DECLARE TableSchema NVARCHAR(128) DECLARE TableName NVARCHAR(128) DECLARE ColumnName NVARCHAR(128) DECLARE Sql NVARCHAR(MAX) DECLARE PKName NVARCHAR(128) -- 创建游标遍历所有用户表 DECLARE table_cursor CURSOR FOR SELECT TABLE_SCHEMA, TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE BASE TABLE AND TABLE_CATALOG DatabaseName OPEN table_cursor FETCH NEXT FROM table_cursor INTO TableSchema, TableName WHILE FETCH_STATUS 0 BEGIN -- 检查表是否有主键 IF NOT EXISTS ( SELECT 1 FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS tc JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE kcu ON tc.CONSTRAINT_NAME kcu.CONSTRAINT_NAME WHERE tc.CONSTRAINT_TYPE PRIMARY KEY AND tc.TABLE_SCHEMA TableSchema AND tc.TABLE_NAME TableName AND tc.TABLE_CATALOG DatabaseName ) BEGIN -- 检查表是否有自增列 IF EXISTS ( SELECT 1 FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA TableSchema AND TABLE_NAME TableName AND TABLE_CATALOG DatabaseName AND COLUMNPROPERTY( OBJECT_ID(QUOTENAME(TableSchema) . QUOTENAME(TableName)), COLUMN_NAME, IsIdentity ) 1 ) BEGIN -- 获取自增列名 SELECT ColumnName COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA TableSchema AND TABLE_NAME TableName AND TABLE_CATALOG DatabaseName AND COLUMNPROPERTY( OBJECT_ID(QUOTENAME(TableSchema) . QUOTENAME(TableName)), COLUMN_NAME, IsIdentity ) 1 -- 设置自增列为主键 SET PKName PK_ TableName SET Sql NALTER TABLE QUOTENAME(TableSchema) . QUOTENAME(TableName) N ADD CONSTRAINT QUOTENAME(PKName) N PRIMARY KEY ( QUOTENAME(ColumnName) N) PRINT N为表 TableSchema . TableName N 设置自增列为主键: Sql EXEC sp_executesql Sql END ELSE BEGIN -- 创建_PanguId_自增主键 SET PKName PK_ TableName SET Sql N IF NOT EXISTS (SELECT * FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA Schema AND TABLE_NAME Table AND COLUMN_NAME _PanguId_) BEGIN ALTER TABLE QUOTENAME(TableSchema) . QUOTENAME(TableName) N ADD _PanguId_ bigint IDENTITY(1,1) NOT NULL END ALTER TABLE QUOTENAME(TableSchema) . QUOTENAME(TableName) N ADD CONSTRAINT QUOTENAME(PKName) N PRIMARY KEY (_PanguId_) PRINT N为表 TableSchema . TableName N 创建_PanguId_自增主键 EXEC sp_executesql Sql, NSchema NVARCHAR(128), Table NVARCHAR(128), Schema TableSchema, Table TableName END END ELSE BEGIN PRINT N表 TableSchema . TableName N 已有主键跳过处理 END FETCH NEXT FROM table_cursor INTO TableSchema, TableName END CLOSE table_cursor DEALLOCATE table_cursor【Mysql批量主键创建脚本】自动创建主键脚本(遍历某个库所有表1.如果有主键则跳过。2.如果有自增列却没有主键则将自增列设置为主键。3.如果没有自增列也没有主键则自动创建Bigint类型名称为_PanguId_的自增主键)下面脚本中的CALL AddMissingPrimaryKeys(A); A替换为自己的数据库DELIMITER $$ DROP PROCEDURE IF EXISTS AddMissingPrimaryKeys$$ CREATE PROCEDURE AddMissingPrimaryKeys(IN target_db VARCHAR(64)) BEGIN DECLARE done INT DEFAULT FALSE; DECLARE tbl_name VARCHAR(64); DECLARE auto_col_name VARCHAR(64) DEFAULT NULL; DECLARE has_pk TINYINT DEFAULT 0; DECLARE has_pangu_col TINYINT DEFAULT 0; DECLARE cur CURSOR FOR SELECT TABLE_NAME FROM information_schema.TABLES WHERE TABLE_SCHEMA target_db AND TABLE_TYPE BASE TABLE; -- 主循环的 NOT FOUND handler DECLARE CONTINUE HANDLER FOR NOT FOUND SET done TRUE; OPEN cur; read_loop: LOOP FETCH cur INTO tbl_name; IF done THEN LEAVE read_loop; END IF; -- 重置状态 SET auto_col_name NULL; SET has_pk 0; SET has_pangu_col 0; -- 检查是否有主键 SELECT COUNT(*) INTO has_pk FROM information_schema.KEY_COLUMN_USAGE WHERE TABLE_SCHEMA target_db AND TABLE_NAME tbl_name AND CONSTRAINT_NAME PRIMARY; IF has_pk 0 THEN ITERATE read_loop; END IF; -- 安全获取自增列使用嵌套块隔离 NOT FOUND BEGIN DECLARE no_auto_inc CONDITION FOR SQLSTATE 02000; DECLARE CONTINUE HANDLER FOR NOT FOUND BEGIN END; -- 吃掉 NOT FOUND SELECT COLUMN_NAME INTO auto_col_name FROM information_schema.COLUMNS WHERE TABLE_SCHEMA target_db AND TABLE_NAME tbl_name AND EXTRA auto_increment LIMIT 1; END; IF auto_col_name IS NOT NULL THEN SET sql CONCAT( ALTER TABLE , target_db, ., tbl_name, , ADD PRIMARY KEY (, auto_col_name, ); ); PREPARE stmt FROM sql; EXECUTE stmt; DEALLOCATE PREPARE stmt; ITERATE read_loop; END IF; -- 安全检查 _PanguId_ 列是否存在COUNT 不会触发 NOT FOUND可不用嵌套 SELECT COUNT(*) INTO has_pangu_col FROM information_schema.COLUMNS WHERE TABLE_SCHEMA target_db AND TABLE_NAME tbl_name AND COLUMN_NAME _PanguId_; IF has_pangu_col 0 THEN SET sql CONCAT( ALTER TABLE , target_db, ., tbl_name, , MODIFY COLUMN _PanguId_ BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, , ADD PRIMARY KEY (_PanguId_); ); PREPARE stmt FROM sql; EXECUTE stmt; DEALLOCATE PREPARE stmt; ITERATE read_loop; END IF; -- 新建 _PanguId_ SET sql CONCAT( ALTER TABLE , target_db, ., tbl_name, , ADD COLUMN _PanguId_ BIGINT UNSIGNED NOT NULL AUTO_INCREMENT FIRST, , ADD PRIMARY KEY (_PanguId_); ); PREPARE stmt FROM sql; EXECUTE stmt; DEALLOCATE PREPARE stmt; END LOOP; CLOSE cur; END$$ DELIMITER ; -- 使用示例 CALL AddMissingPrimaryKeys(A); DROP PROCEDURE IF EXISTS AddMissingPrimaryKeys;4.6.邮件提醒如果需要进行邮件提醒则需要在【邮件提醒】标签页做相关配置默认是设置了163的SMTP服务器也可设置其他邮箱服务器发件人需要是SMTP服务器所指的邮箱类型收件人可以是其他邮箱授权码需要登录163邮箱进行设置如下图所示配置完后可先点击【邮件测试】确认邮件发送没问题然后点击【保存配置】如下图所示以下情况会进行邮件提醒VIP切换时会发送邮件提醒在添加对方IP后主节点会对它们进行监测对方IP连接异常时会发送邮件提醒防止主节点宕机没有备节点可以切换在添加本机Web服务Url后备节点如果检测到Web服务异常后会发送邮件提醒防止主节点Web服务异常没有可用的备节点在添加本机Windows服务后备节点如果检测到Windows服务异常会发送邮件提醒防止主节点Windows服务异常没有可用的备节点在开启Mysql健康检测的情况下备节点断联或同步异常会发送邮件提醒防止主节点宕机切换后数据异常Sqlserver数据同步异常停止任务时会发送邮件邮件格式如下图所示5.关于开机自启动在【IP漂移】点击运行成功后会保存相关信息下次打开软件将自动运行在【执行管理】配置后下次打开将自动运行在【文件同步】配置后下次打开将自动运行在【mysql主从配置】开启健康检测成功后会保存mysql设置的相关信息下次打开软件将自动开启健康检测在【数据同步】添加任务后下次打开将自动运行将软件设置为快捷方式然后WinR输入shell:startup将快捷方式拖入该目录WinR输入gpedit.msc打开组策略依次展开计算机配置---Windows设置---安全设置---本地策略---安全选项---用户账户控制以管理员批准模式运行所有管理员设置为已禁用6.清除配置删除Config文件夹即可