Pulsar3.0 升级指北
Pulsar3.0 介绍
Pulsar3.0 是 Pulsar 社区推出的第一个 LTS 长期支持版本。
如图所示,LTS 版本会最长支持到 36 个月,而 Feature 版本最多只有六个月;类似于我们使用的 JDK11,17,21
都是可以长期使用的;所以也推荐大家都升级到 LTS 版本。
作为首个 LTS 版本,3.0 自然也是自带了许多新特性,这个会在后续介绍。
升级指南
先来看看升级指南:
在官方的兼容表中会发现:不推荐跨版本升级。
也就是说如果你现在还在使用的是 2.10.x,那么推荐是先升级到 2.11.x 然后再升级到 3.0.x.
而且根据我们的使用经验来看,首个版本是不保险的,即便是 LTS 版本;
所以不推荐直接升级到 3.0.0,而是更推荐 3.0.1+,这个小版本会修复 3.0 所带来的一些 bug。
先讲一下我们的升级流程,大家可以用做参考。
升级前准备
根据我们的使用场景,为了以防万一,首先需要将我们的插件依赖升级到对应的版本。
其实简单来说就是更新下依赖,然后再重新打包,在后续的流程进行测试。
预热镜像
之后是预热镜像,我们使用 harbor
搭建了自己的 docker 镜像仓库,这样在升级重启镜像的时候可以更快的从内网拉取镜像。
毕竟一个 pulsar-all 的镜像也不小,尽量的缩短启动时间。
预热的过程也很简单:
docker pull apachepulsar/pulsar-all:3.0.1
docker tag apachepulsar/pulsar-all:3.0.1 harbor-private.xx.com/pulsar/pulsar-all:3.0.1
docker image push harbor-private.xx.com/pulsar/pulsar-all:3.0.1
之后升级的时候就可以使用私服的镜像了。
功能测试
我这边有写了一个 cli
可以帮我快速创建或升级一个集群,然后触发我所编写的功能测试。
./pulsar-upgrade-cli upgrade pulsar-test ./charts/pulsar --version x.x.x -f charts/pulsar/values.yaml -n pulsar-test
这个 cli 很简单,一共就做三件事:
- 使用 helm 接口升级集群
- 等待所有的 Pod 都升级成功
- 触发功能测试
之后的效果如下:
主要就是覆盖了我们的使用场景,都跑通过之后才会走后续的流程。
运行监控
之后会启动一个 200 左右的并发生产和消费数据,模拟线上的使用情况,会一直让这个任务跑着,大概一晚上就可以了,第二天通过监控查看:
- 应用有无异常日志
- 流量是否正常
- 各个组件的内存占用
- 写入延迟等信息
升级步骤
组件的升级步骤这里参考了官方指南:
https://pulsar.apache.org/docs/3.1.x/administration-upgrade/#upgrade-zookeeper-optional
- 升级ZK
- 关闭auto recovery
- 升级Bookkeeper
- 升级Broker
- 升级Proxy
- 开启auto recovery
只要一步步按照这个流程走,问题不大,哪一步出现问题后需要及时回滚,回滚流程参考下面的回滚部分。
同时在升级过程中需要一直查看 broker 的 error 日志,如果有明显的不符合预期的日志一定要注意。
在升级 bookkeeper 的时候,broker 可能会出现 bk 连接失败的异常,这个可以不用在意。
线上验证
都升级完后就是线上业务验证环节了:
- 查看监控面板,是否有明显的流量、内存、延迟的异常指标。 2023-12-24
- topic 元数据完整性验证:这个是因为我们这次升级出了一个 topic 被删除的 bug,所以需要重点验证下;这部分会在下次详细分析。 2023-12-24
- 查看业务消息收发有无异常 2023-12-24
- 链路查询是否正常,我们有一个消息链路查询的页面,主要是使用
Pulsar-SQL
和broker-interceptor
实现的。 2023-12-24
异常回滚
当出现异常的时候需要立即回滚,这里的异常一般就是消息收发异常,客户端掉线等。
经过我的测试 3.0.x 的存储和之前的版本是兼容的,所以 bookkeeper
都能降级其他的组件就没啥可担心的了。
需要降级时直接将所有组件降级为上一个版本即可。
灾难恢复
因为是从 2.x 升级到 3.x 也是涉及到了跨大版本,所以也准备了灾难恢复的方案。
比如极端情况下升级失败,所有数据丢失的情况。
整个灾难恢复的主要目的就是恢复后的集群对外提供的域名不发生变化,同时所有的客户端可以自动重连上来,也就是最坏的情况下所有的数据丢了可以接受,但不能影响业务正常使用。
所以我们的流程如下:
备份 topic
@SneakyThrows
@Test
void backup(){
List<String> topicList = pulsarAdmin.topics().getPartitionedTopicList("tenant/namespace");
log.info("topic size={}",topicList.size());
// create a custom thread pool
CopyOnWriteArrayList<TopicMeta> dataList = new CopyOnWriteArrayList<>();
ExecutorService customThreadPool = Executors.newFixedThreadPool(10);
for (String topicName : topicList) {
customThreadPool.execute(()-> {
PartitionedTopicMetadata metadata;
try {
metadata = pulsarAdmin.topics().getPartitionedTopicMetadata(topicName);
TopicMeta topicMeta = new TopicMeta();
// backup topic
topicMeta.setName(topicName);
topicMeta.setPartition(metadata.partitions);
// backup permission
Map<String, Set<AuthAction>> permissions = pulsarAdmin.topics().getPermissions(topicName);
topicMeta.setPermissions(permissions);
// back sub
List<String> subscriptions = new ArrayList<>();
PartitionedTopicStats topicStats = pulsarAdmin.topics().getPartitionedStats(topicName, true);
topicStats.getSubscriptions().forEach((k,v)-> subscriptions.add(k));
topicMeta.setSubscriptions(subscriptions);
dataList.add(topicMeta);
} catch (PulsarAdminException e) {
throw new RuntimeException(e);
} }); }
customThreadPool.shutdown();
while (!customThreadPool.isTerminated()) {
}
log.info("{}",dataList.size());
log.info("{}",JSONUtil.toJsonStr(dataList));
}
// TopicMetaData
@Data
public class TopicMeta {
private String name;
private int partition;
Map<String, Set<AuthAction>> permissions;
List<String> subscriptions = new ArrayList<>();
}
第一步是备份 topic:
- topic 主要是名称和分区数量
- 备份权限
- 备份 topic 的订阅者
公私钥备份
因为我们客户端使用了 JWT 验证,所有为了使得恢复的 Pulsar 集群可以让客户端无缝切换到新集群,因此必须得使用相同的公私钥。
这个其实比较简单,我们使用的是 helm 安装的集群,所以只需要备份好 Secret
即可。
apiVersion: v1
data:
PRIVATEKEY: XXX
PUBLICKEY: XXX
kind: Secret
metadata:
name: pulsar-token-asymmetric-key
namespace: pulsar
type: Opaque
# 还有几个 superUser 的 Secret
数据恢复
创建新集群
首先使用 helm 重新创建一个新集群:
./scripts/pulsar/prepare_helm_release.sh -n pulsar -k pulsar
helm install \ --values charts/pulsar/values.yaml \ --set namespace=pulsar\
--set initialize=true \
pulsar ./charts/pulsar -n pulsar
恢复公私钥
直接使用刚才备份的公私钥覆盖到新集群即可。
恢复namespace
进入 toolset pod 创建需要使用的 tenant/namespace
k exec -it pulsar-toolset-0 -n pulsar bash
bin/pulsar-admin tenants create tenant
bin/pulsar-admin namespaces create tenant/namespace
元数据恢复
之后便是最重要的元数据恢复了:
@SneakyThrows
@Test
void restore() {
PulsarAdmin pulsarAdmin = PulsarAdmin.builder().serviceHttpUrl("http://url:8080")
.authentication(AuthenticationFactory.token(token))
.build();
Path filePath = Path.of("restore-ns.json");
String fileContent = Files.readString(filePath);
List<TopicMeta> topicMetaList = JSON.parseArray(fileContent, TopicMeta.class);
ExecutorService customThreadPool = Executors.newFixedThreadPool(50);
for (TopicMeta topicMeta : topicMetaList) {
customThreadPool.execute(() -> {
// Create topic
try {
pulsarAdmin.topics().createPartitionedTopic(topicMeta.getName(), topicMeta.getPartition());
} catch (PulsarAdminException e) {
log.error("Create topic error");
}
// Create sub
for (String subscription : topicMeta.getSubscriptions()) {
try {
pulsarAdmin.topics().createSubscription(topicMeta.getName(), subscription, MessageId.latest);
} catch (PulsarAdminException e) {
log.error("createSubscription error");
} }
// Grant permission
topicMeta.getPermissions().forEach((role, authActions) -> {
permission(pulsarAdmin, topicMeta.getName(), role, authActions);
});
log.info("topic:{} restore success", topicMeta.getName());
}); }
customThreadPool.shutdown();
while (!customThreadPool.isTerminated()) {
} log.info("restore success");
}
private synchronized void permission(PulsarAdmin pulsarAdmin, String topic, String role, Set<AuthAction> authActions) {
try {
pulsarAdmin.topics().grantPermission(topic, role, authActions);
} catch (PulsarAdminException e) {
log.error("grantPermission error", e);
}
}
流程和备份类似:
- 创建分区 topic
- 创建订阅者
- 授权角色信息
因为授权接口限制了并发调用,所有需要加锁,导致整个恢复的流程就会比较慢。
8000 topic 的 namespace 大概恢复时间为 40min 左右。
之后依次恢复其他 namespace 即可。
恢复 police
admin.namespaces().setNamespaceMessageTTL("tenant/namespace", 3600 * 6);
admin.namespaces().setBacklogQuota("tenant/namespace", BacklogQuota)
如果之前的集群有设置 TTL 或者是 backlogQuota 时都需要手动恢复。
总结
以上就是整个升级和灾难恢复的流程,当然灾难恢复希望大家不要碰到。
我会在下一篇详细介绍 Pulsar 3.0
的新功能以及所碰到的一些坑。
Pulsar3.0 升级指北的更多相关文章
- java 8 - java 17 升级指北
2014年发布的java SE 8和2017年发布的java EE 8,至今还是使用最广泛的java版本,大部分java开发者对于java 8之后的升级总是敬而远之,这跟java 9以后的破坏性升级和 ...
- [转] iOS开发者的Weex伪最佳实践指北
[From] http://www.cocoachina.com/ios/20170601/19404.html 引子 这篇文章是笔者近期关于Weex在iOS端的一些研究和实践心得,和大家一起分享分享 ...
- Python 简单入门指北(二)
Python 简单入门指北(二) 2 函数 2.1 函数是一等公民 一等公民指的是 Python 的函数能够动态创建,能赋值给别的变量,能作为参传给函数,也能作为函数的返回值.总而言之,函数和普通变量 ...
- Python 简单入门指北(一)
Python 简单入门指北(一) Python 是一门非常容易上手的语言,通过查阅资料和教程,也许一晚上就能写出一个简单的爬虫.但 Python 也是一门很难精通的语言,因为简洁的语法背后隐藏了许多黑 ...
- 可能比文档还详细--VueRouter完全指北
可能比文档还详细--VueRouter完全指北 前言 关于标题,应该算不上是标题党,因为内容真的很多很长很全面.主要是在官网的基础上又详细总结,举例了很多东西.确保所有新人都能理解!所以实际上很多东西 ...
- Celery入门指北
Celery入门指北 其实本文就是我看完Celery的官方文档指南的读书笔记.然后由于我的懒,只看完了那些入门指南,原文地址:First Steps with Celery,Next Steps,Us ...
- 后端API入门到放弃指北
后端API入门学习指北 了解一下一下概念. RESTful API标准] 所有的API都遵循[RESTful API标准]. 建议大家都简单了解一下HTTP协议和RESTful API相关资料. 阮一 ...
- ThinkPHP 3.2.x 集成极光推送指北
3.2版本已经过了维护生命周期,官方已经不再维护,请及时更新至5.0版本 -- ThinkPHP 官方仓库 以上,如果有条件,请关闭这个页面,然后升级至 ThinkPHP 5,如果由于各种各样的原因无 ...
- c#封装DBHelper类 c# 图片加水印 (摘)C#生成随机数的三种方法 使用LINQ、Lambda 表达式 、委托快速比较两个集合,找出需要新增、修改、删除的对象 c# 制作正方形图片 JavaScript 事件循环及异步原理(完全指北)
c#封装DBHelper类 public enum EffentNextType { /// <summary> /// 对其他语句无任何影响 /// </summary> ...
- VMware Workstation 安装以及Linux虚拟机安装 指北
最近有挺多小伙伴跟我说起虚拟机这个东西,所以,今天就给大家写一篇虚拟机安装使用指北吧. 虚拟机(英语:virtual machine),在计算机科学中的体系结构里,是指一种特殊的软件,可以在计算机平台 ...
随机推荐
- Web服务器部署上线的踩坑流程回顾与知新
5月份时曾部署上线了C++的Web服务器,温故而知新,本篇文章梳理总结一下部署流程知识: 最初的解决方案:https://blog.csdn.net/BinBinCome/article/detail ...
- 「Semigroup と Monoid と Functional と」
一个被国内 oi 环境弱化至几乎不存在的概念,不过我觉得还是有学一学的必要.因为我没学过代数结构所以大部分内容都在开黄腔,欲喷从轻. Semigroup 的定义是,\(\forall a,b\in\m ...
- 新零售SaaS架构:面向中小连锁的SaaS系统整体规划
零售企业的发展路径 零售企业的发展路径一般可分为以下几个阶段: 单店经营阶段:企业在一个地区或城市开设单个门店.这时,企业需要把精力放在了解当地市场和顾客需求上,这是积累经验和品牌知名度的重要环节.为 ...
- 用策略模式干掉代码里大量的if-eles或则Swatch,提升B格由面向过程转为面向对象
现象 大量的分支选择型代码段看着让人头疼 for (Field field : declaredFields) { Class<?> type = field.getType(); Str ...
- ElasticSearch系列——查询、Python使用、Django/Flask集成、集群搭建,数据分片、位置坐标实现附近的人搜索
@ 目录 Elasticsearch之-查询 一 基本查询 1.1 match查询 1.2 term查询 1.3 terms查询 1.4 控制查询的返回数量(分页) 1.5 match_all 查询 ...
- 【短道速滑十】非局部均值滤波的指令集优化和加速(针对5*5的搜索特例,可达到单核1080P灰度图 28ms/帧的速度)。
非局部均值滤波(Non Local Means)作为三大最常提起来的去燥和滤波算法之一(双边滤波.非局部均值.BM3D),也是有着很多的论文作为研究和比较的对象,但是也是有着致命的缺点,速度慢,严重的 ...
- Kubernetes:kube-apiserver 之 scheme(一)
0. 前言 在进入 kube-apiserver 源码分析前,有一个非常重要的概念需要了解甚至熟悉的:资源注册表(scheme). Kubernetes 中一切皆资源,管理的是资源,创建.更新.删除的 ...
- linux其他命令(查找,软链接,打包和压缩,软件安装)笔记
1,查找文件 * 是通配符,代表任意字符,0到多个. find 路径 -name "*.txt" : 查找在路径下所有以 .txt 结尾的文件. 2,软链接 (1)将桌面目 ...
- Meissel–Lehmer 算法
前言 推荐先行阅读我的blog文章----Min_25 筛 什么是Meissel–Lehmer 算法 Meissel-Lehmer 算法是一种基于 \(ϕ\) 函数的的快速计算前缀质数个数(当然也可以 ...
- AtCoder Beginner Contest 240 F - Sum Sum Max
原题链接F - Sum Sum Max 首先令\(z_i = \sum\limits_{k = 1}^i y_k\),\(z_0 = 0\),\(z_i\)就是第\(i\)段相同的个数的前缀和. 对于 ...