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),在计算机科学中的体系结构里,是指一种特殊的软件,可以在计算机平台 ...
随机推荐
- 原来你是这样的JAVA[05]--String
1.从概念上讲,java字符串就是Unicode字符串. 2.字符串拼接 用指定分隔符拼接字符串数组时,使用StringJoiner或者String.join()更方便: 用StringJoiner拼 ...
- RabbitMQ 如何实现延迟队列?
延迟队列是指当消息被发送以后,并不是立即执行,而是等待特定的时间后,消费者才会执行该消息. 延迟队列的使用场景有以下几种: 未按时支付的订单,30 分钟过期之后取消订单. 给活跃度比较低的用户间隔 N ...
- Vue源码学习(三):<templete>渲染第二步,创建ast语法树
好家伙,书接上回 在上一篇Vue源码学习(二):<templete>渲染第一步,模板解析中,我们完成了模板解析 现在我们继续,将模板解析的转换为ast语法树 1.前情提要 代码已开 ...
- 618京东到家APP-门详页反爬实战
一.背景与系统安全需求分析 1. 系统的重要性 上图所示是接口所属位置.对电商平台或在线商店而言,分类查商品都是很重要的,通过为用户提供清晰的商品分类,帮助他们快速找到所需产品,节省浏览时间,提升购物 ...
- 循序渐进介绍基于CommunityToolkit.Mvvm 和HandyControl的WPF应用端开发(5) -- 树列表TreeView的使用
在我们展示一些参考信息的时候,有所会用树形列表来展示结构信息,如对于有父子关系的多层级部门机构,以及一些常用如字典大类节点,也都可以利用树形列表的方式进行展示,本篇随笔介绍基于WPF的方式,使用Tre ...
- Record - Nov. 28st, 2020 - Exam. REC
Prob. 1 Desc. & Link. 暴力为 \(\Theta(NK)\). 正解(也许): 把每一个全为正整数的子段找出来. 然后判断一下中间连接的情况即可. 但是这样决策情况太多了. ...
- CAS中ABA问题的解决
转自(here) CAS问题的产生 在运用CAS做Lock-Free操作中有一个经典的ABA问题: 线程1准备用CAS将变量的值由A替换为B,在此之前,线程2将变量的值由A替换为C,又由C替换为A ...
- 教育法学第八章单元测试MOOC
第八章单元测试 返回 本次得分为:100.00/100.00, 本次测试的提交时间为:2020-09-06, 如果你认为本次测试成绩不理想,你可以选择 再做一次 . 1 单选(5分) 社团法人与财团法 ...
- 聊聊Maven的依赖传递、依赖管理、依赖作用域
1. 依赖传递 在Maven中,依赖是会传递的,假如在业务项目中引入了spring-boot-starter-web依赖: <dependency> <groupId>org. ...
- 组合的输出 题解(lgP1157)
一看就是 dfs 然而窝并不会做 调了一个多小时才调出来.漏洞连篇.(第一次写的基本没有对的地方QAQ 题解见注释. #include<bits/stdc++.h> using names ...