Spring Boot 微服务性能下降九成!使用 Arthas 定位根因

简介: 接收到公司业务部门的开发反馈,应用在升级公司内部框架后,UAT(预生产)环境接口性能压测不达标。

背景

接收到公司业务部门的开发反馈,应用在升级公司内部框架后,UAT(预生产)环境接口性能压测不达标。
升级前压测报告:

1.png

升级后压测报告:

2.png

在机器配置(1C4G)相同的情况下,吞吐量从原来的 53.9/s 下降到了 6.4/s,且 CPU 负载较高。

并且开发反馈从公司全链路监控系统 SkyWalking 中查询到的链路信息可以得知大部分请求 Feign 调用的耗时不太正常(390ms),而实际被调用的下游服务响应速度很快(3ms)。

3.png

定位问题

在接收到反馈以后,我立即申请了相应机器的权限,并往相应机器上传了 Arthas(version 3.4.3)。

让业务方保持压测,开始问题定位。

1. 执行 profiler 命令对 CPU 进行性能分析

[arthas@17962]$ profiler start -d 30 -f /tmp/arthas/1.txt

等待 30s 后,打开 1.txt,查看 CPU 性能分析结果,开头部分示例如下:

--- 1630160766 ns (4.24%), 141 samples......[14] org.springframework.boot.loader.LaunchedURLClassLoader.definePackageIfNecessary[15] org.springframework.boot.loader.LaunchedURLClassLoader.loadClass[16] java.lang.ClassLoader.loadClass[17] java.lang.Class.forName0[18] java.lang.Class.forName[19] org.springframework.util.ClassUtils.forName[20] org.springframework.http.converter.json.Jackson2ObjectMapperBuilder.registerWellKnownModulesIfAvailable[21] org.springframework.http.converter.json.Jackson2ObjectMapperBuilder.configure[22] org.springframework.http.converter.json.Jackson2ObjectMapperBuilder.build[23] org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport.addDefaultHttpMessageConverters[24] org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport.getMessageConverters[25] org.springframework.boot.autoconfigure.http.HttpMessageConverters$1.defaultMessageConverters[26] org.springframework.boot.autoconfigure.http.HttpMessageConverters.getDefaultConverters[27] org.springframework.boot.autoconfigure.http.HttpMessageConverters.<init>[28] org.springframework.boot.autoconfigure.http.HttpMessageConverters.<init>[29] org.springframework.boot.autoconfigure.http.HttpMessageConverters.<init>[30] com.zhangmen.xxx.DefaultFeignConfig.lambda$feignDecoder$0[31] com.zhangmen.xxx.DefaultFeignConfig$$Lambda$704.256909008.getObject[32] org.springframework.cloud.openfeign.support.SpringDecoder.decode[33] org.springframework.cloud.openfeign.support.ResponseEntityDecoder.decode......

2. 对可疑的方法执行 trace 命令输出方法路径上每个节点的耗时

分析上一步得到的 CPU 性能分析结果,可以发现最占用 CPU 的栈中,确实有 Feign 相关的栈帧。

并且发现 Feign 相关的栈帧周围出现了 com.zhangmen 相关的栈帧:com.zhangmen.xxx.DefaultFeignConfig$$Lambda$704.256909008.getObject 和 com.zhangmen.xxx.DefaultFeignConfig.lambda$feignDecoder$0。

在 1.txt 中搜索 com.zhangmen.xxx.DefaultFeignConfig,发现有 340 次命中,因此认为这是一个非常可疑的方法。

执行 trace 命令输出该方法路径上每个节点的耗时:

[arthas@17962]$ trace com.zhangmen.xxx.DefaultFeignConfig * '#cost>200' -n 3
`---[603.999323ms] com.zhangmen.xxx.DefaultFeignConfig:lambda$feignEncoder$1()`---[603.856565ms] org.springframework.boot.autoconfigure.http.HttpMessageConverters:<init>() #42

发现 org.springframework.boot.autoconfigure.http.HttpMessageConverters:() 比较耗时,并继续一层层 trace 追踪下去:

[arthas@17962]$ trace org.springframework.boot.autoconfigure.http.HttpMessageConverters <init> '#cost>200' -n 3
......
[arthas@17962]$ trace org.springframework.http.converter.json.Jackson2ObjectMapperBuilder registerWellKnownModulesIfAvailable '#cost>200' -n 3

4.png

最终发现 org.springframework.util.ClassUtils:forName() 比较耗时,并且抛出了异常。

使用 watch 命令查看具体的异常:

[arthas@17962]$ watch org.springframework.util.ClassUtils forName -e "throwExp" -n 

5.png

解决问题

将定位到的问题,反馈给相关业务开发,并建议引入 jackson-datatype-joda 依赖。

引入依赖后压测报告:

6.png

吞吐量从原来的 6.4/s 提升到了 69.3/s,比升级框架前的 53.9/s 还要高。

这时候相关业务开发反馈,这个问题是代码中自定义了 Feign 的编解码器(下图所示)导致的,并且这个编解码器在升级框架前也是一直存在的。

7.png

于是,对升级框架前的代码进行压测并在压测过程中使用 Arthas 执行以下命令:

8.png

发现同样有这个异常。引入 jackson-datatype-joda 依赖,再次进行压测,压测报告如下:

9.png

汇总前面的压测结果:

10.png

可以发现一个新的问题:为什么新旧版本同时不引入依赖,吞吐量相差近 8 倍,新旧版本同时引入依赖,吞吐量相差近 1 倍?

进一步定位问题

根据上一步中发现的新问题,接下来对 未升级框架并引入依赖的版本 和 升级框架并引入依赖的版本 分别进行压测,并在压测过程中使用 Arthas 的 profiler 命令采样 CPU 性能分析数据,得到样本 1 和样本 2 。并从样本 1 和样本 2 中找到相似栈进行对比:

11.png

通过对比可以发现,两个样本的相似栈的前 17 行有所不同。并对样本 2 中的可疑栈帧进行 trace 追踪:

[arthas@10561]$ trace org.apache.catalina.loader.WebappClassLoaderBase$CombinedEnumeration * '#cost>100' -n 3
`---[171.744137ms] org.apache.catalina.loader.WebappClassLoaderBase$CombinedEnumeration:hasMoreElements()`---[171.736943ms] org.apache.catalina.loader.WebappClassLoaderBase$CombinedEnumeration:inc() #2685`---[171.724546ms] org.apache.catalina.loader.WebappClassLoaderBase$CombinedEnumeration:inc()

发现升级框架后,在类加载器这部分存在比较耗时的情况。

而对样本 1 中这部分进行 trace 追踪没有出现耗时大于 100ms 的情况。

又进一步使用 profiler 命令,分别生成两个版本在压测场景下的火焰图,并找到相似栈进行对比:

[arthas@10561]$ profiler start -d 30 -f /tmp/arthas/1.svg

12.png

发现 升级框架并引入依赖的版本 还多出了一些 org/springframework/boot/loader/ 相关的栈。

进一步解决问题

将新的发现反馈给相关业务开发。

他们反映此次除了框架升级外,还有 Spring Boot war to jar 部署的调整。从使用独立的 Tomcat war 部署,改造成用 Spring Boot 内嵌 Tomcat java -jar 部署。故怀疑两种部署方式在类加载器上存在性能差异。
相关业务开发在我上一步定位问题期间,根据我最初定位到的问题,在 Google 搜索 feign com.fasterxml.jackson.datatype.joda.JodaModule,找到了一篇相关的文章《loadClass 导致线上服务卡顿分析》。

文章中的作者,遇到的问题与我们基本相似。

看了这篇文章后,我又 Debug 了部分源码,最后了解到问题产生的根本原因是:SpringEncoder / SpringDecoder 在每次编码 / 解码时都会调用 ObjectFactory.getObject()).getConverters() 获取 HttpMessageConverters。而我们自定义的 DefaultFeignConfig 中配置的ObjectFactory 的实现是每次都 new 一个新的 HttpMessageConverters 对象。

HttpMessageConverters 的构造方法又默认会执行 getDefaultConverters 方法获取默认的 HttpMessageConverter 集合,并初始化这些默认的 HttpMessageConverter。其中的 MappingJackson2HttpMessageConverter(有两个,见下图) 每次初始化时都会加载不在 classpath 中的 com.fasterxml.jackson.datatype.joda.JodaModule和 com.fasterxml.jackson.datatype.joda$JodaModule(org.springframework.util.ClassUtils 加载不到类时,会尝试再加载一下内部类),并抛出 ClassNotFoundException,且该异常最后被生吞。

而部分和 XML 相关的默认的 HttpMessageConverter,SourceHttpMessageConverter 和 Jaxb2RootElementHttpMessageConverter(各有两个,见下图)每次初始化时,会执行 TransformerFactory.newInstance(),执行过程中会使用 SPI 扫描 classpath 下的 META-INF / services 目录获取具体的实现,并且每次扫描完也没有获取到具体的实现,最终使用默认指定的 com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl作为实现。

最终导致每一次 Feign 调用(包含编码和解码),都会加载 4 次不在 classpath 中的 com.fasterxml.jackson.datatype.joda.JodaModule 和 com.fasterxml.jackson.datatype.joda$JodaModule(共8次),且 8 次使用 SPI 扫描 classpath 下的 META-INF / services 目录获取查找不到的实现,而 war to jar 后,类加载器在频繁查找和加载资源上的性能有所下降,最终导致严重影响接口性能。

默认的 HttpMessageConverter 集合:

13.png

部分关键代码如下。

org/springframework/boot/autoconfigure/http/HttpMessageConverters.:

14.png

org/springframework/http/converter/json/Jackson2ObjectMapperBuilder.registerWellKnownModulesIfAvailable:

15.png

org/springframework/util.ClassUtils.forName:

16.png

org/springframework/http/converter/xml/SourceHttpMessageConverter:

17.png

javax/xml/transform/FactoryFinder.find:

18.png

文章中对于这个问题还提供了两种解决方法:

第一种方法,就是我最初建议的引入 jackson-datatype-joda 依赖,避免每次初始化默认的 MappingJackson2HttpMessageConverter 时 ClassLoader 反复加载不在 classpath 中的 com.fasterxml.jackson.datatype.joda.JodaModule 和 com.fasterxml.jackson.datatype.joda$JodaModule。

第二种方法,不初始化默认的 HttpMessageConverter。由于我们此处只需要使用自定义的 FastJsonHttpMessageConverter 来执行编解码,完全可以避免执行 getDefaultConverters 方法,重复初始化许多用不到的默认的 HttpMessageConverter。因此在 new HttpMessageConverters 对象时 ,可以将 addDefaultConverters 参数设置为 false。

ObjectFactory<HttpMessageConverters> objectFactory = () -> new HttpMessageConverters(false, new HttpMessageConverter[] { (HttpMessageConverter)fastJsonHttpMessageConverter });

实际上,我们还可以修改 DefaultFeignConfig 中 ObjectFactory 的实现,避免每次都 new 一个新的 HttpMessageConverters 对象(重复初始化 HttpMessageConverters),实现进一步优化。
故建议相关业务开发,将 DefaultFeignConfig 修改成如下代码:

19.png

在相关业务开发将新旧版本代码中的 DefaultFeignConfig 都进行改进并部署到 FAT(测试)环境以后,我在自己本机用 JMeter 对 FAT 环境进行了模拟压测。

旧版改进后压测结果:

20.png

新版改进后压测结果:

21.png

发现此时,两个版本的接口性能已经基本相同。

最终测试人员在 UAT 环境,对升级框架并改进 DefaultFeignConfig 后的代码再次进行压测,压测结果如下:

22.png

吞吐量从最初不达标的 6.4/s,提升到了160.4/s。

那为什么 war to jar 部署的调整,会导致类加载器在频繁查找和加载资源时性能有所下降呢?

在对 SpringBoot 可执行 jar 的原理做了一番了解以后。怀疑和 Spring Boot 为了做到能够以一个 fat jar 来启动,从而扩展了 JDK 的 JarFile URL 协议,并定制了自己的 ClassLoader 和 jar 文件协议的 Hander,实现了 jar in jar、jar in directory 的加载方式有关。

对 SpringBoot 可执行 jar 原理感兴趣的朋友可以参考:《可执行 jar 包》。

War2Jar 类加载器性能下降根因探究

为了验证自己的猜测,我在自己本机搭建了一个简单的 Demo。

Demo 中有两个服务,A 和 B。将 A 和 B 都注册到 Eureka 注册中心,并且 A 通过 Feign 调用 B。

接下来使用 Jmeter 在相同的配置下对各种场景进行压测,并在压测过程中使用 Arthas 的 profiler 命令生成各种场景下的火焰图。

压测结果如下(-Xms512m -Xmx512m):

23.png

通过对比表格三和表格四可以得知,代码优化后,是否引入依赖,对吞吐量几乎没有影响。

通过表格三和表格四可以得知,代码优化后,在不会频繁查找和加载不存在的资源时,三种部署方式的吞吐量基本一致。

通过表格二可以得知,在频繁使用 SPI 获取 classpath 下查找不到的实现时,Tomcat war 部署性能更好。

通过表格一可以得知,在频繁加载不存在的类时,将 jar 包解压后通过 JarLauncher 启动性能更好。

对比表格一中 ③ 和 ② 相似栈的火焰图:

24.png

可以发现两者在 org/springframework/boot/loader/LaunchedURLClassLoader.loadClass 加载类时,存在差异。

② 不仅会执行 java/lang/ClassLoader.loadClass,还会执行 org/springframework/boot/loader/LaunchedURLClassLoader.definePackageIfNecessary。

查看 org/springframework/boot/loader/LaunchedURLClassLoader.loadClass 的源码:

25.png

发现存在一个条件分支。

查看 org/springframework/boot/loader/Launcher.createArchive 的源码:

26.png

发现这个条件的值与应用是 可执行 jar 文件 还是 文件目录 有关。

对 ② 再次进行压测,并 trace org/springframework/boot/loader/LaunchedURLClassLoader.definePackageIfNecessary:

`---[165.770773ms] org.springframework.boot.loader.LaunchedURLClassLoader:definePackageIfNecessary()+---[0.00347ms] org.springframework.boot.loader.LaunchedURLClassLoader:getPackage() #197`---[165.761244ms] org.springframework.boot.loader.LaunchedURLClassLoader:definePackage() #199

发现这个地方确实存在比较耗时的情况。

阅读该部分源码,从注释中即可得知,definePackageIfNecessary 主要是为了在调用 findClass 之前尝试根据类名去定义类所在的 package,确保 jar 文件嵌套 jar 包里的 manifest 能够和 package 关联起来。

27.png

Debug definePackageIfNecessary 这部分代码,发现在 definePackage 时,会遍历 BOOT-INF/lib/ 下所有的 jar 包 以及 BOOT-INF/classes/。如果发现这些资源中存在指定的类,就继续调用 definePackage 方法,否则遍历完直接返回 null。

28.png

29.png

前面说过,每一次 Feign 调用都会加载 4 次不在 classpath 中的 com.fasterxml.jackson.datatype.joda.JodaModule 和 com.fasterxml.jackson.datatype.joda$JodaModule (共8次)。而我这个简单的 Demo 应用依赖的 jar 有 117 个(实际企业级项目将会更多)。那么每一次 Feign 调用,就会执行 8 * (117 + 1),总计 944 次循环里的逻辑。而逻辑中的 org.springframework.boot.loader.jar.Handler.openConnection 方法在执行过程中又会涉及到比较耗时的 IO 操作,最终导致严重影响接口性能。从生成的火焰图中,也可以看到这部分处理逻辑。

30.png

至此,已经可以确认 war to jar 部署的调整,导致类加载器在频繁查找和加载资源时性能有所下降的根因就是:Spring Boot 为了做到能够以一个 fat jar 来启动,增加了一些定制的处理逻辑,而这部分定制的处理逻辑在频繁执行时,会对程序性能产生较大影响。

至于 [为什么在频繁加载不存在的类时,将 jar 包解压后通过 JarLauncher 启动比 Tomcat war 部署性能更好?] 、[在频繁使用 SPI 获取 classpath 下查找不到的实现时,Tomcat war 部署又比将 jar 包解压后通过 JarLauncher 启动性能更好?] ,受限于篇幅,就不在本文中继续展开了。感兴趣的朋友可以按照本文中介绍的方法,再结合相关源码进行进一步探究。

总结

大家在自定义 Feign 的编解码器时,如果用到了 SpringEncoder / SpringDecoder,应避免 HttpMessageConverters 的重复初始化。如果不需要使用那些默认的 HttpMessageConverter,可以在初始化 HttpMessageConverters 时将第一个入参设置为 false,从而不初始化那些默认的 HttpMessageConverter。

另外,应该了解不同的部署方式在类加载器频繁查找和加载资源时是存在性能差异的。

我们在写代码时,也应该要避免重复初始化,以及反复查找和加载不存在的资源。

最后,善用SkyWalking 和Arthas 可以帮助我们更加高效地排查程序错误和性能瓶颈。

 

作者:王瑞显  掌门教育基础架构部研发工程师

原文链接 

本文为阿里云原创内容,未经允许不得转载

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/514252.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

阿里研究员:线下环境为何不稳定?怎么破

简介&#xff1a; 为什么线下环境的不稳定是必然的&#xff1f;我们怎么办&#xff1f;怎么让它尽量稳定一点&#xff1f; 这篇文章想讲两件事&#xff1a; 为什么线下环境[1]的不稳定是必然的&#xff1f;我们怎么办&#xff1f;怎么让它尽量稳定一点&#xff1f; 此外&#…

谁说技术男不浪漫!90后程序员2天做出猫咪情绪识别软件

整理 | 王晓曼出品 | CSDN&#xff08;ID&#xff1a;CSDNnews&#xff09;9月1日&#xff0c;一则关于#程序员2天做出猫咪情绪识别软件#的话题登上微博热搜&#xff0c;参与阅读的人数达到了8218.1万&#xff0c;讨论次数1.3万&#xff0c;引发网友们的热议。高手在民间&#…

闲鱼如何一招保证推荐流稳如泰山

简介&#xff1a; 风雨不动安如山 背景 近几年互联网的快速发展中&#xff0c;互联网业务发展越来越复杂&#xff0c;业务也被拆分得越来越细&#xff0c;阿里内部业务也发生着翻天覆地的变化&#xff0c;从最初的单体应用&#xff0c;到后面的分布式集群&#xff0c;再到最近…

电商直播平台如何借助容器与中间件实现研发效率提升100%?

简介&#xff1a; 经过实际场景验证及用户的综合评估&#xff0c;电商直播平台借助全面的云原生容器化能力和中间件产品能力&#xff0c;大幅提升开发部署运维效率达50%~100%&#xff0c;极大地提升了用户体验&#xff0c;为业务持续发展打下了坚实的基础。 前言 直播带货是近…

在游戏运营行业,Serverless 如何解决数据采集分析痛点?

简介&#xff1a; 众所周知&#xff0c;游戏行业在当今的互联网行业中算是一棵常青树。在疫情之前的 2019 年&#xff0c;中国游戏市场营收规模约 2884.8 亿元&#xff0c;同比增长 17.1%。2020 年因为疫情&#xff0c;游戏行业更是突飞猛进。玩游戏本就是中国网民最普遍的娱乐…

字节大战腾讯元宇宙;Docker 自己定制镜像;VMware 云桌面助力秦皇岛市第一医院;微软开源 Cloud Katana;...

NEWS本周新闻回顾字节大战腾讯元宇宙&#xff1a;布局社交产品Pixsoul&#xff0c;上线游戏“重启世界”字节投资的代码乾坤&#xff0c;已于近日正式上线了元宇宙游戏《重启世界》。就在两个月前&#xff0c;被称为“元宇宙第一股”的Roblox登陆国内&#xff0c;由腾讯改名为《…

从 RxJS 到 Flink:如何处理数据流?

简介&#xff1a; 前端开发的本质是什么&#xff1f;响应式编程相对于 MVVM 或者 Redux 有什么优点&#xff1f;响应式编程的思想是否可以应用到后端开发中&#xff1f;本文以一个新闻网站为例&#xff0c;阐述在前端开发中如何使用响应式编程思想&#xff1b;再以计算电商平台…

Spring RSocket:基于服务注册发现的 RSocket 负载均衡

简介&#xff1a; RSocket 作为通讯协议的后起之秀&#xff0c;核心是二进制异步化消息通讯&#xff0c;是否也能和 Spring Cloud 技术栈结合&#xff0c;实现服务注册发现、客户端负载均衡&#xff0c;从而更高效地实现面向服务的架构&#xff1f;这篇文章我们就讨论一下 Spri…

双非院校计算机系毕业的学生能进大厂吗?

谈到大厂&#xff0c;我们常常会主动匹配与之对应的高学历。其实不论是大厂还是小公司&#xff0c;都是会筛简历的&#xff0c;这个毋庸置疑。从大厂招聘的结果上看&#xff0c;高学历人才的数量占据大头&#xff0c;而那些成功进入BAT、网易等大厂的专科生、二本三本学生&…

Python - 深夜数据结构与算法之 Heap Binary Heap

目录 一.引言 二.堆与二叉堆介绍 1.Heap 堆 2.Binary Heap 二叉堆 3.HeapifyUp 添加节点 4.HeapifyDown 删除节点 5.Heap 时间复杂度 6.Insert & Delete 代码实现 三.经典算法实战 1.Smallest-K [M14] 2.Sliding-Window-Max [239] 3.Ugly-Number [264] 4.Top-…

如何 0 改造,让单体/微服务应用成为 Serverless Application

简介&#xff1a; 随着 2013 年以 Docker 为代表的容器技术、CNCF 基金会以及 K8s 的发展等&#xff0c;云原生开始被广大开发者所熟知。云原生时代之前还有两个阶段&#xff1a;一是自建 IDC 机房&#xff0c;二是简单地把原有的应用搬迁到云上。自建 IDC 机房很难获得高可用、…

一文了解阿里一站式图计算平台GraphScope

简介&#xff1a; 随着大数据的爆发&#xff0c;图数据的应用规模不断增长&#xff0c;现有的图计算系统仍然存在一定的局限。阿里巴巴拥有全球最大的商品知识图谱&#xff0c;在丰富的图场景和真实应用的驱动下&#xff0c;阿里巴巴达摩院智能计算实验室研发并开源了全球首个一…

c++如何禁用指定的键盘布局_Karabiner Elements for Mac 键盘键位自定义改键工具

文章来源于&#xff1a;风云社区Karabiner Elements for Mac 12.5Karabiner Elements&#xff08;早期是Karabiner&#xff0c;更早是KeyRemap4MacBook&#xff09;是功能强大且稳定的macOS键盘定制器。上【风云社区】&#xff0c;搜索软件名字&#xff0c;即可查看下载特征&am…

Docker Desktop 向大公司宣告收费,网友大呼:是时候弃用了!

作者 | 苏宓 出品 | CSDN&#xff08;ID&#xff1a;CSDNnews&#xff09; 在容器引擎 Docker 诞生的 8 年间&#xff0c;其与开源的容器编排 Kubernetes 共同推动容器技术在云计算领域的应用&#xff0c;也让自身在全球范围内受到了广泛的关注。可以说&#xff0c;做过云计算开…

如何接地气地接入微前端?

简介&#xff1a; 微前端带来明显好处的同时&#xff0c;也面临着痛点。对于已有站点&#xff0c;如何在老的技术栈基础上接入一个微前端&#xff1f;需要哪些通 一 、前言 微前端&#xff0c;这个概念已经在国内不止一次的登上各大热门话题&#xff0c;它所解决的问题也很明显…

东南亚再造天猫 Lazada品牌商城LazMall举办第二届品牌未来论坛

9月1日&#xff0c;东南亚领先的旗舰电商平台Lazada在新加坡滨海湾金沙会展中心举办了2021 LazMall Brands Future Forum年度品牌未来论坛&#xff08;以下简称“BFF”&#xff09;。该论坛以“奔向未来&#xff1a;东南亚的数字商务时代”为主题&#xff0c;在庆祝Lazada品牌商…

高可用的本质

简介&#xff1a; 无论是一个域&#xff0c;一个BG&#xff0c;还是一个站点&#xff0c;虽然范围有大有小&#xff0c;对象有所不同&#xff0c;但其高可用的理念都是相通的&#xff0c;今天将自己对高可用的一点点思考以及总结的【nPRT公式】分享给大家。 我是乐羊&#xff0…

技术干货 | 深度解构 Android 应用面临紧急发版时的救星方案:mPaaS 热修复——DexPatch

简介&#xff1a; 关于 Android 热修复方案——DexPatch 的介绍与使用说明 方案介绍 为了解决 Native 模块上线后的问题&#xff0c;mPaaS 提供了热修复功能&#xff0c;实现不发布客户端 apk 场景下的热修复。目前 Android 端热修复主要包括 andfix 和 dexpatch&#xff0c;考…

李飞飞:阿里云数据库已做好全面服务政企市场的准备

“政企市场是检验云数据库产品竞争力的黄金标准。”9月3日&#xff0c;阿里云智能数据库事业部总负责人李飞飞在北京举办的媒体沟通会上表示&#xff0c;阿里云已经做好全面服务政企数据库市场的准备&#xff0c;并已成功助力多家大型组织实现核心系统对传统商业数据库的替换。…

技术改变生活 浅谈阿里云混合云的探索与实践

简介&#xff1a; 也许你并不了解“阿里云混合云”&#xff0c;甚至没有听说过“混合云”&#xff0c;然而它却在幕后“默默”改变着人们的生活。 也许你并不了解“阿里云混合云”&#xff0c;甚至没有听说过“混合云”&#xff0c;然而它却在幕后“默默”改变着人们的生活。大…