1 分钟阅读

前言

分析log日志,对一个服务器端开发工程师的重要性就不细谈了。

Linux 为什么允许一个进程观察另一个进程?

为什么一个进程能够”看见”另一个进程?很多人认为Process A/B完全隔离。实际上Linux 内核一直知道:PID/Registers/Memory/Open Files/Threads/Signals 等每一个进程的全部状态。例如ps 为何能工作?因为kernel 知道PID/CPU/RSS/COMMAND。

一个进程真正长什么样?真正管理进程的是kernel,真正拥有Memory Map(包括Page Table等)的是kernel, task_struct可以理解为Process Descriptor。

+-----------------------+
| User Space            |
|                       |
| Code                  |
| Heap                  |
| Stack                 |
| mmap                  |
+-----------------------+

──────── System Call ────────

+-----------------------+
| Kernel                |
|                       |
| task_struct           |
| page table            |
| registers             |
| fd table              |
+-----------------------+

gdb(ptrace 用户态前端,正如 ip 是 netlink 的用户态前端)不是直接读Process而是请求Kernel。为什么不是所有人都能看?安全。Linux有ptrace权限,例如只能同一用户CAP_SYS_PTRACE,否则kernel拒绝。所以 有时gdb -p PID 直接Permission denied。为什么很多工具(strace/ltrace)都和 gdb 很像?因为它们实际上都是 ptrace 的不同封装。

ptrace——Linux 的”远程控制协议”/系统调用,允许一个进程(Tracer)控制另一个进程(Tracee)。

  1. 很多人看到 gdb -p 12345 输出:Attaching to process 12345... ,很多人以为gdb 直接连接目标进程,真正发生的是:gdb ==> ptrace() ==> kernel ==> 目标进程,gdb 从来没有直接操作另一个进程,都是kernel 做的。
  2. Linux 提供了一个系统调用: ptrace,名字来自 Process Trace,最开始:它就是为了Debugger。
  3. Kernel 做了什么?
    1. 检查权限,CAP_SYS_PTRACE 或同用户。
    2. 如果允许,kernel 会暂停目标进程(SIGSTOP)。为什么要停?因为如果程序一边运行,一边调试器读取内存,就可能读到一半数据发生变化。目标进程静止后,于是 gdb 可以不断请求 Kernel:读取寄存器;读取内存;读取线程;设置断点;修改变量。ptrace几乎提供了调试器需要的全部基础能力,所以很多 Linux 调试工具其实都是在封装 ptrace。
    3. 执行gdb continue Kernel 解除暂停,程序继续正常执行。

attach 后能做什么?不同工具不同。Read-only Attach/Active Attach.

  1. gdb读内存,改寄存器,单步,断点
  2. strace,观察syscall。strace python app.py 每次系统调用都会发生
     程序进入 syscall
         ↓
     Kernel 暂停
         ↓
     通知 strace
         ↓
     strace 打印
         ↓
     继续运行
    

    所以 strace 在 syscall 非常频繁时会明显变慢。

  3. perf,采样
  4. py-spy,读python Frame,经典实现思路是
    1. ptrace 暂停 Python
    2. 读取 Python 进程内存
    3. 找到 PyThreadState
    4. 找到当前 PyFrameObject
    5. 顺着 Frame 链一直往上走
    6. 恢复运行 所以 py-spy 并没有修改 Python,它只是”读”了 Python 解释器的数据结构。

为什么现代很多 profiler 都尽量不用 ptrace?

  1. 必须暂停进程。对于高 QPS 服务,即使暂停几十毫秒,也可能影响延迟。
  2. 需要较高权限。很多 Kubernetes 集群默认禁止 CAP_SYS_PTRACE。
  3. 频繁采样成本高。如果每秒暂停 100 次:
     STOP → READ → CONTINUE
     STOP → READ → CONTINUE
     ...
    

    对性能影响会越来越明显。

怎么让一个已经运行的进程,开始执行新的代码?

假设 Python 已经跑了三天 python server.py, 现在你执行:memray attach <pid>,然后它开始记录:PyObject_Malloc(),Memray 的代码什么时候 import 进去的?不是启动时,是attach 的时候。

假设

int main() {
    while (1) {
        sleep(1);
    }
}

已经运行了。如果我希望让它执行foo(), 最简单的方法改程序计数器(PC),让它跳到foo()执行,执行完回来。

列出当前目录下最大的10个文件

du -hsx * | sort -rh | head -10

分析web服务的日志

  • 查看特定区域的日志

    程序运行了一阵,莫名其妙停了。

      cat test.log | grep 'Exception'
        
      grep 'Exception' test.log
        
      cat test.log | grep -n 'Exception' 显示行号
    

    但只能看到单行,如果想看到多行,就得借助sed了

      sed -n '/2014-12-17 16:17:20/,/2014-12-17 16:17:36/p'  test.log
        
      // 查看文件的第5行到第10行
      sed -n '5,10p' filename 
    
      // 关键字所在行及之后5行  after
      grep 关键字 filename -A 5
      // 关键字所在行及之前5行  before
      grep 关键字 filename -B 5
      // 关键字所在行及前后5行  before
      grep 关键字 filename -C 5
    
  • 查看部分日志

    如果我们查找的日志很多,打印在屏幕上不方便查看, 有两个方法:

    1. 使用more和less命令, 如: grep -n "地形" test.log | more

      这样就分页打印了,通过点击空格键翻页

    2. 使用 >xxx.txt 将其保存到文件中,到时可以拉下这个文件分析.如:

      cat -n test.log grep “地形” >xxx.txt
  • 从某行开始看

    tail -n +5 xxx.log

查找项目所在的服务器位置

一般公司的测试主机上会部署多个tomcat目录,如果tomcat目录的命名没有规范,则很难确认一个项目运行在哪个目录上。

  • 根据端口查找

      // 找到端口对应进程的pid号
      netstat -anp | grep port
      // 根据进程的pid找到可执行文件所在的目录
      ps -ef | grep pid
    
  • 假设已知该项目的日志在某个目录下,根据日志文件查找

      // 找到日志文件对应进程的pid号
      fuser logfile
      // 根据进程的pid找到可执行文件所在的目录
      ps -ef | grep pid
    

lsof (list open file)

// 输出所有使用pid打开的文件
lsof -p pid

其它

  • 将应用程序后台运行,并记录日志

    笔者经常使用python写一些脚本,会碰到一种情况:一个脚本会运行较长时间(在远端服务器上),因此会趁中午出去吃饭等时间执行它。但个人电脑会自动锁屏,导致个人电脑与远端服务器失联,进而导致脚本执行中断。因此,我们要将脚本后台运行,并将输出导到某个文件上。 python test.py > test.log 2>&1 &

一个好用的shell

直接安装即可

sh -c "$(curl -fsSL https://raw.githubusercontent.com/robbyrussell/oh-my-zsh/master/tools/install.sh)"

引用

linux查找日志技巧

标签:

分类:

更新时间:

留下评论