Java NIO & NIO2 里面的 attachment 是怎么回事?

在 Java NIO 和 NIO2 里面我们经常看到attach 和 attachment 相关的 API, 如:

Objcet SelectionKey.attch(Object obj)
Object SelectionKey.attachment()
SelectionKey AbstractSelector.register(AbstractSelectableChannel ch,int ops, Object att);

这里的 Attachment 是一个 Object 对象, 也就是说它可以 attach 任何对象, 为什么要 attach 一个对象呢?
我们从 Blocking IO 说起, 当 Blocking IO 的时候, 读字节流或字符流的的线程一直 block 在读操作上, 不去干其它事情, 当来一个字节/字符的时候, 它就读一个, 直到返回 -1 代表读完(EOF). 可是当时 NIO 的时候, 读线程直接返回, 是由一个专门的 IO 线程操作 Selector 去读取的, 当有部分数据到达的时候, 它就帮你读取, 读完来的数据之后, 还没读取到 EOF, 那么要继续监听这个 socket, 再次等待它接下来的数据, 那么刚才读取的数据放哪里呢? 之后来的数据怎么拼接到原来的数据之后呢? 那么就需要有一个容器放置还没有读完的半成品, 在下次同一个 socket 来数据的时候, 再次拿出这个容器, 继续放数据, 那么这个容器怎么可以容易的每次都有数据的时候拿到呢? 那就放到 SelectionKey 上面吧, 反正每次都是通过 Selectionkey 知道有数据的, 一旦 SelectionKey 有数据, 就通过它拿到之前装有半成品的容器, 那么可以继续放了.

每次读完通过 attach(Object) 方法附在上面, 下次当有数据来的时候, 通过 attachment 方法拿到之前的容器.

参考: https://jfarcand.wordpress.com/2006/07/06/tricks-and-tips-with-nio-part-ii-why-selectionkey-attach-is-evil/

在 chrome 以屏幕模式打印, 而不是打印模式

有时候我们浏览网页的时候, 想打印该页面, 可是打开打印预览, 发现和正常模式差别很大, 实际上是差很多. 这时候, 我们想以正常模式打印.

  1. 使用命令 Command+Shift+P (Mac) or Control+Shift+P (Windows, Linux, Chrome OS) 打开命令提示菜单;
  2. 选择 Show Rendering, 回车;
  3. 再最下面 选择 Emulate CSS Midea, 选择 Screen.

照抄: https://developers.google.com/web/tools/chrome-devtools/css/print-preview

本文是遇到像打印 oreilly 书的页面的时候, 出现的这个问题. https://learning.oreilly.com

    let classes = [
                "sbo-site-nav",
                "sbo-reading-menu sbo-menu-top",
                "interface-controls interface-controls-top",
                "t-sbo-prev sbo-prev sbo-nav-top",
                "t-sbo-next sbo-next sbo-nav-top",
                "t-sbo-prev sbo-prev sbo-nav-bottom",
                "t-sbo-next sbo-next sbo-nav-bottom",
                "pagefoot t-pagefoot"
            ];

classes.forEach(function(className, i){
    var ele = document.getElementsByClassName(className)[0];
    if (ele) {
        ele.parentNode.removeChild(ele);
    } 
});

var ctt = document.getElementById("sbo-rt-content");
ctt.setAttribute("style", "max-width:700px");

var ct = document.getElementsByClassName("annotator-wrapper")[0];
if (ct) {
    ct.setAttribute("style", "font-size:180%!important");
} 

使用 strace 解决 twagent 狂耗 CPU 问题

最近一段时间, 经常发现生产环境上有些服务器的 CPU 使用率比其它高很多. 检查下来, 都不是我们自己的应用程序导致的, 细分下来有两种, 一种是 puppet agent 导致的(诊断 puppet agent 导致的 CPU 使用率非常高的问题), 另外一种就是 twagent 导致的.

  1. 首先, 通过 top -i -H 可以看到这个进程十分耗 CPU
    twagent.png
  2. 然后, 通过 ps aux | grep twagent | less -w 可以看到它是怎么被启动的

    xiatian 28604 0.0 0.0 10476 2084 pts/7 S+ 03:33 0:00 grep --color=auto twagent
    root 31695 31.9 0.0 494272 11340 ? Ssl May22 60485:45 /opt/tripwire/agent/twagent --service.mode=true --service.type=SysV --agent.dir=/opt/tripwire/agent --plugins.dir=/opt/tripwire/agent/plugins --tools.dir="/opt/tripwire/agent/tools" --data.dir="/var/cache/tripwire" --lock.dir="/var/lock/tripwire" --log.dir="/var/log/tripwire" --spool.dir="/var/spool/tripwire"

  3. 然后, 执行 sudo strace -C -e trace=all -p 31794 (这里一定是要那个耗CPU 的线程, 不是进程号), 可以看到N多这样的 event:

    statfs("/var/spool/tripwire", 0x7fe61a247450) = -1 ENOENT (No such file or directory)
    statfs("/var/spool/tripwire", 0x7fe61a247450) = -1 ENOENT (No such file or directory)

  4. 然后执行 添加文件夹 (我这里是 root 起的这个进程, 所以用 root 加一个文件夹)

    sudo mkdir /var/spool/tripwire

  5. 然后呢, 问题消失了

诊断 puppet agent 导致的 CPU 使用率非常高的问题

问题描述:
看到有一台机器表现很突出, CPU 使用率比其它高, 干活却没比其它机器多:
PerfMon.png

搜集数据:
登录机器, 查看各个进程 CPU 使用情况: 以 root 运行的 puppet 就是那个嫌疑犯
top -i
top.png
嫌疑犯近照:
ps -auxwwww

pdetail.png

因为 strace 只针对一个线程, 如果一个进程里面有多个线程, 首先要查出是哪个线程使用 CPU 比较高, 否则可能出错.
使用 top -i 命令出来之后, 输入 大写的 H 则能进入 thread 模式.
或者 使用 top -H -p
threads.png

然后在使用 strace 命令

诊断:
使用 strace 诊断, 发现较短时间内狂调 sched_yield, google 一下, 发现已知问题
sudo strace -p 14194 -c
strace.png
https://bugs.launchpad.net/debian/+source/ruby2.3/+bug/1834072

修复:

  1. 重启能临时解决
  2. 升级 ruby 能长期解决

strace 常用命令

strace 是一款基于 linux ptrace 系统调用的命令行工具, 对于没有源代码去黑盒 triage 问题很有帮助. 它主要通过拦截分析 进程和系统调用的交互, 产生相应的输出.

常见命令:
strace -p 26380
strace -p 26380 -c
sudo strace -p 4599 -e trace=all

它还可以用来做错误注入 (fault injection)

-e trace=%desc     Trace all file descriptor related system calls.
         %file     Trace all system calls which take a file name as an argument.
         %fstat    Trace fstat and fstatat syscall variants.
         %fstatfs  Trace fstatfs, fstatfs64, fstatvfs, osf_fstatfs, and osf_fstatfs64 system calls.
         %ipc      Trace all IPC related system calls.
         %lstat    Trace lstat syscall variants.
         %memory   Trace all memory mapping related system calls.
         %network  Trace all the network related system calls.
         %process  Trace all system calls which involve process management.
         %pure     Trace syscalls that always succeed and have no arguments.
         %signal   Trace all signal related system calls.
         %stat     Trace stat syscall variants.
         %statfs   Trace statfs, statfs64, statvfs, osf_statfs, and osf_statfs64 system calls.
         %%stat    Trace syscalls used for requesting file status.
         %%statfs  Trace syscalls related to file system statistics.