当前位置: 首页 > 网络应用技术

我已经用kafka在两年内踩了一些非凡的坑

时间:2023-03-07 15:37:21 网络应用技术

  我的博客

  我的香港公司正在制作餐饮系统。在每天的每日餐点高峰期间,不应低估系统的复杂性。为了保险,该公司规定,所有部门在进食时必须轮流在进食时履行职责,以防止在线问题时及时处理。

  我当时在后厨房中显示了系统团队,系统是订单下游业务。用户点击订单后,订单系统将通过发送消息为我们提供系统。系统阅读消息后,它将处理业务逻辑,持续使用订单和菜肴,然后显示给划船客户。这样,厨师知道要制作的订单,有些菜肴已经准备好,您可以通过该系统。系统会自动通知服务员服务。如果服务员完成食物并修改了菜肴,则用户知道已经涂了哪些菜肴,哪些菜肴尚未提供。此系统可以极大地提高后厨房的效率对用户的效率。

  事实证明,所有这些关键是消息中间件:如果有问题,它将直接影响后厨房显示系统的功能。

  接下来,我将与您谈谈您两年来使用哪些坑?

  一开始,我们系统中的商人很少。为了实现快速实现,我们没有太多思考。由于信息之间的通信,当订单系统发送到消息时,订单系统将放置在消息主体中。只要厨房显示订阅,我们就可以获取相关消息数据,然后处理我们的业务。

  但是,此集合有一个关键因素:确保消息的顺序。

  为什么?

  有许多订单的州,例如:订购,付款,完成,撤销等。不可能阅读不可能的新闻。让我们先阅读或新闻。如果是这种情况,数据不会引起混乱?

  好吧,似乎有必要的消息顺序。

  我们都知道的是混乱,但其中一个包含多个,每个内部都是有序的。

  ![图片]()

  这样,这个想法就变得很清楚:只要生产者写一条消息,就可以按照某些规则编写。不同的消费者阅读不同的消息,以确保生产和消费者新闻的顺序。

  我们一开始就做到了。同样的消息被写给同一消息。创建了其中一个,然后将消费者节点部署为形成,与消费者节点相对应。从理论上讲,该解决方案可以保证消息的顺序。

  所有计划似乎都是“无缝的”,我们只是在线。

  该功能已启动了一段时间,起初相对正常。

  但是,美好时光并没有持续很长时间,很快就收到了用户投诉,说划船的客户在划船的客户上看不到一些订单和菜肴,而且蔬菜无法刮擦。

  由于原因,我被定位。在此期间,公司通常不稳定,并且不时报告业务界面,业务请求无法不时连接到数据库。

  可以说这种情况是一个打击。

  你为什么这么说?

  假设发出订单系统:“下订单”,“付款”,以完成三个消息。“由于网络原因导致“顺序”消息失败,并且以下两条消息的数据无法放入仓库中,因为只有“订单”消息的数据是完整的数据,而其他类型的数据是消息只能达到状态。

  此外,我们当时没有这样做,这使这个问题放大了。问题变为:一旦消息的数据库失败,用户将永远不会看到此订单和陈述。

  那么如何解决这个紧急问题?

  一开始,我们的想法是:当消费者处理消息时,如果处理失败,则立即花费了3-5次。但是,如果某些请求需要第六次成功?。这种同步重试机制将阻止其他商人订单的阅读。

  显然,上述异常情况将严重影响消费者的消费速度并降低其吞吐量。

  从这个角度来看,我们必须使用它。

  如果使用异步重试机制,则必须保留故障的消息。

  但是立即出现一个新问题:如何只有一条消息可以确保订单?

  消息确实不能保证订单。如果:“订单”失败了,并且没有时间重新审查。这次,“付款”被消耗,并且不得正常消费。

  目前,“付款”应该等待,并且每次判断,它在以前的新闻中是否被消耗掉了?

  如果您真的这样做,将会有两个问题:

  目前,有一个更简单的解决方案表面:消费者首先确定处理消息时是否存在数据,如果有数据,则直接保存当前消息。如果不是,则执行业务处理。如果出现异常,请保存消息。

  后来,我们使用了它。如果我们在审查后失败,则该消息的状态标记为开发人员的电子邮件通知。

  最后,由于网络不稳定,已经解决了用户对划船客户上某些订单和菜肴看不见的问题。现在,商人偶尔会推迟菜肴,这比我看不到的好得多菜。

  随着销售团队的销售,我们系统中越来越多的商人。消息的数量越来越大,这导致无法处理它的消费者,并且经常拥有消息的积压。对商人的影响非常直观,并且可以在半小时内看到划船客户上的订单和菜肴。我可以忍受一两个分钟。一半新闻的延迟,在哪里忍受一些脾气暴躁的商人,立即抱怨。在此期间,我们经常收到商人的投诉,即订单和菜肴被推迟了。

  尽管加拿大可以解决该问题,但根据公司的省钱公约,我们必须首先进行系统优化,因此我们开始解决问题的旅程。

  尽管据称支持它,从向需要发送消息到网络,将数据写入磁盘需要一个磁盘(写作操作),从首先通过磁盘获得消息(读取操作),然后再通过网络。[图片]()

  从生产到消费的一个简单信息需要传递。如果消息太大,它将不可避免地增加IO的时间消耗,这将影响Kafka生产和消费的速度。由于消费速度太慢,积压了消息将发生。

  除上述问题外,它还将浪费服务器的磁盘空间。如果您不关注,磁盘空间可能不足。

  在这一点上,我们已经达到了需要优化新闻的时间。

  如何优化?

  我们重新分配了业务。不需要知道订单,只知道一个。

  太好了,我们可以这样设计:

  ![图片]()

  果然,经过此调整,新闻的积压很长一段时间都没有出现。

  不要太早开心。中午,有一些商人抱怨订单和菜肴。在我们检查卡夫卡的话题时,就会有一个积压的新闻。

  但是这次有点奇怪,并非所有新闻都有积压,而只有一个。

  一开始,我认为这是由消费节点引起的。但是在调查后,未发现异常。

  这很奇怪,在哪里有问题?

  后来,我检查了日志和数据库,表明几家商人的订单特别大。碰巧,这些商人被分配给同一商人,使新闻数量比其他商人多得多。

  目前,我们意识到,发送消息时的道路规则是不合理的,并且可能有一些消息说消息太多了。消费者无法处理它,但是其中一些人的消息很少,消费者是免费的。

  为了避免这种不平衡的分配,我们需要调整消息的路由规则。

  我们考虑了这一点,路线编号相对均匀,并且没有发出单一订单的情况。除非您遇到了一直在添加蔬菜的人,但是添加蔬菜需要花钱,因此实际上,数量关于同一订单的信息不多。

  调整后,每次将路线按下相同的订单编号。

  调整后,很长一段时间以来,消息积压的问题都没有再次出现。在这段时间内,商人数量很快增加,变得越来越多。

  在高分子场景中,可以说消息的积压如下,并且实际上无法从根本上解决它。在表面上,它已经解决了,但是我不知道什么时候会来出去,例如这次:

  一个下午,产品开始说:几家商人抱怨了,他们说菜肴被推迟了,并检查了原因。

  这个问题有点奇怪。

  你为什么这么说?

  首先,这次有点奇怪。您通常有问题吗?不是在中午还是晚上全部?为什么这个问题在下午出现?

  根据我过去积累的经验,我直接阅读的数据确实具有上述消息的积压,但是这次,每个人都积累的消息没有消耗,这比以前的数量增加了新闻。这个新闻的积压非常不寻常。

  我迅速检查了服务监视,以查看消费者是否被挂断电话,但幸运的是,我没有挂起它。检查服务日志是否不异常。这次,我有些困惑。我问我是否急着问订单小组是否在下午发生?他们说下午有促销活动,批量更新了工作信息。

  目前,我突然像一个梦一样醒来,这是他们批次发送消息的消息引起的一个问题。为什么我们不通知我们?这太坑了。

  尽管问题的原因是,您应该如何处理您面前的新闻?

  目前,如果没有直接调整这个数字,历史新闻已存储给4个固定新闻,只有新闻才能到达新闻。我们需要处理的是现有分区。

  由于同一组的多个组被消耗,但同一组之一的多重消耗可能会导致资源浪费,因此无法直接添加服务节点。

  似乎仅使用多线程处理。

  为了紧急解决问题,我更改为使用处理消息,并配置了核心线程和最大线程。

  调整后,消息的数量继续减少。

  但是目前,有一个更严重的问题:我收到了一封报告电子邮件,还有两个带有两个订单系统的节点倒下的机器。

  很快,订单组中的同事来找我,并说,订单询问界面的越来越多的并发超出了预期的预期,导致两个服务节点悬挂。他们将查询功能设置为单独的服务,仅部署了6个节点,悬挂了6个节点,悬挂了6个节点2个节点,并且没有处理。其他四个节点也将被悬挂。可以说订单服务是公司的核心服务。公司将造成很多损失,情况非常紧迫。

  为了解决此问题,只能首先减少线程的数量。

  幸运的是,可以动态调整线程的数量。我将核心线的数量转移到一个,然后将核心线的数量更改为一个。

  稍后,在重新启动订单服务的两个节点后,操作和维护将恢复正常,以防万一,只需添加两个节点即可确保订单服务没有问题,它将保持当前的消耗速度。后厨房信息的积压显示了系统的积压,一个孩子将在一个孩子后恢复正常。

  后来,我们进行了重新检查,结论是:

  顺便说一句,对于需要严格确保消息顺序的场景,可以将线程池更改为多个队列,并且每个队列都可以用一个线程处理。

  为了防止稍后再次发出消息的积压,消费者以后使用了多线程。

  但是有一天,我们仍然收到大量警报邮件,以提醒我们卡夫卡的主题新闻有积压。我们检查了原因。目前,产品过来说:一些商人投票说这些菜是延迟的,所以快点了。这次她看起来有点不耐烦,她确实进行了多次优化,而且仍然存在同样的问题。

  从外行的角度来看:为什么不能解决同一问题?

  实际上,他们不知道技术的苦难。

  从表面上看,问题的症状是相同的,并且菜肴延迟。他们知道消息的积压。但是他们不知道深层级别的原因,实际上有许多新闻待办事项的原因。这可能是消息中间件的常见问题。

  我保持沉默,我只能将原因定位。

  后来,我检查了消费者消耗了一条消息。过去,现在怎么会变成?

  奇怪的是,尚未调整消费者代码。为什么会发生这种情况?

  在检查在线盘式表之后,单手表的数据量甚至在那里,其他菜肴也相同。现在,单个手表中存储了太多数据。

  我们的小组梳理了业务。实际上,这些菜只显示了最接近客户的菜肴。

  这很容易处理。我们有服务方面,因此最好存档表中的多余数据。因此,DBA帮助我们存档数据,仅保留最新数据。

  调整后,新闻的积压得到了解决,并恢复了过去的平静。

  不要太高兴,还有其他问题,例如:警报电子邮件经常报告数据库异常:主要密钥冲突。

  这种问题通常是由于SQL超过两个或多个主要键。同时,插入数据。在第一个插入成功之后,将在插入第二个插入时报告主键。表的主要键是唯一的,不允许重复。

  我仔细检查了代码,发现代码逻辑将首先查询是否根据主键在表中存在的顺序。如果存在,状态已更新,则不会在没有存在的情况下插入数据,也没有问题。

  当并发量不大时,此判断很有用。但是,在高并发情况下,这两个请求并非同时存在。一个请求首先插入数据,而当数据插入数据时,当主要密钥冲突出现时,另一个请求将是异常的。

  解决此问题的最常规方法是:

  起初我只是想到了。绝对不可能添加数据库悲剧锁,这会影响性能过多。基于版本编号判断的ADD数据库乐观锁通常用于更新操作,并且基本上不使用此插入操作。

  其余的只能用分布式类型锁定。我们的系统正在使用REDIS,该系统可以在Redis上添加一个分布式锁定以锁定订单号。

  但是稍后再考虑:

  因此,我不打算使用分布式锁。

  而是选择使用mySQL语法:

  它将首先尝试将数据插入表格,如果主要密钥冲突,请更新字段。

  在上一句话转换后,主要的关键冲突不再发生。

  一天后,在收到商人的投诉后,收到了命令,可以在划船客户身上看到命令。

  这个问题与过去不同。根据以前的经验,有一定积压的信息,但是这次没有积压。

  我检查了服务日志,发现订单系统接口返回的数据是空的。有些人仅返回订单数据,而没有返回菜肴数据。

  这很奇怪。我直接去了订单组的同事。他们仔细检查了服务而没有找到问题。这次,我们以相同的方式思考,是否存在数据库问题并一起找到它。在库中找到了数据库的主要库同步数据。有时,由于网络原因,偶尔会有延误,有时会延迟。

  如果我们的业务流程从消息到消费消息消耗,则在调用订单详细信息查询接口时可能无法找到数据,或者找不到的不是最新数据。

  这个问题非常严重,这将导致直接数据错误。

  为了解决此问题,我们添加了它。当调用接口查询数据时,如果将数据返回到空,或者仅返回订单,则将添加。

  调整后,解决了商人投诉的问题。

  当消费者消息时,三种模式支持:

  默认模式是,但是此模型可能会导致重复的消费问题,因此我们的业务逻辑必须由Power设计。

  而且,我们的业务场景在保存数据时使用语法,在没有存在时插入并在存在时进行更新,这是自然的支撑力。

  当时,在线环境被分为:(预释放环境)和(生产环境)。这两个环境共享了相同的数据库,并共享了相同的KAFKA群集。

  应该注意的是,在配置时,应添加前缀以区分不同的环境。存在的存在始于pre_order。生产环境始于诸如:product_order之类的产品,它阻止消息在不同环境中串起。

  但是,环境中有一个操作和维护节点。配置后,这是错误的,匹配了。那天发生了,我们有了新的环境功能。结果,环境消耗了一些消息。由于调整了新闻,因此环境的环境处理始终失败。

  结果,在生产环境中丢失了一些新闻。不幸的是,消费者最终阅读了解决该问题的一部分消息,这并没有造成太大的损失。

  除上述问题外,我还遇到了它:

  这两个问题有点复杂,我不会一个一个一个问题。有兴趣的朋友可以关注我的公共帐户,并将我的微信添加到我身上以私下交谈。

  非常感谢您使用消息中间零件的两年经验。尽管我遇到了很多问题,但我踩了很多坑,绕了很多弯路,但实际上我积累了很多宝贵的经验并迅速增长。

  实际上,这是一个非常好的消息中间件。我遇到的大多数问题不是我自己的问题(除了100%的CPU使用情况外,其错误是一个错误)。

  文章来自:su san Say技术

  原始:https://juejin.cn/post/7101570158090682381