kafka消费Clock skew too great (37),CPU打爆

No valid credentials provided (Mechanism level: Clock skew too great (37) - PROCESS_TGS)

​ 记一次生产事故,springboot消费kafka时于凌晨0~4点频繁报错且整天cpu持续90%以上占用。

项目背景

​ 项目背景为:

  • jdk1.8
  • springboot 2.3.4.RELEASE
  • 使用华为MRS-kafka

排查思路

排查思路为

  1. jstack/arhas分析忙碌cpu线程 =》 找到具体代码 =》 生成火焰图(注意:此时为正常的工作日白天)=》发现问题集中在消息的拉取上但此时数据仍正常在进入

此时数据在正常进入,但cpu占90%以上。为服务器不持续报警。重启服务,此时cpu恢复正常。但是第二天检查服务器时发现cpu继续爆满。怀疑此时为正常现象(数据量很大),但是继续重启之后恢复正常。怀疑为代码问题(批量消费)修改代码后重新部署,第三天cpu继续爆满。(此时还伴随着服务器磁盘空间满了。整理了一下日志输出,此排查处方向有问题)。

  1. =》拉取错误日志-》发现错误日志集中在晚0~4点,错误日志为时间相差 >5分钟

发现问题集中时间段为 00:05 1:45 2:45 3:55 因错误日志较多,此处问题时间为节选。日志报错都在描述时间相差过大、但是在此时(白天)在服务器执行date命令后发现应用服务器、kafka服务器时间相同。推断在0~4点有同步时间服务导致此时间段时间差距较大。怀疑为ntp服务导致。

复制代码
Caused by: org.ietf.jgss.GSSException: No valid credentials provided (Mechanism level: Clock skew too great (37) - PROCESS_TGS)
	at sun.security.jgss.krb5.Krb5Context.initSecContext(Krb5Context.java:772)
	at sun.security.jgss.GSSContextImpl.initSecContext(GSSContextImpl.java:248)
	at sun.security.jgss.GSSContextImpl.initSecContext(GSSContextImpl.java:179)
	at com.sun.security.sasl.gsskerb.GssKrb5Client.evaluateChallenge(GssKrb5Client.java:192)
	... 22 common frames omitted
Caused by: sun.security.krb5.KrbException: Clock skew too great (37) - PROCESS_TGS
	at sun.security.krb5.KrbTgsRep.<init>(KrbTgsRep.java:73)
	at sun.security.krb5.KrbTgsReq.getReply(KrbTgsReq.java:225)
	at sun.security.krb5.KrbTgsReq.sendAndGetCreds(KrbTgsReq.java:236)
	at sun.security.krb5.internal.CredentialsUtil.serviceCredsSingle(CredentialsUtil.java:482)
	at sun.security.krb5.internal.CredentialsUtil.serviceCreds(CredentialsUtil.java:340)
	at sun.security.krb5.internal.CredentialsUtil.serviceCreds(CredentialsUtil.java:314)
	at sun.security.krb5.internal.CredentialsUtil.acquireServiceCreds(CredentialsUtil.java:169)
	at sun.security.krb5.Credentials.acquireServiceCreds(Credentials.java:490)
	at sun.security.jgss.krb5.Krb5Context.initSecContext(Krb5Context.java:695)

Kafka客户端在尝试与Kafka Broker进行SASL认证时,没有提供有效的GSSAPI凭据,服务器和客户端之间的时间戳偏差过大

  1. =》查询NTP服务配置=》怀疑为ntp服务配置问题=》排除ntp服务问题

排查ntp后发现应用服务器与kafka服务器NTP服务器不一致。且offset偏差也可能导致时间相差5分钟。但是ntp服务在运行期间是持续轮训同步时间,不可能只有0~4点这个固定时间段存在问题。但是也不能排除NTP服务问题。询问后发现两服务器的NTP服务节点虽IP不同但指向的是同一服务器.NTP服务导致时间差距不大可能。

应用服务NTP如下:

复制代码
# systemctl status ntpd | grep "Active: active"
Active: active (running) since Tue 2023-**-** 10:16:46 CST; ***

kafka服务期NTP如下:

复制代码
# systemctl status ntpd | grep "Active: active"
Active: active (running) since Tue 2023-**-** 10:16:46 CST; ***
  1. =》意外发现有定时任务定时同步硬件时间=》执行定时同步硬件时间脚本=》发现时间相差>5分钟=》删除定时同步硬件时间任务

    发现服务器 crontab -l 在部分kafka节点服务上以及业务服务器上有 定时同步硬件时间的服务(huawei-clock -s)。试着执行此脚本后发现 执行前后时间相差5分钟。且在执行此命令后java 消费服务继续cpu高占用。

    1. 已经有了NTP服务同步时间,为什么还要定时脚本同步硬件时间

      NTP服务依赖于网络,如果网络出现问题或者服务器宕机,那么NTP服务就无法正常工作。而硬件时钟是由电池供电的,即使断电也会继续运行,因此它可以在没有网络的情况下提供准确的时间信息。

      一些重要的系统操作,如数据库备份、日志切割等,对时间的精确度要求非常高,它们通常不会依赖NTP服务,而是直接使用硬件时钟的时间。如果在这些操作进行时NTP服务出现问题,可能会导致任务执行的时间出错。

      对于某些特定的应用,可能还会需要额外的时间同步策略。例如,某些应用程序可能会选择与本地时间源同步,而不是NTP服务器。这时就需要通过定时脚本来手动调整硬件时间。

      NTP服务在大多数情况下可以提供准确的时间同步,但在一些特殊情况下,我们仍然需要定时脚本来同步硬件时间,以确保系统的稳定和可靠运行。

    2. 一个时间段从kafka拉取消息失败为什么不会影响下一时间段且cpu一致在尝试获取没有错误日志产生

      Kafka维护了一个时间戳和偏移量映射(映射到.index文件中的索引项),映射到.log文件中的实际字节偏移量。根据时间戳读取数据比根据位移读取数据要复杂一些,因为需要进行额外的数据查找步骤。此外,时间戳也被用于解决日志保存策略,判断依据就是比较日志段文件的最新修改时间。因此,如果两台服务器间的时间不一致,可能会导致读取的数据顺序错误或者对过期日志的判断失误,从而引发各种问题。

      在Spring Boot中,监听Kafka topic的轮询频率次数是由配置文件中的spring.kafka.consumer.poll-interval属性控制的。默认情况下,spring.kafka.consumer.poll-interval的值为500毫秒。这意味着消费者每500毫秒会向Kafka broker发送一次拉取请求,获取新的消息。

  2. =》排查消费配置

    按照kafka客户端与服务端的交互流程来说

    1. 客户端向Kafka发送连接请求,包括客户端的票据(token)和时间戳。

    2. Kafka接收到连接请求后,验证客户端的票据是否有效。Kafka可以通过验证票据中的签名或访问令牌来验证票据的有效性。如果票据无效,Kafka将拒绝连接请求。

    3. 如果票据有效,Kafka将检查客户端的时间戳与服务器的时间戳是否一致。如果时间戳偏差过大,Kafka将拒绝连接请求,并返回错误信息。

    4. 如果时间戳一致,Kafka将接受连接请求,并将客户端的时间戳记录在日志中。

    5. 客户端和Kafka建立连接后,客户端可以发送消息到Kafka。在发送消息时,客户端会携带消息的时间戳。

    6. Kafka接收到消息后,会验证消息的时间戳是否与客户端的时间戳一致。如果时间戳不一致,Kafka将拒绝接收该消息,并返回错误信息。

    7. 如果时间戳一致,Kafka将正常处理消息,并将其存储在相应的分区中。

      为了保证消息的顺序性和可靠性,从0.10.0.0版本开始,Kafka在每条消息中都增加了一个timestamp字段。这个时间戳有两种类型:CreateTime和LogAppendTime。CreateTime表示producer创建这条消息的时间;而LogAppendTime则表示leader broker将这条消息写入到log的时间。这样,broker接收到消息后可以根据这个时间戳来判断消息的顺序,并保证相同顺序的消息被同一消费者组内的消费实例消费。

我们的配置还是比较变态的的

复制代码
  kafka:
    consumer:
      properties:
        max.poll.interval.ms: 86400000
      max-poll-records: 200
    properties:
      session:
        timeout:
          ms: 120000

max.poll.records 参数决定了consumer一次从Kafka broker中拉取的最大消息数目默认值是500条.如果单次poll调用返回的消息数(即max.poll.records的值)小于或等于系统的吞吐量,那么处理逻辑就需要足够轻量,这样才能确保在session.timeout.ms这个时间内处理完这max.poll.records条数据。

max.poll.interval.ms指定consumer两次poll操作的最大时间间隔(默认值为5分钟),此处设置为24小时(单位毫秒)。如果某个consumer的处理能力不足,无法在session.timeout.ms规定的时间内处理完max.poll.records条数据,那么broker可能会认为该consumer的处理能力较弱。在这种情况下,broker会将该consumer所在的消费组中的分区分配给其他的consumer进行处理,从而触发rebalance过程。

session.timeout.ms消费者在与broker通信时,如果超过这个时间没有发送心跳包,那么该消费者的会话将被认为已经过期。默认情况下,session.timeout.ms的值是10000毫秒(即10秒)当消费者长时间没有向broker发送心跳包时,broker会认为该消费者已经下线,并释放该消费者所消费的分区。这样,其他消费者就可以重新分配这些分区进行消费。这里设置为两分钟。

网上很多博文描述为 Kafka-Consumer0.10版本的一个Bug ,并不是适用于此处,此处使用的是spring-kafka 2.5.6.RELEASE以及kafka-clients 2.4.0-hw-ei-302002

相关推荐
摇滚侠12 小时前
Spring Boot 3零基础教程,WEB 开发 静态资源默认配置 笔记27
spring boot·笔记·后端
wb0430720113 小时前
性能优化实战:基于方法执行监控与AI调用链分析
java·人工智能·spring boot·语言模型·性能优化
AAA小肥杨13 小时前
基于k8s的Python的分布式深度学习训练平台搭建简单实践
人工智能·分布式·python·ai·kubernetes·gpu
爬山算法16 小时前
Redis(73)如何处理Redis分布式锁的死锁问题?
数据库·redis·分布式
Chen-Edward16 小时前
有了Spring为什么还有要Spring Boot?
java·spring boot·spring
magic3341656316 小时前
Springboot整合MinIO文件服务(windows版本)
windows·spring boot·后端·minio·文件对象存储
小学鸡!17 小时前
Spring Boot实现日志链路追踪
java·spring boot·后端
yumgpkpm17 小时前
华为鲲鹏 Aarch64 环境下多 Oracle 、mysql数据库汇聚到Cloudera CDP7.3操作指南
大数据·数据库·mysql·华为·oracle·kafka·cloudera
番茄Salad18 小时前
Spring Boot临时解决循环依赖注入问题
java·spring boot·spring cloud
祈祷苍天赐我java之术18 小时前
Redis 数据类型与使用场景
java·开发语言·前端·redis·分布式·spring·bootstrap