Soul 是基于兴趣图谱和游戏化玩法的产品设计,属于新一代年轻人的虚拟社交网络。成立于2016年,Soul 致力于打造一个“年轻人的社交元宇宙”,最终愿景是“让天下没有孤独的人”。在 Soul,用户可以无顾虑地表达自己,认知他人,探索世界,交流兴趣和观点,获得精神共鸣和认同感,在交流中获取信息,并获得有质量的新关系。

Soul 在 2020 年开始逐渐试探容器服务,在 ECS 转型容器阶段,出现了容器入口网关(Ingress-Nginx),微服务网关,加上统一接入层的 SLB+Tengine;造成了多重网关的架构;链路太长不仅带来成本和 RT 的问题,而且导致排查一个请求异常,需要拉非常多的人解决,定位问题代价非常大。
今年 Ingress-Nginx 社区反馈稳定性和安全问题比较多,暂时停止接收新功能,对 Soul 是一个巨大隐患。


1.由于业务的不确定性,随着业务请求的波动,nginx ingress controller 会出现连接数突增,导致 ingress controller 健康检查不通过;nginx ingress controller上游的检测需要时间及 fail 次数积累,导致这一阶段用户请求大量失败或重试。(如下图)

2.HTTP 路由仅支持 host 和 path 匹配,对于高级路由功能没有通用配置,只能通过 annotation 来实现,比如使用 Nginx Ingress Controller 实现 URL 重定向,需要配置 http://nginx.ingress.kubernetes.io/rewrite-target annotation 已无法适应可编程路由的需求。
3.不同命名空间中的服务要绑定到同一个网关中的情况在实际情况下经常出现,而入口网关无法在多个命名空间中共享;这样就增加 Ingress-Nginx 及 Ingress-Controller的拆分难度。
由于开源 Ingress-Nginx 遇到比较多的问题,由于线上流量巨大难以定位和解决概率超时问题,因此我们考虑投入更多研发人员解决这个问题,还是选择 Envoy 网关解决,还是选择阿里云 ASM、MSE 云原生网关两个产品,因此我们针对这三个新技术方向做了全面评估。

综上所述, Envoy 已是现阶段数据面较好的选择(可以解决现有nginx ingress controller的性能和稳定性问题),由于性能要求比较高,因此我们优先做了性能压测。
我们通过对线上服务三种不同方案的压测数据对比(SLB+Envo+headless svc、ALB、MSE),主要测试性能和 gRPC 负载均衡能力两方面;压测数据显示,MSE 云原生网关在 RT 和成功率上均有优势,并且能满足 Soul gRPC 的转发需要;那 MSE 是否能满足 Soul 所有业务需求呢?是否能解决最大集群超时问题呢?因此我们对 MSE 进行了更全面的评估。






Soul 的网关链路比较长,解决最紧迫超时问题、服务发布预热问题,因此第一期先替换Ingress-Nginx,并将容器入口网关/微服务网关合并;

将网关链路降为最短;下线微服务网关,将http转发rpc能力托管MSE;下线Tengine,将 ECS 转发能力托管在 MSE;最终实现 SLB->MSE->POD/ECS04

MSE 切换后处理及响应请求时间平稳,从峰值 500ms 下降至峰值 50ms

Ingress-Nginx 与 MSE 错误码对比,服务发布期间 502 降为 0,499 平均降低 10%;

落地解决了大部分超时问题,但是启动慢 Java 程序发布超时问题还没解决,因此我们开启服务预热功能,业务启动逐步打流量过来,防止大量流量打到刚启动 Java 进程超时。
开启预热效果:从图中可以看出,Pod 在刚刚启动后,并没有瞬间接收到全量,而是在 5 分钟的时间里逐渐预热服务,这一点在服务 http 入口请求数量,Pod 网络进出流量,Pod CPU 使用率均可以看到;Nginx 需要自己从底层到上层的各种监控,采用云原生网关后,提供一站式观测视图,提供丰富网关 prometheus 指标,方便观测和解决复杂问题。


1. 随着MSE 的落地,可以看到链路明显缩短,问题排查及运维工作大大减少
2. 替代业务网关,Http转Dubbo能力的抽象,大大减少了研发及运维工作量3. 稳定性及平滑迁移方案完善,可以做到真正的开箱即用
本文为阿里云原创内容,未经允许不得转载。
很好奇,就使用rubyonrails自动化单元测试而言,你们正在做什么?您是否创建了一个脚本来在cron中运行rake作业并将结果邮寄给您?git中的预提交Hook?只是手动调用?我完全理解测试,但想知道在错误发生之前捕获错误的最佳实践是什么。让我们理所当然地认为测试本身是完美无缺的,并且可以正常工作。下一步是什么以确保他们在正确的时间将可能有害的结果传达给您? 最佳答案 不确定您到底想听什么,但是有几个级别的自动代码库控制:在处理某项功能时,您可以使用类似autotest的内容获得关于哪些有效,哪些无效的即时反馈。要确保您的提
我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i
导读:随着叮咚买菜业务的发展,不同的业务场景对数据分析提出了不同的需求,他们希望引入一款实时OLAP数据库,构建一个灵活的多维实时查询和分析的平台,统一数据的接入和查询方案,解决各业务线对数据高效实时查询和精细化运营的需求。经过调研选型,最终引入ApacheDoris作为最终的OLAP分析引擎,Doris作为核心的OLAP引擎支持复杂地分析操作、提供多维的数据视图,在叮咚买菜数十个业务场景中广泛应用。作者|叮咚买菜资深数据工程师韩青叮咚买菜创立于2017年5月,是一家专注美好食物的创业公司。叮咚买菜专注吃的事业,为满足更多人“想吃什么”而努力,通过美好食材的供应、美好滋味的开发以及美食品牌的孵
我认为我的问题最好用一个例子来描述。假设我有一个名为“Thing”的简单模型,它有一些简单数据类型的属性。像...Thing-foo:string-goo:string-bar:int这并不难。数据库表将包含具有这三个属性的三列,我可以使用@thing.foo或@thing.bar之类的东西访问它们。但我要解决的问题是当“foo”或“goo”不再包含在简单数据类型中时会发生什么?假设foo和goo代表相同类型的对象。也就是说,它们都是“Whazit”的实例,只是数据不同。所以现在事情可能看起来像这样......Thing-bar:int但是现在有一个新的模型叫做“Whazit”,看起来
我有一个要在我的Rails3项目中使用的数组扩展方法。它应该住在哪里?我有一个应用程序/类,我最初把它放在(array_extensions.rb)中,在我的config/application.rb中我加载路径:config.autoload_paths+=%W(#{Rails.root}/应用程序/类)。但是,当我转到railsconsole时,未加载扩展。是否有一个预定义的位置可以放置我的Rails3扩展方法?或者,一种预先定义的方式来添加它们?我知道Rails有自己的数组扩展方法。我应该将我的添加到active_support/core_ext/array/conversion
我似乎经常遇到一些设计问题,但我不知道是什么是真的很合适。一方面我经常听到我应该限制耦合和坚持单一职责,但当我这样做时,我常常发现它很困难到在需要时将信息获取到程序的一部分。为了例如,classSingerdefinitialize(name)@name=nameendattr:nameend那么Song应该是:classSongdefnew(singer)@singer=singerendend或classSongdefnew(singer_name)@singer_name=singer_nameendend后者耦合性小,按道理应该用。但如果我以后发现宋有什么需要了解更多歌手,我的
我需要使用ActiveMerchant库在我们的一个Rails应用程序中设置支付解决方案。尽管这个问题非常主观,但人们对主要网关(BrainTree、Authorize.net等)的体验如何?它必须:处理定期付款。有能力记入个人帐户。能够取消付款。有办法存储用户的付款详细信息(例如Authotize.netsCIM)。干杯 最佳答案 ActiveMerchant很棒,但在过去一年左右的时间里,我在使用它时发现了一些问题。首先,虽然某些网关可能会得到“支持”——但并非所有功能都包含在内。查看功能矩阵以确保完全支持您选择的网关-http
我有一个像这样的ruby散列{"stuff_attributes"=>{"1"=>{"foo"=>"bar","baz"=>"quux"},"2"=>{"foo"=>"bar","baz"=>"quux"}}}我想把它变成一个看起来像这样的散列{"stuff_attributes"=>[{"foo"=>"bar","baz"=>"quux"},{"foo"=>"bar","baz"=>"quux"}]}我还需要保留键的数字顺序,并且键的数量是可变的。上面是super简化的,但我在底部包含了一个真实的例子。执行此操作的最佳方法是什么?附言还需要递归就递归而言,这是我们可以假设的:1)
参见下面的示例,我想最好使用第二种方法,但第一种也可以。哪种方法最好,使用另一种的后果是什么?classTestdefstartp"started"endtest=Test.newtest.startendclassTest2defstartp"started"endendtest2=Test2.newtest2.start 最佳答案 我肯定会说第二种变体更有意义。第一个不会导致错误,但对象实例化完全过时且毫无意义。外部变量在类的范围内不可见:var="string"classAvar=A.newendputsvar#=>strin
如果我构建了一个应用程序来访问来自Gmail、Twitter和Facebook的一些数据,并且我希望用户只需输入一次他们的身份验证信息,并且在几天或几周后重置,那会怎样是在Ruby中动态执行此操作的最佳方法吗?我看到很多人只是拥有他们客户/用户凭证的配置文件,如下所示:gmail_account:username:myClientpassword:myClientsPassword这看起来a)非常不安全,b)如果我想为成千上万的用户存储此类信息,它就无法工作。推荐的方法是什么?我希望能够在这些服务之上构建一个界面,因此每次用户进行交易时都必须输入凭据是不可行的。