“走在我的鞋子里”-停下来,上面有标记吗?

自2019年以来,俄罗斯实行了强制性标签法。法律不适用于所有商品组,商品组强制性标签的生效条款不同。属于强制标签的第一个类别是烟草,鞋类,药品,之后还会添加其他商品,例如香水,纺织品,牛奶。这项立法创新促使开发了新的IT解决方案,该解决方案将跟踪从生产到最终消费者购买产品的整个生命链,直至过程的所有参与者:国家本身以及所有销售带有强制标签的商品的组织。



在X5中,用于跟踪带有标签的商品并与政府和供应商交换数据的系统称为“ Markus”。让我们按顺序说出它的开发方式和由谁开发,它具有什么样的技术堆栈以及为什么我们值得为之骄傲。







实际高负载



“ Markus”解决了许多问题,主要问题之一是信息系统X5与标签产品状态信息系统(GIS MP)之间的集成交互,以跟踪标签产品的移动。该平台还存储了我们收到的所有标记代码以及这些代码在整个对象上移动的整个历史记录,有助于消除标记产品的重新分类。以第一类带标签商品中所包括的烟草产品为例,仅一辆卡车装的香烟就包含约600,000包,每包都有自己的独特代码。我们系统的任务是跟踪并检查每个此类包装在仓库和商店之间移动的合法性,并最终检查其实施对最终客户的可接受性。而且我们记录的每小时现金交易约为125,000,并且还需要记录每个这样的包装如何进入商店。因此,考虑到对象之间的所有运动,我们预计每年有数百亿条记录。



M队



尽管事实上“ Markus”被认为是X5内的一个项目,但它正在根据产品方法实施。该团队致力于Scrum。该项目的开始是在去年夏天,但是最初的结果是在10月才出现-他们自己的团队已经完全组装好,开发了系统架构并购买了设备。现在,该团队有16个人,其中6个人从事后端和前端的开发,其中3人从事系统分析。另有六个人参与了手动,负载,自动测试和产品支持。此外,我们还有一位SRE专家。



我们团队中的代码不仅是由开发人员编写的,几乎所有的人都知道如何编程和编写自动测试,加载脚本和自动化脚本。我们特别注意这一点,因为即使产品支持也需要高度的自动化。我们总是尽力建议和帮助以前没有编程的同事完成一些小任务。



与冠状病毒大流行有关,我们将整个团队转移到了远程工作,所有开发管理工具的可用性,Jira和GitLab中内置的工作流程使这一阶段变得很容易。在偏远地区度过的几个月时间表明,团队的生产力并没有因此受到影响,因为许多工作上的舒适感增加了,唯一的问题是现场交流不足。



距离之前的团队会议







远程会议







解决方案技术栈



X5的标准存储库和CI / CD工具是GitLab。我们将其用于代码存储,连续测试,部署到测试和生产服务器。当至少有2位同事需要批准开发人员对代码所做的更改时,我们也会使用代码审查的做法。静态代码分析器SonarQube和JaCoCo帮助我们保持代码干净,并提供所需级别的单元测试范围。代码中的所有更改都必须经过这些检查。随后,所有手动运行的测试脚本都将自动执行。



为了使“ Markus”成功执行业务流程,我们必须依次解决一系列技术问题。



任务1.系统水平可伸缩性的需求



为了解决这个问题,我们选择了微服务架构方法。同时,了解服务责任领域非常重要。考虑到流程的细节,我们试图将它们划分为业务运营。例如,在仓库中的收货不是很频繁,而是非常繁琐的操作,在此期间,有必要尽快从国家监管机构获得有关已收到货物单位的信息,其中一次交货的数量达到600,000,检查接受该产品到仓库的可接受性并将所有仓库自动化系统的必要信息。但是从仓库运输的强度要高得多,但同时需要处理少量数据。



我们根据无状态原则实施所有服务,甚至尝试使用我们称为Kafka自主题的方法将内部操作划分为多个步骤。这是微服务向自身发送消息时,它可以平衡负载以进行更多的资源密集型操作并简化产品维护,但稍后会进行更多说明。



我们决定将与外部系统交互的模块分离为单独的服务。这使得解决外部系统的API频繁更改的问题成为可能,而对具有业务功能的服务几乎没有影响。







所有微服务都部署在OpenShift集群中,这不仅解决了扩展每个微服务的问题,而且使我们不再使用第三方服务发现工具。



任务2:需要在平台服务之间维持高负载和非常密集的数据交换:仅在项目启动阶段,每秒执行约600次操作。随着交易对象连接到我们的平台,我们预计该值将增加至5000 op / sec。



通过部署Kafka集群并几乎完全放弃平台微服务之间的同步通信,解决了该任务。由于并非所有操作都可以异步进行,因此这需要对系统要求进行非常仔细的分析。同时,我们不仅通过代理传输事件,而且还在消息中传输所有必需的业务信息。因此,消息大小可能高达数百千字节。卡夫卡中消息数量的限制要求我们准确地预测消息的大小,并在必要时进行划分,但这种划分是合乎逻辑的,与业务运营相关。

例如,货物到达汽车后,我们将它们分成箱子。对于同步操作,将分配单独的微服务,并执行严格的负载测试。使用Kafka给我们带来了另一个挑战-通过Kafka集成测试我们的服务使我们所有的单元测试都是异步的。我们通过使用嵌入式Kafka Broker编写我们自己的实用方法来解决此问题。这并没有消除为单个方法编写单元测试的需要,但是我们更喜欢使用Kafka测试复杂的案例。



我们非常关注跟踪日志,以便在服务操作期间或使用Kafka批处理抛出异常时,不会丢失其TraceId。并且如果第一个没有特殊问题,则在第二种情况下,我们被迫将批处理所伴随的所有TraceId写入日志,然后选择一个继续跟踪。然后,当搜索初始TraceId时,用户将容易地找到跟踪继续跟踪哪个跟踪。



目标3.需要存储大量数据:仅X5每年就有超过10亿个烟草标签。他们需要持续且快速的访问。总共,该系统必须处理大约100亿条这些标记商品的运输历史记录。



为了解决第三个问题,选择了MongoDB NoSQL数据库。我们建立了一个由5个节点组成的碎片,并在每个节点中建立了3个服务器的副本集。这使您可以水平扩展系统,向群集添加新服务器,并确保其容错能力。在这里,我们面临另一个问题-考虑到水平可伸缩微服务的使用,确保mongo集群中的事务性。例如,我们系统的任务之一是检测使用相同标记代码转售商品的尝试。在这里,叠加层会出现错误的扫描或错误的收银员操作。我们发现,这样的重复项既可以在Kafka中处理的一个批次中发生,也可以在并行处理的两个批次中发生。因此,通过查询数据库检查重复项没有任何效果。对于每个微服务,我们根据该服务的业务逻辑分别解决了该问题。例如,对于收据,我们在批处理中添加了一张支票,并在插入时显示了重复项的外观的单独处理。



为了使具有操作历史记录的用户的工作不会影响最重要的事情-业务流程的功能,我们将所有历史数据分离到具有单独数据库的单独服务中,该数据库也通过Kafka接收信息。因此,用户可以使用隔离的服务,而不会影响处理当前操作数据的服务。



任务4.重新处理队列和监视:



在分布式系统中,不可避免地会出现数据库,队列和外部数据源可用性方面的问题和错误。就Markus而言,此类错误的根源是与外部系统的集成。必须找到一种解决方案,该解决方案允许在指定的超时时间内重复请求错误响应,但同时又不能停止在主队列中处理成功的请求。为此,选择了所谓的“基于主题的重试”概念。对于每个主要主题,都会创建一个或几个重试主题,向其发送错误消息,同时,消除了处理来自主要主题的消息的延迟。互动方案-







为了实现这样的方案,我们需要以下内容-将该解决方案与Spring集成在一起并避免代码重复。在庞大的网络中,我们遇到了一个基于Spring BeanPostProccessor的类似解决方案,但在我们看来,它不必要地麻烦。我们的团队制作了一个更简单的解决方案,使我们可以集成到Spring的使用者创建周期中,并添加Retry Consumers。我们向Spring团队提供了解决方案的原型,您可以在此处查看。重试使用者的数量和每个使用者的尝试次数是通过参数配置的,具体取决于业务流程的需求,对于所有正常工作,剩下的就是放置注释org.springframework.kafka.annotation.KafkaListener,这是所有Spring开发人员都熟悉的。



如果在所有重试尝试之后都无法处理该消息,则使用Spring DeadLetterPublishingRecoverer将其发送到DLT(死信主题)。应支持的要求,我们扩展了此功能并提供了单独的服务,该服务使您可以查看消息,stackTrace,traceId以及DLT中有关它们的其他有用信息。此外,监视和警报已添加到所有DLT主题,实际上,现在,在DLT主题中出现消息是解析和建立缺陷的原因。这非常方便-通过该主题的名称,我们可以立即了解问题出现在过程的哪一步,从而大大加快了寻找根本原因的速度。







最近,我们实现了一个接口,该接口允许我们在消除消息的原因(例如,恢复外部系统的可操作性)并确定相应的缺陷进行分析之后,通过我们的支持重新发送消息。这是我们的自我主题派上用场的地方,为了不重新启动较长的处理链,您可以从所需步骤重新启动。







平台运作



该平台已经投入生产,我们每天进行交货和运输,连接新的配送中心和商店。作为试验的一部分,该系统可与“烟草”和“鞋”类商品一起使用。



我们的整个团队都参与进行试点,分析新出现的问题并提出从改进日志到更改流程的改进我们产品的建议。



为了避免重蹈覆辙,我们在自动测试中反映了试点期间发现的所有情况。大量的自动测试和单元测试使您能够进行回归测试,并在短短几个小时内完成修补程序。



现在我们继续开发和完善我们的平台,并不断面临新的挑战。如果您有兴趣,我们将在以下文章中向您介绍我们的解决方案。



All Articles