七月下旬18篇大科技工程文摘

精选来自Netflix,Expedia,Airbnb,Flipkart等的文章!

1.Java 21虚拟线程-伙计,我的锁在哪里?"
Netflix10 min read 29 7月

  • 讨论作为向Java 21迁移的一部分采用虚拟线程
  • 描述Java 21中虚拟线程遇到的性能问题
  • 探讨该问题的症状,包括closeWait状态下的套接字数量增加
  • 分享线程转储的分析和锁定问题的识别

2.“如何使用IndexedDB创建假后端”
通过Andrey Ozornin米罗10 min read 22 7月

  • 讨论如何使用indexedDB作为应用程序演示版本的后端替代品
  • 探讨在浏览器中使用本地存储进行数据存储的限制
  • 介绍如何使用indexedDB作为在会话之间存储数据的更好替代方案
  • 介绍使用indexedDB创建假后端的分步过程

3.“吵闹的JIT制造商”
由Tomasz里切特阿莱格罗 26 min read 26 7月

  • 描述JIT编译器如何在基于Java的应用程序中导致性能问题
  • 探讨JIT编译器对应用程序启动时的CPU峰值和响应时间的影响
  • 共享用于识别问题的诊断工具,包括线程转储和火焰图

让我们把所有部分拼凑起来,看看应用程序中到底发生了什么。

  1. 我们启动应用程序。
  2. 我们允许 k8s 探测健康检查端点,并且在某些时候应用程序被标记为正在运行。
  3. 用户流量进入应用程序。
  4. 几秒钟内,JVM 决定重新编译代码的不同部分。
  5. 两个 C2 线程 100% 工作以按照 JVM 的指示重新编译代码。
  6. 当重新编译给定的函数时,线程只是等待重新编译的版本,从而消耗资源。
  7. 用户和 k8s 都不知道这个特定实例正在大量重新编译代码。在完成之前,它的响应可能会很慢。
  8. 应用程序会经历多次微冻结,直到大部分重新编译完成。

让我们尝试验证这一理论,并为 JIT 编译器添加更多“功能”。我们使用 -XX:CICompilerCount 标志将 C2 编译器的默认线程数从 2 移至 8。到目前为止,每次重启都会导致应用程序 SLA 大幅下降,而使用 8x 线程则速度明显加快。

通过进一步研究:

  • 我们发现在默认设置下,初始 C2 重新编译的主要部分大约需要 30 秒。在此期间,应用程序不符合 SLA。
  • 使用 8 个线程重新编译速度要快得多,现在我们大约需要 10 秒。

这是一个不错的进展,但这更像是一个理论验证和快速修复,而不是解决方案。

我们的目标是确保按时为用户提供服务。我们可以加快重新编译速度,但这并不能改变请求无法得到满足的短暂时间窗口这一事实。我们需要的是仅在重新编译代码中最热门的部分时才允许用户请求。问题是,如果我们不允许流量,如何触发重新编译?在这里,您可以利用 Spring 健康机制与 k8s 启动探测器相结合。

class WarmUpHealthIndicator(private val warmer: Warmer) : AbstractHealthIndicator() {

    override fun doHealthCheck(builder: Health.Builder) {
        val result = warmer.warmUpIfNeeded();
        if (warmer.isWarmedUp()) {
            builder.up()
        } else {
            builder.down()
        }

        builder.withDetail("total", result.total)
            .withDetail("success", result.success)
            .withDetail("failure", result.failure)
    }
}

K8s 将测试启动探测,一旦预热完成,它将打开应用程序以进行用户流量。剩下的就是在 Warmer 中生成一堆请求,然后就好了。

private fun warmUp() = try {
        log.info("Warm-up started")
        val stopwatch = Stopwatch.createStarted()
        callAllTasks(IntRange(1, warmUpProperties.numberOfRequests).map { _ -> callOnEndpoint() }.toList())
        val elapsed = stopwatch.stop().elapsed()
        warmedUp = true
        log.info(
            "Warm-up completed, took: {} ms, total: {}, success: {}, failure: {}",
            elapsed.toMillis(), total.get(), success.get(), failure.get()
        )
    } finally {
        result.set(Result(total = total.get(), success = success.get(), failure = failure.get()))
        executorService.shutdown()
    }


结果
我们发送了几百个请求,代码大量重新编译,为了确保速度,我们将默认 C2 数量从 2 个线程略微增加到 4 个线程(我们没有像上一章测试中那样保留 8 个线程 - 这对于预热来说没有多大意义)。

CPU 现在看起来符合预期,峰值不再占用 20/50 个核心。

最终我们的 SLA 是健康的,重启是完全透明的!

最后的想法
从一开始我们就知道我们的应用程序需要某种预热,但我们并不清楚这样做的原因。由于它有一些外部依赖项,我们预计它与 HTTP 客户端、连接建立、填充缓存等更相关。当然这是流程的一部分,但我们对 JIT 的发现让我们感到惊讶。引入预热和调整 JIT 带来了巨大的好处,因为最终新版本的任何重启对我们的用户都是完全透明的。

如果您的服务启动缓慢,我建议您检查它消耗了多少 CPU,如果您看到峰值,请制作火焰图或线程转储。


更多文摘:

4、“Node.js和工作线程的故事”

  • 在此之前,我一直在等待有关 Node.js 为何会杀死工作线程的线索,但线索始终未出现,事实证明,Node.js 只是在需要回收内存时开始杀死工作线程。
  • 当工作线程死亡时,它创建的套接字会意外挂断。它还很好地解释了活动服务中的读取超时错误,因为进程没有足够的时间(由于其 CPU 资源分配非常低)来读取翻译服务响应。
  • 不幸的是,我们无法轻易获得这些信息,因为活动服务没有检测其事件循环滞后,而事件循环滞后的退化是 API 调用读取超时的常见根本原因。


5、“与Playwright合作的端到端测试探针”

了解我们如何使用 Playwright 为 Zalando 网站设置可靠的自动化端到端测试探测
什么是自动化端到端测试?你需要它们吗?在这篇博文中,我们将深入探讨自动化端到端测试背后的丑陋之处、Zalando 遇到的困难、对我们有效的方法以及我们最新的端到端测试探测解决方案。


6、“如何从DynamoDB中删除旧数据而无需花费数千美元”

旧方法是编写一个脚本来扫描您的数据库并删除不再有用的项目(例如,非常旧的数据)。
问题:使用 Dynamo DB 的成本可能非常高,可能需要几年的时间才能收回成本……

  • 由于旧数据而导致DynamoDB中存储成本高的问题
  • 探讨了将所需数据迁移到新表并删除旧数据的解决方案
  • 介绍用于估算不同清理方案成本的工具
  • 完成处理传入数据和清除表中现有项的过程
  • 分享三种可能的前进道路,并对每个选项进行成本估算


7、“爱马仕:Swiggy的文本到SQL解决方案”

  • 爱马仕是Swiggy开发的一个基于人工智能的工作流,用于在Slack中生成SQL查询并接收结果。
  • 爱马仕V1是使用LLM的简单实现,但V2通过合并中间件和Gen AI模型改进了数据流。
  • 知识库由元数据组成,元数据提供有关数据的基本上下文,帮助模型生成准确的SQL查询。
  • Swiggy的数百名用户正在利用爱马仕执行任务,例如获得尺寸数字,进行深入研究以及在分析期间回答特定问题。
  • 爱马仕的V2迭代对于具有定义良好的元数据的章程的表现明显更好,这证实了单独处理每个章程的必要性。


8、“实时数据传输:RDS到DynamoDB变得简单”

  • 描述将数据迁移到新DynamoDB数据库的过程
  • 讨论在迁移过程中维护最终一致性的挑战
  • 介绍处理新旧系统之间潜在ID冲突的策略
  • 探讨迁移的成本和执行时间注意事项

9、“解决慢哈希表之谜”

  • 描述Java应用程序中慢速哈希表的案例研究
  • 揭示了哈希冲突导致二次时间复杂度的问题
  • 分享故障排除过程和基准测试结果
  • 介绍消除哈希冲突和改进运行时的修复程序

10、排名平台背后的工程Booking.com|系统概述

  • 探索Ranking平台的架构、其在个性化搜索结果中的作用及其在更广泛的生态系统中的地位
  • 概述模型创建和部署过程,包括静态和动态特性的使用
  • 分享排名生态系统的扩展视图,突出可用性搜索引擎和排名平台之间的交互
  • 描述大规模运行排名系统的技术挑战,包括性能优化和模型推理
  • 涵盖用于解决这些挑战的策略,例如回退到静态分数、多阶段排名和模型推理优化

11、“在Pinterest提供更快的分析”

  • 本文讨论了从Druid迁移到StarRocks以获得Pinterest实时见解的决定。
  • Pinterest由于规模和要求的增加而需要一个新系统。
  • 新系统的要求,包括成本效益,SQL支持和摄取管道简化,解释。
  • StarRocks是作为所选解决方案引入的,它具有SQL支持、摄取功能和性能改进的优点。

12、“片状测试?检查您的FactoryBot ID”

  • 描述FactoryBot ID如何导致非确定性的重复测试
  • 在FactoryBot中管理数据库、UUID和外键ID
  • 解释如何使用序列定义没有约束的ID
  • 涵盖测试中排序的潜在问题以及如何解决这些问题

13、Maestro:Netflix的工作流程协调器

  • 推出Maestro,这是一款水平可扩展的工作流编排器,旨在管理大规模数据/ML工作流
  • 讨论与Maestro的合作历程,包括其无缝过渡和处理不断增长的工作负载的能力
  • 描述Maestro的可扩展性和多功能性,支持各种工作流用例并管理大量工作流和作业
  • 探索Maestro的功能,包括工作流运行策略、参数和表达式语言支持、工作流执行模式、步骤配置和步骤参数、步骤配置和信号、配置策略、聚合视图、汇总和Maestro事件发布

14、扩展视野: 应对 Wix 扩展挑战的有效策略

  • 探讨使用垂直和水平扩展选项扩展服务和数据库的挑战
  • 讨论了垂直缩放的局限性和向水平缩放的转变
  • 概述了用于高效数据管理的固定和动态路由和分片策略
  • 介绍Wix针对Kafka基础设施服务、Web流量管理、Reactions应用程序和企业客户数据本地化的扩展示例和解决方案

15、“防御LLM攻击:通过5个基本要素保护集成并降低风险”

  • 讨论确保LLM集成和降低风险的策略
  • 承认LLM API的可访问性,并强调需要严格的访问控制
  • 建议在处理敏感数据时谨慎行事,并建议实施可靠的清理技术
  • 强调了单纯依靠提示阻止攻击的局限性,并建议辅以其他安全措施
  • 鼓励多层次的安全方法,包括持续监控和审计、网络安全措施和数据加密,以加强对各种攻击媒介的防御。

16、“使用微前端解决碎片化UI”

  • 讨论在不同应用程序之间维护内聚UI的挑战
  • 描述采用微前端来解决复杂性、维护、部署和团队自主性等问题
  • 介绍了Podium微前端实现的体系结构和页面渲染流程
  • 解释微前端环境中的样式挑战和解决方案
  • 分享迁移到微前端的好处,例如降低破坏更改的风险、解耦代码库、独立部署以及改进团队自治和协作

17、“GenAI实验:监控和维护Kubernetes集群健康”

  • 讨论在观察和调试Intuit的325多个Kubernetes集群时遇到的挑战
  • 介绍使用Prometheus改进检测的聚类黄金信号
  • 介绍如何使用k8sgpt通过提取实时群集信息并使用AI进行分析来进行更深入的调试
  • 介绍使用公共和私有模型集成GenAI进行补救

18、认识我们的可扩展、一致的元数据缓存解决方案Chrono

  • 本文讨论了一致性缓存的挑战以及对可伸缩的一致性缓存解决方案的需求。
  • 它描述了Chrono的开发,Chrono是一个构建在键值存储系统Panda之上的可扩展、一致的缓存系统。
  • Chrono提供写路径和读路径的API,保证缓存数据的一致性。
  • 本文解释了Chrono的工作原理,并提供了一个具体的实现示例。
  • 它强调了使用TLA+和自检工作负载来验证缓存协议的正确性。