Eric 发布的文章

如何去掉 chrome 里 这些缺少 css map 的警告

做为一个伪全栈工程师, 经常要开发一些自用的页面, 所以在 chrome console 里面写一些代码, 调试一些问题, 打一些日志, 都是平常要做的事情. 但是经常看到下面这些黄色的警告. 它们告诉我, chrome 找不到源代码的 map, 估计是调试用的, (就像 C代码的符号表一样吧, 瞎猜). 其实我根本不想看到这些警告, 那么怎么去掉呢?

DevTools failed to load SourceMap:
cssMap.png

  1. 在 console 右上角找到设置, 点击
    1.png
  2. 选择 Preferences -> 就能看到 "Enable CSS source maps".
    2.png

Linux source 命令

source 是 shell 内置的命令, 它加载给的函数文件, 在当前shell/命令行窗口执行.
格式是:
source filename [arguments]

文件名查找路径根据 $PATH 去查.

它区别于直接执行 sh filename [arguments]的重要区别是: source 在当前 shell 执行, 可能改变当前 shell 的某些全局状态或特性. 而一般的 sh 或 直接 ~$ <可执行文件> 的方式是新开一个 shell 去执行, 也就是它是一个新的 process.

eric@tianxiaohui.com ~$ type source
source is a shell builtin

source 等同于 . 所以:

source script == . script
./script # 新开一个 shell 执行这个 script 脚本

诊断由于低效的代码引起的 CPU 突然增高

临近大促, 有同事发现某个应用在某些时候 CPU 的使用率很是怪异, 经常在某个水平上持续一段时间. 如下图:
cpu.png

图形看上去像叠罗汉一样, 看上去还很美观 (以后将会有专门的一篇讲各种奇怪的监控图形). 这里来解释一下为什么会出现这种情况: 其实这个是因为这个机器(虚拟机) 有 4 个 CPU 核心, 一旦有一个 CPU 被使用到 100%, 并且持续一段时间, 就会升到将近 25%, 保持一段直线. 若同时有第二个 CPU 被使用到 100%, 那么就保持到将近 50%, 以此类推, 最高到接近 100%. 同样原因, 如果有一个 CPU 从煎熬中解脱, 那么将掉 25% 左右.

一开始, 某个同事做了一段时间的 CPU profiling, 从 profiling 的结果看, CPU 花费在了这段代码上面:

"DefaultThreadPool-24" daemon prio=10 tid=0x00007fa85040e000 nid=0xfee9 runnable [0x00007fa849d4b000]
   java.lang.Thread.State: RUNNABLE
    at java.util.HashMap.get(HashMap.java:421)
    at java.util.Collections$UnmodifiableMap.get(Collections.java:1357)
    at java.util.AbstractMap.equals(AbstractMap.java:460)
    at java.util.Collections$UnmodifiableMap.equals(Collections.java:1394)
    at java.util.ArrayList.indexOf(ArrayList.java:303)
...  省略 ...

当时推测, 是不是又是并发使用 HashMap 导致的死循环?
仔细分析一下, 其实不是, 如果是死循环, 这个线程将永远不会退出来, 除非线程死掉, 可是我们看到某个机器的 CPU 会自动降下来. 于是他又推测, 是不是 HashMap 里面一个 bucket 里面太多了? 如果一个 bucket 里面太多, HashMap 将会根据元素的增多增加 bucket, 所以这也不是.

另外, 通过使用 htop 查看进程的使用情况, 也能看到其实燃烧 CPU 的线程过段时间就变掉.

那么, 如果某个代码某段时间内疯狂循环, 也能把 CPU 加热. 于是, 我们做了 heap dump 查看是不是这种情况. 从 heap dump 看, 上面 stack trace 里面的 ArrayList 有 95733 个元素, 而每个元素都是 HashMap, 每个 HashMap 大概有 10 个元素.
burnCPU.png

这种情况下, 会不会很耗 CPU 呢? 答案是当然: 首先我们看 ArrayList.indexOf() 方法怎么做? 它会遍历每个元素去调用他们的 equals() 方法. 平均对比元素个数为 N/2.

    public int indexOf(Object o) {
        if (o == null) {
            for (int i = 0; i < size; i++)
                if (elementData[i]==null)
                    return i;
        } else {
            for (int i = 0; i < size; i++)
                if (o.equals(elementData[i]))
                    return i;
        }
        return -1;
    }

在看 HashMap 的 equals() 方法: 虽然做了很多快速判断, 但是我们的 case 里大概率还是要每个元素的 key 和 value 都做一次 equals() 对比.

public boolean equals(Object o) {
        if (o == this)
            return true;

        if (!(o instanceof Map))
            return false;
        Map<?,?> m = (Map<?,?>) o;
        if (m.size() != size())
            return false;

        try {
            Iterator<Entry<K,V>> i = entrySet().iterator();
            while (i.hasNext()) {
                Entry<K,V> e = i.next();
                K key = e.getKey();
                V value = e.getValue();
                if (value == null) {
                    if (!(m.get(key)==null && m.containsKey(key)))
                        return false;
                } else {
                    if (!value.equals(m.get(key)))
                        return false;
                }
            }
        } catch (ClassCastException unused) {
            return false;
        } catch (NullPointerException unused) {
            return false;
        }

        return true;
    }

从上面的代码来看, 由于ArrayList 里大量的数据加上每个元素都是 HashMap,最终要花费大量的CPU 时间去做对比, 导致 CPU 在某个时间段过热.

使用 tcpkill 杀掉 tcp 连接

debian/Ubuntu 系列安装 tcpkill

sudo apt install dsniff -y

redhat/CentOS 系列安装 tcpkill

yum -y install dsniff -y

杀掉连接

sudo tcpkill -i eth0 -9 port 50185
sudo tcpkill ip host 10.168.1.1
sudo tcpkill -9 port 32145

查看连接

ss -t