目录
sever.propertis 配置文件启动容器,搭建集群:
查看topic
查看当前容器的topic 信息:
1. _consumer_offsets没有做副本
2.其他topic 也没有做副本
3.消费者是单线程的消费(消费速度慢)
kafka-topics.sh --describe --zookeeper 192.168.232.100:2181
查看 topic 的描述信息,主要是看 该topic的所有 partition 的副本的信息,
leader,
replicas, 所有的副本(包含leader)
isr : 和leader 保持一定程度同步的副本 + leader
可以看到,分区的replicas 个数为0, 0:表示的 kafka 配置文件中 broker.id 的值
-----------------------------------------------------------------------------------------------------------
解决方案:
1. 增加topic 的副本数量,细分就是对topic 中每个partition 增加副本(实际就是对partition的操作)
2._counsumer_offset 的副本后面再更新。。。。。。todo
3.增加消费的速度
方案一:
方案二:
方案一:实现简单,通过对一个topic 中每一个 partition 创建一个线程的方式,加速消费
①增加partition 的数量,
②增加 spring.kafka.listener.concurrency= (最好是和partition的数量相同,这样负载更加均衡消费速度更快)
③在生产数据的时候,指定消息的 key 值,这个值需要是对象中一直在变化的,最简单的方式是使用主键,
不知道怎么制定key 值的:
https://blog.csdn.net/yang_zzu/article/details/105657129
key值使用主键的好处:
①如果对一条数据数据进行修改1、修改2、修改3 这几次的修改都会保存在同一个partition中,能够保证消费的顺序,因为kafka 消费的时候只能保证局部顺序的一致(同一partition 中的数据是顺序消费的)
②由于使用的主键数据肯定是不相同的,这样能够更加均匀的分布到不同的partition中
方案一:缺点:可能会遇到key 值扎堆的现象,即多个不同的key 值被分配到了同一partition 中这样可能会降低消费的速度,但是整体的消费速度是得到了很大的提升。
方案二:实现复杂,
大概的实现原理是,,和方案一前面都差不多,都是通过一个partition 对应一个 对应一个消费者线程,
所做的优化,是在每个消费者线程中,有多少个不同的key 就创建多少个线程,然后进行消费具体的还在学习中,后面更新该文章。。。。。。todo
----------------------------------------------------------------------------------------------------------
线上手动进行副本的增加:
副本的负载均衡,增加副本数量,都是一样的操作步骤:
1.新建,xxx.json 文件,
这个文件最好是在linux 系统上创建,然后在windows 系统上面编辑
因为windows 系统的行尾结束符 和 linux系统的行尾结束符是不一样的。
将文件上传到服务器某一个文件夹内,然后在该文件内,执行命令
-
{
-
"version":1,
-
"partitions":[
-
{
-
"topic":
"studentTopic",
-
"partition":0,
-
"replicas":[
-
0,
-
1,
-
2
-
]
-
},
-
{
-
"topic":
"studentTopic",
-
"partition":1,
-
"replicas":[
-
1,
-
2,
-
0
-
]
-
},
-
{
-
"topic":
"studentTopic",
-
"partition":2,
-
"replicas":[
-
2,
-
0,
-
1
-
]
-
}
-
]
-
}
2.执行命令:
/opt/kafka/bin/kafka-reassign-partitions.sh --zookeeper 192.168.232.100:2181 --reassignment-json-file replication3.json --execute
/opt/kafka/bin/kafka-reassign-partitions.sh --zookeeper 192.168.232.100:2181 --reassignment-json-file replication3.json --execute
-- 查看副本增加的状态,要使用同一个 xxx.json 文件
/opt/kafka/bin/kafka-reassign-partitions.sh --zookeeper 192.168.232.100:2181 --reassignment-json-file replication3.json --verify
/opt/kafka/bin/kafka-reassign-partitions.sh --zookeeper 192.168.232.100:2181 --reassignment-json-file replication3.json --verify
3.验证结果:
/opt/kafka/bin/kafka-topics.sh --topic studentTopic --describe --zookeeper 192.168.232.100:2181
/opt/kafka/bin/kafka-topics.sh --topic studentTopic --describe --zookeeper 192.168.232.100:2181
只查看 studentTopic 的信息:
由于之前在写xxxx.json 文件的时候,replicas 里面broker id 的顺序是一样的,就导致,全部分区的主节点都在同一个broker 节点上面,由于kafka 的读写都是通过 partition 的leader 节点进行的,所以这样的话,有的服务器的压力就比较大。
放在那里等待了一会,每个partition 的leader 节点发生了变化,推算,应该是自己动态变化的。不过需要时间。
发现这个leader 是动态变化的,好像可以自己进行负载均衡的样子
如果在其他节点都宕机了,剩下一个,这样所有的leader 节点就都在 这个正在运行的 broker 上面了
这个时候将其他节点启动,再查看发现,全部的leader 还是在一个节点上面,
如果要马上进行负载均衡的话,再次运行
/opt/kafka/bin/kafka-topics.sh --topic studentTopic --describe --zookeeper 192.168.232.100:218
这样会马上进行负载均衡,
猜想:如果不理会应该也会进行进行负载均衡,因为leader 本身好想是在动态变化的样子。
4.注意
尽可能的将 每个partition 的副本在集群中分开,这样就算有一两个集群节点宕机了,但是集群仍然是可用的,
我们这里数据量不是很大,大概是500M 左右,这样使用3个副本,将3个副本均匀分布在3台broker(服务器上面),一个服务器上面产生的数据量是1500M 硬盘足够存储。(一定要看一下产生的数据量大小,否则如果增加多个副本,然后数据量又恨到,会导致磁盘报警。)
副本的数量 <= broker数量(集群节点的数量)
5.遇到的问题
Reassigment of partition xxxxx faied
我是没有 找到合适的办法,关闭kafka 容器,然后启动kafka 容器,所有broker 节点都要执行,由于是虚拟机可能出现任何情况,就这个测试,我发现有台虚拟机的网卡还找不到,怎么重启,添加网卡都没办法,最后又克隆了一台。
线上手动pairtiton数量的增加:
1. 执行命令:
/opt/kafka/bin/kafka-topics.sh --alter --topic studentTopic --partitions 6 --zookeeper 192.168.232.100:2181
将studentTopic 的partition 数量增加到6 个,
这个时候会提示:
如果为具有键的主题增加分区,则会影响分区逻辑或消息的排序
添加分区成功了!
这是因为之前该topic 里面存在有数据,不过不影响数据的消费。
2. 查看topic 添加分区的信息:
貌似添加的新的分区,会自动进行副本的创建。
再等待一会,kafka 会自动的进行负载均衡,
————————————————————————
kakfa 配置文件的修改:
broker.id 可以在容器启动的时候进行制定,但是,不建议这么使用,因为在生产环境的时候,是需要进行文件映射的,这样在后面维护的时候更加的方便
指定日志文件的位置 log.dir=
指定一个topic 的partition 的数量 num.partitions=
每个数据目录在启动时用于日志恢复和关闭时用于刷新的线程数 num.recovery.threads.per.data.dir=
指定每个topic 的副本数量 offsets.topic.replication.factor=
事务状态日志文件的副本数量 transaction.state.log.replication.factor=
事务主题的min.insync.replicas配置,ISR集合中至少有个副本存在(个人理解,可能有误,但是网上找不到更详细的解释) transaction.state.log.min.isr=
sever.propertis 配置文件启动容器,搭建集群:
这个需要使用到之前搭建的kafka 集群,下面是链接,如果已经搭建好的可以不用理会这个章节
https://blog.csdn.net/yang_zzu/article/details/105628683
集群环境搭建,并且通过sever.propertis 配置文件进行启动容器
1.创建脚本:
替换 server.properties 文件中,以broker.id 为起始的行,注意 c 为命令的关键字
sed -i '/^broker.id/cbroker.id=0' /opt/kafka_2.12-2.4.1/config/server.properties
-
######################### 二次启动容器,让kafka 正常工作 ###########################
-
fireStart=`systemctl start firewalld.service`
-
if [ $? -eq 0 ];
then
-
echo
'防火墙启动成功。。。。。。。'
-
else
-
echo
'防火墙启动失败!!!!!'
-
exit 1
-
fi
-
kafkaStart=`docker start wurstmeister-kafka`
-
if [ $? -eq 0 ];
then
-
echo
'kafka容器启动成功。。。。。。。'
-
else
-
echo
'kafka容器启动失败!!!!!'
-
exit 1
-
fi
-
fireStop=`systemctl stop firewalld.service`
-
if [ $? -eq 0 ];
then
-
echo
'防火墙关闭成功。。。。。。。'
-
else
-
echo
'防火墙关闭失败!!!!!'
-
exit 1
-
fi
-
######################### 二次启动容器,end ###########################
-
-
-
#######创建文件夹
-
if [ ! -d /opt/kafka ];
then
-
mkdir -p /opt/kafka
-
if [ $? -eq 0 ];
then
-
echo
'/opt/kafka 创建成功。。。。。。。'
-
else
-
echo
'/opt/kafka 创建失败!!!!!'
-
exit 1
-
fi
-
fi
-
if [ ! -d /opt/kafka/logs ];
then
-
mkdir /opt/kafka/logs
-
if [ $? -eq 0 ];
then
-
echo
'/opt/kafka/logs 创建成功。。。。。。。'
-
else
-
echo
'/opt/kafka/logs 创建失败!!!!!'
-
exit 1
-
fi
-
fi
-
-
######复制配置文件
-
config=`docker cp wurstmeister-kafka:/opt/kafka/config /opt/kafka/`
-
if [ $? -eq 0 ];
then
-
echo
'config 复制成功。。。。。。。'
-
else
-
echo
'config 复制失败!!!!!'
-
exit 1
-
fi
-
######复制bin 可执行文件
-
bin=`docker cp wurstmeister-kafka:/opt/kafka/bin /opt/kafka/`
-
if [ $? -eq 0 ];
then
-
echo
'bin 复制成功。。。。。。。'
-
else
-
echo
'bin 复制失败!!!!!'
-
exit 1
-
fi
-
-
#获得该服务器的IP地址,网卡 ens33 需要查看服务器的网卡名称,进行调整
-
ip=`ifconfig ens33 | grep
'inet' | awk
'{ print $2}' | egrep
'[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}'`
-
if [ $? -eq 0 ];
then
-
echo
"ip地址为:$ip"
-
if [
"$ip" =
"192.168.232.100" ];
then
-
brokerid=`sed -i
'/^broker.id/cbroker.id=0' /opt/kafka/config/server.properties`
-
if [ $? -eq 0 ];
then
-
echo
'brokerid_0 修改成功。。。。。。。'
-
else
-
echo
'brokerid_0 修改失败!!!!!'
-
exit 1
-
fi
-
######修改 advertised.listeners, 看了一下生产环境将这个配置给注释掉了
-
advertisedListeners100=`sed -i
'/^advertised.listeners=/cadvertised.listeners=PLAINTEXT://192.168.232.100:9092' /opt/kafka/config/server.properties `
-
if [ $? -eq 0 ];
then
-
echo
'advertisedListeners100 修改成功。。。。。。。'
-
else
-
echo
'advertisedListeners100 修改失败!!!!!'
-
exit 1
-
fi
-
elif [
"$ip" =
"192.168.232.101" ];
then
-
brokerid=`sed -i
'/^broker.id/cbroker.id=1' /opt/kafka/config/server.properties`
-
if [ $? -eq 0 ];
then
-
echo
'brokerid_1 修改成功。。。。。。。'
-
else
-
echo
'brokerid_1 修改失败!!!!!'
-
exit 1
-
fi
-
######修改 advertised.listeners, 看了一下生产环境将这个配置给注释掉了 advertised.listeners=PLAINTEXT://192.168.232.101:9092
-
advertisedListeners101=`sed -i
'/^advertised.listeners=/cadvertised.listeners=PLAINTEXT://192.168.232.101:9092' /opt/kafka/config/server.properties `
-
if [ $? -eq 0 ];
then
-
echo
'advertisedListeners101 修改成功。。。。。。。'
-
else
-
echo
'advertisedListeners101 修改失败!!!!!'
-
exit 1
-
fi
-
elif [
"$ip" =
"192.168.232.102" ];
then
-
brokerid=`sed -i
'/^broker.id/cbroker.id=2' /opt/kafka/config/server.properties`
-
if [ $? -eq 0 ];
then
-
echo
'brokerid_2 修改成功。。。。。。。'
-
else
-
echo
'brokerid_2 修改失败!!!!!'
-
exit 1
-
fi
-
######修改 advertised.listeners, 看了一下生产环境将这个配置给注释掉了
-
advertisedListeners102=`sed -i
'/^advertised.listeners=/cadvertised.listeners=PLAINTEXT://192.168.232.102:9092' /opt/kafka/config/server.properties `
-
if [ $? -eq 0 ];
then
-
echo
'advertisedListeners102 修改成功。。。。。。。'
-
else
-
echo
'advertisedListeners102 修改失败!!!!!'
-
exit 1
-
fi
-
fi
-
else
-
echo
'ip地址获取失败!!!!!'
-
exit 1
-
fi
-
######修改 listeners=PLAINTEXT://0.0.0.0:9092
-
#listeners=`sed -i '/^listeners=/clisteners=PLAINTEXT://0.0.0.0:9092' /opt/kafka/config/server.properties `
-
#if [ $? -eq 0 ];then
-
# echo 'listeners 修改成功。。。。。。。'
-
# else
-
# echo 'listeners 修改失败!!!!!'
-
# exit 1
-
#fi
-
-
######修改 zookeeper.connect=192.168.232.100:2181
-
zookeeperConnect=`sed -i
'/^zookeeper.connect=/czookeeper.connect=192.168.232.100:2181,192.168.232.101:2181,192.168.232.102:2181' /opt/kafka/config/server.properties`
-
if [ $? -eq 0 ];
then
-
echo
'zookeeperConnect 修改成功。。。。。。。'
-
else
-
echo
'zookeeperConnect 修改失败!!!!!'
-
exit 1
-
fi
-
-
######修改 log.dirs=/kafka/kafka-logs-localhost.localdomain
-
#logDirs=`sed -i '/^log.dirs=/clog.dirs=/kafka/logs' /opt/kafka/config/server.properties`
-
#if [ $? -eq 0 ];then
-
# echo 'logDirs 修改成功。。。。。。。'
-
# else
-
# echo 'logDirs 修改失败!!!!!'
-
# exit 1
-
#fi
-
-
######修改 num.partitions=1
-
numPartitions=`sed -i
'/^num.partitions=/cnum.partitions=3' /opt/kafka/config/server.properties`
-
if [ $? -eq 0 ];
then
-
echo
'numPartitions 修改成功。。。。。。。'
-
else
-
echo
'numPartitions 修改失败!!!!!'
-
exit 1
-
fi
-
-
######修改 offsets.topic.replication.factor=3
-
offsetsTopicReplicationFactor=`sed -i
'/^offsets.topic.replication.factor=/coffsets.topic.replication.factor=3' /opt/kafka/config/server.properties`
-
if [ $? -eq 0 ];
then
-
echo
'offsetsTopicReplicationFactor 修改成功。。。。。。。'
-
else
-
echo
'offsetsTopicReplicationFactor 修改失败!!!!!'
-
exit 1
-
fi
-
-
######修改 transaction.state.log.replication.factor=3
-
transactionStateLogReplicationFactor=`sed -i
'/^transaction.state.log.replication.factor=/ctransaction.state.log.replication.factor=3' /opt/kafka/config/server.properties`
-
if [ $? -eq 0 ];
then
-
echo
'transactionStateLogReplicationFactor 修改成功。。。。。。。'
-
else
-
echo
'transactionStateLogReplicationFactor 修改失败!!!!!'
-
exit 1
-
fi
-
-
####################### 开启防火墙 #######################
-
fireStart=`systemctl start firewalld.service`
-
if [ $? -eq 0 ];
then
-
echo
'防火墙启动成功。。。。。。。'
-
else
-
echo
'防火墙启动失败!!!!!'
-
exit 1
-
fi
-
-
################################# 关闭旧的kafka 容器,删除旧容器 #################################
-
kafkaId=`docker ps -a | grep wurstmeister-kafka | awk
'{print $1}'`
-
if [ ! -n
"$kafkaId" ];
then
-
echo
"容器id为:$kafkaId"
-
else
-
echo
"容器id为:$kafkaId"
-
echo
"正在清除之前的wurstmeister-kafka容器..................."
-
echo
">>>>>>>>>>>>>>>>>>>>>>>"
-
kafkaStop=`docker stop
$kafkaId`
-
if [ $? -eq 0 ];
then
-
echo
"wurstmeister-kafka容器停止成功..................."
-
kafkaRm=`docker rm
$kafkaId`
-
if [ $? -eq 0 ];
then
-
echo
"wurstmeister-kafka容器清除成功..................."
-
else
-
echo
"wurstmeister-kafka容器清除失败!!!!!!!!!!!!"
-
exit 1
-
fi
-
else
-
echo
"wurstmeister-kafka容器停止失败!!!!!!!!!!!!"
-
exit 1
-
fi
-
fi
-
-
############################# 创建新的 kafka 容器 #############################
-
newKafaRun=`docker run -i -t -d --network host --name wurstmeister-kafka -v /opt/kafka/config:/opt/kafka/config -v /opt/kafka/config:/opt/kafka_2.12-2.4.1/config -v /opt/kafka/bin:/opt/kafka/bin -v /opt/kafka_2.12-2.4.1/bin:/opt/kafka_2.12-2.4.1/bin -v /opt/kafka/logs:/kafka/kafka-logs-localhost.localdomain wurstmeister/kafka /opt/kafka/bin/kafka-server-start.sh /opt/kafka/config/server.properties`
-
if [ $? -eq 0 ];
then
-
echo
'新的kafka 创建成功。。。。。。。'
-
else
-
echo
'新的kafka 创建失败!!!!!'
-
exit 1
-
fi
-
-
################ 关闭防火墙 ################
-
fireStop=`systemctl stop firewalld.service`
-
if [ $? -eq 0 ];
then
-
echo
'防火墙关闭成功。。。。。。。'
-
else
-
echo
'防火墙关闭失败!!!!!'
-
exit 1
-
fi
-
-
-
2. 通过 rz 命令上传到服务器,
3. 修改为可执行权限,
4. 执行文件
5.验证:
6.再次开启容器可能遇到找不到文件的问题:
将容器关闭后再使用 docker start wurstmeister-kafka 开启可能会遇到:
提示没有文件或者文件夹,明明文件是存在的。
这个时候不要慌,看看之前的容器是否存在
docker ps -a
存在的话,将之前的容器删除
docker rm wurstmeister-kafka
然后再开启一个终端,执行(这个是最稳妥的方法)
docker run -i -t -d --network host --name wurstmeister-kafka -v /opt/kafka/config:/opt/kafka/config -v /opt/kafka/config:/opt/kafka_2.12-2.4.1/config -v /opt/kafka/bin:/opt/kafka/bin -v /opt/kafka_2.12-2.4.1/bin:/opt/kafka_2.12-2.4.1/bin -v /opt/kafka/logs:/kafka/kafka-logs-localhost.localdomain wurstmeister/kafka /opt/kafka/bin/kafka-server-start.sh /opt/kafka/config/server.properties
或者是多试几次:我后面在启动的时候,通过多试几次成功将容器起来。
我这边三台机器,只有一台出现了这个再次启动找不到文件的异常,命名都是通过同样的的脚本文件进行搭建的,就是不一样,具体是什么原因造成的不是很清楚,(有大佬的话,可以在评论区指出,感谢!)
扫盲isr:
分区中所有的副本+leader 组成 AR
与leader保持一定程度同步的副本+leader组成 ISR
与leader相比滞后过多的副本 组成 OSR
AR = ISR +OSR
LEO 表示 的是:在该partition 中下一条数据写入的位置
HW 表示的是高水位,它表示了一个特定消息的偏移量(offset),消费之只能拉取到这个offset之前的消息。即消费只能拉取到0-5 的offset 的数据
HW 的值是 ISR 中最小的 LEO 的值,
ISR 的扩容:即当 OSR 中某个副本的LEO 和 HW 的值相等,则该副本就会进入到 ISR 中
Lag 值的计算:
消息堆积是消费滞后(Lag)的一种表现形式,消息中间件服务端中所留存的消息与消费掉的消息之间的差值即为消息堆积量,也称之为消费滞后(Lag)量。
正常情况下:Lag 的值
补充:
LSO特指LastStableOffset。它具体与kafka的事物有关。表示的某个未完成事务的第一条消息的位置
LSO 起作用:
1.开启kafka事务
2.消费者客户端的isolation.level的参数配置为“read_committed"(该值的默认参数为:“read_uncommitted")
LogStartOffset:表示一个Partition的起始位移,初始为0,虽然消息的增加以及日志清除策略的影响,这个值会阶段性的增大。
因为一个 partition 中的文件存储形式是以多个 segment 文件的形式进行存在的,LogStartOffset 表示 的是当前的 segment 文件的起始offset 值。
对于已经完成的事务而言,它的值等同于HW相同,所以我们可以得出一个结论:LSO ≤ HW ≤ LEO
当事务执行完的时候,这个时候 Lag = LSO - ComsumerOffset
-------------------------------------------------------------------------------
linux 的替换命令:
转载:https://blog.csdn.net/yang_zzu/article/details/107729699