重新思考:Netflix 的边缘负载均衡
声明
本文是对Netflix 博客的翻译
前言
在先前关于Zuul 2开源的文章中,我们简要概述了近期在负载均衡方面的一些工作。在这篇文章中,我们将更详细地介绍这项工作的原因、方法和结果。
因此,我们开始从Zuul和其他团队那里学习,并改进我们的负载均衡实现,以进一步减少由服务器过载引起的错误。
背景
在Zuul的实现中,我们持续采用Ribbon负载均衡器,它运用轮询算法和过滤机制,以识别并隔离连接失败率高的服务器。
多年来,我们经历了一些改进和定制,旨在向最近启动的服务器发送更少的流量,以避免它们过载。这些方法已经取得了显著的改进,但是对于一些特别麻烦的源集群,我们仍然会看到与负载相关的错误率比期望的要高得多。
如果集群中的所有服务器都过载,那么我们在选择一个服务器而不是另一个服务器时几乎没有什么改进,但是我们经常看到只有一部分服务器过载的情况。例如:
- 启动后的冷服务器(在红黑部署和自动伸缩事件期间)
- 由于交错的动态属性/脚本/数据更新或大型GC事件,服务器暂时变慢/阻塞。
- 服务器硬件不好。我们经常会看到一些服务器的运行速度永远比其他服务器慢,这可能是由于邻居的噪音或不同的硬件。
指导原则
项目启动之初,确立一些核心原则至关重要,它们将引导我们在软件开发过程中做出明智的决策。
在现有负载均衡器框架的约束下工作
我们将之前的负载均衡定义与Zuul代码库相结合,这使得我们无法与Netflix的其他团队共享这些功能。所以这次我们决定接受约束和额外的投资,并从一开始就考虑重用。这使得在其他系统中的采用更加直接,并减少了重新发明轮子的机会。
运用从别人那里学到的东西
尝试在别人的想法和实现的基础上进行构建。例如,之前在Netflix在其他IPC堆栈中试用的choice-of-2和试用算法。
避免分布式状态
更倾向于局部决策,以避免弹性问题、复杂性和跨集群协调状态的滞后。
避免客户端配置和手动调优
我们多年来使用Zuul的操作经验表明,将服务配置的一部分置于不属于同一团队的客户端服务中……会导致问题。
一个问题是,这些客户端配置往往与服务器端不断变化的现实不同步,或者在不同团队拥有的服务之间引入变更管理的耦合
例如,升级了用于Service X的EC2实例类型,从而减少了该集群所需的节点。因此,现在Service Y中的“每台主机的最大连接数”客户端配置应该增加,以反映新增加的容量。应该先进行客户端更改,还是先进行服务器端更改,还是同时进行两者的更改?更有可能的是,设置被完全遗忘,导致更多的问题。
在可能的情况下,不要配置静态阈值,而是使用根据当前流量、性能和环境变化的自适应机制。
负载均衡方法
一个核心理念是,尽管客户端视角是获取服务器延迟信息的最佳途径,但服务器本身则是提供服务器利用率信息的最佳来源。结合这两个数据源应该会给我们带来最有效的负载均衡。
我们使用了相互补充的机制组合,其中大多数已经被其他人开发和使用过,尽管以前可能没有以这种方式组合。
- 在服务器之间进行选择的二选一(choice-of-2 algorithm)算法
- 主要根据负载均衡器对服务器利用率的视图进行均衡
- 其次,根据服务器的利用率视图进行均衡
- 基于缓慢释放流量和服务器生命周期的机制,以避免新启动的服务器过载 - 避免刚启动的服务突然接受流量洪峰顶不住
- 收集到的服务器指标随时间衰减为零 - 服务指标衰减是为了避免指标差的服务永远得不到请求的机会
将最短队列加入与服务器报告的利用率相结合
我们决定采用广泛使用的最短队列连接(JSQ)算法,并结合基于服务器自报利用率的算法,以期达到两者优势的融合。
加入最短队列对于单个负载均衡器非常有效,但如果是在集群中的负载均衡,则会出现严重问题。问题是,负载均衡器将倾向于惊群(Herd),并同时选择相同的低利用率服务器,从而使它们过载,然后转移到下一个利用率最低的服务器并使其过载,然后继续……
这可以通过结合使用JSQ和choice-of-2算法来解决。这在很大程度上消除了“**惊群”**问题,除了每个负载均衡器没有完整的服务器利用率之外,它工作得很好。
JSQ通常通过仅从本地负载均衡器计算到服务器的正在使用的连接数来实现,但是当有10到100个负载均衡器节点时,本地视图可能会产生误导。
例如在上图中,负载均衡器A有一个流量请求服务X和Z,但是没有请求到Y。当有一个新的请求到来时他应该请求哪个服务,从数据上看应该选择Y。但这是不正确的,实际上其他两个负载均衡器正在请求他,他已经利用率最大了,但是负载均衡器A没法知道。
这说明了单个负载均衡器的视角如何与实际情况完全不同
我们在只依赖客户端视图时遇到的另一个问题是,对于大型集群(特别是在低流量的情况下),负载均衡器通常只有几个正在使用的连接,连接到数百个池中的服务器子集。因此,当它选择哪个服务器负载最少时,它通常只能在零和零之间进行选择。它没有任何关于它所选择的服务器的利用率的数据,因此只能随机猜测。
这个问题的一个解决方案可能是与所有其他负载均衡器共享每个负载均衡器的进行中的请求数量,但这样你就有一个分布式状态问题需要解决。
我们通常将分布式可变状态作为最后的手段,因为所获得的价值需要超过所涉及的实质性成本:
- 操作开销和复杂性会增加,比如部署和金丝雀发布
- 与数据损坏的爆炸半径相关的弹性风险(即 1% 的负载均衡器上的坏数据会令人烦恼,100% 的负载均衡器上的坏数据会导致中断
- 在负载均衡器之间实现P2P分布式状态系统的成本,或者操作具有处理大量读写流量所需的性能和弹性凭证的单独数据库的成本。
另一种更简单的解决方案——也是我们选择的一种——是依赖服务器向每个负载均衡器报告它们的使用情况……
利用率
采用每台服务器对其利用率的自我评估的优势在于,它汇总了所有负载均衡器对该服务器的使用情况,从而解决了JSQ算法可能存在的信息不全面问题。
我们可以通过两种方式实现这一点:
- 使用运行状况检查端点主动轮询每个服务器的当前利用率。
- 被动地跟踪带有当前利用率数据注释的服务器的响应
我们选择了第二个选项,因为它很简单,允许频繁更新这些数据,并且避免了让N个负载均衡器每隔几秒钟轮询M个服务器而给服务器带来的额外负载。
这种被动策略的一个影响是,负载均衡器向一台服务器发送请求的频率越高,它对该服务器利用率的看法就越最新。所以RPS越高,负载均衡的效率就越高。但反过来说,RPS越低,负载均衡的效果就越差。
这对我们来说不是问题,但对于通过一个特定负载均衡器接收低RPS的服务(同时通过另一个单独的负载均衡器接收高RPS),主动轮询运行状况检查可能更有效。临界点是负载均衡器向每个服务器发送的RPS低于用于运行状况检查的轮询频率。
服务器实现
我们在服务器端实现了这一点,通过简单地跟踪进行中的计数,将其转换为该服务器配置的最大值的百分比,并将其作为HTTP响应头写出来:
X-Netflix.server.utilization: <current-utilization>[, target=<target-utilization>]
可选的目标利用率可以由服务器指定,以指示它们在正常条件下打算使用的利用率百分比。然后,负载均衡器将使用它进行一些粗粒度的过滤,如后面所述。
我们尝试使用进行中请求以外的指标,如操作系统报告的cpu利用率和平均负载,但发现它们似乎会引起振荡,这是由于它们基于滚动平均值而引起的延迟。因此,我们决定现在只使用计算飞行请求的相对简单的实现。
Choice-of-2 算法代替轮循
由于我们希望能够通过比较服务器的统计信息来选择服务器,因此必须放弃现有的简单循环实现。
在Ribbon中,我们尝试了将JSQ与ServerListSubsetFilter结合的另一种方案,目的是减轻分布式JSQ可能导致的惊群问题。这给出了合理的结果,但是最终的跨目标服务器的请求分布仍然太广。
因此,我们转而应用了Netflix另一个团队的一些早期经验,并实现了“二选一”算法。这样做的优点是易于实现,使负载均衡器上的cpu成本保持在较低水平,并提供良好的请求分发。
根据综合因素选择
在选择服务器时,我们依据三个独立因素对它们进行评估:
- 客户端运行状况:该服务器的连接错误率的滚动百分比。
- 服务器利用率:该服务器提供的最新分数。
- 客户端利用率:从此负载均衡器发送到该服务器的当前请求数。
这3个因素被用来为每个服务器分配分数,然后比较总分数来选择获胜者。
使用像这样的多个因素确实会使实现变得更加复杂,但它可以避免仅依赖一个因素可能出现的边缘情况问题。
例如,如果一台服务器开始出现故障并拒绝所有请求,那么报告的利用率将会低得多——因为拒绝请求比接受请求快——如果仅有一个评判因子,那么所有负载均衡器将开始向该故障服务器发送更多请求。客户机综合选择因素缓解了这种情况。
过滤
在随机挑选两台服务器进行比较的过程中,我们将排除那些利用率和运行状况超出我们设定的保守阈值的服务器。
此过滤针对每个请求执行,以避免仅定期过滤的过时问题。为了避免在负载均衡器上造成高cpu负载,我们只尽最大努力进行N次尝试,以找到一个随机选择的可行服务器,然后在必要时退回到未过滤的服务器。
当大部分服务器池存在持续的问题时,这样的过滤非常有用。在这种情况下,随机选择2个服务器经常会导致选择2个坏服务器进行比较,即使有许多好的服务器可用。
缓慢释放
对于负载均衡器尚未收到响应的任何服务器,我们一次只允许一个进行中请求。我们过滤掉这些试用中的服务器,直到从它们那里收到响应。
这有助于避免在新启动的服务器有机会表明它们的利用情况之前,因为大量的请求而使服务器过载。
基于服务器生命周期的预热
我们依据服务器的生命周期,在新服务器启动后的最初90秒内,逐步增加其接收的流量。
统计衰变
为避免服务器被永久性地列入黑名单,我们对所有用于负载均衡决策的统计数据实施了衰减机制(目前设定为超过30秒的线性衰减)。例如,如果服务器的错误率上升到80%,我们停止向它发送流量,那么我们使用的值将在30秒内衰减到零(即。15秒后会变成40%)。
操作的影响
放弃使用轮询来实现负载均衡的一个负面影响是,以前我们在集群中的服务器之间有一个非常紧密的请求分布,现在我们在服务器之间得到了更大的增量。
使用choice-of-2算法有助于减轻这种情况(与跨集群中所有服务器或服务器子集的JSQ相比),但不可能完全避免这种情况。
因此,在操作方面确实需要考虑到这一点,特别是在金丝雀分析中,我们通常会比较请求计数、错误率、cpu等的绝对值。
较慢的服务器接收较少的流量
显然,这是预期的效果,但对于使用 round-robin 的团队来说,流量是平均分配的,这对操作方面有一些连锁反应。
由于源服务器之间的流量分布现在取决于它们的利用率,如果一些服务器正在运行效率更高或更低的不同版本,那么它们将接收或多或少的流量。所以:
- 当集群进行红黑部署时,如果新的服务器组有性能退化,那么该组的流量比例将小于50%
- 同样的效果也可以在金丝雀上看到——基线可能接收到与金丝雀集群不同的流量。所以在查看参数时,最好将RPS和CPU结合在一起(游戏邦注:例如RPS在金丝雀中较低,而CPU则相同)
- 不太有效的异常检测——我们通常有自动化来监视集群内的异常服务器(通常是由于某些硬件问题而从启动开始就变慢的VM)并终止它们。当这些异常值由于负载均衡而接收到较少的流量时,这种检测就更加困难
滚动动态数据更新
从 round-robin 到这个新的负载均衡器的有用效果是,它可以很好地与动态数据和属性的分阶段推出一起工作。
我们的最佳实践是一次部署一个区域(数据中心)的数据更新,以限制意外问题的影响范围。
即使没有数据更新本身引起的任何问题,服务器应用更新的行为也可能导致短暂的负载峰值(通常与GC相关)。如果此峰值同时发生在集群中的所有服务器上,则可能导致负载减少和错误向上游传播的大峰值。在这种情况下,负载均衡器几乎无能为力,因为所有服务器都在承受高负载。
综合负载测试结果
在开发、测试和调优这个负载均衡器的不同方面时,我们广泛地使用了综合负载测试场景。这些对于验证真实集群和网络的有效性非常有用,作为单元测试之上的可重复步骤,但尚未使用真实的用户流量。
关于这个测试的更多细节将在后面的附录中列出,但总结一下要点:
- 与轮循实现相比,启用了所有特性的新负载均衡器在负载减少和连接错误方面有了数量级的减少。
- 在平均和长尾延迟方面有了实质性的改进(与轮询实现相比减少了3倍)。
- 服务器利用率特性本身的添加增加了显著的价值,提供了一个数量级的错误减少和大部分延迟减少。
对实际生产流量的影响
我们发现新的负载均衡器在将尽可能多的流量分配到每个源服务器上时非常有效。这在不需要任何人工干预的情况下,可以绕过间歇性和持续降级的服务器进行路由,从而避免了导致工程师在半夜被唤醒的重大生产问题。
在正常运行期间,很难说明这种影响,但在生产事件期间,甚至在某些服务的正常稳态运行期间,都可以看到这种影响。
进行中事件
最近的一个事件涉及到服务中的一个bug,该bug导致越来越多的服务器线程随着时间的推移而阻塞。从服务器启动开始,每小时会有几个线程阻塞,直到它最终达到最大值并释放负载。
在下面的每台服务器的RPS图表中,您可以看到,在凌晨3点之前,服务器之间存在广泛的分布。这是由于阻塞线程数量较多的服务器通过负载均衡器发送的流量较少。然后在凌晨3点25分之后,自动伸缩开始启动更多的服务器,每个服务器的RPS大约是现有服务器的两倍——因为它们还没有任何阻塞的线程,因此可以成功处理更多的流量。
现在,如果我们看一下同一时间范围内每台服务器的错误率图表,您可以看到,在整个事件过程中,所有服务器的错误分布是相当均匀的,尽管我们知道有些服务器的容量比其他服务器小得多。这表明负载均衡器在有效地工作,并且由于集群中的总体可用容量太少,所有服务器的负载都略微超过了它们的有效容量。
然后,当自动扩展启动新服务器时,它们会被发送尽可能多的流量,直到它们与集群的其他服务器在相同的低水平上出错。
总之,负载均衡在将流量分配给服务器方面非常有效,但在本例中,没有足够多的新服务器启动,因此无法将总体错误级别降至零。
稳态
我们还看到,在一些服务器的服务中,由于GC事件而出现几秒钟的负载下降,仅在稳态噪声方面就有了显著的减少。在启用新的负载均衡器后,可以看到错误大大减少:
警告间隙
一个意想不到的影响是突出了我们自动警报中的一些漏洞。一些现有的基于服务错误率的警报,以前会在渐进问题只影响集群的一小部分时触发,现在会延迟触发,或者根本不会触发,因为错误率保持在较低水平。这意味着团队有时没有收到影响其集群的大问题的通知。解决方案是通过在利用率指标中添加额外的偏差警报(而不仅仅是错误指标)来填补这些差距。
结论
本文的主旨不在于推广Zuul——尽管它无疑是一个卓越的系统——而是在于与代理、服务网格、负载均衡社区分享经验,为其中那些引人入胜的方法增添新的视角。Zuul是测试、实现和改进这些类型的负载均衡方案的好系统;根据Netflix的需求和规模来运行它们,使我们有能力证明和改进这些方法。
与任何软件系统一样,您应该根据自己组织的约束条件和目标做出决策,并尽量避免追求完美。
如果你对这类工作感兴趣,请随时联系我或我们Netflix的云网关团队。
Reference
- 原文链接
相关文章:

重新思考:Netflix 的边缘负载均衡
声明 本文是对Netflix 博客的翻译 前言 在先前关于Zuul 2开源的文章中,我们简要概述了近期在负载均衡方面的一些工作。在这篇文章中,我们将更详细地介绍这项工作的原因、方法和结果。 因此,我们开始从Zuul和其他团队那里学习&#…...

元组的创建和删除
目录 使用赋值运算符直接创建元组 创建空元组 创建数值元组 删除元组 自学python如何成为大佬(目录):https://blog.csdn.net/weixin_67859959/article/details/139049996?spm1001.2014.3001.5501 元组(tuple)是Python中另一个重要的序列结构&#…...
CSS3用户界面
用户界面 appearance appearance 属性用于控制元素是否采用用户代理(浏览器)的默认样式(外观) element {appearance: auto | none;}auto(默认):元素采用浏览器提供的默认样式。none:元素不采用任何默认样式,显示为“裸”元素,通常表现为无特定样式的简单框。input[…...

STL源码刨析:序列式容器之vector
目录 1.序列式容器和关联式容器 2.vector的定义和结构 3.vector的构造函数和析构函数的实现 4.vector的数据结构以及实现源码 5.vector的元素操作 前言 本系列将重点对STL中的容器进行讲解,而在容器的分类中,我们将容器分为序列式容器和关联式容器。本章…...
Flutter 中的 AbsorbPointer 小部件:全面指南
Flutter 中的 AbsorbPointer 小部件:全面指南 在Flutter中,AbsorbPointer是一个特殊的小部件,用于吸收(或“吞噬”)所有传递到其子组件的指针事件(如触摸或鼠标点击)。这在某些情况下非常有用&…...

Web开发学习总结
学习路线 Web 全球广域网,也称为万维网(www World Wide Web),能够通过浏览器访问的网站 初识Web前端 Web标准也称为网页标准,由一系列的标准组成,大部分由W3C(World Wide Web Consortium,万维网联盟)负责制定。三个组…...
springboot相关知识集锦----1
一、springboot是什么? springboot是一个用于构建基于spring框架的独立应用程序的框架。它采用自动配置的原则,以减少开发人员在搭建应用方面的时间和精力。同时提升系统的可维护性和可扩展性。 二、springboot的优点 约定优于配置 版本锁定…...

App推广新境界:Xinstall助你轻松突破运营痛点,实现用户快速增长!
在移动互联网时代,App已经成为企业营销不可或缺的一部分。然而,如何有效地推广App,吸引并留住用户,成为了众多企业面临的难题。今天,我们将为您揭秘一款神奇的App推广工具——Xinstall,它将助您轻松突破运营…...

YOLOv10 论文学习
论文链接:https://arxiv.org/pdf/2405.14458 代码链接:https://github.com/THU-MIG/yolov10 解决了什么问题? 实时目标检测是计算机视觉领域的研究焦点,目的是以较低的延迟准确地预测图像中各物体的类别和坐标。它广泛应用于自动…...

[Spring Boot]baomidou 多数据源
文章目录 简述本文涉及代码已开源 项目配置pom引入baomidouyml增加dynamic配置启动类增加注解配置结束 业务调用注解DS()TransactionalDSTransactional自定义数据源注解MySQL2 测试调用查询接口单数据源事务测试多数据源事务如果依然使用Transactional会怎样?测试正…...

Drone+Gitee自动执行构建、测试和发布工作流
拉取Drone:(至于版本,你可以下载最新的) sudo docker pull drone/drone:2 拉取runner: sudo docker pull drone/drone-runner-docker 在Gitee中添加第三方应用: 进入个人主页,点击设置: 往下翻,找到数…...
Unity3D MMORPG 主城角色动画控制与消息触发详解
Unity3D是一款强大的游戏开发引擎,它提供了丰富的功能和工具,使开发者能够轻松创建出高质量的游戏。其中,角色动画控制和消息触发是游戏开发中非常重要的一部分,它们可以让游戏角色表现出更加生动和多样的动作,同时也能…...

【Text2SQL 经典模型】HydraNet
论文:Hybrid Ranking Network for Text-to-SQL ⭐⭐⭐ arXiv:2008.04759 HydraNet 也是利用 PLM 来生成 question 和 table schema 的 representation 并用于生成 SQL,并在 SQLova 和 X-SQL 做了改进,提升了在 WikiSQL 上的表现。 一、Intro…...

Mysql-根据字段名查询字段在哪些表里
SELECT * FROM information_schema.COLUMNS WHERE COLUMN_NAMElabel_name;...
牛逼!50.3K Star!一个自动将屏幕截图转换为代码的开源工具
1、背景 在当今快节奏的软件开发环境中,设计师与开发者之间的协同工作显得尤为重要。然而,理解并准确实现设计稿的意图常常需要耗费大量的时间和沟通成本。为此,开源社区中出现了一个引人注目的项目——screenshot-to-code,它利用…...

八种单例模式
文章目录 1.单例模式基本介绍1.介绍2.单例模式八种方式 2.饿汉式(静态常量,推荐)1.基本步骤1.构造器私有化(防止new)2.类的内部创建对象3.向外暴露一个静态的公共方法 2.代码实现3.优缺点分析 3.饿汉式(静态…...

禅道密码正确但是登录异常处理
禅道密码正确,但是登录提示密码错误的异常处理 排查内容 # 1、服务器异常,存储空间、数据库异常 # 2、服务异常,文件丢失等异常问题定位 # 1、df -h 排查服务器存储空间 # 2、根据my.php排查数据库连接是否正常 # 3、修改my.pho,debugtrue…...

Go微服务: Nacos的搭建和基础API的使用
Nacos 概述 文档:https://nacos.io/docs/latest/what-is-nacos/搭建:https://nacos.io/docs/latest/quickstart/quick-start-docker/有很多种搭建方式,我们这里使用 docker 来搭建 Nacos 的搭建 这里,我们选择单机模式…...
基于Hadoop的城市公共交通大数据时空分析
基于Hadoop的城市公共交通大数据时空分析 “Spatio-temporal Analysis of Urban Public Transportation Big Data based on Hadoop” 完整下载链接:基于Hadoop的城市公共交通大数据时空分析 文章目录 基于Hadoop的城市公共交通大数据时空分析摘要第一章 引言1.1 研究背景1.2 …...

DNS服务的部署与配置(2)
1、dns的安装及开启 dnf install bind.x86_64 -y #安装 #Berkeley Internet Name Domain (BIND) systemctl enable --now named #启用dns服务,服务名称叫named firewall-cmd --permanent --add-servicedns #火墙设置 firewall-cmd --reload …...
云原生核心技术 (7/12): K8s 核心概念白话解读(上):Pod 和 Deployment 究竟是什么?
大家好,欢迎来到《云原生核心技术》系列的第七篇! 在上一篇,我们成功地使用 Minikube 或 kind 在自己的电脑上搭建起了一个迷你但功能完备的 Kubernetes 集群。现在,我们就像一个拥有了一块崭新数字土地的农场主,是时…...
R语言AI模型部署方案:精准离线运行详解
R语言AI模型部署方案:精准离线运行详解 一、项目概述 本文将构建一个完整的R语言AI部署解决方案,实现鸢尾花分类模型的训练、保存、离线部署和预测功能。核心特点: 100%离线运行能力自包含环境依赖生产级错误处理跨平台兼容性模型版本管理# 文件结构说明 Iris_AI_Deployme…...
MySQL 隔离级别:脏读、幻读及不可重复读的原理与示例
一、MySQL 隔离级别 MySQL 提供了四种隔离级别,用于控制事务之间的并发访问以及数据的可见性,不同隔离级别对脏读、幻读、不可重复读这几种并发数据问题有着不同的处理方式,具体如下: 隔离级别脏读不可重复读幻读性能特点及锁机制读未提交(READ UNCOMMITTED)允许出现允许…...

LeetCode - 394. 字符串解码
题目 394. 字符串解码 - 力扣(LeetCode) 思路 使用两个栈:一个存储重复次数,一个存储字符串 遍历输入字符串: 数字处理:遇到数字时,累积计算重复次数左括号处理:保存当前状态&a…...
python爬虫:Newspaper3k 的详细使用(好用的新闻网站文章抓取和解析的Python库)
更多内容请见: 爬虫和逆向教程-专栏介绍和目录 文章目录 一、Newspaper3k 概述1.1 Newspaper3k 介绍1.2 主要功能1.3 典型应用场景1.4 安装二、基本用法2.2 提取单篇文章的内容2.2 处理多篇文档三、高级选项3.1 自定义配置3.2 分析文章情感四、实战案例4.1 构建新闻摘要聚合器…...
Linux云原生安全:零信任架构与机密计算
Linux云原生安全:零信任架构与机密计算 构建坚不可摧的云原生防御体系 引言:云原生安全的范式革命 随着云原生技术的普及,安全边界正在从传统的网络边界向工作负载内部转移。Gartner预测,到2025年,零信任架构将成为超…...

Python爬虫(一):爬虫伪装
一、网站防爬机制概述 在当今互联网环境中,具有一定规模或盈利性质的网站几乎都实施了各种防爬措施。这些措施主要分为两大类: 身份验证机制:直接将未经授权的爬虫阻挡在外反爬技术体系:通过各种技术手段增加爬虫获取数据的难度…...

C++ 求圆面积的程序(Program to find area of a circle)
给定半径r,求圆的面积。圆的面积应精确到小数点后5位。 例子: 输入:r 5 输出:78.53982 解释:由于面积 PI * r * r 3.14159265358979323846 * 5 * 5 78.53982,因为我们只保留小数点后 5 位数字。 输…...

AI,如何重构理解、匹配与决策?
AI 时代,我们如何理解消费? 作者|王彬 封面|Unplash 人们通过信息理解世界。 曾几何时,PC 与移动互联网重塑了人们的购物路径:信息变得唾手可得,商品决策变得高度依赖内容。 但 AI 时代的来…...

推荐 github 项目:GeminiImageApp(图片生成方向,可以做一定的素材)
推荐 github 项目:GeminiImageApp(图片生成方向,可以做一定的素材) 这个项目能干嘛? 使用 gemini 2.0 的 api 和 google 其他的 api 来做衍生处理 简化和优化了文生图和图生图的行为(我的最主要) 并且有一些目标检测和切割(我用不到) 视频和 imagefx 因为没 a…...