1. 环境准备:三节点Ubuntu 20.04基础配置
在开始部署Storm高可用集群之前,我们需要先准备好三台运行Ubuntu 20.04的服务器。这里我推荐使用虚拟机进行实验,VirtualBox或VMware Workstation都可以。实际生产环境中,这三台机器可以是物理服务器或云主机。
首先确保三台机器都安装了最小化的Ubuntu 20.04 Server版本。为什么选择Server版而不是Desktop版?因为Server版资源占用更少,更适合作为服务器运行。安装完成后,我们需要做一些基础配置:
- 更新系统软件包:
sudo apt update && sudo apt upgrade -y- 配置静态IP(以master节点为例):
sudo vim /etc/netplan/00-installer-config.yaml配置内容示例:
network: ethernets: ens33: dhcp4: no addresses: [192.168.209.143/24] gateway4: 192.168.209.1 nameservers: addresses: [8.8.8.8, 8.8.4.4]应用配置:
sudo netplan apply- 修改主机名并配置hosts文件(所有节点都需要):
sudo hostnamectl set-hostname master # 在slave1和slave2上分别设置 sudo vim /etc/hosts添加以下内容:
192.168.209.143 master 192.168.209.144 slave1 192.168.209.145 slave2- 配置SSH免密登录(从master节点操作):
ssh-keygen -t rsa # 连续回车 ssh-copy-id master ssh-copy-id slave1 ssh-copy-id slave2这些基础配置完成后,建议在三台机器上互相ping主机名测试网络连通性。我在实际部署中发现,如果hosts文件配置不正确,后续的ZooKeeper和Storm集群都会出现各种奇怪的连接问题。
2. ZooKeeper集群部署与高可用配置
Storm依赖ZooKeeper来协调集群状态,所以我们需要先搭建一个三节点的ZooKeeper集群。这里我使用的是ZooKeeper 3.6.3版本,你可以根据需要选择其他稳定版本。
- 在所有节点安装ZooKeeper:
sudo apt install -y zookeeperd zookeeper- 配置ZooKeeper(所有节点都需要修改):
sudo vim /etc/zookeeper/conf/zoo.cfg添加/修改以下内容:
tickTime=2000 initLimit=10 syncLimit=5 dataDir=/var/lib/zookeeper dataLogDir=/var/log/zookeeper clientPort=2181 server.1=master:2888:3888 server.2=slave1:2888:3888 server.3=slave2:2888:3888- 创建myid文件(每个节点内容不同):
echo "1" | sudo tee /var/lib/zookeeper/myid # master节点 echo "2" | sudo tee /var/lib/zookeeper/myid # slave1节点 echo "3" | sudo tee /var/lib/zookeeper/myid # slave2节点- 启动ZooKeeper服务:
sudo systemctl restart zookeeper sudo systemctl enable zookeeper- 验证集群状态:
echo stat | nc localhost 2181 | grep Mode正常情况下,三个节点中会有一个显示为"leader",另外两个显示为"follower"。
在实际部署中,我遇到过ZooKeeper节点无法形成集群的问题,大多数情况下是因为防火墙没有开放2888和3888端口。Ubuntu默认使用ufw防火墙,可以通过以下命令开放端口:
sudo ufw allow 2888/tcp sudo ufw allow 3888/tcp3. Storm核心组件安装与配置
现在我们可以开始安装和配置Storm了。这里我使用的是Apache Storm 2.3.0版本,你可以根据需要选择其他版本。
- 在所有节点下载并解压Storm:
wget https://archive.apache.org/dist/storm/apache-storm-2.3.0/apache-storm-2.3.0.tar.gz tar -xzf apache-storm-2.3.0.tar.gz sudo mv apache-storm-2.3.0 /opt/storm- 配置环境变量(所有节点):
echo 'export STORM_HOME=/opt/storm' | sudo tee -a /etc/profile echo 'export PATH=$PATH:$STORM_HOME/bin' | sudo tee -a /etc/profile source /etc/profile- 配置storm.yaml(所有节点):
vim /opt/storm/conf/storm.yaml关键配置如下:
storm.zookeeper.servers: - "master" - "slave1" - "slave2" storm.local.dir: "/opt/storm/data" nimbus.seeds: ["master", "slave1"] supervisor.slots.ports: - 6700 - 6701 - 6702 - 6703 ui.port: 8080 drpc.port: 3772这里有几个关键点需要注意:
nimbus.seeds配置了多个Nimbus节点,这是实现高可用的关键storm.local.dir需要提前创建并设置正确权限- 端口配置要根据实际环境调整,避免冲突
- 创建数据目录并设置权限:
sudo mkdir -p /opt/storm/data sudo chown -R $USER:$USER /opt/storm4. 启动Storm集群与高可用验证
现在我们可以启动Storm集群了。不同节点需要启动不同的服务:
- 在master和slave1节点启动Nimbus(这两个节点将组成高可用的Nimbus):
nohup storm nimbus > $STORM_HOME/logs/nimbus.log 2>&1 &- 在所有节点启动Supervisor:
nohup storm supervisor > $STORM_HOME/logs/supervisor.log 2>&1 &- 在master节点启动UI(也可以在其他节点启动以实现UI的高可用):
nohup storm ui > $STORM_HOME/logs/ui.log 2>&1 &- 在所有节点启动Logviewer(方便查看日志):
nohup storm logviewer > $STORM_HOME/logs/logviewer.log 2>&1 &启动完成后,可以通过jps命令检查进程是否正常运行:
jps | grep -v JPS正常情况下,你应该看到类似下面的输出:
- Nimbus节点:Nimbus、Supervisor、Logviewer
- Supervisor节点:Supervisor、Logviewer
现在你可以通过浏览器访问http://master:8080查看Storm UI界面。为了验证高可用性,你可以尝试停止master节点的Nimbus进程,然后观察slave1节点是否会接管Nimbus职责。正常情况下,拓扑任务应该会继续运行而不中断。
在实际测试中,我发现Storm的高可用切换大约需要30-60秒时间,这期间新的拓扑提交可能会失败,但已经运行的拓扑不会受到影响。这是设计上的权衡,因为Storm更注重数据处理的不间断性而非控制平面的瞬时可用性。
5. 运行测试拓扑与性能调优
集群搭建完成后,我们需要运行一个测试拓扑来验证集群功能。Storm自带了一些示例拓扑,我们可以使用经典的WordCount例子:
- 打包示例代码:
cd $STORM_HOME/examples/storm-starter mvn clean package -DskipTests- 提交拓扑到集群:
storm jar $STORM_HOME/examples/storm-starter/target/storm-starter-*.jar org.apache.storm.starter.WordCountTopology wordcount- 在Storm UI中观察拓扑运行情况,正常情况下你应该能看到拓扑的各个组件(Spout和Bolt)分布在不同的Supervisor节点上。
对于生产环境,我们还需要考虑一些性能调优参数:
- 调整worker进程数(在拓扑代码中设置):
Config conf = new Config(); conf.setNumWorkers(3); // 根据集群规模调整- 调整并行度(在拓扑代码中设置):
builder.setSpout("spout", new RandomSentenceSpout(), 4); // 并行度为4 builder.setBolt("split", new SplitSentence(), 8).shuffleGrouping("spout");- 调整消息处理超时时间(storm.yaml中设置):
storm.messaging.netty.server_worker_threads: 4 storm.messaging.netty.client_worker_threads: 4 topology.message.timeout.secs: 60在实际项目中,我发现并行度的设置对性能影响最大。一般建议:
- 每个Supervisor节点的worker数不超过slot数(即配置的端口数)
- 每个CPU核心可以处理2-3个executor
- 内存分配要合理,避免频繁GC
6. 常见问题排查与运维建议
在Storm集群的运维过程中,我遇到过不少问题,这里分享一些常见问题的解决方法:
Nimbus无法选举:
- 检查ZooKeeper集群状态是否正常
- 确认所有Nimbus节点都能连接到ZooKeeper
- 查看Nimbus日志中的异常信息
Supervisor无法注册:
- 检查Supervisor节点的storm.yaml配置是否正确
- 确认Supervisor能连接到ZooKeeper集群
- 检查网络连接和防火墙设置
拓扑提交失败:
- 检查Nimbus服务是否正常运行
- 查看拓扑jar包是否包含所有依赖
- 检查Storm UI中是否有相关错误信息
性能瓶颈排查:
storm list # 查看运行中的拓扑 storm kill topology-name # 停止问题拓扑 storm deactivate topology-name # 暂停拓扑 storm activate topology-name # 恢复拓扑
对于生产环境,我建议:
- 定期清理storm.local.dir目录下的旧数据
- 设置日志轮转,避免日志文件过大
- 监控关键指标:处理延迟、吞吐量、worker资源使用率
- 考虑使用Storm的调度器功能来优化资源分配
我在一个实时数据处理项目中,曾经因为worker内存配置不合理导致频繁Full GC,最终通过调整worker数量和每个worker的内存分配解决了问题。关键是要根据实际数据量和处理逻辑来调整参数,而不是简单地使用默认值。