LeeQingShui's Blog

  • 标签

  • 分类

  • 归档

  • 关于

击电奔星:数据迁移利器——DataX

发表于 2022-11-01 | 更新于 2023-07-31
本文字数: 2.5k | 阅读时长 ≈ 4 分钟
此文章不对外开放
阅读全文 »

神兵利器:妙用 Linux 抓包工具 tcpdump 排查网络问题

发表于 2022-09-06 | 更新于 2024-02-08 | 分类于 Ops
本文字数: 3.3k | 阅读时长 ≈ 5 分钟

序言

  作为开发人员,我们经常需要和第三方公司进行接口联调工作。

  要想联调成功,除了需要双方按照约定的接口文档进行代码开发外,还有个要求——双方网络得保持畅通。

  然鹅,网络这个家伙有时候非常调皮,偏偏喜欢搞事情,emmm,为了甩锅(啊不,为了定位问题),我们可以使用抓包工具去观察下数据包的出入流量情况,来确定到底是哪一方的问题。

  tcpdump是 Linux 自带的一个不错的抓包工具,那么,就跟随这篇文章来学习怎么使用它吧!

阅读全文 »

(杂)数据结构之树

发表于 2022-08-19 | 更新于 2023-08-31 | 分类于 数据结构与算法
本文字数: 3.1k | 阅读时长 ≈ 4 分钟

序言

  树是一种很常用的数据结构,此文汇总了树的一些相关概念。

阅读全文 »

轻量级对象存储系统——Minio

发表于 2022-06-21 | 更新于 2024-10-07 | 分类于 开发工具
本文字数: 3k | 阅读时长 ≈ 4 分钟

序言

  MinIO 是在 GNU Affero 通用公共许可证 v3.0 下发布的高性能对象存储。 MinIO 提供与 Amazon S3 云存储服务兼容的 API,使用 MinIO 可以为机器学习、分析和应用程序数据工作负载构建高性能基础架构。

阅读全文 »

神兵利器: GitLab CI/CD UP 工作效率 🚀🚀🚀

发表于 2022-03-26 | 更新于 2025-10-13 | 分类于 开发工具
本文字数: 14k | 阅读时长 ≈ 21 分钟

前言

  在互联网行业中,当新产品的一个个需求确立下来,开发同学不仅仅需要进行代码开发,在每个功能完善的同时,都需要重新发布测试环境,换而言之,开发同学还肩负着持续的部署工作。

  为什么需要频繁部署?

  因为产品时由多个功能点组合而成,所以一般会拆分为各个功能点划分给不同的开发同学协同合作推进产品成型,每一个功能点完成后,都需要发布到测试环境交由测试同学进行验证,若出现 Bug,则告知开发同学进行修复,因此,在一个功能点完成后,一个 Bug 修复后,都需要发布到测试环境。

  开发同学是如何进行部署工作的呢?
  开发同学一般是在功能点完成或 Bug 修复后,进行一系列以下操作:

  • ① 将代码打包
  • ② 上传到测试环境服务器
  • ③ 删除(备份)旧包,kill 旧包进程,start 新包进程

  这一系列人工操作,是重复且会花费开发同学一定时间的。
  那么,以上操作能否自动化?降低开发同学的部署时间,提升团队的工作效率呢?

  当然可以,这个时候就需要使用 CI/CD 工具了,并且它的作用远不止于此。

阅读全文 »

聚沙成塔:巧用 Nexus 搭建 Maven 私服

发表于 2022-03-19 | 更新于 2025-02-10 | 分类于 开发工具
本文字数: 3.2k | 阅读时长 ≈ 5 分钟

前言

  在互联网行业中,成熟的公司都会有专门的技术团队开发出各式各样的产品供用户使用。对于公司内部的不同产品而言,并不是每一个产品都需要重零构建,大多数情况下都是在旧产品基础上组合拼凑,衍生出新产品。
  如果说 B、C 产品都是在 A 产品基础上开发的新产品,那么意味着什么呢?
  对程序员而言,这代表着继承,也可以说是代码复用。
  那么,就有个问题了,如何去让 B、C 产品的代码继承 A 产品代码呢?
  A 产品代码打个包嘛,每个 Java 程序员都会使用 Maven,引入下不就好了?
  话是这么说,但是有个问题,A 产品的包放在哪里?不可能放中央仓库吧?这可是公司内部的产品呀!
  嘿嘿,这个时候,就需要专门搭建一个存放公司产品包的仓库,去管理这些内部产品包了。(这种内部产品包被称为二方包,公司搭建的仓库被成为二方库)。

  一般而言,公司内部的二方库早就有开发搭建好了,用不着新人动手,但由于罗马并不是一天就能建成的,有的公司技术部门可能刚刚创立,会存在没搭建过私服的情况,这个时候就需要我们手动动手了。

  那么,下面跟随本文来搭建一个 Maven 私服吧!

阅读全文 »

(运维篇)MySQL 读写分离中间件—— ProxySQL

发表于 2022-02-26 | 更新于 2022-09-12 | 分类于 关系型数据库
本文字数: 3.3k | 阅读时长 ≈ 5 分钟
此文章不对外开放
阅读全文 »

(运维篇)MySQL 高可用架构 MGR

发表于 2022-02-22 | 更新于 2022-12-20 | 分类于 关系型数据库
本文字数: 2.7k | 阅读时长 ≈ 4 分钟
此文章不对外开放
阅读全文 »

(运维篇)MySQL 主从复制探秘

发表于 2022-02-19 | 更新于 2023-10-03 | 分类于 关系型数据库
本文字数: 7.9k | 阅读时长 ≈ 11 分钟

序言

  MySQL 从 3.23 版本开始提供复制的功能。
  复制是指将主数据库的 DDL 和 DML 操作通过二进制日志传到复制服务器(也叫从库)上,然后在从库上对这些日志重新执行(也叫重做),从而使得从库和主库的数据保持同步。
  MySQL 支持一台主库同时向多台从库进行复制,从库同时也可以作为其他服务器的主库, 实现链状的复制。
  MySQL 复制的优点主要包括以下三个方面:

  • 高可用:如果主库出现问题,可以快速切换到从库提供服务;
  • 负载均衡:读写分离使得可以在从库上执行查询操作,降低主库的访问压力;
  • 数据安全:可以在从库上执行备份,以避免备份期间影响主库的服务
阅读全文 »

线上诊断神器──Arthas

发表于 2022-02-16 | 更新于 2025-10-15 | 分类于 开发工具
本文字数: 3k | 阅读时长 ≈ 4 分钟

Thread

Thread 命令可以查看当前线程信息,查看线程的堆栈.

定位 CPU 问题:thread

直接使用thread命令将默认按照 CPU 增量时间降序排列,只显示第一页数据。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
$ thread
Threads Total: 33, NEW: 0, RUNNABLE: 9, BLOCKED: 0, WAITING: 3, TIMED_WAITING: 4, TERMINATED: 0, Internal threads: 17
ID NAME GROUP PRIORITY STATE %CPU DELTA_TIME TIME INTERRUPT DAEMON
-1 C2 CompilerThread0 - -1 - 5.06 0.010 0:0.973 false true
-1 C1 CompilerThread0 - -1 - 0.95 0.001 0:0.603 false true
23 arthas-command-execute system 5 RUNNABLE 0.17 0.000 0:0.226 false true
-1 VM Periodic Task Thread - -1 - 0.05 0.000 0:0.094 false true
-1 Sweeper thread - -1 - 0.04 0.000 0:0.011 false true
-1 G1 Young RemSet Sampling - -1 - 0.02 0.000 0:0.025 false true
12 Attach Listener system 9 RUNNABLE 0.0 0.000 0:0.022 false true
11 Common-Cleaner InnocuousThrea 8 TIMED_WAI 0.0 0.000 0:0.000 false true
3 Finalizer system 8 WAITING 0.0 0.000 0:0.000 false true
2 Reference Handler system 10 RUNNABLE 0.0 0.000 0:0.000 false true
4 Signal Dispatcher system 9 RUNNABLE 0.0 0.000 0:0.000 false true
15 arthas-NettyHttpTelnetBootstra system 5 RUNNABLE 0.0 0.000 0:0.029 false true
22 arthas-NettyHttpTelnetBootstra system 5 RUNNABLE 0.0 0.000 0:0.196 false true
24 arthas-NettyHttpTelnetBootstra system 5 RUNNABLE 0.0 0.000 0:0.038 false true
16 arthas-NettyWebsocketTtyBootst system 5 RUNNABLE 0.0 0.000 0:0.001 false true
17 arthas-NettyWebsocketTtyBootst system 5 RUNNABLE 0.0 0.000 0:0.001 false true

展示当前最忙的前 N 个线程:thread -n

展示当前最忙的前 N 个线程并打印堆栈:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
$ thread -n 3
"C1 CompilerThread0" [Internal] cpuUsage=1.63% deltaTime=3ms time=1170ms


"arthas-command-execute" Id=23 cpuUsage=0.11% deltaTime=0ms time=401ms RUNNABLE
at java.management@11.0.7/sun.management.ThreadImpl.dumpThreads0(Native Method)
at java.management@11.0.7/sun.management.ThreadImpl.getThreadInfo(ThreadImpl.java:466)
at com.taobao.arthas.core.command.monitor200.ThreadCommand.processTopBusyThreads(ThreadCommand.java:199)
at com.taobao.arthas.core.command.monitor200.ThreadCommand.process(ThreadCommand.java:122)
at com.taobao.arthas.core.shell.command.impl.AnnotatedCommandImpl.process(AnnotatedCommandImpl.java:82)
at com.taobao.arthas.core.shell.command.impl.AnnotatedCommandImpl.access$100(AnnotatedCommandImpl.java:18)
at com.taobao.arthas.core.shell.command.impl.AnnotatedCommandImpl$ProcessHandler.handle(AnnotatedCommandImpl.java:111)
at com.taobao.arthas.core.shell.command.impl.AnnotatedCommandImpl$ProcessHandler.handle(AnnotatedCommandImpl.java:108)
at com.taobao.arthas.core.shell.system.impl.ProcessImpl$CommandProcessTask.run(ProcessImpl.java:385)
at java.base@11.0.7/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515)
at java.base@11.0.7/java.util.concurrent.FutureTask.run(FutureTask.java:264)
at java.base@11.0.7/java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:304)
at java.base@11.0.7/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
at java.base@11.0.7/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
at java.base@11.0.7/java.lang.Thread.run(Thread.java:834)


"VM Periodic Task Thread" [Internal] cpuUsage=0.07% deltaTime=0ms time=584ms
  • 没有线程 ID,包含[Internal]表示为 JVM 内部线程,参考dashboard命令的介绍。
  • cpuUsage为采样间隔时间内线程的 CPU 使用率,与dashboard命令的数据一致。
  • deltaTime为采样间隔时间内线程的增量 CPU 时间,小于 1ms 时被取整显示为 0ms。
  • time 线程运行总 CPU 时间。

注意:线程栈为第二采样结束时获取,不能表明采样间隔时间内该线程都是在处理相同的任务。建议间隔时间不要太长,可能间隔时间越大越不准确。 可以根据具体情况尝试指定不同的间隔时间,观察输出结果。

thread –all, 显示所有匹配的线程

显示所有匹配线程信息,有时需要获取全部 JVM 的线程数据进行分析。

显示指定线程的运行堆栈:thread id

1
2
3
4
5
6
7
8
9
$ thread 1
"main" Id=1 WAITING on java.util.concurrent.CountDownLatch$Sync@29fafb28
at sun.misc.Unsafe.park(Native Method)
- waiting on java.util.concurrent.CountDownLatch$Sync@29fafb28
at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:836)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireSharedInterruptibly(AbstractQueuedSynchronizer.java:997)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireSharedInterruptibly(AbstractQueuedSynchronizer.java:1304)
at java.util.concurrent.CountDownLatch.await(CountDownLatch.java:231)

线程死锁:thread -b

有时候我们发现应用卡住了, 通常是由于某个线程拿住了某个锁, 并且其他线程都在等待这把锁造成的。 为了排查这类问题,可以通过thread -b命令 一键找出罪魁祸首。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
$ thread -b
"http-bio-8080-exec-4" Id=27 TIMED_WAITING
at java.lang.Thread.sleep(Native Method)
at test.arthas.TestThreadBlocking.doGet(TestThreadBlocking.java:22)
- locked java.lang.Object@725be470 <---- but blocks 4 other threads!
at javax.servlet.http.HttpServlet.service(HttpServlet.java:624)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:731)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:303)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
at test.filter.TestDurexFilter.doFilter(TestDurexFilter.java:46)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:220)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:122)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:505)
at com.taobao.tomcat.valves.ContextLoadFilterValve$FilterChainAdapter.doFilter(ContextLoadFilterValve.java:191)
at com.taobao.eagleeye.EagleEyeFilter.doFilter(EagleEyeFilter.java:81)
at com.taobao.tomcat.valves.ContextLoadFilterValve.invoke(ContextLoadFilterValve.java:150)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:170)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:103)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:429)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1085)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:625)
at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:318)
- locked org.apache.tomcat.util.net.SocketWrapper@7127ee12
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:745)

Number of locked synchronizers = 1
- java.util.concurrent.ThreadPoolExecutor$Worker@31a6493e

注意, 目前只支持找出 synchronized 关键字阻塞住的线程, 如果是java.util.concurrent.Lock, 目前还不支持。

其他

指定采样时间间隔:thread -i,

  • thread -i 1000 : 统计最近 1000ms 内的线程 CPU 时间。
  • thread -n 3 -i 1000 : 列出 1000ms 内最忙的 3 个线程栈
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
$ thread -n 3 -i 1000
"as-command-execute-daemon" Id=4759 cpuUsage=23% RUNNABLE
at sun.management.ThreadImpl.dumpThreads0(Native Method)
at sun.management.ThreadImpl.getThreadInfo(ThreadImpl.java:440)
at com.taobao.arthas.core.command.monitor200.ThreadCommand.processTopBusyThreads(ThreadCommand.java:133)
at com.taobao.arthas.core.command.monitor200.ThreadCommand.process(ThreadCommand.java:79)
at com.taobao.arthas.core.shell.command.impl.AnnotatedCommandImpl.process(AnnotatedCommandImpl.java:96)
at com.taobao.arthas.core.shell.command.impl.AnnotatedCommandImpl.access$100(AnnotatedCommandImpl.java:27)
at com.taobao.arthas.core.shell.command.impl.AnnotatedCommandImpl$ProcessHandler.handle(AnnotatedCommandImpl.java:125)
at com.taobao.arthas.core.shell.command.impl.AnnotatedCommandImpl$ProcessHandler.handle(AnnotatedCommandImpl.java:122)
at com.taobao.arthas.core.shell.system.impl.ProcessImpl$CommandProcessTask.run(ProcessImpl.java:332)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:756)

Number of locked synchronizers = 1
- java.util.concurrent.ThreadPoolExecutor$Worker@546aeec1
...

查看指定状态的线程:thread –state

1
2
3
4
5
6
[arthas@28114]$ thread --state WAITING
Threads Total: 16, NEW: 0, RUNNABLE: 9, BLOCKED: 0, WAITING: 3, TIMED_WAITING: 4, TERMINATED: 0
ID NAME GROUP PRIORITY STATE %CPU DELTA_TIME TIME INTERRUPTE DAEMON
3 Finalizer system 8 WAITING 0.0 0.000 0:0.000 false true
20 arthas-UserStat system 9 WAITING 0.0 0.000 0:0.001 false true
14 arthas-timer system 9 WAITING 0.0 0.000 0:0.000 false true

生成火焰图

通过命令开启采样,观察一段事件后停止,输出一个 html 火焰图文件打开观察即可。

1
profiler start

1
profiler status
1
profiler stop

火焰图的效果大致如下图:

火焰图

图中的每个色块代表的是一个线程栈帧,色块中是该栈帧加载执行的函数以及一些采样信息。Y 轴代表调用栈的深度,调用从底部开始向上进行,顶部是正在执行的函数,下面是它的父函数,调用栈越深,火焰就越高。X 轴代表抽样数,如果一个函数在 X 轴占据的宽度越大,表示它被抽取到的次数越多,也就意味着它占用的 CPU 时间越长。

需要注意的是,图中的颜色并不重要,只用于区分不同的函数,同时 X 轴的从左到右的顺序也不重要,默认按照字典顺序排序。

我们可以简单举个例子来理解。一般在使用性能分析工具时,我们会选取一个合适的时机启动分析采样,然后等待一段时间后停止采样。假设采样时间为 20 秒,每秒采样 100 次,那么共采样 2000 次,在这 2000 次中,共有 1800 次执行的是 main 方法,其余 200 次执行的是 run 方法,同时 main 方法又调用了很多其他方法,run 方法也是,这就形成了一个从下往上的调用链,在这些调用链中,又同时会收集到每个方法采样的次数,最终形成一张火焰图。

火焰图是可以互动的,点击某个色块,该色块会被放大并占据所有的宽度,这样可以方便地查看某个函数内部的调用链信息。一般观察火焰图,就是看顶层函数占用的宽度,如果有些函数占用的宽度很大,形成了“平顶”,那么就代表该函数可能存在性能问题。当然,有时候直接观察平顶并不能快速定位问题,因为很多时候顶部的函数都是一些底层的库函数,这时候就应该先观察业务代码在火焰图中的宽度,然后再往上观察顶部的库函数来缩小范围。

从上面的火焰图发现TestController类的wl方法占据的 x 轴宽度较长,这是因为我们程序写了一个死循环到消耗了 CPU 。

1
2
3
4
5
6
7
8
9
10
11
@RestController
@RequestMapping("/test")
public class TestController {

@GetMapping("/wl")
@ApiOperationSupport(order = 1)
public Result<String> wl(String id) {
while (true){
System.out.println(1);
}
}

trace

使用 trace 命令查看耗时

我们写几个不同循环次数的方法,分别代表方法耗时不同,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
//示例代码,timeCost是个接口

public String timeCost(){

cost1();

cost2();

cost3();

.......

}

private void cost3() {

//进行200万次循环......

}

private void cost2() {

//进行10万次循环......

}

private void cost1() {

//进行10次循环......

}

部署之后我们使用 trace 来查找最耗时的方法,在此过程中需要知道包名、类名,以及方法的名字。上述代码方法所在包名为 com.cctest.arthas_demo.controller,类名为 StressSceneController,所以我们需要输入如下 trace 命令:

1
2
3
trace

com.cctest.arthas_demo.controller.StressSceneController timeCost

输完命令后回车,然后 arthas 程序就进入了等待访问状态。这时候访问接口 /timeCost,我们就可以看到被测程序台在疯狂打印日志,等结束之后,arthas 命令窗口便输出了各方法耗时时间,如图 3 所示:

vmtool

查看spring所管理的所有的bean名称

vmtool –action getInstances –className org.springframework.context.ApplicationContext –express ‘instances[0].getBeanDefinitionNames()’

查看具体的某个bean及其属性

vmtool –action getInstances –className org.springframework.context.ApplicationContext –express ‘instances[0].getBean(“testController”)’ -x 3

调用 bean 的方法

vmtool –action getInstances –className org.springframework.context.ApplicationContext –express ‘instances[0].getBean(“testController”).ok(1)’

ognl

ognl 语法:

  • #开头变量 在ognl 里面是变量全局的,可以传递 ;
  • 字段类型要注意
    • Doubble -> 1D
    • Long - >1L
    • String ->""
  • Class对象-> @xxxClass@class 相当于一个静态的变量

调用 Spring Bean 及对应方法

步骤说明

主要分为三步:

  • sc 获取工具类的 classLoaderHash
  • ognl 指定工具类的 classLoaderHash 获取对应 Bean
  • 根据需要调用的 Bean 对象相关方法进行调用

实战运用

1
sc -d cn.lovike.function.osier.core.util.SpringBeanUtils
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
[arthas@14466]$ sc -d cn.lovike.function.osier.core.util.SpringBeanUtils
class-info cn.lovike.function.osier.core.util.SpringBeanUtils
code-source /Users/wk/Documents/Code/Github/Personal/osier/osier-core/target/classes/
name cn.lovike.function.osier.core.util.SpringBeanUtils
isInterface false
isAnnotation false
isEnum false
isAnonymousClass false
isArray false
isLocalClass false
isMemberClass false
isPrimitive false
isSynthetic false
simple-name SpringBeanUtils
modifier public
annotation org.springframework.stereotype.Component
interfaces org.springframework.context.ApplicationContextAware
super-class +-java.lang.Object
class-loader +-sun.misc.Launcher$AppClassLoader@18b4aac2
+-sun.misc.Launcher$ExtClassLoader@79ca92b9
classLoaderHash 18b4aac2

调用 Redis 工具类查看某个 Redis Key 的类型

1
ognl -c 18b4aac2 -x 3 '@cn.lovike.function.osier.core.util.SpringBeanUtils@getBean("redisUtils").type("osier:sys:dict")'

返回结果:

ognl -c 2e5d6d97 -x 3 '@com.it.chenyuan.business.utils.SpringUtil@getBean(“MyRedisUtil”).get(“aper_duty_rate:hwzy:1868547696917106690”)’

1
@DataType[HASH]

调用 Redis 工具类查看某个 Redis Key 是否存在

1
ognl -c 18b4aac2 -x 3 '@cn.lovike.function.osier.core.util.SpringBeanUtils@getBean("redisUtils").exists("osier:sys:dict")'

返回结果:

1
@Boolean[true]

单独设置UserController的logger level

1
ognl --classLoaderClass org.springframework.boot.loader.LaunchedURLClassLoader '@com.example.demo.arthas.user.UserController@logger.setLevel(@ch.qos.logback.classic.Level@DEBUG)'

排查HTTP请求返回401

请求接口没有权限的时候一般就返回401 Unauthorized。

401通常是被权限管理的Filter拦截了,那么到底是哪个Filter处理了这个请求,返回了401?

跟踪所有的Filter函数

开始trace:

1
trace javax.servlet.Filter *

可以在调用树的最深层,找到AdminFilterConfig$AdminFilter返回了401

1
2
3
+---[3.806273ms] javax.servlet.FilterChain:doFilter()
| `---[3.447472ms] com.example.demo.arthas.AdminFilterConfig$AdminFilter:doFilter()
| `---[0.17259ms] javax.servlet.http.HttpServletResponse:sendError()
123…15
LeeQingShui

LeeQingShui

144 日志
16 分类
68 标签
RSS
© 2018 – 2025 LeeQingShui | 站点总字数: 846k
赣 ICP 备 2022002212 号
本站已运行
本站总访问量 次 | 本站访客 人次
0%