草庐IT

从前,有一个简单的通道系统叫尤娜……

编程一生 2023-03-28 原文

从前,有个女生宿舍,住着小A、小B、尤娜和我4个人。有天,小A不小心把小B的床板坐塌了。小B非常生气,当场和小A翻脸。不论人缘最好的尤娜怎么中间调解都不管用。一直到毕业,小A和小B再没有说过一句话。

 

后来,小A、小B和尤娜都成了公司老板,只有我一事无成。小A公司需要使用小B公司的系统,小A还记着当年的事情,没敢直接找小B,就找尤娜商量。尤娜就找到小B诉说原委。有生意小B自然是愿意做的,但是想到关系这么僵了,还是放不下身段。尤娜叹了口气:“这样吧,我们公司做一个系统,你俩都来接我吧。”

 

于是,尤娜成立了一个以自己名字命名的项目,看着我实在找不到工作,就让我自学编程,给她做开发。于是尤娜初版就这样上线了。架构是这样的:

 

 

我还只是个菜鸟,所以我的做法只是把B的http接口包装了一下,其他什么也没有做。上线之后,我发现A的调用请求一天有几个时间调用量特别大,小B公司的老师说:“扛不住了,不要把流量直接透传过来呀!”

 

我通过自己的学习调查,发现可以使用消息中间件做个缓冲。当A请求过来,我先把请求放到消息队列里,然后再自己消费后转发请求给B。因为消费是匀速的,就起到了削峰填谷的作用。

 

但是这样,我怎么把返回结果再返回给A呢?聪明如我怎么会想不到办法,我把B返回的结果记录到数据库中。当A的请求发送到消息中间件后就循环去数据库里取结果,取到就返回这个结果给A。完美!

 

于是我跟尤娜商量了这个想法,尤娜是我的好姐妹,我的想法她马上表示支持,让我放手去做,资源呀什么都不是问题。

 

我按照网上找到的《项目中怎样做技术选型》的文章,结合目前的特点,优缺点比较之后,消息中间件使用kafka,数据库使用mysql。经过自己的努力,尤娜第二版上线啦。架构是这样的:

 

 

kafka集群的内部架构,我是参考《Kafka生产端实际项目中的使用分析》这篇文章,使用zookeeper做分布式协调。上线不久后,意想不到的事情发生了:kafka broker集群挂了。不管三七二十一先重启再说。

 

重启之后,尤娜消费端没有恢复,每隔3ms报一个warn日志:

 

Auto offset commit failed for group XXX:

 Commit cannot be completed since the group has already rebalanced and assigned the partitions to another member.

 This means that the time between subsequent calls to poll() was longer than the configured max.poll.interval.ms,

 which typically implies that the poll loop is spending too much time message processing.

 

我根据auto offset commit failed(自动提交offset失败了)这个信息在网上搜索了一下。通过之前的学习我知道:kafka的数据更新消费都是通过在zookeeper中标记一个偏移量(offset)来记录每个分区的消费位置,所以一旦offset更新失败,会出现重复消费数据的问题。

 

最终我分总结出:kafka消费者在处理消息时,在指定时间内(session.time.out)没有处理完。kafka消费要在消息处理完之后,自己提交当前的offset给kafka集群。而这时候已经超时断开连接了,导致自动提交offset失败。因此就会像日志中所说的发生rebalanced(重平衡即重新分配partition给客户端),而之前提交的offset已经失败了,所以重新分配的客户端又会消费之前的数据,接着consumer重新消费,又出现了消费超时,无限循环下去。

 

出现这个原因是因为我客户端使用时就是使用了spring-kafka,只用了一个@KafkaListener,没有修改任何默认配置。而默认enable.auto.commit设置成true,可以改为false,不采用自动提交方式。所谓不自动提交实际上是消费端收到消息不先处理而是先提交offset再处理。

 

这种解决方案,万一提交了offset之后消费失败了不会再次处理。这样次数多了向A不好交代呀。还是先不改了。我决定先修改session.time.out时间设置长一些,重启解决问题。

 

目前服务已经恢复了正常,作为菜鸟新人解决了问题觉得好激动。但是实际上细想还有好多问题没有弄明白,比如:kafka broker集群为什么挂了?太晚了,先睡觉再说。

 

突然想起那时候在宿舍我们四个一起读《飘》的情景,特别喜欢里面那句名言:无论如何,明天又是新的一天!

 

后记:

尤娜系统的第一次飞行中换引擎的架构垂直拆分改造

四种常用的微服务架构拆分方式

有关从前,有一个简单的通道系统叫尤娜……的更多相关文章

  1. ruby - 使用 Vim Rails,您可以创建一个新的迁移文件并一次性打开它吗? - 2

    使用带有Rails插件的vim,您可以创建一个迁移文件,然后一次性打开该文件吗?textmate也可以这样吗? 最佳答案 你可以使用rails.vim然后做类似的事情::Rgeneratemigratonadd_foo_to_bar插件将打开迁移生成的文件,这正是您想要的。我不能代表textmate。 关于ruby-使用VimRails,您可以创建一个新的迁移文件并一次性打开它吗?,我们在StackOverflow上找到一个类似的问题: https://sta

  2. ruby-on-rails - Rails - 一个 View 中的多个模型 - 2

    我需要从一个View访问多个模型。以前,我的links_controller仅用于提供以不同方式排序的链接资源。现在我想包括一个部分(我假设)显示按分数排序的顶级用户(@users=User.all.sort_by(&:score))我知道我可以将此代码插入每个链接操作并从View访问它,但这似乎不是“ruby方式”,我将需要在不久的将来访问更多模型。这可能会变得很脏,是否有针对这种情况的任何技术?注意事项:我认为我的应用程序正朝着单一格式和动态页面内容的方向发展,本质上是一个典型的网络应用程序。我知道before_filter但考虑到我希望应用程序进入的方向,这似乎很麻烦。最终从任何

  3. ruby-on-rails - 渲染另一个 Controller 的 View - 2

    我想要做的是有2个不同的Controller,client和test_client。客户端Controller已经构建,我想创建一个test_clientController,我可以使用它来玩弄客户端的UI并根据需要进行调整。我主要是想绕过我在客户端中内置的验证及其对加载数据的管理Controller的依赖。所以我希望test_clientController加载示例数据集,然后呈现客户端Controller的索引View,以便我可以调整客户端UI。就是这样。我在test_clients索引方法中试过这个:classTestClientdefindexrender:template=>

  4. ruby-on-rails - 如果 Object::try 被发送到一个 nil 对象,为什么它会起作用? - 2

    如果您尝试在Ruby中的nil对象上调用方法,则会出现NoMethodError异常并显示消息:"undefinedmethod‘...’fornil:NilClass"然而,有一个tryRails中的方法,如果它被发送到一个nil对象,它只返回nil:require'rubygems'require'active_support/all'nil.try(:nonexisting_method)#noNoMethodErrorexceptionanymore那么try如何在内部工作以防止该异常? 最佳答案 像Ruby中的所有其他对象

  5. ruby - 为什么 SecureRandom.uuid 创建一个唯一的字符串? - 2

    关闭。这个问题需要detailsorclarity.它目前不接受答案。想改进这个问题吗?通过editingthispost添加细节并澄清问题.关闭8年前。Improvethisquestion为什么SecureRandom.uuid创建一个唯一的字符串?SecureRandom.uuid#=>"35cb4e30-54e1-49f9-b5ce-4134799eb2c0"SecureRandom.uuid方法创建的字符串从不重复?

  6. ruby - 简单获取法拉第超时 - 2

    有没有办法在这个简单的get方法中添加超时选项?我正在使用法拉第3.3。Faraday.get(url)四处寻找,我只能先发起连接后应用超时选项,然后应用超时选项。或者有什么简单的方法?这就是我现在正在做的:conn=Faraday.newresponse=conn.getdo|req|req.urlurlreq.options.timeout=2#2secondsend 最佳答案 试试这个:conn=Faraday.newdo|conn|conn.options.timeout=20endresponse=conn.get(url

  7. ruby-on-rails - Rails - 从另一个模型中创建一个模型的实例 - 2

    我有一个正在构建的应用程序,我需要一个模型来创建另一个模型的实例。我希望每辆车都有4个轮胎。汽车模型classCar轮胎模型classTire但是,在make_tires内部有一个错误,如果我为Tire尝试它,则没有用于创建或新建的activerecord方法。当我检查轮胎时,它没有这些方法。我该如何补救?错误是这样的:未定义的方法'create'forActiveRecord::AttributeMethods::Serialization::Tire::Module我测试了两个环境:测试和开发,它们都因相同的错误而失败。 最佳答案

  8. ruby - 用 Ruby 编写一个简单的网络服务器 - 2

    我想在Ruby中创建一个用于开发目的的极其简单的Web服务器(不,不想使用现成的解决方案)。代码如下:#!/usr/bin/rubyrequire'socket'server=TCPServer.new('127.0.0.1',8080)whileconnection=server.acceptheaders=[]length=0whileline=connection.getsheaders想法是从命令行运行这个脚本,提供另一个脚本,它将在其标准输入上获取请求,并在其标准输出上返回完整的响应。到目前为止一切顺利,但事实证明这真的很脆弱,因为它在第二个请求上中断并出现错误:/usr/b

  9. ruby - 一个 YAML 对象可以引用另一个吗? - 2

    我想让一个yaml对象引用另一个,如下所示:intro:"Hello,dearuser."registration:$introThanksforregistering!new_message:$introYouhaveanewmessage!上面的语法只是它如何工作的一个例子(这也是它在thiscpanmodule中的工作方式。)我正在使用标准的ruby​​yaml解析器。这可能吗? 最佳答案 一些yaml对象确实引用了其他对象:irb>require'yaml'#=>trueirb>str="hello"#=>"hello"ir

  10. ruby-on-rails - 简单的 Ruby on Rails 问题——如何将评论附加到用户和文章? - 2

    我意识到这可能是一个非常基本的问题,但我现在已经花了几天时间回过头来解决这个问题,但出于某种原因,Google就是没有帮助我。(我认为部分问题在于我是一个初学者,我不知道该问什么......)我也看过O'Reilly的RubyCookbook和RailsAPI,但我仍然停留在这个问题上.我找到了一些关于多态关系的信息,但它似乎不是我需要的(尽管如果我错了请告诉我)。我正在尝试调整MichaelHartl'stutorial创建一个包含用户、文章和评论的博客应用程序(不使用脚手架)。我希望评论既属于用户又属于文章。我的主要问题是:我不知道如何将当前文章的ID放入评论Controller。

随机推荐