首页
提效神器
常用运维脚本汇总
电子书阅读
推荐
电子书阅读
事物管理
Search
1
安装docker时报错container-selinux >= 2:2.74
207 阅读
2
rsync命令介绍(可替代rm删除巨量文件)
168 阅读
3
kubernetes集群各组件安装过程汇总
163 阅读
4
docker 镜像加速器配置,daemon.json文件详解
148 阅读
5
docker search命令提示i/o timeout的解决方案
106 阅读
运维
自动化运维
数据库
容器与k8s
环境
云计算
脚本
ai
登录
/
注册
Search
标签搜索
命令
nginx
zabbix
Mingrui
累计撰写
113
篇文章
累计收到
8
条评论
首页
栏目
运维
自动化运维
数据库
容器与k8s
环境
云计算
脚本
ai
页面
提效神器
常用运维脚本汇总
电子书阅读
推荐
电子书阅读
事物管理
搜索到
15
篇与
的结果
2025-12-09
批量服务器管理指南
管理好几十上百台服务器,核心思路是把 非标准化的烂摊子变成流水线作业。 凡是需要操作超过两次的,写成脚本。凡是需要在两台机器以上执行的,用 Ansible。凡是需要人肉盯着看的,交给 Prometheus。摸底与规范化处理刚接手大批量的机器时,最可怕的是乱。系统版本不一致,主机名未设置或与实际运行的服务不一致,等等。因此,为了方便维护大批量的服务器,第一步就是要规范主机名。规范主机名按照 地区-环境-业务-角色-序号 的方式来给每台服务器修改HostName。通过Shell脚本,配合IP和主机名对应表,循环跑一遍hostnamectl set-hostname命令。示例:bj-prod-shop-nginx-01bj:北京节点prod:生产环境shop:电商商城业务nginx:服务角色01:第一台统一系统版本要想批量维护服务器时不出错,操作系统版本必须锁死。别一会儿 CentOS 7.6,一会儿 7.9,一会儿又冒出个 Ubuntu。内核版本不同,有些内核参数的表现是不一样的。新机器到手,先跑一遍初始化脚本。主要包括以下内容:更换 YUM/APT 源: 换成阿里云或清华源,内网有条件的自建 Repo 更好,速度就是生命。安装基础工具包: vim, lrzsz, wget, curl, net-tools, sysstat (iostat, mpstat, sar 全靠它),tcpdump。哪怕现在用不上,装上总没错,省得排错时抓瞎。时间同步(Chrony) :把 NTP 换成 Chrony 吧,同步速度快,精度高。配置好内网的 NTP server,别让 100 台机器都去公网对时,防火墙要是严一点就瞎了。文件描述符限制: echo "* - nofile 65535" >> /etc/security/limits.conf。别等业务跑起来报 "Too many open files" 再去改,那时候通常得重启进程使用Ansible自动化执行命令大批量管理主机时,使用Ansible是最高效的选择。遇到在执行命令的时候遇到网络波动某些机器的某些命令没有执行,可以重复执行Ansilble脚本,因为它是幂等的。跑一次和跑十次,结果都是一样的,不会因为重复执行而出错。SSH优化Ansible 既然走 SSH,那 SSH 的连接速度就决定了你的执行效率。100 台机器,每台慢 1 秒,就是慢 100 秒。关闭 DNS 解析:在 /etc/ssh/sshd_config 里设置 UseDNS no。否则每次连上去它都要反查你的 IP,慢得要死。复用连接(ControlPersist):在你的管理机(Ansible控制端)的 ~/.ssh/config 或者 ansible.cfg 里配置开启 ControlMaster 和 ControlPersist。建立一次连接后,socket 文件保留一段时间,后续的命令直接复用通道,速度起飞。Ansible调优默认 Ansible 的并发数(forks)是 5。意思是一次只操作 5 台。遇到几百台机器的时候跑完得猴年马月。在 ansible.cfg 里,把 forks 改成 20 甚至 50。取决于你控制机的 CPU 和带宽。示例: 批量分发配置:修改所有 Nginx 的 nginx.conf。- name: Update Nginx Config hosts: web_group tasks: - name: Push config file copy: src: ./nginx.conf dest: /etc/nginx/nginx.conf backup: yes # 关键!覆盖前先备份,救命用的参数 notify: Reload Nginx # 触发器,只有文件变了才重启 handlers: - name: Reload Nginx service: name: nginx state: reloaded合理配置监控监控不是越多越好,是越准越好(可观测性)。没有监控,运维就是瞎子。但几十上百台机器,如果监控策略没搞好,会触发洪水泛滥一般的“告警风暴”。Prometheus + Grafana 是标配放弃 Zabbix 吧(虽然它是经典),Prometheus 在自动发现和容器化支持上更现代化。每台机器装个 node_exporter,这就把 CPU、内存、磁盘 IO、网络流量全收上来了。关于 Load Average 的误区很多新手喜欢监控 CPU 使用率,设定超过 80% 就报警。其实在 Linux 下,Load Average(负载) 往往比 CPU 使用率更能反映问题。CPU 高可能是单纯计算密集型任务,机器还能响应。但如果 Load 高(超过 CPU 核数),说明有进程在排队等待 CPU 或者等待磁盘 IO(D状态进程)。建议的报警策略:Load Average > CPU 核数 * 1.5(持续 5 分钟):严重报警。磁盘剩余空间 < 15%:预警(给人处理的时间)。磁盘 Inodes 使用率:别忘了这个!有时候磁盘没满,但小文件太多把 Inode 耗尽了,一样写不进数据。告警收敛这是个大坑。如果交换机抖了一下,大量机器同时报“网络不可达”,你的手机短信能瞬间炸了。因此需要配置 Alertmanager 的 group_wait 和 group_interval,把同一时间段、同一类别的报警合并成一条发出来。比如:“[严重] 100台机器 SSH 连接超时”,而不是 100 条短信。日志集中管理当日志存储在本地的时候,如果机器少,出问题了 ssh 上去 tail -f /var/log/messages还可以接受。但现在是个大的集群,里面可能有几十上百台机器。如果用户反馈“访问报错”,请求是随机分发到某台机器的,这时该怎么找?难道开 100 个终端窗口去 grep?Loki+Promtail+Grafana传统的 ELK (Elasticsearch, Logstash, Kibana) 确实强大,但是吃内存大户。Elasticsearch 维护起来也得要点水平。如果资源有限,推荐 Loki + Promtail + Grafana (PLG)方案。Promtail:部署在每台服务器上,极轻量,只负责采集日志文件,打上标签(Label),推送到 Loki。Loki:日志存储。它不像 ES 那样做全文索引(费内存),它只索引标签。查日志的时候类似 grep,但是是分布式的 grep。Grafana:展示界面。这样,开发跑过来问:“帮我查下这个订单号为什么失败”,你直接在 Grafana 里输入 {app="shop"} |= "ORDER123456",一秒钟出结果。安全防护Jumpserver 堡垒机千万别把服务器的真实 IP 和 root 密码直接给开发人员,甚至运维内部也别互相传私钥。搭建一个开源的 Jumpserver。统一入口:所有人都得先登堡垒机,再跳转。权限回收:某人离职了,你只需要在堡垒机上禁用他的账号,而不用去 100 台机器上删他的公钥。录像审计:这是甩锅神器。万一数据库被删了,回放录像,谁敲的 rm -rf,几点几分敲的,一清二楚。Sudo 权限控制别给所有人 root。用 Ansible 批量分发 /etc/sudoers 配置。利用 Linux 的 Group 功能,比如 dev 组只能 sudo systemctl restart nginx,而不能 sudo su -。精确控制权限范围。
2025年12月09日
10 阅读
0 评论
0 点赞
2025-12-08
使用nginx进行灰度发布的几种方式介绍
通常一个新功能开发完,测试环境可能跑得好好的,但生产环境因为数据量、并发量、网络环境完全不一样,可能会产生各种意料之外的错误。等发现问题的时候,可能已经造成了不小的影响。因此,新功能的发布推荐使用灰度发布的方式,先给少量用户试用新版本,确认无问题后再逐渐放量到全部用户。先给少量(如5%)的用户试用新版本,观察一段时间如果没问题,再逐步放量到20%、50%、100%一旦发现问题,立刻切回旧版本整个过程用户基本无感知值得注意的是,进行灰度发布时,监控和告警特别重要 。推荐做法:在Nginx日志里加上版本标记,然后用ELK收集日志,实时对比新旧版本的各项指标。这样在Kibana里就能看到每个版本的请求量、错误率、响应时间等指标,一目了然。此外还应配置告警规则,如果新版本的错误率比旧版本高出10%,或者响应时间慢了50%,就会自动发送告警,甚至可以自动回滚。log_format canary '$remote_addr - $remote_user [$time_local]' '"$request" $status $body_bytes_sent ' '"$http_referer" "$http_user_agent" ' 'backend=$backend rt=$request_time'; access_log /var/log/nginx/access.log canary;优化建议灰度策略要灵活 不要一上来就5%、10%、50%、100%这样机械地放量。要根据实际情况灵活调整。比如一个小功能,可能5%观察半小时没问题,就直接100%了。但如果是核心功能的大改动,可能要5%观察一天,10%观察一天,慢慢来。最好是先在内部员工里测试,没问题后再给1%的真实用户,然后5%、10%、30%、50%、100%,每个阶段都要观察一段时间。做好回滚预案 灰度发布虽然降低了风险,但不代表没有风险。一定要做好回滚预案。推荐做法是,每次发布前都要演练一遍回滚流程,确保出问题的时候能在5分钟内回滚。而且回滚不能只是把流量切回去,还要考虑数据一致性、缓存清理等问题。用户体验要考虑 虽然灰度发布对用户来说应该是无感知的,但有些细节还是要注意。比如不要在用户操作的过程中切换版本,这样可能导致数据丢失或者页面错乱。我们的做法是,用Cookie做用户粘性,保证同一个用户在一段时间内(比如24小时)始终访问同一个版本。还有就是,如果新旧版本的UI差异比较大,最好在客户端做个平滑过渡,不要让用户觉得突兀。{lamp/}使用nginx可以通过多种 不同的方式来进行灰度发布,分别介绍如下:基于权重的流量分配这是最简单的一种方式,原理就是通过upstream的权重参数,把流量按比例分配到不同版本的服务器上。下面这个配置的意思是,100个请求里面,95个会打到旧版本服务器,5个会打到新版本。不过这种方式有个问题,就是同一个用户的请求可能一会儿打到旧版本,一会儿打到新版本,体验不太好。因此最好设置一个ip_hash。{callout color="#f0ad4e"}一、ip_hash 的作用ip_hash 是 Nginx 负载均衡的一种策略,主要提供会话保持(Session Persistence)功能:会话粘性:确保来自同一客户端 IP 的请求总是被转发到同一台后端服务器解决状态问题:当后端应用服务器没有共享会话状态时,避免用户会话丢失提升缓存效率:同一客户端的请求路由到同一服务器,可提高本地缓存命中率简化架构:避免部署复杂的分布式会话存储系统{/callout}upstream backend { ip_hash; server 192.168.1.10:8080 weight=95; # 旧版本 server 192.168.1.11:8080 weight=5; # 新版本 } server { listen 80; server_name api.example.com; location / { proxy_pass http://backend; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } }基于Cookie的灰度发布一个用户第一次访问的时候,我们给他打个标记,后续的请求都根据这个标记来决定走哪个版本。实现方式:用户第一次访问的时候,随机决定他是不是可以访问新版本,然后种个Cookie。后续请求都会带着这个Cookie,保证同一个用户始终访问同一个版本。但是这个方案还是有点粗糙,因为Nginx原生不支持生成随机数,我们需要借助一些技巧或者第三方模块。upstream backend_v1 { server 192.168.1.10:8080; } upstream backend_v2 { server 192.168.1.11:8080; } server { listen 80; server_name api.example.com; location / { set $backend "backend_v1"; # 如果Cookie中有canary标记,走新版本 if ($http_cookie ~* "canary=true") { set $backend "backend_v2"; } # 随机给5%的新用户打上canary标记 set $random_canary ""; if ($http_cookie !~* "canary") { set $random_canary "${random_canary}A"; } # 生成1-100的随机数 set $rand_num $request_id; if ($random_canary = "A") { # 这里简化处理,实际可以用Lua脚本 add_header Set-Cookie "canary=false; Path=/; Max-Age=86400"; } proxy_pass http://$backend; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } }基于Header的灰度发布可以更精确地控制哪些用户走新版本,比如内部员工、测试账号、特定地区的用户等等。这时候可以用Header来做判断。这种方式特别适合做内部测试。使用方式:在客户端(比如App或者前端页面)加个开关,员工登录后自动在请求头里加上特定标记,这样就能体验新版本了。upstream backend_v1 { server 192.168.1.10:8080; } upstream backend_v2 { server 192.168.1.11:8080; } server { listen 80; server_name api.example.com; location / { set $backend "backend_v1"; # 如果请求头中有特定标记,走新版本 if ($http_x_canary_version = "v2") { set $backend "backend_v2"; } # 内部员工走新版本 if ($http_x_employee_id != "") { set $backend "backend_v2"; } proxy_pass http://$backend; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } }基于IP地址的灰度发布还有一种场景,比如计划先在某个地区试点新功能,或者只给公司内网用户开放新版本。这时候可以用IP地址来做判断。geo模块是一个Nginx内置核心模块,用于根据客户端 IP 地址创建变量,实现基于地理位置或 IP 段的条件处理。它允许服务器对不同来源的请求执行不同的操作,无需额外安装,随 Nginx 一起编译。geo $canary_user { default 0; 10.0.0.0/8 1; # 公司内网 192.168.1.0/24 1; # 特定网段 123.45.67.89 1; # 特定IP } upstream backend_v1 { server 192.168.1.10:8080; } upstream backend_v2 { server 192.168.1.11:8080; } server { listen 80; server_name api.example.com; location / { set $backend "backend_v1"; if ($canary_user = 1) { set $backend "backend_v2"; } proxy_pass http://$backend; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } }灰度发布中的一些常见问题Session一致性问题 如果Session存在服务器本地,用户的请求可能一会儿打到v1,一会儿打到v2,那么就会造成Session的丢失。于是就会造成用户登录状态老是丢失的问题。解决办法有两个:把Session存到Redis这种共享存储里用Cookie或者Header做用户粘性,保证同一个用户的请求打到同一个版本数据库兼容性问题 比如新版本改了数据库表结构,结果灰度发布的时候,新旧版本同时在跑,旧版本写入的数据新版本读不了,新版本写入的数据旧版本也读不了,整个系统乱套了。解决方案先发布一个兼容版本,既能处理旧数据格式,也能处理新数据格式等兼容版本全量发布后,再发布纯新版本这样虽然麻烦点,但安全多了。
2025年12月08日
2 阅读
0 评论
0 点赞
2025-12-02
kafka常用命令
topic 相关说明:红色的是必需要指定的参数使用bin/kafka-topics.sh 可查看所有的参数信息参数描述--bootstrap-server <String: server connect to> 连接kafka broker主机名称和端口号--topic <String: topic> 操作的topic名称--create创建主题--delete删除主题--alter修改主题--list查看所有主题--describe查看主题详细描述--partitions <Integer: # of partitions>设置分区数--replication-factor <Integer: replication factor>设置分区副本--config <String: name=value>更新系统默认的配置root@kf1:/opt/kafka# bin/kafka-topics.sh --bootstrap-server kf1:9092 --describe --topic first Topic: first TopicId: o4AxZZfwQhG-QR38nHUGxQ PartitionCount: 3 ReplicationFactor: 3 Configs: min.insync.replicas=1,segment.bytes=1073741824 Topic: first Partition: 0 Leader: 1 Replicas: 1,2,3 Isr: 1,2,3 Elr: LastKnownElr: Topic: first Partition: 1 Leader: 2 Replicas: 2,3,1 Isr: 2,3,1 Elr: LastKnownElr: Topic: first Partition: 2 Leader: 3 Replicas: 3,1,2 Isr: 3,1,2 Elr: LastKnownElr: Topic: 主题名称TopicId: 主题IDPartitionCount: 分区数量ReplicationFactor: 副本数量Configs: min.insync.replicas=1,segment.bytes=1073741824Topic:Partition: 分区IDLeader: 副本的leaderReplicas: 副本存储位置Isr: 连接的副本LastKnownElr
2025年12月02日
10 阅读
0 评论
0 点赞
2025-11-27
Kafka——Kafka安装(kafka_2.13-4.1.1)
kafka2.8.0版本引入了基于Raft共识协议的新特性,它允许kafka集群在没有ZooKeeper的情况下运行。为了剥离和去除ZooKeeper,Kafka引入了自己的KRaft(Kafka Raft Metadata Mode)。KRaft是一个新的元数据管理架构,基于Raft一致性算法实现的一种内置元数据管理方式,旨在替代ZooKeeper的元数据管理功能。KRaft的优势有以下几点:简化部署:Kafka 集群不再依赖外部的 ZooKeeper 集群,简化了部署和运维的复杂性。KRaft 将所有协调服务嵌入 Kafka 自身,不再依赖外部系统,这样大大简化了部署和管理,因为管理员只需关注 Kafka 集群。高效的一致性协议:Raft 是一种简洁且易于理解的一致性算法,易于调试和实现。KRaft 利用 Raft 协议实现了强一致性的元数据管理,优化了复制机制。提高性能:由于元数据管理不再依赖 ZooKeeper,Kafka 集群的性能得到了提升,尤其是在元数据读写方面。增强可扩展性:KRaft 模式支持更大的集群规模,可以有效地扩展到数百万个分区。提高元数据操作的扩展性:新的架构允许更多的并发操作,并减少了因为扩展性问题导致的瓶颈,特别是在高负载场景中。更快的控制器故障转移:控制器(Controller)的选举和故障转移速度更快,提高了集群的稳定性。消除 ZooKeeper 作为中间层之后,Kafka 的延迟性能有望得到改善,特别是在涉及选主和元数据更新的场景中。KRaft模式下,kafka集群中的一些节点被指定为控制器(Controller),它们负责集群的元数据管理和共识服务,所有的元数据都存储在kafka内部的主题中,而不是ZooKeeper,控制器通过KRaft协议来确保元数据在集群中的准确复制,这种模式使用了基于时间的存储模型,通过定期快照来保证元数据日志不会无限增长。完全自主:因为是自家产品,所以产品的架构设计,代码开发都可以自己说了算,未来架构走向完全控制在自己手上。控制器(Controller)节点的去中心化:KRaft 模式中,控制器节点由一组 Kafka 服务进程代替,而不是一个独立的 ZooKeeper 集群。这些节点共同负责管理集群的元数据,通过 Raft 实现数据的一致性。日志复制和恢复机制:利用 Raft 的日志复制和状态机应用机制,KRaft 实现了对元数据变更的强一致性支持,这意味着所有控制器节点都能够就集群状态达成共识。动态集群管理:KRaft允许动态地向集群中添加或移除节点,而无需手动去ZooKeeper中更新配置,这使得集群管理更为便捷。下载在 kakfa官网 下载最新的安装包,推荐下载已经编译好的二进制包。wget https://dlcdn.apache.org/kafka/4.1.1/kafka_2.13-4.1.1.tgz tar -xzf kafka_2.13-4.1.1.tgz mv kafka_2.13-4.1.1 /opt/kafka修改配置文件修改位于config目录下的server.properties############################# Server Basics ############################# #定义节点角色。broker,处理消息存储、生产者/消费者请求;controller,管理集群元数据(分区状态、副本分配)。 process.roles=broker,controller # 节点id,要求集群内唯一,每个节点的id都要不同(如 1、2、3)。 node.id=1 #Controller节点启动时发现的初始服务器列表(用于加入集群)。 controller.quorum.bootstrap.servers=kf1:9093,kf2:9093,kf3:9093 #controller集群成员列表,集群内部选举和同步元数据,所有 Controller 节点必须在此列表中,且数量需满足多数派(如 3 节点集群需至少 2 个在线)。 controller.quorum.voters=1@kf1:9093,2@kf2:9093,3@kf3:9093 ############################# Socket Server Settings ##################### #节点绑定的网络接口和端口。PLAINTEXT:Broker服务端口(接收客户端请求),CONTROLLER:Controller间通信端口。 listeners=PLAINTEXT://0.0.0.0:9092,CONTROLLER://0.0.0.0:9093 #Broker 之间通信使用的监听器名称 inter.broker.listener.name=PLAINTEXT #客户端实际连接的地址(Broker 会返回此地址给客户端)。 advertised.listeners=PLAINTEXT://192.168.88.51:9092,CONTROLLER://192.168.88.51:9093 #Controller 节点间通信使用的监听器名称 controller.listener.names=CONTROLLER #监听器名称与安全协议的映射关系。 listener.security.protocol.map=CONTROLLER:PLAINTEXT,PLAINTEXT:PLAINTEXT,SSL:SSL,SASL_PLAINTEXT:SASL_PLAINTEXT,SASL_SSL:SASL_SSL #处理网络请求的线程数(如接收请求、发送响应)。 num.network.threads=3 #处理磁盘 I/O 的线程数(如读写日志文件)。 num.io.threads=8 #Socket 缓冲区 socket.send.buffer.bytes=102400 #发送数据缓冲区大小(100KB)。 socket.receive.buffer.bytes=102400 #接收数据缓冲区大小(100KB)。 socket.request.max.bytes=104857600 #请求最大长度(100MB),防止 OOM。 ############################# Log Basics ############################# #消息日志存储目录(可配置多个路径,逗号分隔)。 log.dirs=/opt/kafka_data # 日志目录(可选) kafka_logs_dir=/var/log/kafka #分区与恢复 num.partitions=3 #新建 Topic 的默认分区数。 num.recovery.threads.per.data.dir=1 #每个日志目录用于崩溃恢复的线程数。 ############################# Internal Topic Settings #################### #副本因子与 ISR offsets.topic.replication.factor=3 # __consumer_offsets 副本数(生产环境建议 ≥3) share.coordinator.state.topic.replication.factor=2 # Share Group 状态主题副本数 share.coordinator.state.topic.min.isr=2 #share.coordinator.state.topic:Kafka Share Group 协调器的状态主题(内部主题)。min.isr:最小同步副本数(Minimum In-Sync Replicas),即写入操作需确认的最小同步副本数量(含 Leader)。配置值 1:表示向 share.coordinator.state.topic写入数据时,只需 Leader 副本确认即可认为成功(无需等待 Follower 副本同步)。逻辑:ISR(In-Sync Replicas,同步副本集)是 Leader 副本及与其保持同步的 Follower 副本的集合。min.isr=1意味着只要 Leader 副本存活且可写,写入就成功(即使没有其他同步副本)。 transaction.state.log.replication.factor=3 #transaction.state.log:Kafka 事务协调器的状态日志主题。事务协调器负责管理分布式事务(如跨分区/主题的事务提交/中止),该主题存储事务元数据(如事务 ID、参与者列表、状态(进行中/已提交/已中止)、超时时间等)。replication.factor:副本因子,即主题每个分区的副本总数(含 Leader 副本)。配置值 1:表示 transaction.state.log的每个分区仅有 1 个副本(仅 Leader 副本,无 Follower 副本)。逻辑:副本因子决定数据冗余度。replication.factor=1意味着数据仅存储在单个 Broker 上,无任何备份。 transaction.state.log.min.isr=3 #transaction.state.log:指定该参数作用于 事务状态日志(而非普通业务 Topic)。min.isr:即“最小同步副本数”,表示事务状态日志的每个分区,必须至少有 N 个副本(包括 Leader 副本)与 Leader 保持同步,否则该分区会进入“不可用”状态(无法写入新事务记录)。当事务状态日志的某个分区进行写入时,Kafka 会确保该分区的 同步副本集(ISR)大小 ≥ 3。只有当至少 3 个副本(Leader + 2 个 Follower)都成功复制了事务日志条目后,才会向生产者返回“事务提交成功”的响应。 default.replication.factor=3 #普通主题默认的副本因子数量 ############################# Log Flush Policy ############################ #日志保留策略 log.retention.hours=168 #日志保留时间(168 小时 = 7 天)。 log.segment.bytes=1073741824 #单个日志分段大小(1GB),达到后滚动生成新文件。 log.retention.check.interval.ms=300000 #检查日志保留的间隔(5 分钟)。在节点2上修改node.id=2 advertised.listeners=PLAINTEXT://192.168.88.52:9092,CONTROLLER://192.168.88.52:9093在节点3上修改node.id=3 advertised.listeners=PLAINTEXT://192.168.88.53:9092,CONTROLLER://192.168.88.53:9093初始化集群并启动首次启动时执行#在任一节点执行,仅执行一次,生成唯一集群ID bin/kafka-storage.sh random-uuid 0jQIB8NvQ3muEJg2vXIRRA #在每个节点执行,格式化存储 bin/kafka-storage.sh format -t 0jQIB8NvQ3muEJg2vXIRRA -c config/server.propertie Formatting metadata directory /opt/kafka_data with metadata.version 4.1-IV1.启动服务配置开机自启创建service文件vim /etc/systemd/system/kafka.service [Unit] Description=Apache Kafka Server Documentation=http://kafka.apache.org/documentation.html Requires=network.target remote-fs.target After=network.target remote-fs.target [Service] Type=simple User=kafka Group=kafka ExecStart=/opt/kafka/bin/kafka-server-start.sh /opt/kafka/config/server.properties ExecStop=/opt/kafka/bin/kafka-server-stop.sh Restart=on-abnormal RestartSec=10 KillMode=mixed TimeoutStopSec=30 Environment="LOG_DIR=/var/log/kafka" Environment="KAFKA_HEAP_OPTS=-Xmx1G -Xms1G" # 显式设置堆内存 # 日志重定向 StandardOutput=file:/var/log/kafka/service.log StandardError=file:/var/log/kafka/service-error.log [Install] WantedBy=multi-user.target# 重载 systemd 配置 sudo systemctl daemon-reload创建 Kafka 专用用户和目录# 创建系统用户 sudo useradd -r -s /sbin/nologin kafka # 创建数据/日志目录 sudo mkdir -p /opt/kafka_data sudo mkdir -p /var/log/kafka sudo chown -R kafka:kafka /opt/kafka_data /var/log/kafka # 授权 Kafka 安装目录 sudo chown -R kafka:kafka /opt/kafka按顺序启动节点可以使用systemctl命令或者手动的方式启动服务,#systemctl启动 systemctl enable --now kafka #前台启动 bin/kafka-server-start.sh config/server.properties #后台启动 nohup bin/kafka-server-start.sh config/server.properties &查看集群状态bin/kafka-broker-api-versions.sh --bootstrap-server 127.0.0.1:9092 # 192.168.88.51:9092 Broker 对外提供服务的 IP:端口(客户端实际连接的地址)。 #id: 1 Broker 的唯一标识 broker.id(集群中必须唯一,此处为 1、2、3)。 # rack: null 机架信息(未配置,故为 null,用于副本跨机架分布策略)。 #isFenced: false Broker 未被“隔离”(正常工作状态,若为 true则无法处理请求)。 192.168.88.51:9092 (id: 1 rack: null isFenced: false) -> ( Produce(0): 0 to 13 [usable: 13], #Produce(0) API 名称(Produce,消息生产 API),括号内 0是该 API 的 固定 key(Kafka 定义)。 #0 to 13 该 API 支持的 版本范围(从 v0 到 v13,共 14 个版本)。 #usable: 13 客户端与 Broker 协商后 实际使用的版本(取双方都支持的最高版本,性能最优)。 Fetch(1): 4 to 18 [usable: 18], ListOffsets(2): 1 to 10 [usable: 10], Metadata(3): 0 to 13 [usable: 13], OffsetCommit(8): 2 to 9 [usable: 9], OffsetFetch(9): 1 to 9 [usable: 9], FindCoordinator(10): 0 to 6 [usable: 6], JoinGroup(11): 0 to 9 [usable: 9], Heartbeat(12): 0 to 4 [usable: 4], LeaveGroup(13): 0 to 5 [usable: 5], SyncGroup(14): 0 to 5 [usable: 5], DescribeGroups(15): 0 to 6 [usable: 6], ListGroups(16): 0 to 5 [usable: 5], SaslHandshake(17): 0 to 1 [usable: 1], ApiVersions(18): 0 to 4 [usable: 4], CreateTopics(19): 2 to 7 [usable: 7], DeleteTopics(20): 1 to 6 [usable: 6], DeleteRecords(21): 0 to 2 [usable: 2], InitProducerId(22): 0 to 5 [usable: 5], OffsetForLeaderEpoch(23): 2 to 4 [usable: 4], AddPartitionsToTxn(24): 0 to 5 [usable: 5], AddOffsetsToTxn(25): 0 to 4 [usable: 4], EndTxn(26): 0 to 5 [usable: 5], WriteTxnMarkers(27): 1 [usable: 1], TxnOffsetCommit(28): 0 to 5 [usable: 5], DescribeAcls(29): 1 to 3 [usable: 3], CreateAcls(30): 1 to 3 [usable: 3], DeleteAcls(31): 1 to 3 [usable: 3], DescribeConfigs(32): 1 to 4 [usable: 4], AlterConfigs(33): 0 to 2 [usable: 2], AlterReplicaLogDirs(34): 1 to 2 [usable: 2], DescribeLogDirs(35): 1 to 4 [usable: 4], SaslAuthenticate(36): 0 to 2 [usable: 2], CreatePartitions(37): 0 to 3 [usable: 3], CreateDelegationToken(38): 1 to 3 [usable: 3], RenewDelegationToken(39): 1 to 2 [usable: 2], ExpireDelegationToken(40): 1 to 2 [usable: 2], DescribeDelegationToken(41): 1 to 3 [usable: 3], DeleteGroups(42): 0 to 2 [usable: 2], ElectLeaders(43): 0 to 2 [usable: 2], IncrementalAlterConfigs(44): 0 to 1 [usable: 1], AlterPartitionReassignments(45): 0 to 1 [usable: 1], ListPartitionReassignments(46): 0 [usable: 0], OffsetDelete(47): 0 [usable: 0], DescribeClientQuotas(48): 0 to 1 [usable: 1], AlterClientQuotas(49): 0 to 1 [usable: 1], DescribeUserScramCredentials(50): 0 [usable: 0], AlterUserScramCredentials(51): 0 [usable: 0], DescribeQuorum(55): 0 to 2 [usable: 2], UpdateFeatures(57): 0 to 2 [usable: 2], DescribeCluster(60): 0 to 2 [usable: 2], DescribeProducers(61): 0 [usable: 0], UnregisterBroker(64): 0 [usable: 0], DescribeTransactions(65): 0 [usable: 0], ListTransactions(66): 0 to 2 [usable: 2], ConsumerGroupHeartbeat(68): 0 to 1 [usable: 1], ConsumerGroupDescribe(69): 0 to 1 [usable: 1], GetTelemetrySubscriptions(71): UNSUPPORTED, PushTelemetry(72): UNSUPPORTED, ListConfigResources(74): 0 to 1 [usable: 1], DescribeTopicPartitions(75): 0 [usable: 0], ShareGroupHeartbeat(76): 1 [usable: 1], ShareGroupDescribe(77): 1 [usable: 1], ShareFetch(78): 1 [usable: 1], ShareAcknowledge(79): 1 [usable: 1], AddRaftVoter(80): 0 [usable: 0], RemoveRaftVoter(81): 0 [usable: 0], InitializeShareGroupState(83): 0 [usable: 0], ReadShareGroupState(84): 0 [usable: 0], WriteShareGroupState(85): 0 [usable: 0], DeleteShareGroupState(86): 0 [usable: 0], ReadShareGroupStateSummary(87): 0 [usable: 0], StreamsGroupHeartbeat(88): UNSUPPORTED, StreamsGroupDescribe(89): UNSUPPORTED, DescribeShareGroupOffsets(90): 0 [usable: 0], AlterShareGroupOffsets(91): 0 [usable: 0], DeleteShareGroupOffsets(92): 0 [usable: 0] ) 192.168.88.52:9092 (id: 2 rack: null isFenced: false) -> ( …… ) 192.168.88.53:9092 (id: 3 rack: null isFenced: false) -> ( …… )
2025年11月27日
7 阅读
0 评论
0 点赞
2025-11-25
zookeeper安装
ZooKeeper 是一个分布式协调服务,常用于管理配置、命名和同步服务。长期以来,Kafka 使用 ZooKeeper 负责管理集群元数据、控制器选举和消费者组协调等任务理,包括主题、分区信息、ACL(访问控制列表)等。ZooKeeper 为 Kafka 提供了选主(leader election)、集群成员管理等核心功能,为 Kafka提供了一个可靠的分布式协调服务,使得 Kafka能够在多个节点之间进行有效的通信和管理。然而,随着 Kafka的发展,其对 ZooKeeper的依赖逐渐显露出一些问题,这些问题也是下面 Kafka去除 Zookeeper的原因。kafka 2.8+ 为什么要移除zookeeper组件呢?kafka 4.0+版本彻底移除了zookeeper组件1.复杂性增加ZooKeeper 是独立于 Kafka 的外部组件,需要单独部署和维护,因此,使用 ZooKeeper 使得 Kafka的运维复杂度大幅提升。运维团队必须同时管理两个分布式系统(Kafka和 ZooKeeper),这不仅增加了管理成本,也要求运维人员具备更高的技术能力。2. 性能瓶颈作为一个协调服务,ZooKeeper 并非专门为高负载场景设计, 因此,随着集群规模扩大,ZooKeeper在处理元数据时的性能问题日益突出。例如,当分区数量增加时,ZooKeeper需要存储更多的信息,这导致了监听延迟增加,从而影响Kafka的整体性能。在高负载情况下,ZooKeeper可能成为系统的瓶颈,限制了Kafka的扩展能力。3. 一致性问题Kafka 内部的分布式一致性模型与 ZooKeeper 的一致性模型有所不同。由于 ZooKeeper和 Kafka控制器之间的数据同步机制不够高效,可能导致状态不一致,特别是在处理集群扩展或不可用情景时,这种不一致性会影响消息传递的可靠性和系统稳定性。4.发展自己的生态Kafka 抛弃 ZooKeeper,最核心的原因:Kafka生态强大了,需要自立门户,这样就不会被别人卡脖子。纵观国内外,有很多这样鲜活的例子,当自己弱小时,会先选择使用别家的产品,当自己羽翼丰满时,再选择自建完善自己的生态圈。但是一些旧版的kafka仍需配置ZooKeeper服务,因为Kafka依赖ZooKeeper进行集群协调、Broker注册、Topic管理等操作。安装ZooKeeperJava环境ZooKeeper是基于Java开发的,因此在部署时需要确保机器上有Java运行环境(JRE/JDK)。检查当前 Java 环境首先确认系统是否已安装 Java,以及版本是否符合要求java -version openjdk version "25.0.1" 2025-10-21 OpenJDK Runtime Environment (build 25.0.1+8-Ubuntu-124.04) OpenJDK 64-Bit Server VM (build 25.0.1+8-Ubuntu-124.04, mixed mode, sharing)若提示 command not found,说明未安装 Java,需继续安装java -version 找不到命令 “java”,但可以通过以下软件包安装它: apt install openjdk-17-jre-headless # version 17.0.17+10-1~24.04, or apt install openjdk-21-jre-headless # version 21.0.9+10-1~24.04 apt install default-jre # version 2:1.17-75 apt install openjdk-19-jre-headless # version 19.0.2+7-4 apt install openjdk-20-jre-headless # version 20.0.2+9-1 apt install openjdk-22-jre-headless # version 22~22ea-1 apt install openjdk-11-jre-headless # version 11.0.29+7-1ubuntu1~24.04 apt install openjdk-25-jre-headless # version 25.0.1+8-1~24.04 apt install openjdk-8-jre-headless # version 8u472-ga-1~24.04 root@zookeeper1:~/zookeeper# apt install openjdk-11-jre-headless 正在读取软件包列表... 完成 正在分析软件包的依赖关系树... 完成 正在读取状态信息... 完成 将会同时安装下列软件: alsa-topology-conf alsa-ucm-conf ca-certificates-java java-common libasound2-data libasound2t64 建议安装: default-jre alsa-utils libasound2-plugins libnss-mdns fonts-dejavu-extra fonts-ipafont-gothic fonts-ipafont-mincho fonts-wqy-microhei | fonts-wqy-zenhei fonts-indic下载并解压ZooKeeper点击 ZooKeeper下载列表 ,下载最新版本的安装包。wget -O zookeeper-3.9.4-bin.tar.gz https://dlcdn.apache.org/zookeeper/zookeeper-3.9.4/apache-zookeeper-3.9.4-bin.tar.gz tar -xf zookeeper-3.9.4-bin.tar.gz mv apache-zookeeper-3.9.4-bin/ /opt/zookeeper注意:集群模式至少需要三台服务器,强烈建议拥有奇数台服务器。如果你只有两台服务器,那么如果其中一台故障,机器数量不足以形成多数法定人数。两台服务器本质上比单台服务器稳定性差,因为存在两个单点故障。配置所有的服务器都拥有相同的配置文件。在ZooKeeper目录下的conf目录中,有个配置文件的示例,拷贝这个文件并修改其中的部分内容cp conf/zoo_sample.cfg conf/zoo.cfg修改项:tickTime=2000 initLimit=10 syncLimit=5 dataDir=/var/zookeeper/data dataLogDir=/var/zookeeper/logs clientPort=2181 server.1=192.168.88.31:2888:3888 server.2=192.168.88.32:2888:3888 server.3=192.168.88.33:2888:3888说明:tickTime:ZooKeeper 使用的基本时间单位(毫秒)。它用于读取心跳,最小会话超时时间是tickTime的两倍。initLimit:用来限制法定人数服务器连接领导者所需时间的超时syncLimit:限制服务器与领导者的过时距离dataDir:存储内存数据库快照的位置,除非另有说明,存储数据库更新的事务日志。dataLogDir:存储日志文件的位置clientPort:用于监听客户端连接的端口server.1=192.168.88.31:2888:3888 集群地址,“2888”和“3888”。对等节点使用前一个端口连接其他节点。这种连接是必要的,以便对等端能够通信,例如达成更新顺序的一致。更具体地说,ZooKeeper服务器利用该端口将追随者连接到领导者。当出现新的领导者时,跟随者会通过该端口与该领导者开启TCP连接。由于默认领导人选举也使用TCP,我们目前要求领导人选举需要另一个端口。这是服务器条目的第二个端口。确保dataDir和dataLogDir目录存在,如果不存在就创建它们。配置myid 在data/目录下,按集群顺序依次创建myid文件并写入id信息。#88.31机器上 echo 1 >myid #88.32机器上 echo 2 >myid #88.33机器上 echo 3 >myid开启服务bin/zkServer.sh start /usr/bin/java ZooKeeper JMX enabled by default Using config: /root/zookeeper/bin/../conf/zoo.cfg Starting zookeeper ... STARTED root@zookeeper2:~/zookeeper# bin/zkServer.sh status /usr/bin/java ZooKeeper JMX enabled by default Using config: /root/zookeeper/bin/../conf/zoo.cfg Client port found: 2181. Client address: localhost. Client SSL: false. Mode: leader 配置开机启动(service服务)vim /etc/systemd/system/zookeeper.service [Unit] Description=Apache ZooKeeper Service Documentation=https://zookeeper.apache.org After=network.target [Service] Type=forking ExecStart=/root/zookeeper/bin/zkServer.sh start ExecStop=/root/zookeeper/bin/zkServer.sh stop ExecReload=/root/zookeeper/bin/zkServer.sh restart Restart=on-failure [Install] WantedBy=multi-user.target systemctl daemon-reload systemctl enable zookeeper --now
2025年11月25日
2 阅读
0 评论
0 点赞
1
2
3