关于arthas:聊聊arthas的HttpTermServer

序本文次要钻研一下arthas的HttpTermServer TermServercom/taobao/arthas/core/shell/term/TermServer.java public abstract class TermServer { /** * Create a term server for the Telnet protocol. * * @param configure * @return the term server */ public static TermServer createTelnetTermServer(Configure configure, ShellServerOptions options) { int port = configure.getTelnetPort() != null ? configure.getTelnetPort() : ArthasConstants.TELNET_PORT; return new TelnetTermServer(configure.getIp(), port, options.getConnectionTimeout()); } /** * Create a term server for the HTTP protocol, using an existing router. * * @return the term server */ public static TermServer createHttpTermServer() { // TODO return null; } /** * Set the term handler that will receive incoming client connections. When a remote terminal connects * the {@code handler} will be called with the {@link Term} which can be used to interact with the remote * terminal. * * @param handler the term handler * @return this object */ public abstract TermServer termHandler(Handler<Term> handler); /** * Bind the term server, the {@link #termHandler(Handler)} must be set before. * * @return this object */ public TermServer listen() { return listen(null); } /** * Bind the term server, the {@link #termHandler(Handler)} must be set before. * * @param listenHandler the listen handler * @return this object */ public abstract TermServer listen(Handler<Future<TermServer>> listenHandler); /** * The actual port the server is listening on. This is useful if you bound the server specifying 0 as port number * signifying an ephemeral port * * @return the actual port the server is listening on. */ public abstract int actualPort(); /** * Close the server. This will close any currently open connections. The close may not complete until after this * method has returned. */ public abstract void close(); /** * Like {@link #close} but supplying a handler that will be notified when close is complete. * * @param completionHandler the handler to be notified when the term server is closed */ public abstract void close(Handler<Future<Void>> completionHandler);}TermServer是一个抽象类,它定义了termHandler、listen、actualPort、close形象办法HttpTermServercom/taobao/arthas/core/shell/term/impl/HttpTermServer.java ...

February 21, 2024 · 4 min · jiezi

关于arthas:聊聊arthas的ArthasBootstrap

序本文次要钻研一下arthas的ArthasBootstrap getInstancecom/taobao/arthas/core/server/ArthasBootstrap.java /** * 单例 * * @param instrumentation JVM加强 * @return ArthasServer单例 * @throws Throwable */ public synchronized static ArthasBootstrap getInstance(Instrumentation instrumentation, Map<String, String> args) throws Throwable { if (arthasBootstrap == null) { arthasBootstrap = new ArthasBootstrap(instrumentation, args); } return arthasBootstrap; }ArthasBootstrap提供了getInstance的静态方法用户创立ArthasBootstrapArthasBootstrappublic class ArthasBootstrap { private static final String ARTHAS_SPY_JAR = "arthas-spy.jar"; public static final String ARTHAS_HOME_PROPERTY = "arthas.home"; private static String ARTHAS_HOME = null; public static final String CONFIG_NAME_PROPERTY = "arthas.config.name"; public static final String CONFIG_LOCATION_PROPERTY = "arthas.config.location"; public static final String CONFIG_OVERRIDE_ALL = "arthas.config.overrideAll"; private static ArthasBootstrap arthasBootstrap; private ArthasEnvironment arthasEnvironment; private Configure configure; private AtomicBoolean isBindRef = new AtomicBoolean(false); private Instrumentation instrumentation; private InstrumentTransformer classLoaderInstrumentTransformer; private Thread shutdown; private ShellServer shellServer; private ScheduledExecutorService executorService; private SessionManager sessionManager; private TunnelClient tunnelClient; private File outputPath; private static LoggerContext loggerContext; private EventExecutorGroup workerGroup; private Timer timer = new Timer("arthas-timer", true); private TransformerManager transformerManager; private ResultViewResolver resultViewResolver; private HistoryManager historyManager; private HttpApiHandler httpApiHandler; private HttpSessionManager httpSessionManager; private SecurityAuthenticator securityAuthenticator; private ArthasBootstrap(Instrumentation instrumentation, Map<String, String> args) throws Throwable { this.instrumentation = instrumentation; initFastjson(); // 1. initSpy() initSpy(); // 2. ArthasEnvironment initArthasEnvironment(args); String outputPathStr = configure.getOutputPath(); if (outputPathStr == null) { outputPathStr = ArthasConstants.ARTHAS_OUTPUT; } outputPath = new File(outputPathStr); outputPath.mkdirs(); // 3. init logger loggerContext = LogUtil.initLogger(arthasEnvironment); // 4. 加强ClassLoader enhanceClassLoader(); // 5. init beans initBeans(); // 6. start agent server bind(configure); executorService = Executors.newScheduledThreadPool(1, new ThreadFactory() { @Override public Thread newThread(Runnable r) { final Thread t = new Thread(r, "arthas-command-execute"); t.setDaemon(true); return t; } }); shutdown = new Thread("as-shutdown-hooker") { @Override public void run() { ArthasBootstrap.this.destroy(); } }; transformerManager = new TransformerManager(instrumentation); Runtime.getRuntime().addShutdownHook(shutdown); } //......} ArthasBootstrap的结构器执行initFastjson、initSpy、initArthasEnvironment、LogUtil.initLogger(arthasEnvironment)、enhanceClassLoader、initBeans、bind,最初注册shutdownHook来执行destroy办法initFastjson private void initFastjson() { // ignore getter error #1661 // #2081 JSON.config(JSONWriter.Feature.IgnoreErrorGetter, JSONWriter.Feature.WriteNonStringKeyAsString); }initFastjson这里应用fastjson2的config办法来疏忽getter的error,以及设置WriteNonStringKeyAsStringinitSpy private void initSpy() throws Throwable { // TODO init SpyImpl ? // 将Spy增加到BootstrapClassLoader ClassLoader parent = ClassLoader.getSystemClassLoader().getParent(); Class<?> spyClass = null; if (parent != null) { try { spyClass =parent.loadClass("java.arthas.SpyAPI"); } catch (Throwable e) { // ignore } } if (spyClass == null) { CodeSource codeSource = ArthasBootstrap.class.getProtectionDomain().getCodeSource(); if (codeSource != null) { File arthasCoreJarFile = new File(codeSource.getLocation().toURI().getSchemeSpecificPart()); File spyJarFile = new File(arthasCoreJarFile.getParentFile(), ARTHAS_SPY_JAR); instrumentation.appendToBootstrapClassLoaderSearch(new JarFile(spyJarFile)); } else { throw new IllegalStateException("can not find " + ARTHAS_SPY_JAR); } } }initSpy将Spy增加到BootstrapClassLoaderinitArthasEnvironment private void initArthasEnvironment(Map<String, String> argsMap) throws IOException { if (arthasEnvironment == null) { arthasEnvironment = new ArthasEnvironment(); } /** * <pre> * 脚本里传过来的配置项,即命令行参数 > System Env > System Properties > arthas.properties * arthas.properties 提供一个配置项,能够反转优先级。 arthas.config.overrideAll=true * https://github.com/alibaba/arthas/issues/986 * </pre> */ Map<String, Object> copyMap; if (argsMap != null) { copyMap = new HashMap<String, Object>(argsMap); // 增加 arthas.home if (!copyMap.containsKey(ARTHAS_HOME_PROPERTY)) { copyMap.put(ARTHAS_HOME_PROPERTY, arthasHome()); } } else { copyMap = new HashMap<String, Object>(1); copyMap.put(ARTHAS_HOME_PROPERTY, arthasHome()); } MapPropertySource mapPropertySource = new MapPropertySource("args", copyMap); arthasEnvironment.addFirst(mapPropertySource); tryToLoadArthasProperties(); configure = new Configure(); BinderUtils.inject(arthasEnvironment, configure); }initArthasEnvironment按命令行参数 > System Env > System Properties > arthas.properties这个程序来配置ArthasEnvironmentinitLogger public static LoggerContext initLogger(ArthasEnvironment env) { String loggingConfig = env.resolvePlaceholders(LOGGING_CONFIG); if (loggingConfig == null || loggingConfig.trim().isEmpty()) { return null; } AnsiLog.debug("arthas logging file: " + loggingConfig); File configFile = new File(loggingConfig); if (!configFile.isFile()) { AnsiLog.error("can not find arthas logging config: " + loggingConfig); return null; } try { LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory(); loggerContext.reset(); String fileName = env.getProperty(FILE_NAME_PROPERTY); if (fileName != null) { loggerContext.putProperty(ARTHAS_LOG_FILE, fileName); } String filePath = env.getProperty(FILE_PATH_PROPERTY); if (filePath != null) { loggerContext.putProperty(ARTHAS_LOG_PATH, filePath); } JoranConfigurator configurator = new JoranConfigurator(); configurator.setContext(loggerContext); configurator.doConfigure(configFile.toURI().toURL()); // load logback xml file // 查找 arthas.log appender Iterator<Appender<ILoggingEvent>> appenders = loggerContext.getLogger("root").iteratorForAppenders(); while (appenders.hasNext()) { Appender<ILoggingEvent> appender = appenders.next(); if (appender instanceof RollingFileAppender) { RollingFileAppender fileAppender = (RollingFileAppender) appender; if ("ARTHAS".equalsIgnoreCase(fileAppender.getName())) { logFile = new File(fileAppender.getFile()).getCanonicalPath(); } } } return loggerContext; } catch (Throwable e) { AnsiLog.error("try to load arthas logging config file error: " + configFile, e); } return null; }initLogger从env获取相应的日志配置,而后设置到LoggerContext,而后设置到logback的JoranConfiguratorenhanceClassLoader void enhanceClassLoader() throws IOException, UnmodifiableClassException { if (configure.getEnhanceLoaders() == null) { return; } Set<String> loaders = new HashSet<String>(); for (String s : configure.getEnhanceLoaders().split(",")) { loaders.add(s.trim()); } // 加强 ClassLoader#loadClsss ,解决一些ClassLoader加载不到 SpyAPI的问题 // https://github.com/alibaba/arthas/issues/1596 byte[] classBytes = IOUtils.getBytes(ArthasBootstrap.class.getClassLoader() .getResourceAsStream(ClassLoader_Instrument.class.getName().replace('.', '/') + ".class")); SimpleClassMatcher matcher = new SimpleClassMatcher(loaders); InstrumentConfig instrumentConfig = new InstrumentConfig(AsmUtils.toClassNode(classBytes), matcher); InstrumentParseResult instrumentParseResult = new InstrumentParseResult(); instrumentParseResult.addInstrumentConfig(instrumentConfig); classLoaderInstrumentTransformer = new InstrumentTransformer(instrumentParseResult); instrumentation.addTransformer(classLoaderInstrumentTransformer, true); if (loaders.size() == 1 && loaders.contains(ClassLoader.class.getName())) { // 如果只加强 java.lang.ClassLoader,能够缩小查找过程 instrumentation.retransformClasses(ClassLoader.class); } else { InstrumentationUtils.trigerRetransformClasses(instrumentation, loaders); } }enhanceClassLoader会应用instrumentation来加强configure.getEnhanceLoaders()initBeans private void initBeans() { this.resultViewResolver = new ResultViewResolver(); this.historyManager = new HistoryManagerImpl(); }initBeans则创立ResultViewResolver、HistoryManagerImplbind private void bind(Configure configure) throws Throwable { long start = System.currentTimeMillis(); if (!isBindRef.compareAndSet(false, true)) { throw new IllegalStateException("already bind"); } // init random port if (configure.getTelnetPort() != null && configure.getTelnetPort() == 0) { int newTelnetPort = SocketUtils.findAvailableTcpPort(); configure.setTelnetPort(newTelnetPort); logger().info("generate random telnet port: " + newTelnetPort); } if (configure.getHttpPort() != null && configure.getHttpPort() == 0) { int newHttpPort = SocketUtils.findAvailableTcpPort(); configure.setHttpPort(newHttpPort); logger().info("generate random http port: " + newHttpPort); } // try to find appName if (configure.getAppName() == null) { configure.setAppName(System.getProperty(ArthasConstants.PROJECT_NAME, System.getProperty(ArthasConstants.SPRING_APPLICATION_NAME, null))); } try { if (configure.getTunnelServer() != null) { tunnelClient = new TunnelClient(); tunnelClient.setAppName(configure.getAppName()); tunnelClient.setId(configure.getAgentId()); tunnelClient.setTunnelServerUrl(configure.getTunnelServer()); tunnelClient.setVersion(ArthasBanner.version()); ChannelFuture channelFuture = tunnelClient.start(); channelFuture.await(10, TimeUnit.SECONDS); } } catch (Throwable t) { logger().error("start tunnel client error", t); } try { ShellServerOptions options = new ShellServerOptions() .setInstrumentation(instrumentation) .setPid(PidUtils.currentLongPid()) .setWelcomeMessage(ArthasBanner.welcome()); if (configure.getSessionTimeout() != null) { options.setSessionTimeout(configure.getSessionTimeout() * 1000); } this.httpSessionManager = new HttpSessionManager(); if (IPUtils.isAllZeroIP(configure.getIp()) && StringUtils.isBlank(configure.getPassword())) { // 当 listen 0.0.0.0 时,强制生成明码,避免被近程连贯 String errorMsg = "Listening on 0.0.0.0 is very dangerous! External users can connect to your machine! " + "No password is currently configured. " + "Therefore, a default password is generated, " + "and clients need to use the password to connect!"; AnsiLog.error(errorMsg); configure.setPassword(StringUtils.randomString(64)); AnsiLog.error("Generated arthas password: " + configure.getPassword()); logger().error(errorMsg); logger().info("Generated arthas password: " + configure.getPassword()); } this.securityAuthenticator = new SecurityAuthenticatorImpl(configure.getUsername(), configure.getPassword()); shellServer = new ShellServerImpl(options); List<String> disabledCommands = new ArrayList<String>(); if (configure.getDisabledCommands() != null) { String[] strings = StringUtils.tokenizeToStringArray(configure.getDisabledCommands(), ","); if (strings != null) { disabledCommands.addAll(Arrays.asList(strings)); } } BuiltinCommandPack builtinCommands = new BuiltinCommandPack(disabledCommands); List<CommandResolver> resolvers = new ArrayList<CommandResolver>(); resolvers.add(builtinCommands); //worker group workerGroup = new NioEventLoopGroup(new DefaultThreadFactory("arthas-TermServer", true)); // TODO: discover user provided command resolver if (configure.getTelnetPort() != null && configure.getTelnetPort() > 0) { logger().info("try to bind telnet server, host: {}, port: {}.", configure.getIp(), configure.getTelnetPort()); shellServer.registerTermServer(new HttpTelnetTermServer(configure.getIp(), configure.getTelnetPort(), options.getConnectionTimeout(), workerGroup, httpSessionManager)); } else { logger().info("telnet port is {}, skip bind telnet server.", configure.getTelnetPort()); } if (configure.getHttpPort() != null && configure.getHttpPort() > 0) { logger().info("try to bind http server, host: {}, port: {}.", configure.getIp(), configure.getHttpPort()); shellServer.registerTermServer(new HttpTermServer(configure.getIp(), configure.getHttpPort(), options.getConnectionTimeout(), workerGroup, httpSessionManager)); } else { // listen local address in VM communication if (configure.getTunnelServer() != null) { shellServer.registerTermServer(new HttpTermServer(configure.getIp(), configure.getHttpPort(), options.getConnectionTimeout(), workerGroup, httpSessionManager)); } logger().info("http port is {}, skip bind http server.", configure.getHttpPort()); } for (CommandResolver resolver : resolvers) { shellServer.registerCommandResolver(resolver); } shellServer.listen(new BindHandler(isBindRef)); if (!isBind()) { throw new IllegalStateException("Arthas failed to bind telnet or http port! Telnet port: " + String.valueOf(configure.getTelnetPort()) + ", http port: " + String.valueOf(configure.getHttpPort())); } //http api session manager sessionManager = new SessionManagerImpl(options, shellServer.getCommandManager(), shellServer.getJobController()); //http api handler httpApiHandler = new HttpApiHandler(historyManager, sessionManager); logger().info("as-server listening on network={};telnet={};http={};timeout={};", configure.getIp(), configure.getTelnetPort(), configure.getHttpPort(), options.getConnectionTimeout()); // 异步回报启动次数 if (configure.getStatUrl() != null) { logger().info("arthas stat url: {}", configure.getStatUrl()); } UserStatUtil.setStatUrl(configure.getStatUrl()); UserStatUtil.setAgentId(configure.getAgentId()); UserStatUtil.arthasStart(); try { SpyAPI.init(); } catch (Throwable e) { // ignore } logger().info("as-server started in {} ms", System.currentTimeMillis() - start); } catch (Throwable e) { logger().error("Error during start as-server", e); destroy(); throw e; } }bind办法次要是启动AgentServer,若有设置tunnelServer则初始化tunnelClient,而后创立ShellServerImpl,对于有设置telnetPort的则注册HttpTelnetTermServer,对于有设置httpPort的则注册HttpTermServer,而后执行shellServer.listen,UserStatUtil.arthasStart(),最初执行SpyAPI.init()destroy public void destroy() { if (shellServer != null) { shellServer.close(); shellServer = null; } if (sessionManager != null) { sessionManager.close(); sessionManager = null; } if (this.httpSessionManager != null) { httpSessionManager.stop(); } if (timer != null) { timer.cancel(); } if (this.tunnelClient != null) { try { tunnelClient.stop(); } catch (Throwable e) { logger().error("stop tunnel client error", e); } } if (executorService != null) { executorService.shutdownNow(); } if (transformerManager != null) { transformerManager.destroy(); } if (classLoaderInstrumentTransformer != null) { instrumentation.removeTransformer(classLoaderInstrumentTransformer); } // clear the reference in Spy class. cleanUpSpyReference(); shutdownWorkGroup(); UserStatUtil.destroy(); if (shutdown != null) { try { Runtime.getRuntime().removeShutdownHook(shutdown); } catch (Throwable t) { // ignore } } logger().info("as-server destroy completed."); if (loggerContext != null) { loggerContext.stop(); } }destroy办法执行shellServer.close()、sessionManager.close()、httpSessionManager.stop()、timer.cancel()、tunnelClient.stop()、executorService.shutdownNow()、transformerManager.destroy()、instrumentation.removeTransformer(classLoaderInstrumentTransformer)、cleanUpSpyReference()、shutdownWorkGroup()、UserStatUtil.destroy()、Runtime.getRuntime().removeShutdownHook、loggerContext.stop()小结ArthasBootstrap的结构器执行initFastjson、initSpy、initArthasEnvironment、LogUtil.initLogger(arthasEnvironment)、enhanceClassLoader、initBeans、bind,最初注册shutdownHook来执行destroy办法。 ...

February 20, 2024 · 7 min · jiezi

关于arthas:聊聊arthas的springbootstarter

序本文次要钻研一下arthas的spring-boot-starter ArthasConfigurationarthas-spring-boot-starter/src/main/java/com/alibaba/arthas/spring/ArthasConfiguration.java @ConditionalOnProperty(name = "spring.arthas.enabled", matchIfMissing = true)@EnableConfigurationProperties({ ArthasProperties.class })public class ArthasConfiguration { private static final Logger logger = LoggerFactory.getLogger(ArthasConfiguration.class); @Autowired ConfigurableEnvironment environment; /** * <pre> * 1. 提取所有以 arthas.* 结尾的配置项,再对立转换为Arthas配置 * 2. 防止某些配置在新版本里反对,但在ArthasProperties里没有配置的状况。 * </pre> */ @ConfigurationProperties(prefix = "arthas") @ConditionalOnMissingBean(name="arthasConfigMap") @Bean public HashMap<String, String> arthasConfigMap() { return new HashMap<String, String>(); } @ConditionalOnMissingBean @Bean public ArthasAgent arthasAgent(@Autowired @Qualifier("arthasConfigMap") Map<String, String> arthasConfigMap, @Autowired ArthasProperties arthasProperties) throws Throwable { arthasConfigMap = StringUtils.removeDashKey(arthasConfigMap); ArthasProperties.updateArthasConfigMapDefaultValue(arthasConfigMap); /** * @see org.springframework.boot.context.ContextIdApplicationContextInitializer#getApplicationId(ConfigurableEnvironment) */ String appName = environment.getProperty("spring.application.name"); if (arthasConfigMap.get("appName") == null && appName != null) { arthasConfigMap.put("appName", appName); } // 给配置全加上前缀 Map<String, String> mapWithPrefix = new HashMap<String, String>(arthasConfigMap.size()); for (Entry<String, String> entry : arthasConfigMap.entrySet()) { mapWithPrefix.put("arthas." + entry.getKey(), entry.getValue()); } final ArthasAgent arthasAgent = new ArthasAgent(mapWithPrefix, arthasProperties.getHome(), arthasProperties.isSlientInit(), null); arthasAgent.init(); logger.info("Arthas agent start success."); return arthasAgent; }}ArthasConfiguration注册了arthasConfigMap及arthasAgent两个beanArthasAgentarthas-agent-attach/src/main/java/com/taobao/arthas/agent/attach/ArthasAgent.java ...

February 19, 2024 · 3 min · jiezi

关于arthas:为什么在容器中-1-号进程挂不上-arthas

最近在容器环境中,发现在 Java 过程是 1 号过程的状况下,无奈应用 arthas。 提醒 AttachNotSupportedException: Unable to get pid of LinuxThreads manager thread。具体操作和报错如下:# java -jar arthas-boot.jar[INFO] arthas-boot version: 3.5.6[INFO] Found existing java process, please choose one and input the serial number of the process, eg : 1. Then hit ENTER.* [1]: 1 com.alibabacloud.mse.demo.ZuulApplication1[INFO] arthas home: /home/admin/.opt/ArmsAgent/arthas[INFO] Try to attach process 1[ERROR] Start arthas failed, exception stack trace:com.sun.tools.attach.AttachNotSupportedException: Unable to get pid of LinuxThreads manager thread at sun.tools.attach.LinuxVirtualMachine.<init>(LinuxVirtualMachine.java:86) at sun.tools.attach.LinuxAttachProvider.attachVirtualMachine(LinuxAttachProvider.java:78) at com.sun.tools.attach.VirtualMachine.attach(VirtualMachine.java:250) at com.taobao.arthas.core.Arthas.attachAgent(Arthas.java:117) at com.taobao.arthas.core.Arthas.<init>(Arthas.java:27) at com.taobao.arthas.core.Arthas.main(Arthas.java:166)[INFO] Attach process 1 success.之前也遇到过,总是调整了下镜像,让 Java 过程不是 1 号过程就能够了。但这个不是长久之计,还是要抽时间看下这个问题。 ...

February 17, 2023 · 3 min · jiezi

关于arthas:基于alpine的docker镜像使用arthas火焰图遇到的问题解决

背景:须要应用arthas的火焰图查看程序的运行状况,arthas其余性能可失常应用,然而输出profiler start后报错。 环境:程序是由alpine镜像构建的,基于jdk8。docker采纳swarm模式搭建的集群。 问题: libstdc++.so.6: cannot open shared object fileNo access to perf events. Try --fdtransfer or --all-user option or 'sysctl kernel.perf_event_paranoid=1'解决: 构建镜像时 Dockerfile中退出RUN apk add libstdc++即可解决分步解决 2.1 docker容器个别应用宿主机的kernel参数,将宿主机的perf_event_paranoid设置为1后,在容器中查看对应参数曾经变为1了,但还是无奈启动。 2.2 通过一系列搜寻看到在docker run时能够增加--cap-add SYS_ADMIN,尝试后可失常应用。 2.3 查看docker文档,批改部署yaml后,再次部署发现不反对cap_add参数。应用雷同的配置用docker-compose就能够启动,并能够应用profiler。 2.4 再次一系列查问,发现在swarm环境下cap-add有bug,在20.10版本之前去除了,将本机docker降级一下就能够失常应用。总结:当初应该没有应用docker swarm的中央了,仅后面两步解决还是很简略的,在k8s环境下也很好设置。次要是前面的解决步骤,在此记录。

May 9, 2022 · 1 min · jiezi

关于arthas:使用-Arthas-排查开源-Excel-组件问题

简介:有了理论的应用之后,未免会想到,Arthas 是如何做到在程序运行时,动静监测咱们的代码的呢?带着这样的问题,咱们一起来看下 Java Agent 技术实现原理。 背景介绍 我的项目中有应用到 com.github.dreamroute excel-helper 这个工具来辅助 Excel 文件的解析,出错时的代码是这样写的:如下所示(非源代码) try { excelDTOS = ExcelHelper.importFromFile(ExcelType.XLSX, file, ExcelDTO.class); } catch (Exception e) { log.error("ExcelHelper importFromFile exception msg {}", e.getMessage()); } 因为打印异样信息时,应用了 e.getMessage() 办法,没有将异样信息打印进去。而且本地复现也没有复现进去。所以只能思考应用 arthas 来帮助排查这个问题了。 排查过程 1、线上服务器装置 Arthas。 https://arthas.aliyun.com/doc/install-detail.html 2、应用 watch 命令监控指定办法,打印出异样的堆栈信息,命令如下: watch com.github.dreamroute.excel.helper.ExcelHelper importFromFile '{params,throwExp}' -e -x 3再次调用办法,捕捉到异样栈信息如下: 曾经捕捉到异样,并打印出堆栈信息。 3、依据对应的堆栈信息,定位到具体的代码,如下: 代码很简略,从代码中能够很清晰的看到如果没有从 headerInfoMap 中没有获取到指定的 headerInfo ,就会抛这个异样。没有找到只有两种状况: headerInfoMap 中保留的信息不对。cell 中的 columnIndex 超出的失常的范畴导致没有获取到对应 HeaderInfo 。对于第二种状况,首先去校验了一下上传的 Excel 文件是否有问题,本地测试了一下 Excel 文件,没有任何问题。本地测试也是胜利的,所以主观判断,第二种状况的可能性不大。 ...

July 1, 2021 · 3 min · jiezi

关于arthas:使用-Arthas-排查开源-Excel-组件问题

简介: 有了理论的应用之后,未免会想到,Arthas 是如何做到在程序运行时,动静监测咱们的代码的呢?带着这样的问题,咱们一起来看下 Java Agent 技术实现原理。 背景介绍我的项目中有应用到 com.github.dreamroute excel-helper 这个工具来辅助 Excel 文件的解析,出错时的代码是这样写的:如下所示(非源代码) try { excelDTOS = ExcelHelper.importFromFile(ExcelType.XLSX, file, ExcelDTO.class); } catch (Exception e) { log.error("ExcelHelper importFromFile exception msg {}", e.getMessage()); }因为打印异样信息时,应用了 e.getMessage() 办法,没有将异样信息打印进去。而且本地复现也没有复现进去。所以只能思考应用 arthas 来帮助排查这个问题了。 排查过程 1、线上服务器装置 Arthas。https://arthas.aliyun.com/doc/install-detail.html 2、应用 watch 命令监控指定办法,打印出异样的堆栈信息,命令如下: watch com.github.dreamroute.excel.helper.ExcelHelper importFromFile '{params,throwExp}' -e -x 3再次调用办法,捕捉到异样栈信息如下: 曾经捕捉到异样,并打印出堆栈信息。 3、依据对应的堆栈信息,定位到具体的代码,如下: 代码很简略,从代码中能够很清晰的看到如果没有从 headerInfoMap 中没有获取到指定的 headerInfo ,就会抛这个异样。没有找到只有两种状况: headerInfoMap 中保留的信息不对。cell 中的 columnIndex 超出的失常的范畴导致没有获取到对应 HeaderInfo 。对于第二种状况,首先去校验了一下上传的 Excel 文件是否有问题,本地测试了一下 Excel 文件,没有任何问题。本地测试也是胜利的,所以主观判断,第二种状况的可能性不大。 所以说次要查看第一种状况是否产生,这个时候能够再去看一下该办法的第一行代码 ...

June 29, 2021 · 3 min · jiezi

关于arthas:开源之夏-阿里开源近百任务上线

简介:快来加入 赢取丰富奖品~ 2021年,由中国开源软件推动联盟COPU牵头公布了《2021中国开源倒退蓝皮书》,涵盖当今寰球开源的总体状况剖析、开发者剖析、项目分析、畛域案例,绘制了一副"开源数字生态地图"。让咱们全面地看到了开源畛域的中国力量。 报告指出: 国内的企业阿里开源活跃度排名第一,有的指标值甚至是其它公司之和,并且在社区化/凋谢等方面也做得不错;Dubbo、RocketMQ 两大云原生中间件开源我的项目处于 Apache 软件基金会中国的我的项目开源象限第一方阵(全球化+影响力两大维度);中国的 Top 20 我的项目列表中 Nacos、Seata 两大中间件开源我的项目上榜。往年,阿里云原生开源大家族 14 大开源我的项目退出中国科学院软件研究所开源软件供应链点亮打算反对下的系列高校开源流动——暑期2021。流动官网:_https://summer.iscas.ac.cn/_ 通过本流动,同学们能够在顶级开源导师的领导下,深度体验真实世界的软件开发,感触开源技术共建的魅力。参加本次打算的我的项目导师不乏 Apache 顶级我的项目 PMC & Committer、CNCF TOC 等,我的项目波及畛域微服务、容器、Serverless、混沌工程等多个热门方向。 我的项目介绍Apache Dubbo Dubbo 是阿里巴巴于 2011 年开源的高性能 RPC  框架,并逐步从一个 RPC  框架向微服务生态系统转变。2019 年 5 月从  Apache 软件基金会毕业,并成为 Apache 顶级我的项目。2021年,Dubbo 3.0 Preview 公布,间接发表下一代云原生的技术蓝图。 Dubbo idea list:_https://summer.iscas.ac.cn/#/org/orgdetail/apachedubbo?lang=chi_ Dubbogo idea list:_https://summer.iscas.ac.cn/#/org/orgdetail/dubbogo?lang=chi_ Apache RocketMQ RocketMQ是阿里巴巴在2012年开源的分布式消息中间件,2016年捐献给Apache软件基金会,并于2017年9月25日成为Apache的顶级我的项目。 idea list:_https://summer.iscas.ac.cn/#/org/orgdetail/rocketmq?lang=chi_ KubeVela KubeVela 是一个“可编程式”的云原生利用治理与交付平台。作为 OAM(Open Application Model)在 Kubernetes 上的实现,KubeVela 从 2020 年 11 月正式发表开源起,在演进至今的短短半年工夫,社区贡献者达到100+名,该我的项目不仅间断登上 GitHub Go 语言趋势榜首和 HackerNews 首页,更是迅速播种了包含 MasterCard、Springer Nature、第四范式、SILOT、Upbound 等来自世界各地、不同行业的终端用户,甚至还呈现了像 Oracle Cloud、Napptive 等基于它构建的商业化产品。 idea list:_https://github.com/oam-dev/kubevela/discussions_ ...

June 15, 2021 · 2 min · jiezi

关于arthas:Windows下Arthas的简单使用

前言后面咱们就曾经说了怎么装置Arthas了,那明天咱们就来聊一下Arthas的应用 一、筹备咱们须要筹备一个java程序,启动之后不能进行的,那我就用一个简略的死循环程序上面是一个死循环程序,始终输入a的值 public class test { public static void main(String[] args) { int a = 1; while (a==1){ System.out.println(a); } } }二、测试Windows下测试启动这个程序,并且让他后盾运行 而后菜单键+R,运行cmd关上命令行,而后进入到Arthas的arthas-boot.jar目录,比方我的在D盘,所以我须要先进入D盘的门路,而后能力cd进入到我的目录 进入目录之后,应用下列命令启动Arthas java -jar arthas-boot.jar而后就会显示出咱们刚刚启动的test这个程序了,输出1之后按回车就能够启动Arthas来检测了如果你想要检测其余的java程序的话,就输出程序名后面对应的数字 当然你也能够在浏览器里进行监控的操作,上图中有个链接,你在浏览器输出这个地址就能够应用浏览器来执行arthas命令 三、执行咱们先执行一下help,看看有什么命令 显然,arthas的命令还是挺多的,前面会介绍的 那我先介绍一下几条罕用的吧 常用命令提前说一条清理的命令,前面的常用命令展现的货色太多,须要清掉来难看一点 Windows下就是clear,Linux下就是cls 1.dashborad仪表板输出dashborad之后,会呈现一个表格(如果没有呈现,阐明可能那个程序停了,要放弃test程序还在运行),这个叫仪表板 次要有三个局部,第一个是所有的线程状态,第二个是内存应用的状况,第三个是JVM的状态和Windows的信息 这些内容是会刷新的,可依据这些数据对这个程序以及java虚拟机进行监控,须要退出的话按Q或者Ctrl+C即可退出。 2.thread线程板输出这个命令之后,也会呈现一张表,这个跟下面的第一条是相似的,显示的是所有线程的状况 每个线程后面会有一个id,输出 thread +对应的id能够查看的该线程的一些信息 3.jad反编译这个命令是一个反编译的命令,能够把jar包反编译成代码展现在屏幕上,例如我的是test程序,那我就输出jad test 个别的程序的话,就须要装置上面的步骤来输出 jad 包名.类名 输出之后返回了几行货色,第一个红色字体下的是类加载器,第二个是门路,上面的就是源码和反编译的工夫了 4.watch监测间接翻译就是监督,有点相似debug那种,能够看到这个类中函数的返回值,上面是规范应用的格局 $ watch 包名.类名 办法名 primeFactors returnObj那我就须要改良一下,把我的程序改成函数调用的模式,当初我改成这样,成果是跟后面的是一样的 public class test { public static void main(String[] args) { int a = 1; while (a==1){ System.out.println(outs(a)); } } public static int outs(int x){ return x; }}那我 测试这个outs办法,同样的因为我这个程序没有包名,所以包名能够省略,那我就输出 ...

June 3, 2021 · 1 min · jiezi

关于arthas:BUG日记20210518

问题IDEA运行Spring Boot我的项目报错 “Web server failed to start. Port 8123 was already in use.” 解决方法一、本地查问被应用的端口是哪个利用在应用用管理员身份运行cmd,输出:netstat -ano|findstr 8080 找到对应的过程号,而后查看过程:tasklist|findstr “过程号” 终止该过程:taskkill /pid 8080 /f

May 18, 2021 · 1 min · jiezi

关于arthas:聊聊部署在docker容器里面的springboot项目如何启用arthas

前言arthas是啥可能大家都晓得了,为了凑字数,我把官网的介绍再抄一下 Arthas 是Alibaba开源的Java诊断工具,深受开发者青睐。当你遇到以下相似问题而大刀阔斧时,Arthas能够帮忙你解决: 这个类从哪个 jar 包加载的?为什么会报各种类相干的 Exception?我改的代码为什么没有执行到?难道是我没 commit?分支搞错了?遇到问题无奈在线上 debug,难道只能通过加日志再从新公布吗?线上遇到某个用户的数据处理有问题,但线上同样无奈 debug,线下无奈重现!是否有一个全局视角来查看零碎的运行状况?有什么方法能够监控到JVM的实时运行状态?怎么疾速定位利用的热点,生成火焰图?明天不具体讲如何应用arthas,因为之前有专门写了一篇博文介绍过,感兴趣的敌人能够查看如下链接 java利用线上诊断神器--Arthas 随着容器化的炽热,可能有相当一部分的我的项目都是基于docker部署,明天次要就聊下运行在docker环境中的springboot我的项目,如何启用arthas docker环境中的springboot我的项目,如何启用arthas计划一、进入容器外部执行相应命令 docker exec -it d2ce06ad8855 /bin/bash 进入容器后,再运行 curl -O https://arthas.aliyun.com/arthas-boot.jar java -jar arthas-boot.jar这种计划的弊病在于容器销毁后,下次运行容器后,要再次下载arthas-boot.jar 计划二、把arthas装置到根底镜像FROM openjdk:8-jdk-alpineVOLUME /tmp#ENV JAVA_OPTS="-Dcom.sun.management.jmxremote.port=39083 -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false"ENV JAVA_OPTS=""COPY localtime /etc/localtimeRUN echo "Asia/Shanghai" > /etc/timezoneONBUILD COPY app.jar app.jarARG ARTHAS_VERSION="3.5.0"ARG MIRROR=falseENV MAVEN_HOST=https://repo1.maven.org/maven2 \ ALPINE_HOST=dl-cdn.alpinelinux.org \ MIRROR_MAVEN_HOST=https://maven.aliyun.com/repository/public \ MIRROR_ALPINE_HOST=mirrors.aliyun.com # if use mirror change to aliyun mirror siteRUN if $MIRROR; then MAVEN_HOST=${MIRROR_MAVEN_HOST} ;ALPINE_HOST=${MIRROR_ALPINE_HOST} ; sed -i "s/dl-cdn.alpinelinux.org/${ALPINE_HOST}/g" /etc/apk/repositories ; fi && \ # https://github.com/docker-library/openjdk/issues/76 apk add --no-cache tini && \ # download & install arthas wget -qO /tmp/arthas.zip "${MAVEN_HOST}/com/taobao/arthas/arthas-packaging/${ARTHAS_VERSION}/arthas-packaging-${ARTHAS_VERSION}-bin.zip" && \ mkdir -p /opt/arthas && \ unzip /tmp/arthas.zip -d /opt/arthas && \ rm /tmp/arthas.zipENTRYPOINT ["/sbin/tini", "--", "sh", "-c", "java $JAVA_OPTS -Djava.security.egd=file:/dev/./urandom -jar /app.jar" ]计划三、应用arthas-spring-boot-starter1、在我的项目的pom.xml引入 <dependency> <groupId>com.taobao.arthas</groupId> <artifactId>arthas-spring-boot-starter</artifactId> <version>${arthas.version}</version> </dependency>2、在yml进行配置这边配置又有两种形式 ...

May 11, 2021 · 1 min · jiezi