【JAVA】大杂烩-Arthas || JVMTI || 业务思想 || jmap/jstack/jinfo/NMT

96 阅读7分钟

背景

前面热更新agent想到了arthas,所以就整理学习下arthas的一个个命令【可能】是依靠什么实现的。

执行

懒狗不想看源码,又想看别人看完源码整理的概要😀。

那只能专业的人要敢于下判断了。

把arthas装冰箱里一共分几步?

1、打开冰箱门:

  • 需要网络联通:Attach JVM 2、把arthas-core塞冰箱里:JVM提供的Agent能力埋点

3、寄生等待指令:指令解析工具

4、一切的基础:JVM Tool Interface封装提供对应的业务服务能力

  • 之前就认定了各种看起来“高大上”(对于新手)的东西,底层一定是jvm/java本身的口子,现在看来也差不多。
  • 什么JVM Tool Interface 、 什么jamp/jstat等一堆工具命令,又不能无中生有,底层原理说烂了就是JVM基于C,C的源码模板埋点/网络交互/控制台super demo。

Arthas不能无中生有,一个个扩散了解下它每个能力基础和兄弟吧~

  • 首先要理解一个事,arthas的实现思路可能是什么?

最土的就是模拟shell调用现有的jmap/jstat等tool

但土的有点不太可能,随便看下arthas的classloader能力就超过相似的jmap所能提供的能力了

倒叙:万物起源JVMTI

也是挺感慨的,信息大杂烩搜集资料时做了什么都记不清了,结果最后知道了结论和逻辑链,但要复述搜集信息的过程已经不可能了

各类java提供的tool,其也应是基于JVMTI的。

毕竟是C构建java环境屏蔽差异,一次构建适配,提供标准环境java随意移植。那么如果想对JVM指指点点,也大概率是基于C的。

**Oracle官网就有文档:[JVM(TM) 工具界面 1.2.3]

(docs.oracle.com/javase/8/do…)**

Arthas大抵是基于这个来封装的C实现的Native方法,然后和自己闭环的。

举几个例子

普通代理执行java代码

包括
base64
cat

类操作

classloader
JVM(TM) 工具界面 1.2.3
image.png

JVM状态

包括
dashboard
JVM(TM) 工具界面 1.2.3
image.png

大多数都可以找到对应的native接口,或者是agent instrument, 总之可以实现,但有几个比较在意没找到的

  • 不做过度深究,我更想在结尾发散下关于实际业务、系统建设的想法思路
heapdump如何实现的堆下载
image.png
mc如何编译的
dump、jad如何反编译的
jfr是什么?

//todo回答上述。

杂项

  • arthas与它们原理大致一致,应为基于agent或JVMTI的能力封装。
jstat可以看到JVM统计信息

【JVM】jstat命令详解---JVM的统计监测工具-CSDN博客

jstack可以看到线程信息
jinfo可以看各种系统信息
jmap可以做到heapdump

image.png

NMT本地内存追踪是什么

JVM中的本地内存追踪NMT(Native Memory Tracking)_nativememorytracking-CSDN博客

没想到什么应用场景,和别的tool有些重叠

业务与技术

我们的业务线主打计算,JAVA做调度前台,C负责高性能运算。

一直以来的祖传架构(如果算得上架构的话),是通过数据库中介在C与JAVA间传递业务信息的。存在合理,但不代表不该优化。

数据库中介就注定了会存在扫表的数据库性能瓶颈:一条消息入到中介表后,数据库自身要做复制,C一堆节点轮询不同CN节点这个表,人为制造了热点表。当然可以说中介表也分租户,但很不优雅(力大转飞当然可行,但内生的热点问题在租户内依旧存在)

而如果改为分片表降低压力,又增加了系统设计熵,C的节点存活/扩容与表分片又存在了耦合,更何况模拟消息队列,扫最新的分片不顶用。至于为什么不直接接队列?因为摆

而如果降低轮询,就会导致实时性降低,虽然我们的业务场景可以接受,但不代表不该优化。

且C在扫描后,因为计算的资源密集特性,各类业务基础数据/内存资源都和节点高度绑定(租户化),其内部就还会做一次分发。这个分发逻辑理论上当然可以java提前做好,但从现有C和JAVA仅队列交互的设计上来说,保持纯净JAVA不该做这个事。

且C的封闭导致自己玩自己的,运维/扩容/下线都很难。

综合来说现状:当前业务场景是非高频扫复制表,其内部还进行租户分发,C++节点的调度运维人工性过强,因为封闭,无法与外部交互,任何交互都要多方讨论设计。

  • 如果结合arthas了解到的JVMTI,能否带来新思路?

我们可以自己编写JNI方法,这就可以直接与C++交互,不再需要中介,即等价于可以将C节点纳入JAVA微服务体系,借此引出一个新的思路:

将JAVA套壳C--Java-Wrapped-C服务,整合为一个服务,提供纯粹C计算能力

(1)C彻底计算能力化,C天生不适合实现业务,就由JAVA全部屏蔽。

(2)C计算节点与Wrapped应用部署同容器,最差的情况C可以提供接口用于租户运维,!甚至说C可以将计算能力封装为native方法。运维部署时将只需要维护一个“JAVA”服务,一切都是实时不需要中介的能力调用。

(3)纳入JAVA微服务体系后,可以轻松融入云体系,扩容下线,相关的租户管理功能都将变得更加单层简单透明。

(4)C和JAVA职责上更加明确,专注于各自领域,维护好标准接口文档即可。

类似于JAVA的Runtime接口告诉外界你的状态,但你只计算,调度由外界做,你只诚实执行。

可能带来的问题:

(1)C计算逻辑中的资源独立问题

会有些业务数据加载到主机内存用以计算,那么如果想要真的将计算能力化,就要去除或适应这种“个性”。

三个方向:如果做那就是两种计算上下文,对于不同客户现状不同实现,按需缝合。

1:JAVA更复杂的调度路由算法:以一个节点同时只处理一个最小租户计算单元为前提进行负载路由设计。

2:平台更灵活的扩容机制:如果最小租户计算单元不存在实例,就新建专用的;如果存在但是繁忙,那该排队排队。

3:C++更灵活的内存基础:大云Memory,随取随用拉取本地。严格说要求C支持不同策略,比如随取随用策略、单一租户节点策略、全云策略,对应的标准接口也会有不同实现。

(2)改造代价

总有业务淡季,会有新血液卷死老混子,业务淡季狠狠的加戏。

是否已经有这种思路承载方式了?

有,云原生下,C提供Http接口,其它微服务调用容器化的内网服务地址即可。

那这么做是否还有独特的价值

有,如果作为一个产品,不能要求所有客户都有云原生平台,此时JAVA微服务架构整合的套壳JAVAC将很有价值。甚至可以发散到非微服务的不同策略实现。

即使搞定了上面提到的“为什么不用MQ,C真的接mq了”,那只是解决了准实时通信的问题,该有的封闭独立问题还是可以进行优化。

简单扯几句实现:

  • 系统不变的前提是:

计算由业务JAVA调度;C自身分为核心的计算模块、RunTime信息模块、和按需配置的容器化web接口/集群web接口/native接口适配器模块供调用;

  • 整体看,如果进行改造,在一个个应用场景中实践完善,最终就会出现和开源框架类似的版本双向依赖表,什么版本?C支持的计算上下文/内存策略、JAVA的调度策略、当然还有C必须考虑的操作系统环境包策略。