[分享经验] 新西兰 One NZ eSim 卡迁移到新手机有个奇怪的限制,要删除旧手机上的 eSim,不仅仅是禁用,才能在新手机上重新激活
已经找客服要到新的二维码,但激活失败。试了一下午,后来心一横,删除旧手机上的 eSim 后再激活就可以了。
xiaohack博客专注前沿科技动态与实用技术干货分享,涵盖 AI 代理、大模型应用、编程工具、文档解析、SEO 实战、自动化部署等内容,提供开源项目教程、科技资讯日报、工具使用指南,助力开发者、AI 爱好者获取前沿技术与实战经验。
已经找客服要到新的二维码,但激活失败。试了一下午,后来心一横,删除旧手机上的 eSim 后再激活就可以了。
S.EE 上线文件分享功能了。
跟那些套路网盘不一样,没倒计时、没广告、没限速,给链接就能下。
fs.to / files.to / fileshare.to,也支持绑自己的域名直链链接可以在分享页面里获取
wget 拉文件我们的 SM.MS 图床从 2015 年运营到现在 10 年了,S.EE 是同一个开发团队。
文件分享需要付费账号,套餐详情: https://s.ee/pricing/
有问题随时反馈 🙏
大佬们好,我最近花了几个月的时间做了一个英雄联盟云顶之弈自动挂机的软件,初衷是为了全自动刷通行证和宝典。
Github 地址:Tft-Hextech-Helper

具体的方案是纯粹的视觉识别:OCR+模版匹配。不涉及任何的内存读取,操作则控制鼠标进行点击。同时使用了 LOL 官方公开的 API 接口来实现自动排队,自动接收对局等,目前可以做到全流程打通,挂一整天完全不用手动。我高强度挂机了两天,从青铜打到了白银三,期间没有被封过。
这里想跟各位大佬交流一下,这种完全不读取内存的方案,存在被封号的可能性吗?会不会检查玩家的鼠标移动是否平滑之类的?希望大佬们积极解答,也欢迎使用和 star 。
把以前写的饭否 iOS 客户端开饭使用 AI 重写了,感觉很不错了,很多功能我以前根本不会写,我只能说 AI 真的太强了
更新日志:
更流畅的体验
转发、回复交互逻辑修改
支持语音输入
支持 ocr 输入
拍照支持多种滤镜
iPad 上支持分屏界面
支持自定义 tab 栏
支持自定义字体
支持分享图片、复制图片
使用本机数据库存储 节省流量更流畅
主题只保留黑色、白色和跟随系统
增加一些动画效果
下载链接
https://apps.apple.com/hk/app/开饭-饭否客户端/id1189449526
以前的我:
这个我不会,这页面好卡,这里怎么闪退了
现在有了 AI 的我:
我现在强得可怕

团队里越来越多的人开始 vibe coding ,但我还是比较反感的,主要原因如下:
已经找客服要到新的二维码,但激活失败。试了一下午,后来心一横,删除旧手机上的 eSim 后再激活就可以了。
S.EE 上线文件分享功能了。
跟那些套路网盘不一样,没倒计时、没广告、没限速,给链接就能下。
fs.to / files.to / fileshare.to,也支持绑自己的域名直链链接可以在分享页面里获取
wget 拉文件我们的 SM.MS 图床从 2015 年运营到现在 10 年了,S.EE 是同一个开发团队。
文件分享需要付费账号,套餐详情: https://s.ee/pricing/
有问题随时反馈 🙏
大佬们好,我最近花了几个月的时间做了一个英雄联盟云顶之弈自动挂机的软件,初衷是为了全自动刷通行证和宝典。
Github 地址:Tft-Hextech-Helper

具体的方案是纯粹的视觉识别:OCR+模版匹配。不涉及任何的内存读取,操作则控制鼠标进行点击。同时使用了 LOL 官方公开的 API 接口来实现自动排队,自动接收对局等,目前可以做到全流程打通,挂一整天完全不用手动。我高强度挂机了两天,从青铜打到了白银三,期间没有被封过。
这里想跟各位大佬交流一下,这种完全不读取内存的方案,存在被封号的可能性吗?会不会检查玩家的鼠标移动是否平滑之类的?希望大佬们积极解答,也欢迎使用和 star 。
记得之前有个切换年付巨便宜的 bug ,现在又出现了这个升级高级版订阅随机延长免费试用时长 bug 。。。
https://www.microsoft.com/en-us/microsoft-365/college-student-pricing
前提条件:edu 邮箱验证。步骤:
升级高级版虽然只显示 1 个月试用,但订阅成功后的邮件里通知 renewal date 都到 5 年后 2031 了。。。无法绑卡但是套 gpay 付款成功,左下角可修改地区。
记得之前有个切换年付巨便宜的 bug ,现在又出现了这个升级高级版订阅随机延长免费试用时长 bug 。。。
https://www.microsoft.com/en-us/microsoft-365/college-student-pricing
前提条件:edu 邮箱验证。步骤:
升级高级版虽然只显示 1 个月试用,但订阅成功后的邮件里通知 renewal date 都到 5 年后 2031 了。。。无法绑卡但是套 gpay 付款成功,左下角可修改地区。
可以单纯作为 YouTube 下载器的备用软件。
PS: 如果在使用基于 yt-dlp 的软件时出现没法正常下载的情况,基本都是节点不行,需要更换可用节点
我大概用了两周的 coding agent 工作流:Superpowers(obra/superpowers)。今天看到它出现在 claude-plugins-official 列表里(我这边 /plugin 能看到 source),顺便分享下它的工作流思路。
来源:
Reddit 讨论:https://www.reddit.com/r/ClaudeCode/comments/1qgkupf/superpowers_is_now_on_the_official_claude/
它有一套最近大家在聊的很火的 skills,用来把 agent 拉回 “先想清楚、再动手、再验证” 的节奏,核心链路大概是:
brainstorming(/superpowers:brainstorm):任何 “要开始写 / 改功能” 之前先用它,把需求 / 约束 / 成功标准摸清楚,先出设计再实现(分段确认)
writing-plans(/superpowers:write-plan):把实现拆成很小、可验证的 steps,避免一口气写一大坨
executing-plans(/superpowers:execute-plan):按批次执行计划,每批做一次 review/checkpoint
test-driven-development:强调 red/green/refactor(先失败的测试,再最小实现)
verification-before-completion + systematic-debugging:先验证再宣称 “修好了”,遇到 bug 用更系统的方法追根因
安装我就不复读了:README 里 Claude Code/Codex/OpenCode 都有对应的入口和指令。我个人感觉最有用的是先从 brainstorming 那套问答 / 设计确认开始。
我也在不断熟悉这套工作流中,感觉它就是我想要的 coding agent 工作流。
看了其他佬友的,正常是 2 年,也有 5 年
4 年是什么原理?已有佬友在评论区展现 us 区 + Gpay,欢迎大家分享经验!
注意注意,先领取普通版 365,再去尝试 Premium 团队版 365!
分享下我的踩坑流程,希望能给大家带来帮助
1. 我先在 tw 区的链接,edu 的认证什么的都很顺利,但是卡在了绑卡上,试了 PayPal 和直接输入卡号都不行
https://checkout.microsoft365.com/acquire/purchase?language=zh-TW&market=TW&requestedDuration=Month&scenario=microsoft-365-student&client=poc&campaign=StudentFree12M
2. 于是换成 us 区,还是用之前的 edu(之前屯的 tw 的 edu)使用以下链接 https://checkout.microsoft365.com/acquire/purchase?language=en-US&market=US&requestedDuration=Month&scenario=microsoft-365-student&client=poc&campaign=StudentFree12M
这次还是卡在绑卡上,发现可以使用 Gpay,绑定,顺利通过!
3. 领取普通版本的 365 之后,尝试领取 Premium 版本的 365,也是 us 区,使用如下链接
https://checkout.microsoft365.com/acquire/purchase?language=en-US&market=US&requestedDuration=Month&scenario=microsoft-365-premium&client=poc&campaign=StudentPremiumFree12M
4. 它会一直显示错误,刷新也错误,本来我听别人说封车了,但是不要放弃!在不断尝试刷新、隐私网页再登陆领取,最后和之前一样的流程,绑定 Gpay 之后领取成功了
5. 最后在这里查看订阅时长:https://account.microsoft.com/services/
30 年 2 月 17 日到期,总共领取 4 年!
不清楚为什么和其他人不同,可能和地区或者邮箱有关吧,但是我个人用的是 us 区 + tw 的 edu,这种混搭感觉也不是很靠谱,佬友们参考看看吧
领到的佬友们记得取消自动续期哦
在 PostgresSql HA 方案中,流复制方案集性能,可靠性,部署成本低等优点,也是目前被普遍采用的方案
在流复制 HA 集群管理工具中,Pacenmaker+Corosysnc 是相对程序可靠的
pcs status //查看集群状态
pcs resource show //查看资源
pcs resource create ClusterIP IPaddr2 ip=192.168.0.120 cidr_netmask=32 //创建一个虚拟IP资源
pcs resource cleanup //xx表示虚拟资源名称,当集群有资源处于unmanaged的状态时,可以用这个命令清理掉失败的信息,然后重置资源状态
pcs resource list //查看资源列表
pcs resource restart //重启资源
pcs resource enable //启动资源
pcs resource disable //关闭资源
pcs resource delete //删除资源
crm_mon -Arf -1 //查看同步状态和资源 Usage:
pg_ctl init[db] [-D DATADIR] [-s] [-o OPTIONS]
pg_ctl start [-D DATADIR] [-l FILENAME] [-W] [-t SECS] [-s] [-o OPTIONS] [-p PATH] [-c]
pg_ctl stop [-D DATADIR] [-m SHUTDOWN-MODE] [-W] [-t SECS] [-s]
pg_ctl restart [-D DATADIR] [-m SHUTDOWN-MODE] [-W] [-t SECS] [-s] [-o OPTIONS] [-c]
pg_ctl reload [-D DATADIR] [-s]
pg_ctl status [-D DATADIR]
pg_ctl promote [-D DATADIR] [-W] [-t SECS] [-s]
pg_ctl logrotate [-D DATADIR] [-s]
pg_ctl kill SIGNALNAME PID
CentOS Linux release 7.9.2009 (Core)
pgsql:(14)
PCS 相关版本:
[root@k8s-master01 pgsql_cluster]# rpm -qa|grep pacemaker
pacemaker-cli-1.1.23-1.el7_9.1.x86_64
pacemaker-cluster-libs-1.1.23-1.el7_9.1.x86_64
pacemaker-1.1.23-1.el7_9.1.x86_64
pacemaker-libs-1.1.23-1.el7_9.1.x86_64
[root@k8s-master01 pgsql_cluster]# rpm -qa|grep pcs
pcs-0.9.169-3.el7.centos.3.x86_64
[root@k8s-master01 pgsql_cluster]# rpm -qa|grep corosync
corosync-2.4.5-7.el7_9.2.x86_64
corosynclib-2.4.5-7.el7_9.2.x86_64
192.168.28.151 pg-151
192.168.28.152 pg-152
192.168.28.153 pg-153
192.168.28.41 vip-master
192.168.28.141 vip-slave
cat /etc/hosts
192.168.28.151 pg-151
192.168.28.152 pg-152
192.168.28.153 pg-153
#systemctl disable firewalld #systemctl stop firewalld #systemctl status firewalld #sestatus
SELinux status: disabled
ntpdate ntp1.aliyun.com
yum -y install libsmb*
yum install -y pacemaker pcs corosync
yum install -y autoconf automake libtool
yum install -y docbook-style-xsl
yum install -y gcc-c++ glib2-devel
需要注意的是,安装时可能会报 Missing Dependency :kernel-header
安装 安装 kernel-headers 即可解决问题,如下
wget http://mirror.centos.org/centos/7/updates/x86_64/Packages/kernel-headers-3.10.0-1160.102.1.el7.x86_64.rpm
rpm -ivh kernel-headers-3.10.0-1160.102.1.el7.x86_64.rpm
wget https://github.com/ClusterLabs/resource-agents/releases/tag/v4.12.0
unzip resource-agents-4.12.0.zip
./autogen.sh
/configure
make && make install
确认支持 PG12 以上版本
/usr/lib/ocf/resource.d/heartbeat/pgsql 文件,1918 行,包含 ocf_version_cmp “$version” “12”
if is_replication || [ "$OCF_RESKEY_rep_mode" = "slave" ]; then if [ `printf "$version\n9.1" | sort -n | head -1` != "9.1" ]; then
ocf_exit_reason "Replication mode needs PostgreSQL 9.1 or higher." return $OCF_ERR_INSTALLED fi
ocf_version_cmp "$version" "12"
rc=$?
if [ $rc -eq 1 ]||[ $rc -eq 2 ]; then # change the standby method for PosrgreSQL 12 or later. systemctl start pcsd
systemctl enable pcsd
systemctl enable corosync
systemctl enable pacemaker
echo hacluster|passwd hacluster --stdin
pcs cluster auth -u hacluster -p hacluster pg-151 pg-152 pg-153 pcs cluster setup --last_man_standing=1 --name pgcluster pg-151 pg-152 pg-153 --force 注意 --force 会强行覆盖原有集群配置
#启动集群
pcs cluster start --all
#查看集群状态
pcs status --full sudo yum install -y https://download.postgresql.org/pub/repos/yum/reporpms/EL-7-x86_64/pgdg-redhat-repo-latest.noarch.rpm
sudo yum install -y postgresql14-server
sudo /usr/pgsql-14/bin/postgresql-14-setup initdb
sudo systemctl enable postgresql-14
sudo systemctl start postgresql-14
mkdir -p /data/postgresql/pgdata/pg-5432
mkdir -p /data/postgresql/pg_archive/pg-5432
chown postgres:postgres /data/postgresql
chmod 700 /data/postgresql
su - postgres
-bash-4.2$ cat .bash_profile
[ -f /etc/profile ] && source /etc/profile
PGDATA=/data/postgresql/pgdata/pg-5432
export PGDATA
export PATH=/usr/pgsql-14/bin:$PATH # If you want to customize your settings, # Use the file below. This is not overridden # by the RPMS.
[ -f /var/lib/pgsql/.pgsql_profile ] && source /var/lib/pgsql/.pgsql_profile
initdb -D /data/postgresql/pgdata/pg-5432/ pg_hba.conf (用于设置主机访问)
local all all trust
host all all 192.168.28.0/24 md5
# IPv4 local connections:
host all all 127.0.0.1/32 trust
# IPv6 local connections:
host all all ::1/128 trust
# Allow replication connections from localhost, by a user with the
# replication privilege.
local replication all trust
host replication repluser 192.168.28.0/24 md5
host replication all 127.0.0.1/32 trust
host replication all ::1/128 trust
先运行 matser 数据库pg_ctl start
再创建复制用户
psql (14.10)
Type "help" for help.
postgres=# create user repluser with replication password 'repluser'; pg_basebackup -h pg-151 -U repluser -p 5432 -D /data/postgresql/pgdata/pg-5432/ -X stream -P pg_ctl stop
pcs cluster cib pgsql_cfg
pcs -f pgsql_cfg property set no-quorum-policy="ignore"
pcs -f pgsql_cfg property set stonith-enabled="false"
pcs -f pgsql_cfg resource defaults resource-stickiness="INFINITY"
pcs -f pgsql_cfg resource defaults migration-threshold="1"
pcs -f pgsql_cfg resource create vip-master IPaddr2 \
ip="192.168.28.41" \
nic="eth0" \
cidr_netmask="24" \
op start timeout="60s" interval="0s" on-fail="restart" \
op monitor timeout="60s" interval="10s" on-fail="restart" \
op stop timeout="60s" interval="0s" on-fail="block"
pcs -f pgsql_cfg resource create vip-slave IPaddr2 \
ip="192.168.28.141" \
nic="eth0" \
cidr_netmask="24" \
meta migration-threshold="0" \
op start timeout="60s" interval="0s" on-fail="stop" \
op monitor timeout="60s" interval="10s" on-fail="restart" \
op stop timeout="60s" interval="0s" on-fail="ignore"
pcs -f pgsql_cfg resource create pgsql pgsql \
pgctl="/usr/pgsql-14/bin//pg_ctl" \
psql="/usr/pgsql-14/bin//psql" \
pgdata="/data/postgresql/pgdata/pg-5432" \
config="/data/postgresql/pgdata/pg-5432/postgresql.conf" \
rep_mode="async" \
node_list="pg-151 pg-152 pg-153" \
master_ip="192.168.28.41" \
repuser="repluser" \
primary_conninfo_opt="password=repluser keepalives_idle=60 keepalives_interval=5 keepalives_count=5" \
restart_on_promote='true' \
op start timeout="60s" interval="0s" on-fail="restart" \
op monitor timeout="60s" interval="4s" on-fail="restart" \
op monitor timeout="60s" interval="3s" on-fail="restart" role="Master" \
op promote timeout="60s" interval="0s" on-fail="restart" \
op demote timeout="60s" interval="0s" on-fail="stop" \
op stop timeout="60s" interval="0s" on-fail="block" \
op notify timeout="60s" interval="0s"
pcs -f pgsql_cfg resource master msPostgresql pgsql \
master-max=1 master-node-max=1 clone-max=5 clone-node-max=1 notify=true
pcs -f pgsql_cfg resource group add master-group vip-master
pcs -f pgsql_cfg resource group add slave-group vip-slave
pcs -f pgsql_cfg constraint colocation add master-group with master msPostgresql INFINITY
pcs -f pgsql_cfg constraint order promote msPostgresql then start master-group symmetrical=false score=INFINITY
pcs -f pgsql_cfg constraint order demote msPostgresql then stop master-group symmetrical=false score=0
pcs -f pgsql_cfg constraint colocation add slave-group with slave msPostgresql INFINITY
pcs -f pgsql_cfg constraint order promote msPostgresql then start slave-group symmetrical=false score=INFINITY
pcs -f pgsql_cfg constraint order demote msPostgresql then stop slave-group symmetrical=false score=0
pcs cluster cib-push pgsql_cfg
运行脚本
chmox +x cluster_setup.sh
sh cluster_setup.sh cibadmin --query > tmp.xml
//将当前集群配置信息保存到tmp.xml文件中 cibadmin --query > tmp.xml
vi tmp.xml
//使用编辑器对XML文件进行修改 vim tmp.xml
cibadmin --replace --xml-file tmp.xml
//将修改后的XML文件替换掉当前集群的配置信息 cibadmin --replace --xml-file tmp.xml cibadmin 是用于操作 Heartbeat CIB 的低级管理命令。它可以用来转储、更新或修改所有或部分 CIB,删除整个 CIB 或执行各种 CIB 管理操作。
集群配置信息是 Pacemaker 集群中 CIB 信息的关键组成部分,Pacemaker 的集群配置信息决定了集群最终应该如何工作以及集群最终的运行状态,因为只有一个正确的集群配置才能驱动集群资源运行在正常的状态。通常情况下,集群的配置信息由集群配置选项 (crm_config)、集群节点 (nodes)、集群资源 (resources) 和资源约束 (constraints) 四个配置段组成,通过 cibadmin --query 可查。
1. 启动集群并设置开机自启动
数据库无需配置自启动,由集群软件自动拉起
pcs cluster start --all
pcs cluster enable --all 2. 查看集群状态
[root@k8s-master01 pgsql_cluster]# pcs status Cluster name: pgcluster Stack: corosync Current DC: pg-153 (version 1.1.23-1.el7_9.1-9acf116022) - partition with quorum Last updated: Tue Nov 21 16:47:19 2023 Last change: Tue Nov 21 16:38:42 2023by root via crm_attribute on pg-151 3 nodes configured 7 resource instances configured Online: [ pg-151 pg-152 pg-153 ]
Full list of resources: Master/Slave Set: msPostgresql [pgsql]
Masters: [ pg-151 ]
Slaves: [ pg-152 pg-153 ]
Resource Group: master-group vip-master (ocf::heartbeat:IPaddr2): Started pg-151 Resource Group: slave-group vip-slave (ocf::heartbeat:IPaddr2): Started pg-152 Daemon Status: corosync: active/enabled pacemaker: active/enabled pcsd: active/enabled 3、查看本机集群状态及资源状态
crm_mon -Afr -1
[root@k8s-master01 pgsql_cluster]# crm_mon -Afr -1
Stack: corosync
Current DC: pg-153 (version 1.1.23-1.el7_9.1-9acf116022) - partition with quorum
Last updated: Tue Nov 21 16:47:54 2023
Last change: Tue Nov 21 16:38:42 2023 by root via crm_attribute on pg-151
3 nodes configured
7 resource instances configured
Online: [ pg-151 pg-152 pg-153 ]
Full list of resources:
Master/Slave Set: msPostgresql [pgsql]
Masters: [ pg-151 ]
Slaves: [ pg-152 pg-153 ]
Resource Group: master-group
vip-master (ocf::heartbeat:IPaddr2): Started pg-151
Resource Group: slave-group
vip-slave (ocf::heartbeat:IPaddr2): Started pg-152
Node Attributes:
* Node pg-151:
+ master-pgsql : 1000
+ pgsql-data-status : LATEST
+ pgsql-master-baseline : 00000000220000A0
+ pgsql-status : PRI
* Node pg-152:
+ master-pgsql : -INFINITY
+ pgsql-data-status : STREAMING|ASYNC
+ pgsql-status : HS:async
* Node pg-153:
+ master-pgsql : -INFINITY
+ pgsql-data-status : STREAMING|ASYNC
+ pgsql-status : HS:async
Migration Summary:
* Node pg-153:
* Node pg-152:
* Node pg-151:
4. 查看主节点流复制状态 (master)
su - postgres
-bash-4.2$ psql
psql (14.10)
Type "help" for help.
postgres=# select client_addr,sync_state from pg_stat_replication;
client_addr | sync_state
----------------+------------
192.168.28.153 | async 192.168.28.152 | async
(2 rows)
5. 验证 vip [all service]
ipconfig
在主节点上创建一个新表
postgres=# create table ysl(id int);
CREATE TABLE
postgres=# insert into ysl values(1);
INSERT 0 1
postgres=# select * from ysl;
id
----
1
(1 row)
在 slave 节点上查看
-bash-4.2$ psqlpsql (14.10)
Type "help" for help.
postgres=# select * from ysl; id
----
1
(1 row)
停掉主库 pg-151,备库 pg-152 提升为主节点
-bash-4.2$ pg_ctl stop
waiting for server to shut down.... done
[root@k8s-master01 pgsql_cluster]# pcs status
Cluster name: pgcluster
Stack: corosync
Current DC: pg-153 (version 1.1.23-1.el7_9.1-9acf116022) - partition with quorum
Last updated: Tue Nov 21 16:59:30 2023
Last change: Tue Nov 21 16:59:29 2023 by root via crm_attribute on pg-152
3 nodes configured
7 resource instances configured
Online: [ pg-151 pg-152 pg-153 ]
Full list of resources:
Master/Slave Set: msPostgresql [pgsql]
Masters: [ pg-152 ]
Slaves: [ pg-153 ]
Stopped: [ pg-151 ]
Resource Group: master-group
vip-master (ocf::heartbeat:IPaddr2): Started pg-152
Resource Group: slave-group
vip-slave (ocf::heartbeat:IPaddr2): Started pg-153
Failed Resource Actions:
* pgsql_monitor_3000 on pg-151 'not running' (7): call=92, status=complete, exitreason='',
last-rc-change='Tue Nov 21 16:58:59 2023', queued=0ms, exec=0ms
Daemon Status:
corosync: active/enabled
pacemaker: active/enabled
pcsd: active/enabled
注意 master 节点挂掉之后,使用 crm_mon -Arf -1 命令看到末尾有 "You have to remove /var/lib/pgsql/tmp/PGSQL.lock file to force start." 字样,master 宕机启动时,需要删除临时锁文件方可进行集群角色转换。即执行 rm -rf /var/lib/pgsql/tmp/PGSQL.lock
拉起数据库不需要执行 pg_ctl start, 只需要 pcs resource cleanup
[root@k8s-master01 pgsql_cluster]# pcs resource cleanup
Cleaned up all resources on all nodes
Waiting for 1 reply from the CRMd. OK
[root@k8s-master01 pgsql_cluster]# pcs status
Cluster name: pgcluster
Stack: corosync
Current DC: pg-153 (version 1.1.23-1.el7_9.1-9acf116022) - partition with quorum
Last updated: Tue Nov 21 17:01:57 2023
Last change: Tue Nov 21 17:01:26 2023 by hacluster via crmd on pg-151
3 nodes configured
7 resource instances configured
Online: [ pg-151 pg-152 pg-153 ]
Full list of resources:
Master/Slave Set: msPostgresql [pgsql]
Masters: [ pg-152 ]
Slaves: [ pg-153 ]
Stopped: [ pg-151 ]
Resource Group: master-group
vip-master (ocf::heartbeat:IPaddr2): Started pg-152
Resource Group: slave-group
vip-slave (ocf::heartbeat:IPaddr2): Started pg-153
Failed Resource Actions:
* pgsql_start_0 on pg-151 'unknown error' (1): call=127, status=complete, exitreason='My data may be inconsistent. You have to remove /var/lib/pgsql/tmp/PGSQL.lock file to force start.',
last-rc-change='Tue Nov 21 17:01:28 2023', queued=1ms, exec=615ms
Daemon Status:
corosync: active/enabled
pacemaker: active/enabled
pcsd: active/enabled
此时可以看到 pg-153,pg-151 成为 pg-152 的备机
postgres=# select * from pg_stat_replication;
pid | usesysid | usename | application_name | client_addr | client_hostname | client_port |
backend_start | backend_xmin | state | sent_lsn | write_lsn | flush_lsn | replay_ls
n | write_lag | flush_lag | replay_lag | sync_priority | sync_state | reply_time
-------+----------+----------+------------------+----------------+-----------------+-------------+-----
--------------------------+--------------+-----------+------------+------------+------------+----------
--+-----------+-----------+------------+---------------+------------+-------------------------------
13234 | 16384 | repluser | pg-153 | 192.168.28.153 | | 60624 | 2023
-11-21 08:59:27.197402+00 | 12918 | streaming | 0/2D004748 | 0/2D004748 | 0/2D004748 | 0/2D00474
8 | | | | 0 | async | 2023-11-21 09:04:16.90261+00
31795 | 16384 | repluser | pg-151 | 192.168.28.151 | | 44678 | 2023
-11-21 09:04:05.741284+00 | 12918 | streaming | 0/2D004748 | 0/2D004748 | 0/2D004748 | 0/2D00474
8 | | | | 0 | async | 2023-11-21 09:04:15.822551+00
(2 rows)
参考:
PgSQL Replicated Cluster:
如果加入家庭组后还是《free》。
如果账号突然《账号无权限,已跳过自动刷新》。
都去验证一下年龄,验证通过。等个几分钟就好了!
希望能帮到大家
上面是我的经验之谈,我的号是这么恢复的,可能我接触得少。看完大家的回复,得出结论,方法不一定有效,大家可以试试,不行也没办法了。
首先,官方文档非常值得细细品味,看完官方文档倒也可以考虑不用看其他的文章了(针对 skill,mcp 这一块感觉描述一般,mcp 太多东西了):
MCP 在会话启动时全量加载所有工具定义到上下文:
会话启动 → 加载所有 MCP 服务器 → 注入全部工具定义(JSON-Schema)
就拿我使用的 mcp 来说:
| MCP 服务器 | 工具数 | Token 占用 |
|---|---|---|
| auggie-mcp | 1 | ~1k |
| grok-search | 5 | ~3k |
| memory | 9 | ~5k |
| sequential-thinking | 1 | ~2k |
| 多服务器叠加 | - | 轻松突破 10k+ |
随便用几个占用就非常大了
Skill 采用渐进式披露,仅在需要时加载:
| 阶段 | 加载内容 | Token 占用 |
|---|---|---|
| 启动时 | 仅 name + description 索引 | ~10-100 tokens/skill |
| 触发时 | 完整 SKILL.md 内容 | ~1,000-5,000 tokens/skill |
我使用的 skill:90K 的 Skills 目录,/context 仅显示 513 tokens,和 mcp 对比起来,非常直观。
| 维度 | MCP | Skill |
|---|---|---|
| 启动时占用 | 全量(10k+ tokens) | 索引(~500 tokens) |
| 使用时增量 | 无(已加载) | 按需逐步加载 |
MCP(Model Context Protocol)即模型上下文协议,采用 Host-Client-Server 三层架构:
Host (Claude Code)
│
├── Client ←──JSON-RPC──→ context7 Server
├── Client ←──JSON-RPC──→ sequential-thinking Server
└── Client ←──JSON-RPC──→ your Server | 角色 | 是什么 |
|---|---|
| Host | AI 应用程序(比如 Claude Code、VS Code、Cursor 等) |
| Client | 通信管道,负责与 Server 建立连接、发送 JSON-RPC 请求、接收响应 |
| Server | 提供工具 / 上下文的程序(== 日常说的「安装 MCP」就是安装 Server==) |
| JSON-RPC | Client 与 Server 之间传输的数据格式(所有 MCP 都遵守此协议) |
| Tool Schema | 启动时 Server 返回的「工具说明书」,告诉 Claude 有哪些工具、怎么调用 |
Host 和 Client 由应用自动管理,开发者 / 使用者只需关注 Server。再比如 FastMCP 框架会自动处理协议细节。
my-mcp-server/
├── pyproject.toml # 包定义(必需)
│ ├── name = "mcp-server-xxx"
│ └── version = "1.0.0"
├── src/
│ ├── server.py # 入口,初始化 FastMCP
│ ├── tools.py # Tool 定义(单文件,适合 <10 个工具)
│ ├── tools/ # Tool 定义(多文件,按功能拆分)
│ │ ├── __init__.py
│ │ ├── search.py
│ │ └── fetch.py
│ └── resources.py # Resource 提供者(可选)
└── README.md
tools.py和tools/二选一,可根据数量决定。
从这里就可以看出,其实和接口非常像,请求 -> 回调数据,实际上多数的 mcp 也都可以理解成三方接口。
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("weather")
@mcp.tool() async def get_weather(location: str) -> str:
"""Get weather for a location.""" return f"Weather in {location}: 72°F, Sunny" if __name__ == "__main__":
mcp.run(transport="stdio")
配置示例:
{ "args": [ "-y", "@upstash/context7-mcp" ], "command": "npx", "type": "stdio" } mcp 服务器的 json 格式,让配置起来非常方便,cv 万岁
Skill 是 Claude Code 的知识 / 流程包,本质是一个 Markdown 文件夹,用于:
额外说明:
Skill 只能提供指导,无法执行外部 API 调用、网络请求、会话管理等操作,毕竟只是 md 文件夹,但是能指导 cc 运行脚本,包括但不限于自带的脚本资源,这句话应该会有嚼头。
以下规范取自
skill-creatorSkill, 我觉得配置比 cc 官方文档里面的描述更详细
skill-name/ ├── SKILL.md (必需) │ ├── YAML frontmatter ──→ 索引层(始终加载,~100 words) │ │ ├── name: (必需) │ │ └── description: (必需,唯一触发机制) │ └── Markdown 正文 ────→ 内容层(触发时加载,建议 <500 行) └── Bundled Resources (可选) ──→ 内容层(按需加载) ├── scripts/ - 可执行脚本(Python/Bash) ├── references/ - 参考文档(Claude 判断需要时加载) └── assets/ - 输出资源(模板、图片,不加载到上下文) 双层架构说明:
description 是唯一触发机制
# ✅ 好的 description(包含触发场景) description: >
Comprehensive document creation and editing with tracked changes.
Use when Claude needs to work with .docx files for:
(1) Creating new documents, (2) Modifying content,
(3) Working with tracked changes, (4) Adding comments # ❌ 差的 description(太模糊) description: A useful document tool 是不是觉得模式 1,3 非常相似?我也觉得。不过
skill-creator还是分成了这三种,就全罗列出来了
模式 1:高层指南 + 引用
# PDF Processing ## Quick start
[核心代码示例]
## Advanced features - **Form filling**: See [FORMS.md](references/FORMS.md)
- **API reference**: See [REFERENCE.md](references/REFERENCE.md)
Claude 仅在需要时加载 FORMS.md 或 REFERENCE.md。
模式 2:按领域 / 变体组织
cloud-deploy/
├── SKILL.md (工作流 + 选择指南)
└── references/
├── aws.md ← 用户选 AWS 时才加载
├── gcp.md
└── azure.md模式 3:条件详情
## Editing documents
For simple edits, modify XML directly.
**For tracked changes**: See [REDLINING.md](references/REDLINING.md)
**For OOXML details**: See [OOXML.md](references/OOXML.md)
用户请求 → Claude 扫描所有 Skill 的 description → 匹配 → 加载 SKILL.md 正文 → 按需加载 references → 执行
特点:
结论先行:MCP 在版本管理上绝对优于 Skill。
MCP 直接复用 npm/PyPI 成熟生态,版本管理由包管理器自动处理。
工作原理:
npx 或 uvx 命令启动时,包管理器会自动处理下载和缓存package.json(npm)或 pyproject.toml(PyPI)中更新行为:
| 模式 | 行为 | 启动速度 | 适用场景 |
|---|---|---|---|
| 默认 | 使用本地缓存,不查询 registry | 快 | 日常使用 |
| 强制更新 | 每次查询 registry,版本变化时才下载(@latest 或 --refresh) | 慢 | 需要最新版本时 |
获取方式对比:
| 获取方式 | 配置示例 | 更新机制 |
|---|---|---|
| npx (npm) | npx -y @pkg/server | 默认用缓存,需 @latest 或清缓存强制更新 |
| uvx (pip) | uvx mcp-server-fetch | 默认用缓存,需 --refresh 或清缓存强制更新 |
| 本地命令 | auggie --mcp | 需手动 pip install --upgrade |
配置示例:
// ~/.claude.json { "mcpServers": { "memory": { "command": "npx", "args": ["-y", "@modelcontextprotocol/server-memory"] } } } 推荐方式:手动清理缓存
当 MCP 服务器有新版本时,清理缓存即可:
# 清理 npx 缓存 rm -rf ~/.npm/_npx #(不推荐!不推荐!不推荐!) # 清理 uvx 缓存
uv cache clean #(不推荐!不推荐!不推荐!) # 上述的清理会清理系统中所有的缓存,但mcp的缓存位置各有不同,需要主动寻找,且无规律可言,最好还是让cc自己来吧 工作流程:
优点:日常启动快,需要更新时才清理缓存
不推荐使用 @latest 或 --refresh
虽然可以自动更新,但会显著影响启动速度(每次都查询 registry)。
配置示例:
{ "mcpServers": { "memory": { "command": "npx", "args": ["-y", "@modelcontextprotocol/server-memory@latest"] // npx 使用 @latest }, "fetch": { "command": "uvx", "args": ["--refresh", "mcp-server-fetch"] // uvx 使用 --refresh } } } 与 MCP 不同,一般来说 Skill 没有任何版本管理机制:
Skill 在某些时候更像可以随意定制的小玩具,在原本的基础上又能随意修改
Skill 的获取与更新方式:
| 获取方式 | 更新方式 | 版本控制 |
|---|---|---|
| GitHub 克隆 | git pull 手动更新 | 依赖 Git commit hash |
| 下载 ZIP 文件 | 手动替换文件 | 无 |
| CC 直接生成 | 即时生效 | 无 |
问题:
唯一的版本管理方案是官方 Marketplace,但有严格限制:
Marketplace 版本管理示例:
// marketplace.json { "name": "my-plugins", "plugins": [ { "name": "review-plugin", "source": "./plugins/review-plugin", "version": "2.1.0" // ← 需要手动维护 } ] } 限制:
ps:这一块应该是这样的吧,没有官号诶
尽管缺乏版本管理,Skill 还有一个 MCP 无法比拟的优势:
即时生效:修改 Skill 文件后无需重启服务,下次触发时自动加载最新内容。
对比 MCP:
适用场景:
事先声明: 这里的 /ccg 不是使用的 skill,我才发现,哎呀!!
但是我都按照这个写了,不想再改了。
/ccg 的工作流程是 /cmd → 自己的脚本
请你们假装 是 /cmd → skill → skill 的脚本
Skill 依赖 Claude 自动匹配描述,存在以下问题:
实际体验:虽然 Skill 理论上能够自动触发,但实际触发率较低。比如我即使在 CLAUDE.md 中明确写了 "让 Codex 和 Gemini 参与协作",Claude 偶尔还是会忽略。所以之前我都会主动在需求后面添加这句话。
解决方案:使用 cmd 可以 100% 稳定触发。例如:/ccg:feat 需求描述 总比主动描述或者期待 cc 记得安心。
为什么需要 Command:
Skill 可能包含复杂的命令调用和参数配置,这些细节难以通过自然语言稳定触发。例如:
/home/nobug/.claude/bin/codeagent-wrapper --backend gemini--backend codex、--SESSION_ID xxx这些精确的指令和参数通过语言描述很难稳定触发,而 Command 可以将这些细节明确定义在文件中。
模式 1 示例(简单流程):
场景:应用主题到 Artifact
├── ~/.claude/skills/theme-factory/
│ └── SKILL.md # 主题定义、应用指南
└── ~/.claude/commands/
└── theme-factory.md # 内容:"Execute the theme-factory skill"
用户输入 /theme-factory 应用深色主题
↓
Command 触发 → Claude 加载 SKILL.md → 自主执行
模式 2 示例(复杂流程):
场景:前端专项开发
└── ~/.claude/commands/ccg/
└── frontend.md # 完整工作流定义
用户输入 /ccg:frontend 实现响应式导航栏
↓
Claude 加载 frontend.md 内容
↓
按照 Command 中定义的 6 个阶段执行:
1. Prompt 增强(可选)
2. 研究(代码检索)
3. 构思(调用 Gemini 分析)
4. 计划(调用 Gemini 规划)
5. 执行(Claude 实施)
6. 优化(调用 Gemini 审查)
外部工具说明:像 codeagent-wrapper 这样的工具是外部可执行文件(位于 ~/.claude/bin/),不是 Skill。Skill 只能提供指导,无法执行外部 API 调用、网络请求、会话管理等操作,这些必须由外部工具完成。
核心原则:
第一次写文章,本来只是想说 mcp 的包管理很爽 ,其他的都是为了这碟醋包的饺子
又到年终汇报时间,又要搞 word 格式,又要 ppt 形式述职,下面总结一下经验可以给佬们参考。
先根据每个月的月总按照公司模板生成年总需要填写的内容,这里我用的 Google AI Studio - Gemini 3 pro。没有月总的可以看看自己 Git 提交记录找找今年做了什么。
使用 Z.ai 生成 PPT。
这里导出的 PPTX 打开后,会发现样式有变化。
可以使用先导出 PDF,之后使用 Python 脚本将 PDF 转为图片,图片再转为 PPTX,这样就解决样式变化的问题了。
pip install pymupdf python-pptx
pdf2pptx.py,内容:import fitz # PyMuPDF
from pptx import Presentation
from pptx.util import Inches
import io
import os
def pdf_to_pptx(pdf_path, pptx_path, dpi=300):
"""
将 PDF 转换为 PPTX(每一页作为一张全屏图片)
:param pdf_path: 输入 PDF 文件路径
:param pptx_path: 输出 PPTX 文件路径
:param dpi: 渲染清晰度,300 已经非常清晰,如果文件太大可以降到 200
"""
# 1. 打开 PDF
pdf_doc = fitz.open(pdf_path)
prs = Presentation()
# 2. 获取 PDF 第一页的尺寸,并设置为 PPT 的幻灯片尺寸
# PDF 默认单位是点 (points), 1 inch = 72 points
first_page = pdf_doc[0]
width_pts, height_pts = first_page.rect.width, first_page.rect.height
prs.slide_width = Inches(width_pts / 72)
prs.slide_height = Inches(height_pts / 72)
print(f"开始转换: {pdf_path}")
print(f"总页数: {len(pdf_doc)}")
# 3. 逐页处理
for page_num in range(len(pdf_doc)):
page = pdf_doc.load_page(page_num)
# 渲染页面为图片 (设置缩放倍数以提高清晰度)
zoom = dpi / 72
mat = fitz.Matrix(zoom, zoom)
pix = page.get_pixmap(matrix=mat, alpha=False)
# 将图片存入内存流中,避免产生临时文件
img_stream = io.BytesIO(pix.tobytes("png"))
# 添加一张空白幻灯片 (6 是空白布局)
slide_layout = prs.slide_layouts[6]
slide = prs.slides.add_slide(slide_layout)
# 将图片插入幻灯片,铺满全屏
slide.shapes.add_picture(img_stream, 0, 0, width=prs.slide_width, height=prs.slide_height)
print(f"正在处理第 {page_num + 1} 页...")
# 4. 保存文件
prs.save(pptx_path)
pdf_doc.close()
print(f"转换完成!已保存至: {pptx_path}")
if __name__ == "__main__":
# === 使用说明 ===
# 将下面的文件名替换为你实际的文件名
input_pdf = "input.pdf"
output_pptx = "output.pptx"
if os.path.exists(input_pdf):
pdf_to_pptx(input_pdf, output_pptx)
else:
print(f"错误:找不到文件 {input_pdf}")
input.pdf,然后执行:python pdf2pptx.py
output.pptx。可以再让 AI 帮你输出一份口述草稿配合起来就行了。有尝试过在线 ILovePDF 网站去转,但是样式还是有问题。
试过 NotebookLM 生成 PPT,效果一般般,没想到 Z.ai 生成的效果还挺好看的
介绍
发布和订阅使用了 pg 的逻辑复制功能,通过发布端创建 publication 与表绑定,订阅端创建 subscription 同时会在发布端创建逻辑复制槽实现逻辑复制功能
一个 发布者(Publisher) 上可以有多个发布,一个 订阅者(Subscriber) 上可以有多个 订阅 。
一个发布可被多个订阅者订阅,一个订阅只能订阅一个发布者,但可订阅同发布者上的多个不同发布。
迁移,跨 PostgreSQL 大版本,跨操作系统平台进行复制。
CDC,收集数据库(或数据库的一个子集)中的增量变更,在订阅者上为增量变更触发触发器执行定制逻辑。
分拆,将多个数据库集成为一个,或者将一个数据库拆分为多个,进行精细的分拆集成与访问控制。
一个被纳入发布中的表,必须带有复制标识(Replica Identity),只有这样才可以在订阅者一侧定位到需要更新的行,完成 UPDATE 与 DELETE 操作的复制。
默认情况下,主键 (Primary Key)是表的复制标识,非空列上的唯一索引 (UNIQUE NOT NULL)也可以用作复制标识。
如果没有任何复制标识,可以显式将复制标识设置为 FULL,也就是把整个行当作复制标识
使用 FULL 模式的复制标识效率很低(因为每一行修改都需要在订阅者上执行全表扫描,很容易把订阅者拖垮),所以这种配置只能是保底方案。
使用 FULL 模式的复制标识还有一个限制,订阅端的表上的复制身份所包含的列,要么与发布者一致,要么比发布者更少
version: pg16
发布端: 5433
订阅端: 5434
主机 IP: 192.168.28.11
在发布者端,wal_level 必须被设置为 logical,而 max_replication_slots 中设置的值必须至少是预期要连接的订阅数加上保留给表同步的连接数。max_wal_senders 应该至少被设置为 max_replication_slots 加上同时连接的物理复制体的数量。
订阅者必须配置 max_replication_slots。它必须设置为至少是订阅者数,加上一些用于表同步的预留。max_logical_replication_workers 必须至少被设置为订阅数加上保留给表同步的连接数。此外,可能需要调整 max_worker_processes 以容纳复制工作者,至少为 (max_logical_replication_workers + 1)。注意,一些扩展和并行查询也会从 max_worker_processes 中取得工作者槽。
vim postgres.conf
wal_level = logical
max_wal_senders = 100 #max_wal_senders大于max_replication_slots vim pg_hba.conf
host all repl 订阅者IP/32 md5
重启 pgsql ,配置生效
su postgres
pg_ctl restart -D /data/postgresql/pgdata/pg-5433/ su postgres
psql -P 5433
psql (16.9 (Ubuntu 16.9-0ubuntu0.24.10.1))
Type "help" for help.
#创建用户
postgres=# create user repuser password 'repuser' replication;
CREATE ROLE
#在postgres库中创建表,并插入一条数据
postgres=# create table test1(id int primary key,name varchar(10) );
postgres=# insert into test1 values(1,'a'); # 赋予复制用户select表权限
postgres=# grant select on table test1 to repuser; create publication pub_test01 for table test1;
vim postgres.conf
max_replication_slots=8
max_logical_replication_workers=10
max_worker_processes=8
max_logical_replication_workers 逻辑复制进程数,应大于订阅节点的数量,并且给表同步预留一些进程数量
2. 重启 pgsql
pg_ctl restart -D /data/postgresql/pgdata/pg-5434/ CREATE SUBSCRIPTION subs_test01 CONNECTION 'host=192.168.28.11 dbname=postgres port=5433 user=repuser password=repuser' PUBLICATION pub_test01;
create table test3 (id int,name varchar(10));alter table test3 REPLICA IDENTITY full;ALTER PUBLICATION pub1 ADD TABLE test3;在订阅端执行刷新ALTER SUBSCRIPTION sub1 REFRESH PUBLICATION ;
在发布端执行 test3 表的 insert、delete、update、truncate 操作,看订阅端是否能同步
select * from pg_replication_slots; --查看所有复制槽 select * from pg_stat_replication; --查看复制槽的同步状态 select * from pg_publication; --查看所有发布 select * from pg_publication_tables; --查看所有发布对应的表 select usename,a.pubname,c.*,pubinsert,pubupdate,pubdelete,pubtruncate from pg_publication a,pg_user b,pg_publication_tables c where a.pubowner=b.usesysid and c.pubname=a.pubname;
select * from pg_subscription; --查看所有订阅 select srrelid::regclass from pg_subscription_rel; --查看订阅的所有表 select usename,datname,subname,srrelid::regclass,srsublsn,subconninfo from pg_subscription a,pg_user b,pg_subscription_rel c ,pg_database d where a.oid=c.srsubid and a.subowner=b.usesysid and a.subdbid=d.oid;
订阅在运行的情况下,需要一下操作:
ALTER SUBSCRIPTION pub_test01;
##首先需要停止当前的订阅 ALTER SUBSCRIPTION subs_test01 (slot_name =NONE);
##然后将订阅的复制槽设置成空
drop subscription subs_test01;
##最后就可以删除订阅了。 ##另外一个问题,复制订阅中,如果订阅的服务停止,或无法再次连接的情况下,需要关注 发布端的数据wal log 无法清理以及膨胀的问题。 ##所以在复制订阅中的订阅停止后,如果确认订阅无法再次恢复,或者不确认多长时间恢复,则需要删除复制槽 select * from pg_replication_slots;
select pg_drop_replication_slot(slot_name) from pg_replication_slots where slot_name = 'pub_test01';概述
使用 postgresql + etcd + patroni + haproxy + keepalived 可以实现 PG 的高可用集群,其中,以 postgresql 做数据库,Patroni 监控本地的 PostgreSQL 状态,并将本地 PostgreSQL 信息 / 状态写入 etcd 来存储集群状态,所以,patroni 与 etcd 结合可以实现数据库集群故障切换(自动或手动切换),而 haproxy 可以实现数据库读写分离 + 读负载均衡(通过不同端口实现),keepalived 实现 VIP 跳转,对 haproxy 提供了高可用,防止 haproxy 宕机。
Patroni 是一个基于 Python 的用于实现 PostgreSQL HA 解决方案的框架。为了最大程度的兼容性,它支持多种分布式配置存储,包括 ZooKeeper、etcd、Consul 或 Kubernetes。旨在帮助数据库工程师、DBA、DevOps 工程师和 SRE 快速部署数据中心(或任何地方)的 HA PostgreSQL 环境。
当前支持的 PostgreSQL 版本从 9.3 到 16。支持自动化故障转移、物理复制和逻辑复制、提供 RESTful API 接口,允许外部应用或运维工具直接操作 PostgreSQL 集群,进行如启停、迁移等操作,与 Linux watchdog 集成,以避免脑裂现象。
etcd 是一个分布式键值存储数据库,支持跨平台,拥有强大的社区。etcd 的 Raft 算法,提供了可靠的方式存储分布式集群涉及的数据。etcd 广泛应用在微服务架构和 Kubernates 集群中,不仅可以作为服务注册与发现,还可以作为键值对存储的中间件。从业务系统 Web 到 Kubernetes 集群,都可以很方便地从 etcd 中读取、写入数据。
etcd 完整的 cluster(集群)至少有三台,这样才能选举出一个 master 节点,两个 slave 节点。如果小于 3 台则无法进行选举,造成集群不可用。Etcd 使用 2379 和 2380 端口。
2379 端口:提供 HTTP API 服务,和 etcdctl 交互
2380 端口:集群中节点间通讯
项目地址:[[GitHub - etcd-io/etcd: Distributed reliable key-value store for the most critical data of a distributed system]]
| 服务器名 | ip 地址 | os | 数据库读写端口 | 只读端口 | 组件 | 组件端口 |
|---|---|---|---|---|---|---|
| k8s-mater01 | 192.168.28.11 | ubuntu 24.10 | 15433 | 25433 | PostgreSQL,Patroni、Etcd,haproxy、keepalived | 8008 |
| k8s-mater02 | 192.168.28.12 | ubuntu 24.10 | 15433 | 25433 | PostgreSQL,Patroni、Etcd,haproxy、keepalived | 8008 |
| k8s-mater01 | 192.168.28.13 | ubuntu 24.10 | 15433 | 25433 | PostgreSQL,Patroni、Etcd,haproxy、keepalived | 8008 |
| vip | 192.168.28.10 | PostgreSQL,Patroni、Etcd,haproxy、keepalived | 8008 |
| 软件名 | 版本 |
|---|---|
| Patroni | 4.0.6 |
| Etcd | 3.5.16 |
| Keepalived | 2.3.1 |
| Haproxy | 2.9.10-1ubuntu1.2 |
| PostgreSQL | 16.9 |
| watchdog | 5.16 |
| python | 3.12.7 |
这个架构中,PostgreSQL 提供数据服务,Patroni 负责主从切换,etcd 提供一致性存储,HAProxy 提供访问路由,Keepalived 提供网络 VIP 高可用,Watchdog 提供节点存活及脑裂防护机制。 六者协同组成一个企业级高可用数据库集群
关闭防火墙 (相对简单,但是不安全)
放行对应的端口(安全)
sudo apt install curl ca-certificates
sudo install -d /usr/share/postgresql-common/pgdg
sudo curl -o /usr/share/postgresql-common/pgdg/apt.postgresql.org.asc --fail https://www.postgresql.org/media/keys/ACCC4CF8.asc
. /etc/os-release
sudo sh -c "echo 'deb [signed-by=/usr/share/postgresql-common/pgdg/apt.postgresql.org.asc] https://apt.postgresql.org/pub/repos/apt $VERSION_CODENAME-pgdg main' > /etc/apt/sources.list.d/pgdg.list" sudo apt update
sudo apt -y install postgresql
mkdir -p /data/postgresql/pgdata/
mkdir -p /data/postgresql/pg_archive/
chown -R postgres:postgres /data/postgresql/
mkdir -p /home/postgres/
chown -R postgres:postgres /home/postgres/
vim /etc/passwd
#修改postgres 家目录为/home/postgres postgres:x:114:113:PostgreSQL administrator,,,:/home/postgres:/bin/bash vim /home/postgres/.bashrc
[ -f /etc/profile ] && source /etc/profile
export PATH=/usr/lib/postgresql/16/bin:$PATH # If you want to customize your settings, # Use the file below. This is not overridden # by the RPMS.
[ -f /var/lib/pgsql/.pgsql_profile ] && source /var/lib/pgsql/.pgsql_profile
vim /etc/sudoers
#行末新增
postgres ALL=(ALL) NOPASSWD: ALL wget https://github.com/etcd-io/etcd/releases/download/v3.6.4/etcd-v3.6.4-linux-amd64.tar.gz
tar -xf etcd-v3.6.4-linux-amd64.tar.gz --strip-components=1 -C /usr/local/bin etcd-v3.6.4-linux-amd64/etcd etcd-v3.6.4-linux-amd64/etcdctl
mkdir -p /etc/etcd/
mkdir -p /data/etcd/
touch /etc/etcd/etcd-pg.config.yml
#节点1配置文件
vim /etc/etcd/etcd-pg.config.yml
#节点名
name: pg-etcd01
#数据目录
data-dir: /data/etcd
snapshot-count: 5000
#选举和心跳参数
heartbeat-interval: 100
election-timeout: 1000
#存储新能优化
quota-backend-bytes: 8589934592
max-request-bytes: 10485760
max-concurrent-requests: 5000
#自动压缩与碎片整理
auto-compaction-mode: periodic
auto-compaction-retention: "2h"
#集群通信配置
listen-peer-urls: "http://192.168.28.11:12380"
listen-client-urls: "http://192.168.28.11:12379,http://127.0.0.1:12379"
max-snapshots: 3
max-wals: 5
cors:
initial-advertise-peer-urls: "http://192.168.28.11:12380"
advertise-client-urls: "http://192.168.28.11:12379"
discovery:
discovery-fallback: 'proxy'
discovery-proxy:
discovery-srv:
initial-cluster: "pg-etcd01=http://k8s-etcd01:12380,pg-etcd02=http://k8s-etcd02:12380,pg-etcd03=http://k8s-etcd03:12380"
initial-cluster-token: 'etcd-cluster-pg'
initial-cluster-state: 'new'
strict-reconfig-check: false
enable-v2: true
enable-pprof: true
proxy: 'off'
proxy-failure-wait: 5000
proxy-refresh-interval: 30000
proxy-dial-timeout: 1000
proxy-write-timeout: 5000
proxy-read-timeout: 0
#节点2配置文件
name: pg-etcd02
data-dir: /data/etcd
snapshot-count: 5000
#选举和心跳参数
heartbeat-interval: 100
election-timeout: 1000
#存储新能优化
quota-backend-bytes: 8589934592
max-request-bytes: 10485760
max-concurrent-requests: 5000
#自动压缩与碎片整理
auto-compaction-mode: periodic
auto-compaction-retention: "2h"
#集群通信配置
listen-peer-urls: "http://192.168.28.12:12380"
listen-client-urls: "http://192.168.28.12:12379,http://127.0.0.1:12379"
max-snapshots: 3
max-wals: 5
cors:
initial-advertise-peer-urls: "http://192.168.28.12:12380"
advertise-client-urls: "http://192.168.28.12:12379"
discovery:
discovery-fallback: 'proxy'
discovery-proxy:
discovery-srv:
initial-cluster: "pg-etcd01=http://k8s-etcd01:12380,pg-etcd02=http://k8s-etcd02:12380,pg-etcd03=http://k8s-etcd03:12380"
initial-cluster-token: 'etcd-cluster-pg'
initial-cluster-state: 'new'
strict-reconfig-check: false
enable-v2: true
enable-pprof: true
proxy: 'off'
proxy-failure-wait: 5000
proxy-refresh-interval: 30000
proxy-dial-timeout: 1000
proxy-write-timeout: 5000
proxy-read-timeout: 0
#节点3配置文件
name: pg-etcd03
data-dir: /data/etcd
snapshot-count: 5000
#选举和心跳参数
heartbeat-interval: 100
election-timeout: 1000
#存储新能优化
quota-backend-bytes: 8589934592
max-request-bytes: 10485760
max-concurrent-requests: 5000
#自动压缩与碎片整理
auto-compaction-mode: periodic
auto-compaction-retention: "2h"
#集群通信配置
listen-peer-urls: "http://192.168.28.13:12380"
listen-client-urls: "http://192.168.28.13:12379,http://127.0.0.1:12379"
max-snapshots: 3
max-wals: 5
cors:
initial-advertise-peer-urls: "http://192.168.28.13:12380"
advertise-client-urls: "http://192.168.28.13:12379"
discovery:
discovery-fallback: 'proxy'
discovery-proxy:
discovery-srv:
initial-cluster: "pg-etcd01=http://k8s-etcd01:12380,pg-etcd02=http://k8s-etcd02:12380,pg-etcd03=http://k8s-etcd03:12380"
initial-cluster-token: 'etcd-cluster-pg'
initial-cluster-state: 'new'
strict-reconfig-check: false
enable-v2: true
enable-pprof: true
proxy: 'off'
proxy-failure-wait: 5000
proxy-refresh-interval: 30000
proxy-dial-timeout: 1000
proxy-write-timeout: 5000
proxy-read-timeout: 0
vim /etc/systemd/system/etcd-pg.service
[Unit]
Description=Etcd Server
After=network.target
After=network-online.target
Wants=network-online.target
[Service]
Type=notify
ExecStart=/usr/local/bin/etcd --config-file=/etc/etcd/etcd-pg.config.yml
Restart=on-failure
RestartSec=5
LimitNOFILE=65536
[Install]
WantedBy=multi-user.target
启动 etcd-pg 服务
systemctl daemon-reload
systemctl start etcd-pg.service
systemctl enable etcd-pg.service
root@k8s-master01:~# etcdctl --endpoints="k8s-etcd01:12379,k8s-etcd02:12379,k8s-etcd03:12379" member list -w=table
+------------------+---------+-----------+-------------------------+----------------------------+------------+
| ID | STATUS | NAME | PEER ADDRS | CLIENT ADDRS | IS LEARNER |
+------------------+---------+-----------+-------------------------+----------------------------+------------+
| 2bb79737c88dd84d | started | pg-etcd03 | http://k8s-etcd03:12380 | http://192.168.28.13:12379 | false |
| 354b7a6aa8551f4a | started | pg-etcd02 | http://k8s-etcd02:12380 | http://192.168.28.12:12379 | false |
| 84101e54de967367 | started | pg-etcd01 | http://k8s-etcd01:12380 | http://192.168.28.11:12379为了简化命令,可以通过 alisa 配置
cd ~
vim .profile
alias etcdctlpg="etcdctl --endpoints="k8s-etcd01:12379,k8s-etcd02:12379,k8s-etcd03:12379" " source .profile
root@k8s-master01:~# etcdctlpg member list -w=table
+------------------+---------+-----------+-------------------------+----------------------------+------------+
| ID | STATUS | NAME | PEER ADDRS | CLIENT ADDRS | IS LEARNER |
+------------------+---------+-----------+-------------------------+----------------------------+------------+
| 2bb79737c88dd84d | started | pg-etcd03 | http://k8s-etcd03:12380 | http://192.168.28.13:12379 | false |
| 354b7a6aa8551f4a | started | pg-etcd02 | http://k8s-etcd02:12380 | http://192.168.28.12:12379 | false |
| 84101e54de967367 | started | pg-etcd01 | http://k8s-etcd01:12380 | http://192.168.28.11:12379 | false |
watchdog 防止脑裂。Patroni 支持通过 Linux 的 watchdog 监视 patroni 进程的运行,当 patroni 进程无法正常往 watchdog 设备写入心跳时,由 watchdog 触发 Linux 重启。
# 安装软件,linux内置功能 sudo apt install -y watchdog
# 初始化watchdog字符设备 sudo modprobe softdog
# 修改/dev/watchdog设备权限 sudo chmod 666 /dev/watchdog
sudo chown postgres:postgres /dev/watchdog
# 启动watchdog服务 sudo systemctl start watchdog
sudo systemctl enable watchdog
1. pip3 install --break-system-packages psycopg2-binary
2. pip3 install --break-system-packages patroni[etcd]
3. pip3 install --break-system-packages python-json-logger
4. mkdir -p /etc/patroni
cat /etc/systemd/system/patroni-5433.service
[Unit]
Description=Patroni high-availability PostgreSQL
After=syslog.target network.target etcd.service
Requires=etcd-pg.service
[Service]
Type=simple
User=postgres
Group=postgres
# 使用watchdog进行服务监控 ExecStartPre=-/usr/bin/sudo /sbin/modprobe softdog ExecStartPre=-/usr/bin/sudo /bin/chown postgres /dev/watchdog
PermissionsStartOnly=true
WorkingDirectory=/home/postgres/
ExecStart=/usr/local/bin/patroni /etc/patroni/patroni-5433.yaml
ExecReload=/bin/kill -HUP
KillMode=process
Restart=always
RestartSec=10
LimitNOFILE=65536
[Install]
WantedBy=multi-user.target
systemctl daemon-reload
su postgres
cd ~
#备库从主库同步WAL日志使用,主备倒换后,主库降备库,新备库使用,所以备库也配置
touch .pgpass
vim .pgpass
192.168.28.11:5433:*:replica:replica 192.168.28.12:5433:*:replica:replica 192.168.28.13:5433:*:replica:replica sudo mkdir -p /var/log/patroni/
sudo chown -R postgres:postgres /var/log/patroni/
根据节点依次启动 Patroni
sudo systemctl daemon-reload
sudo systemctl restart patroni-5433.service
sudo systemctl enable patroni-5433.service
sudo systemctl status patroni-5433.service
查看服务状态,默认情况下,根据配置文件中,initdb 内容,Patroni 会自动对数据库进行初始化操作,并创建用户,配置文件,拉起数据库并建立主从关系及流复制
root@k8s-master01:~# patronictl -c /etc/patroni/patroni-5433.yaml list
+ Cluster: pg_patroni_etcd () ---+-----------+----+-----------+ | Member | Host | Role | State | TL | Lag in MB | + | pg_patroni_5433_01 | 192.168.28.11:5433 | Leader | running | 17 | | | pg_patroni_5433_02 | 192.168.28.12:5433 | Replica | streaming | 17 | 0 | | pg_patroni_5433_03 | 192.168.28.13:5433 | Replica | streaming | 17 | 0 | + 通过 alisa 设置简易命令
alias patr5433="patronictl -c /etc/patroni/patroni-5433.yaml" patronictl -c /etc/patroni/patroni-5433.yaml list
reinit 先是移除了整个 data 目录。然后选择正确的节点进行备份恢复。
patronictl -c /etc/patroni/patroni-5433.yaml reinit [nodename]
patronictl -c /etc/patroni/patroni-5433.yaml show-config
patronictl -c /etc/patroni/patroni-5433.yaml edit-config
#重载参数
patronictl -c /etc/patroni/patroni-5433.yaml reload [nodename]
patronictl -c /etc/patroni/patroni-5433.yaml restart [clustername] [nodename] patronictl -c /etc/patroni/patroni-5433.yaml restart [clustername] --pending patronictl -c /etc/patroni/patroni-5433.yaml restart [clustername]
patronictl pause 暂时将 Patroni 集群置于维护模式并禁用自动
在某些情况下,Patroni 需要暂时退出集群管理,同时仍然在 DCS 中保留集群状态。可能的用例是集群上不常见的活动,例如主要版本升级或损坏恢复。在这些活动期间,节点经常因为 Patroni 不知道的原因而启动和停止,有些节点甚至可以暂时提升,这违反了只运行一个主节点的假设。因此,Patroni 需要能够与正在运行的集群 “分离”,在 Pacemaker 中实现与维护模式相当的功能。
patronictl resume 将使 Patroni 集群退出维护模式,并重新启用自动故障转移。
自动拉起所有数据库
# Switchover
root@k8s-master01:~# patr5433 switchover
Current cluster topology
+ Cluster: pg_patroni_etcd (7540584003720074567) ---+-----------+----+-----------+
| Member | Host | Role | State | TL | Lag in MB |
+--------------------+--------------------+---------+-----------+----+-----------+
| pg_patroni_5433_01 | 192.168.28.11:5433 | Leader | running | 22 | |
| pg_patroni_5433_02 | 192.168.28.12:5433 | Replica | streaming | 22 | 0 |
| pg_patroni_5433_03 | 192.168.28.13:5433 | Replica | streaming | 22 | 0 |
+--------------------+--------------------+---------+-----------+----+-----------+
Primary [pg_patroni_5433_01]:
Candidate ['pg_patroni_5433_02', 'pg_patroni_5433_03'] []: pg_patroni_5433_02
When should the switchover take place (e.g. 2025-08-26T12:26 ) [now]: now
Are you sure you want to switchover cluster pg_patroni_etcd, demoting current leader pg_patroni_5433_01? [y/N]: y
2025-08-26 11:26:32.31189 Successfully switched over to "pg_patroni_5433_02"
+ Cluster: pg_patroni_etcd (7540584003720074567) ---+---------+----+-----------+
| Member | Host | Role | State | TL | Lag in MB |
+--------------------+--------------------+---------+---------+----+-----------+
| pg_patroni_5433_01 | 192.168.28.11:5433 | Replica | stopped | | unknown |
| pg_patroni_5433_02 | 192.168.28.12:5433 | Leader | running | 22 | |
| pg_patroni_5433_03 | 192.168.28.13:5433 | Replica | running | 22 | 0 |
+--------------------+--------------------+---------+---------+----+-----------+
root@k8s-master01:~# patr5433 list
+ Cluster: pg_patroni_etcd (7540584003720074567) ---+-----------+----+-----------+
| Member | Host | Role | State | TL | Lag in MB |
+--------------------+--------------------+---------+-----------+----+-----------+
| pg_patroni_5433_01 | 192.168.28.11:5433 | Replica | streaming | 23 | 0 |
| pg_patroni_5433_02 | 192.168.28.12:5433 | Leader | running | 23 | |
| pg_patroni_5433_03 | 192.168.28.13:5433 | Replica | streaming | 23 | 0 |
+--------------------+--------------------+---------+-----------+----+-----------+
数据库从 pg_patroni_5433_01 switchover 到 pg_patroni_5433_02
[root@pgtest1 ~]# curl -s http://192.168.28.11:8008/switchover -XPOST -d '{"leader":"pg_patroni_5433_01","candidate":"pg_patroni_5433_02"}'
Successfully switched over to "pg_patroni_5433_02" patronictl failover
# Failover
[postgres@pgtest1 ~]$ patronictl -c /etc/patroni/patroni-5433.yaml failover
Candidate ['pg_patroni_5433_01', 'pg_patroni_5433_02','pg_patroni_5433_03'] []: pg_patroni_5433_01
Current cluster topology
... ...
Are you sure you want to failover cluster pg_cluster, demoting current master pg_patroni_5433_02? [y/N]: y
2021-10-28 03:47:56.13486 Successfully failed over to "pg_patroni_5433_01"
... ...
root@k8s-master01:~# patronictl -c /etc/patroni/patroni-5433.yaml dsn
host=192.168.28.12 port=5433 sudo apt install haproxy
sudo vim /etc/haproxy/haproxy.cfg
global
maxconn 2000
ulimit-n 16384
log 127.0.0.1 local0 err
stats timeout 30s
defaults
log global
mode http
option httplog
timeout connect 5000
timeout client 50000
timeout server 50000
timeout http-request 15s
timeout http-keep-alive 15s
listen status_page
bind *:8888
stats enable
stats uri /haproxy-status
stats auth admin:admin
stats realm "Welcome to the haproxy load balancer status page of k8s-master"
frontend monitor-in
bind *:33305
mode http
option httplog
monitor-uri /monitor
# 主库读写端口
listen master
bind *:15433
mode tcp
option tcplog
balance roundrobin
option httpchk OPTIONS /master
http-check expect status 200
default-server inter 3s fall 3 rise 2 on-marked-down shutdown-sessions
server pgtest1 192.168.28.11:5433 maxconn 1000 check port 8008 inter 5000 rise 2 fall 2
server pgtest2 192.168.28.12:5433 maxconn 1000 check port 8008 inter 5000 rise 2 fall 2
server pgtest3 192.168.28.13:5433 maxconn 1000 check port 8008 inter 5000 rise 2 fall 2
#从库读端口
listen replicas
bind *:25433
mode tcp
option tcplog
balance roundrobin
option httpchk OPTIONS /replica
http-check expect status 200
default-server inter 3s fall 3 rise 2 on-marked-down shutdown-sessions
server pgtest1 192.168.28.11:5433 maxconn 1000 check port 8008 inter 5000 rise 2 fall 2
server pgtest2 192.168.28.12:5433 maxconn 1000 check port 8008 inter 5000 rise 2 fall 2
server pgtest3 192.168.28.13:5433 maxconn 1000 check port 8008 inter 5000 rise 2 fall 2
sudo systemctl enable haproxy
sudo systemctl start haproxy
登录地址:[[http://192.168.28.11:8888/haproxy-status]] (也可以通过各个节点 IP + 端口登录)
默认用户密码:admin/admin
sudo apt install -y keepalived
vim /etc/keepalived/keepalived.conf
global_defs {
router_id LVS_DEVEL00
script_user root
enable_script_security
}
vrrp_script check_haproxy {
script "/etc/keepalived/check_haproxy.sh" interval 2 weight 5 fall 3 rise 5 timeout 2
}
vrrp_instance VI_1 {
state Master interface ens18 virtual_router_id 80 priority 100 advert_int 1 authentication { auth_type PASS auth_pass 12345 } virtual_ipaddress { 192.168.28.10/24 } track_script { check_haproxy }
}
vim /etc/keepalived/keepalived.conf
global_defs {
router_id LVS_DEVEL01
script_user root
enable_script_security
}
vrrp_script check_haproxy {
script "/etc/keepalived/check_haproxy.sh" interval 2 weight 5 fall 3 rise 5 timeout 2
}
vrrp_instance VI_1 {
state BACKUP interface ens18 virtual_router_id 80 priority 90 advert_int 1 authentication { auth_type PASS auth_pass 12345 } virtual_ipaddress { 192.168.28.10/24
}
track_script {
check_haproxy
}
}
vim /etc/keepalived/keepalived.conf
global_defs {
router_id LVS_DEVEL02
script_user root
enable_script_security
}
vrrp_script check_haproxy {
script "/etc/keepalived/check_haproxy.sh" interval 2 weight 5 fall 3 rise 5 timeout 2
}
vrrp_instance VI_1 {
state BACKUP interface ens18 virtual_router_id 80 priority 80 advert_int 1 authentication { auth_type PASS auth_pass 12345 } virtual_ipaddress { 192.168.24.15/24
}
track_script {
check_haproxy
}
}
vim /etc/keepalived/check_haproxy.sh
#!/bin/bash
count=`ps aux | grep -v grep | grep haproxy | wc -l`
if [ $count -eq 0 ]; then exit 1
else exit 0
fi 赋予执行权限
chmod +x /etc/keepalived/check_haproxy.sh
sudo systemctl start keepalived
sudo systemctl enable keepalived感谢 @elky 大佬开源此项目
大佬沉迷 coding ,更新了也不发贴
我近期也是疯狂的给大佬提需求 (偶尔提交几个 PR
更新说明: 本次更新距离上次版本已有较长时间,带来了多项功能新增和改进