蚊章汇 - 性能
type: channel
link: https://linuxcn.bwsl.wang/tag/%E6%80%A7%E8%83%BD/
items: 使用开源工具识别 Linux 的性能瓶颈
items: 在 Linux 中如何使用 iotop 和 iostat 监控磁盘 I/O 活动？
items: 五种加速 Go 的特性
items: 服务端 I/O 性能：Node、PHP、Java、Go 的对比
items: Linux 容器轻松应对性能工程
items: 理解 Linux 的平均负载和性能监控
items: cpustat：在 Linux 下根据运行的进程监控 CPU 使用率
items: pyDash：一个基于 web 的 Linux 性能监测工具
items: Python 是慢，但我无所谓
items: 深入解析面向数据的哈希表性能

使用开源工具识别 Linux 的性能瓶颈
type: item
date: 2021-06-07T16:00:00+08:00
description: 不久前，识别硬件瓶颈还需要深厚的专业知识。今天的开源 GUI 性能监视器使它变得相当简单。计算机是一个集成的系统，它的性能取决于最慢的硬件组件。如果一个组件的能力比其他组件差，性能落后而不能跟上，它就会拖累你的整个系统。这就是一个 性能瓶颈。消除一个严重的瓶颈可以使你的系统飞起来。本文解释了如何识别 Linux 系统中的硬件瓶颈。这些技术同时适用于个人的电脑和服务器。我强调的是个人电脑 —— 我不会涉及局域网管理或数据库系统等领域的服务器特定的瓶颈。这些通常涉及专门的工具。我也不会多谈解决方案。这对本文来说是个太大的话题。相反，我将写一篇关于性能调整的后续文章。我将只使用开源的图形用户界面（GUI）工具来完成这项工作。大多数关于 Linux 瓶颈的文章都相当复杂。它们使用专门的命令，并深入研究神秘的细节。开源提供的 GUI 工具使得识别许多瓶颈变得简单。我的目标是给你一个快速、简单的方法，你可以在任何地方使用。从哪里开始一台计算机由六个关键的硬件资源组成。处理器内存存储器USB 端口互联网连接图形处理器如果任何一个资源表现不佳，就会产生一个性能瓶颈。为了识别瓶颈，你必须监测这六种资源。开源提供了大量的工具来完成这项工作。我会使用 GNOME 系统监视器。它的输出很容易理解，而且你可以在大多数软件库中找到它。启动它并点击“资源”标签。你可以马上发现许多性能问题。图 1. 系统监控器发现问题。(Howard Fosdick, CC BY-SA 4.0)在“资源”面板上显示三个部分：CPU 历史、内存和交换历史，以及网络历史。一眼就能看出你的处理器是否不堪负荷了，还是你的电脑没有内存了，抑或你的网络带宽被用光了。我将在下面探讨这些问题。现在，当你的电脑速度变慢时，首先检查系统监视器。它可以立即为你提供最常见的性能问题的线索。现在让我们来探讨一下如何识别特定方面的瓶颈。如何识别处理器的瓶颈要发现瓶颈，你必须首先知道你有什么硬件。开源为这个目的提供了几个工具。我喜欢 HardInfo，因为它的屏幕显示很容易阅读，而且广泛流行。启动 HardInfo。它的“计算机->摘要”面板可以识别你的 CPU 并告诉你它的核心数、线程数和速度。它还能识别你的主板和其他计算机部件。图 2. HardInfo 显示了硬件细节。(Howard Fosdick, CC BY-SA 4.0)HardInfo 显示，这台计算机有一个物理 CPU 芯片。该芯片包含两个处理器（或称为核心）。每个核心支持两个线程（或称为逻辑处理器）。这就是总共四个逻辑处理器 —— 正是图 1 中系统监控器的 CPU 历史部分所显示的。当处理器不能在其时间内对请求做出反应时，就会出现 处理器瓶颈，说明它们已经很忙了。当系统监控器显示逻辑处理器的利用率持续在 80% 或 90% 以上时，你就可以确定这一点。这里有一个例子，四个逻辑处理器中有三个被淹没在 100% 的利用率中。这是一个瓶颈，因为它没有留下多少 CPU 用于其他工作。图 3. 一个处理器的瓶颈。(Howard Fosdick, CC BY-SA 4.0)哪个程序导致了这个问题？你需要找出是哪个程序在消耗所有的 CPU。点击系统监视器的“进程”标签。然后点击“CPU 百分比”标头，根据它们消耗的 CPU 的多少对进程进行排序。你将看到哪些应用程序正在扼杀你的系统。图 4. 识别违规的进程。(Howard Fosdick, CC BY-SA 4.0)前三个进程各消耗了 总 CPU 资源的 24%。由于有四个逻辑处理器，这意味着每个进程消耗了一整个处理器。这就像图 3 所示。在“进程”面板上，一个名为“analytical\_AI”的程序被确定为罪魁祸首。你可以在面板上右键单击它，以查看其资源消耗的更多细节，包括内存使用、它所打开的文件、其输入/输出细节，等等。如果你的登录会话有管理员权限，你可以管理这个进程。你可以改变它的优先级，并停止、继续、结束或杀死它。因此，你可以在这里立即解决你的瓶颈问题。图 5. 右键点击一个进程来管理它。(Howard Fosdick, CC BY-SA 4.0)如何解决处理瓶颈问题？除了实时管理违规的进程外，你也可以防止瓶颈的发生。例如，你可以用另一个应用程序来代替违规进程，绕过它，改变你使用该应用程序的行为，将该应用程序安排在非工作时间，解决潜在的内存问题，对该应用程序或你的系统软件进行性能调整，或升级你的硬件。这里涉及的内容太多，所以我将在下一篇文章中探讨这些方式。常见的处理器瓶颈在用系统监控器监控你的 CPU 时，你会遇到几种常见的瓶颈问题。有时一个逻辑处理器出现瓶颈，而其他所有的处理器都处于低利用率。这意味着你有一个应用程序，它的代码不够智能，无法利用一个以上的逻辑处理器，而且它已经把正在使…

在 Linux 中如何使用 iotop 和 iostat 监控磁盘 I/O 活动？
type: item
date: 2019-05-05T18:11:09+08:00
description: 你知道在 Linux 中我们使用什么工具检修和监控实时的磁盘活动吗？如果 Linux 系统性能变慢，我们会用 top 命令 来查看系统性能。它被用来检查是什么进程在服务器上占有如此高的使用率，对于大多数 Linux 系统管理员来说很常见，现实世界中被 Linux 系统管理员广泛采用。如果在进程输出中你没有看到很大的不同，你仍然有选择查看其他东西。我会建议你在 top 输出中检查 wa 状态，因为大多数时间里服务器性能由于在硬盘上的高 I/O 读和写降低了性能。如果它很高或者波动，很可能就是它造成的。因此，我们需要检查硬盘上的 I/O 活动。我们可以在 Linux 中使用 iotop 和 iostat 命令监控所有的磁盘和文件系统的磁盘 I/O 统计。什么是 iotop？iotop 是一个类似 top 的工具，用来显示实时的磁盘活动。iotop 监控 Linux 内核输出的 I/O 使用信息，并且显示一个系统中进程或线程的当前 I/O 使用情况。它显示每个进程/线程读写 I/O 带宽。它同样显示当等待换入和等待 I/O 的线程/进程花费的时间的百分比。Total DISK READ 和 Total DISK WRITE 的值一方面表示了进程和内核线程之间的总的读写带宽，另一方面也表示内核块设备子系统的。Actual DISK READ 和 Actual DISK WRITE 的值表示在内核块设备子系统和下面硬件（HDD、SSD 等等）对应的实际磁盘 I/O 带宽。如何在 Linux 中安装 iotop ？我们可以轻松在包管理器的帮助下安装，因为该软件包在所有的 Linux 发行版仓库中都可以获得。对于 Fedora 系统，使用 DNF 命令 来安装 iotop。$ sudo dnf install iotop对于 Debian/Ubuntu 系统，使用 API-GET 命令 或者 APT 命令 来安装 iotop。$ sudo apt install iotop对于基于 Arch Linux 的系统，使用 Pacman Command 来安装 iotop。$ sudo pacman -S iotop对于 RHEL/CentOS 的系统，使用 YUM Command 来安装 iotop。$ sudo yum install iotop对于使用 openSUSE Leap 的系统，使用 Zypper Command 来安装 iotop。$ sudo zypper install iotop在 Linux 中如何使用 iotop 命令来监控磁盘 I/O 活动/统计？iotop 命令有很多参数来检查关于磁盘 I/O 的变化：# iotop如果你想检查那个进程实际在做 I/O，那么运行 iotop 命令加上 -o 或者 --only 参数。# iotop --only细节：IO：它显示每个进程的 I/O 利用率，包含磁盘和交换。SWAPIN： 它只显示每个进程的交换使用率。什么是 iostat？iostat 被用来报告中央处理单元（CPU）的统计和设备与分区的输出/输出的统计。iostat 命令通过观察与它们平均传输率相关的设备活跃时间来监控系统输入/输出设备负载。iostat 命令生成的报告可以被用来改变系统配置来更好的平衡物理磁盘之间的输入/输出负载。所有的统计都在 iostat 命令每次运行时被报告。该报告包含一个 CPU 头部，后面是一行 CPU 统计。在多处理器系统中，CPU 统计被计算为系统层面的所有处理器的平均值。设备头行后紧跟显示每个配置的设备一行的统计。iostat 命令生成两种类型的报告，CPU 利用率报告和设备利用率报告。在 Linux 中怎样安装 iostat？iostat 工具是 sysstat 包的一部分，所以我们可以轻松地在包管理器地帮助下安装，因为在所有的 Linux 发行版的仓库都是可以获得的。对于 Fedora 系统，使用 DNF Command 来安装 sysstat。$ sudo dnf install sysstat对于 Debian/Ubuntu 系统，使用 APT-GET Command 或者 APT Command 来安装 sysstat。$ sudo apt install sysstat对于基于 Arch Linux 的系统，使用 Pacman Command 来安装 sysstat。$ sudo pacman -S sysstat对于 RHEL/CentOS 系统，使用 YUM Command 来安装 sysstat。$ sudo yum install sysstat对于 openSUSE Leap 系统，使用 Zypper Command 来安装 sysstat。$ sudo zy…

五种加速 Go 的特性
type: item
date: 2018-10-11T23:06:40+08:00
description: Anthony Starks 使用他出色的 Deck 演示工具重构了我原来的基于 Google Slides 的幻灯片。你可以在他的博客上查看他重构后的幻灯片, mindchunk.blogspot.com.au/2014/06/remixing-with-deck。我最近被邀请在 Gocon 发表演讲，这是一个每半年在日本东京举行的 Go 的精彩大会。Gocon 2014 是一个完全由社区驱动的为期一天的活动，由培训和一整个下午的围绕着生产环境中的 Go 这个主题的演讲组成.（LCTT 译注：本文发表于 2014 年）以下是我的讲义。原文的结构能让我缓慢而清晰的演讲，因此我已经编辑了它使其更可读。我要感谢 Bill Kennedy 和 Minux Ma，特别是 Josh Bleecher Snyder，感谢他们在我准备这次演讲中的帮助。大家下午好。我叫 David.我很高兴今天能来到 Gocon。我想参加这个会议已经两年了，我很感谢主办方能提供给我向你们演讲的机会。我想以一个问题开始我的演讲。为什么选择 Go？当大家讨论学习或在生产环境中使用 Go 的原因时，答案不一而足，但因为以下三个原因的最多。这就是 TOP3 的原因。第一，并发。Go 的 并发原语 Concurrency Primitives 对于来自 Nodejs，Ruby 或 Python 等单线程脚本语言的程序员，或者来自 C++ 或 Java 等重量级线程模型的语言都很有吸引力。易于部署。我们今天从经验丰富的 Gophers 那里听说过，他们非常欣赏部署 Go 应用的简单性。然后是性能。我相信人们选择 Go 的一个重要原因是它 快。在今天的演讲中，我想讨论五个有助于提高 Go 性能的特性。我还将与大家分享 Go 如何实现这些特性的细节。我要谈的第一个特性是 Go 对于值的高效处理和存储。这是 Go 中一个值的例子。编译时，gocon 正好消耗四个字节的内存。让我们将 Go 与其他一些语言进行比较由于 Python 表示变量的方式的开销，使用 Python 存储相同的值会消耗六倍的内存。Python 使用额外的内存来跟踪类型信息，进行 引用计数 Reference Counting 等。让我们看另一个例子：与 Go 类似，Java 消耗 4 个字节的内存来存储 int 型。但是，要在像 List 或 Map 这样的集合中使用此值，编译器必须将其转换为 Integer 对象。因此，Java 中的整数通常消耗 16 到 24 个字节的内存。为什么这很重要？ 内存便宜且充足，为什么这个开销很重要？这是一张显示 CPU 时钟速度与内存总线速度的图表。请注意 CPU 时钟速度和内存总线速度之间的差距如何继续扩大。两者之间的差异实际上是 CPU 花费多少时间等待内存。自 1960 年代后期以来，CPU 设计师已经意识到了这个问题。他们的解决方案是一个缓存，一个更小、更快的内存区域，介入 CPU 和主存之间。这是一个 Location 类型，它保存物体在三维空间中的位置。它是用 Go 编写的，因此每个 Location 只消耗 24 个字节的存储空间。我们可以使用这种类型来构造一个容纳 1000 个 Location 的数组类型，它只消耗 24000 字节的内存。在数组内部，Location 结构体是顺序存储的，而不是随机存储的 1000 个 Location 结构体的指针。这很重要，因为现在所有 1000 个 Location 结构体都按顺序放在缓存中，紧密排列在一起。Go 允许您创建紧凑的数据结构，避免不必要的填充字节。紧凑的数据结构能更好地利用缓存。更好的缓存利用率可带来更好的性能。函数调用不是无开销的。调用函数时会发生三件事。创建一个新的 栈帧 Stack Frame ，并记录调用者的详细信息。在函数调用期间可能被覆盖的任何寄存器都将保存到栈中。处理器计算函数的地址并执行到该新地址的分支。由于函数调用是非常常见的操作，因此 CPU 设计师一直在努力优化此过程，但他们无法消除开销。函调固有开销，或重于泰山，或轻于鸿毛，这取决于函数做了什么。减少函数调用开销的解决方案是 内联 Inlining 。Go 编译器通过将函数体视为调用者的一部分来内联函数。内联也有成本，它增加了二进制文件大小。只有当调用开销与函数所做工作关联度的很大时内联才有意义，因此只有简单的函数才能用于内联。复杂的函数通常不受调用它们的开销所支配，因此不会内联。这个例子显示函数 Double 调用 util.Max。为了减少调用 util.Max 的开销，编译器可以将 util.Max 内联到 Double 中，就象这样内联后不再调用 util.Max，但是 Double 的行为没有改变。内联并不是 Go …

服务端 I/O 性能：Node、PHP、Java、Go 的对比
type: item
date: 2017-10-31T17:42:59+08:00
description: 了解应用程序的输入/输出（I/O）模型意味着理解应用程序处理其数据的载入差异，并揭示其在真实环境中表现。或许你的应用程序很小，在不承受很大的负载时，这并不是个严重的问题；但随着应用程序的流量负载增加，可能因为使用了低效的 I/O 模型导致承受不了而崩溃。和大多数情况一样，处理这种问题的方法有多种方式，这不仅仅是一个择优的问题，而是对权衡的理解问题。 接下来我们来看看 I/O 到底是什么。在本文中，我们将对 Node、Java、Go 和 PHP + Apache 进行对比，讨论不同语言如何构造其 I/O ，每个模型的优缺点，并总结一些基本的规律。如果你担心你的下一个 Web 应用程序的 I/O 性能，本文将给你最优的解答。I/O 基础知识: 快速复习要了解 I/O 所涉及的因素，我们首先深入到操作系统层面复习这些概念。虽然看起来并不与这些概念直接打交道，但你会一直通过应用程序的运行时环境与它们间接接触。了解细节很重要。系统调用首先是系统调用，其被描述如下：程序（所谓“ 用户端 user land ”）必须请求操作系统内核代表它执行 I/O 操作。“ 系统调用 syscall ”是你的程序要求内核执行某些操作的方法。这些实现的细节在操作系统之间有所不同，但基本概念是相同的。有一些具体的指令会将控制权从你的程序转移到内核（类似函数调用，但是使用专门用于处理这种情况的专用方式）。一般来说，系统调用会被阻塞，这意味着你的程序会等待内核返回（控制权到）你的代码。内核在所需的物理设备（ 磁盘、网卡等 ）上执行底层 I/O 操作，并回应系统调用。在实际情况中，内核可能需要做许多事情来满足你的要求，包括等待设备准备就绪、更新其内部状态等，但作为应用程序开发人员，你不需要关心这些。这是内核的工作。阻塞与非阻塞上面我们提到过，系统调用是阻塞的，一般来说是这样的。然而，一些调用被归类为“非阻塞”，这意味着内核会接收你的请求，将其放在队列或缓冲区之类的地方，然后立即返回而不等待实际的 I/O 发生。所以它只是在很短的时间内“阻塞”，只需要排队你的请求即可。举一些 Linux 系统调用的例子可能有助于理解：read() 是一个阻塞调用 - 你传递一个句柄，指出哪个文件和缓冲区在哪里传送它所读取的数据，当数据就绪时，该调用返回。这种方式的优点是简单友好。分别调用 epoll_create()、epoll_ctl() 和 epoll_wait() ，你可以创建一组句柄来侦听、添加/删除该组中的处理程序、然后阻塞直到有任何事件发生。这允许你通过单个线程有效地控制大量的 I/O 操作，但是现在谈这个还太早。如果你需要这个功能当然好，但须知道它使用起来是比较复杂的。了解这里的时间差异的数量级是很重要的。假设 CPU 内核运行在 3GHz，在没有进行 CPU 优化的情况下，那么它每秒执行 30 亿次 周期 cycle （即每纳秒 3 个周期）。非阻塞系统调用可能需要几十个周期来完成，或者说 “相对少的纳秒” 时间完成。而一个被跨网络接收信息所阻塞的系统调用可能需要更长的时间 - 例如 200 毫秒（1/5 秒）。这就是说，如果非阻塞调用需要 20 纳秒，阻塞调用需要 2 亿纳秒。你的进程因阻塞调用而等待了 1000 万倍的时长！内核既提供了阻塞 I/O （“从网络连接读取并给出数据”），也提供了非阻塞 I/O （“告知我何时这些网络连接具有新数据”）的方法。使用的是哪种机制对调用进程的阻塞时长有截然不同的影响。调度关键的第三件事是当你有很多线程或进程开始阻塞时会发生什么。根据我们的理解，线程和进程之间没有很大的区别。在现实生活中，最显著的性能相关的差异在于，由于线程共享相同的内存，而进程每个都有自己的内存空间，使得单独的进程往往占用更多的内存。但是当我们谈论 调度 Scheduling 时，它真正归结为一类事情（线程和进程类同），每个都需要在可用的 CPU 内核上获得一段执行时间。如果你有 300 个线程运行在 8 个内核上，则必须将时间分成几份，以便每个线程和进程都能分享它，每个运行一段时间，然后交给下一个。这是通过 “ 上下文切换 context switch ” 完成的，可以使 CPU 从运行到一个线程/进程到切换下一个。这些上下文切换也有相关的成本 - 它们需要一些时间。在某些快速的情况下，它可能小于 100 纳秒，但根据实际情况、处理器速度/体系结构、CPU 缓存等，偶见花费 1000 纳秒或更长时间。而线程（或进程）越多，上下文切换就越多。当我们涉及数以千计的线程时，每个线程花费数百纳秒，就会变得很慢。然而，非阻塞调用实质上是告诉内核“仅在这些连接之一有新的数据或事件时再叫我”。这些非阻塞调用旨在有效地处理大量 I/O 负载并减少上下文交换。这些你明白了…

Linux 容器轻松应对性能工程
type: item
date: 2017-08-21T02:42:00+08:00
description: 应用程序的性能决定了软件能多快完成预期任务。这回答有关应用程序的几个问题，例如：峰值负载下的响应时间与替代方案相比，它易于使用，受支持的功能和用例运营成本（CPU 使用率、内存需求、数据吞吐量、带宽等）该性能分析的价值超出了服务负载所需的计算资源或满足峰值需求所需的应用实例数量的估计。性能显然与成功企业的基本要素挂钩。它揭示了用户的总体体验，包括确定什么会拖慢客户预期的响应时间，通过设计满足带宽要求的内容交付来提高客户粘性，选择最佳设备，最终帮助企业发展业务。问题当然，这是对业务服务的性能工程价值的过度简化。为了理解在完成我刚刚所描述事情背后的挑战，让我们把它放到一个真实的稍微有点复杂的场景中。现实世界的应用程序可能托管在云端。应用程序可以利用非常大（或概念上是无穷大）的计算资源。在硬件和软件方面的需求将通过云来满足。从事开发工作的开发人员将使用云交付功能来实现更快的编码和部署。云托管不是免费的，但成本开销与应用程序的资源需求成正比。除了 搜索即服务 Search as a Service （SaaS）、 平台即服务 Platform as a Service （PaaS）、 基础设施即服务 Infrastructure as a Service （IaaS）以及 负载平衡即服务 Load Balancing as a Service （LBaaS）之外，当云端管理托管程序的流量时，开发人员可能还会使用这些快速增长的云服务中的一个或多个： 安全即服务 Security as a Service （SECaaS），可满足软件和用户的安全需求 数据即服务 Data as a Service （DaaS），为应用提供了用户需求的数据 登录即服务 Logging as a Service （LaaS），DaaS 的近亲，提供了日志传递和使用的分析指标 搜索即服务 Search as a Service （SaaS），用于应用程序的分析和大数据需求 网络即服务 Network as a Service （NaaS），用于通过公共网络发送和接收数据云服务也呈指数级增长，因为它们使得开发人员更容易编写复杂的应用程序。除了软件复杂性之外，所有这些分布式组件的相互作用变得越来越多。用户群变得更加多元化。该软件的需求列表变得更长。对其他服务的依赖性变大。由于这些因素，这个生态系统的缺陷会引发性能问题的多米诺效应。例如，假设你有一个精心编写的应用程序，它遵循安全编码实践，旨在满足不同的负载要求，并经过彻底测试。另外假设你已经将基础架构和分析工作结合起来，以支持基本的性能要求。在系统的实现、设计和架构中建立性能标准需要做些什么？软件如何跟上不断变化的市场需求和新兴技术？如何测量关键参数以调整系统以获得最佳性能？如何使系统具有弹性和自我恢复能力？你如何更快地识别任何潜在的性能问题，并尽早解决？进入容器软件容器以微服务设计或面向服务的架构（SoA）的优点为基础，提高了性能，因为包含更小的、自足的代码块的系统更容易编码，对其它系统组件有更清晰、定义良好的依赖。测试更容易，包括围绕资源利用和内存过度消耗的问题比在宏架构中更容易确定。当扩容系统以增加负载能力时，容器应用程序的复制快速而简单。安全漏洞能更好地隔离。补丁可以独立版本化并快速部署。性能监控更有针对性，测量更可靠。你还可以重写和“改版”资源密集型代码，以满足不断变化的性能要求。容器启动快速，停止也快速。它比虚拟机（VM）有更高效资源利用和更好的进程隔离。容器没有空闲内存和 CPU 闲置。它们允许多个应用程序共享机器，而不会丢失数据或性能。容器使应用程序可移植，因此开发人员可以构建并将应用程序发送到任何支持容器技术的 Linux 服务器上，而不必担心性能损失。容器生存在其内，并遵守其集群管理器（如 Cloud Foundry 的 Diego、Kubernetes、Apache Mesos 和 Docker Swarm）所规定的配额（比如包括存储、计算和对象计数配额）。容器在性能方面表现出色，而即将到来的 “serverless” 计算（也称为 功能即服务 Function as a Service （FaaS））的浪潮将扩大容器的优势。在 FaaS 时代，这些临时性或短期的容器将带来超越应用程序性能的优势，直接转化为在云中托管的间接成本的节省。如果容器的工作更快，那么它的寿命就会更短，而且计算量负载纯粹是按需的。作者简介：Garima 是 Red Hat 的工程经理，专注于 OpenShift 容器平台。在加入 Red Hat 之前，Garima 帮助 Akamai Technologies＆MathWorks Inc. 开创了创新。via: https://opensource.com/article…

理解 Linux 的平均负载和性能监控
type: item
date: 2017-06-24T03:33:12+08:00
description: 在本文中，我们将解释 Linux 系统中最关键的管理任务之一——关于系统 / CPU 的 负载 （ load ） 和 平均负载 （ Load average ） 的性能监控。首先来看所有的类 UNIX 系统中两个重要的表述:系统负载 / CPU 负载 – 衡量 Linux 系统的 CPU 过载或利用率低的指标，即处于运算状态或等待状态的 CPU 核心数。平均负载 – 通过固定的时间周期如 1、5、15 分钟计算出的平均的系统负载。Linux 中，平均负载一般指在内核运行队列中被标记为运行或不可打断状态的进程的平均数。注意：几乎没有 Linux 或类 Unix 系统不为用户展示平均负载的值。完全空闲的 Linux 系统平均负载为 0，不包括空闲进程。绝大多数类 Unix 系统只统计运行和等待状态的进程。但是在 Linux 中，平均负载也包括处于不可打断的睡眠状态的进程——它们是在等待其它系统资源如磁盘 I/O 等的进程。如何监测 Linux 系统平均负载有诸多方式监测系统平均负载，如 uptime，它会展示系统运行时间、用户数量及平均负载：$ uptime 07:13:53 up 8 days, 19 min, 1 user, load average: 1.98, 2.15, 2.21 平均负载的数字从左到右的含义依次为:最近 1 分钟的平均负载为 1.98最近 5 分钟的平均负载为 2.15最近 15 分钟的平均负载为 2.21高平均负载意味着系统是过载的：许多进程在等待 CPU 时间。下一节将介绍平均负载和 CPU 核数的关系。此外，常用的工具 top 和 glances 可以实时显示 Linux 系统的运行状态：Top命令$ top 显示运行中的Linux进程：top - 12:51:42 up 2:11, 1 user, load average: 1.22, 1.12, 1.26 Tasks: 243 total, 1 running, 242 sleeping, 0 stopped, 0 zombie %Cpu(s): 17.4 us, 2.9 sy, 0.3 ni, 74.8 id, 4.6 wa, 0.0 hi, 0.0 si, 0.0 st KiB Mem : 8069036 total, 388060 free, 4381184 used, 3299792 buff/cache KiB Swap: 3906556 total, 3901876 free, 4680 used. 2807464 avail Mem PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 6265 tecmint 20 0 1244348 170680 83616 S 13.3 2.1 6:47.72 Headset 2301 tecmint 9 -11 640332 13344 9932 S 6.7 0.2 2:18.96 pulseaudio 2459 tecmint 20 0 1707692 315628 62992 S 6.7 3.9 6:55.45 cinnamon 2957 tecmint 20 0 2644644 1.035g 137968 S 6.7 13.5 50:11.13 firefox 3208 tecmint 20 0 507060 52136 33152 S 6.7 0.6 0:04.34 gnome-terminal- 3272 tecmint 20 0 1521380 391324 178348 S 6.7 4.8 6:21.01 chrome 6220 tecmint 20 0 1595392 106964 76836 S 6.7 1.3 3:31.94 Headset 1 root 20 0 120056 6204 3964 S 0.0 0.1 0:01.83 systemd 2 root 20 0 0 0 0 S 0.0 0.0 0:00.00 kthreadd 3 root 20 0 0 0 0 S 0.0 0.0 0:00.10 ksoftirqd/0 5 root 0 -20 0 0 0 S 0.0 0.0 0:00.00 kworker/0:0H .... Glances 工具$ glances Glances – Linux系统监测工具：TecMint (LinuxMint 18 64bit / Linux 4.4.0-21-generic) Uptime: 2:16:06 CPU 16.4% nice: 0.1% LOAD 4-core MEM 60.5% active: 4.90G SWAP 0.1% user: 10.2% …

cpustat：在 Linux 下根据运行的进程监控 CPU 使用率
type: item
date: 2017-05-02T05:31:00+08:00
description: cpustat 是 Linux 下一个强大的系统性能测量程序，它用 Go 编程语言 编写。它通过使用 “用于分析任意系统的性能的方法（USE）”，以有效的方式显示 CPU 利用率和饱和度。它高频率对系统中运行的每个进程进行取样，然后以较低的频率汇总这些样本。例如，它能够每 200ms 测量一次每个进程，然后每 5 秒汇总这些样本，包括某些度量的最小/平均/最大值（min/avg/max）。推荐阅读： 监控 Linux 性能的 20 个命令行工具cpustat 能用两种方式输出数据：定时汇总的纯文本列表和每个取样的彩色滚动面板。如何在 Linux 中安装 cpustat为了使用 cpustat，你的 Linux 系统中必须安装有 Go 语言（GoLang），如果你还没有安装它，点击下面的链接逐步安装 GoLang：在 Linux 下安装 GoLang（Go 编程语言）安装完 Go 以后，输入下面的 go get 命令安装 cpustat，这个命令会将 cpustat 二进制文件安装到你的 GOBIN 变量（所指的路径）：# go get github.com/uber-common/cpustat 如何在 Linux 中使用 cpustat安装过程完成后，如果你不是以 root 用户控制系统，像下面这样使用 sudo 命令获取 root 权限运行 cpustat，否则会出现下面显示的错误信息：$ $GOBIN/cpustat This program uses the netlink taskstats interface, so it must be run as root. 注意：想要像你系统中已经安装的其它 Go 程序那样运行 cpustat，你需要把 GOBIN 变量添加到 PATH 环境变量。打开下面的链接学习如何在 Linux 中设置 PATH 变量。学习如何在 Linux 中永久设置你的 $PATH 变量cpustat 是这样工作的：在每个时间间隔查询 /proc 目录获取当前进程 ID 列表，然后：对于每个 PID，读取 /proc/pid/stat，然后计算和前一个样本的差别。如果是一个新的 PID，读取 /proc/pid/cmdline。对于每个 PID，发送 netlink 消息获取 taskstat，计算和前一个样本的差别。读取 /proc/stat 获取总的系统统计信息。根据获取所有这些统计信息所花费的时间，会调整每个休息间隔。另外，通过每次取样之间实际经过的时间，每个样本也会记录它用于测量的时间。这可用于计算 cpustat 自身的延迟。当不带任何参数运行时，cpustat 默认会显示以下信息：样本间隔：200ms；汇总间隔：2s（10 个样本）；显示前 10 个进程；用户过滤器：all；pid 过滤器：all。正如下面截图所示：$ sudo $GOBIN/cpustat cpustat – 监控 Linux CPU 使用在上面的输出中，之前显示的系统范围的度量字段意义如下：usr - 用户模式运行时间占 CPU 百分比的 min/avg/max 值。sys - 系统模式运行时间占 CPU 百分比的 min/avg/max 值。nice - 用户模式低优先级运行时间占 CPU 百分比的 min/avg/max 值。idle - 用户模式空闲时间占 CPU 百分比的 min/avg/max 值。iowait - 等待磁盘 IO 的 min/avg/max 延迟时间。prun - 处于可运行状态的 min/avg/max 进程数量（同“平均负载”一样）。pblock - 被磁盘 IO 阻塞的 min/avg/max 进程数量。pstat - 在本次汇总间隔里启动的进程/线程数目。同样还是上面的输出，对于一个进程，不同列的意思分别是：name - 从 /proc/pid/stat 或 /proc/pid/cmdline 获取的进程名称。pid - 进程 ID，也被用作 “tgid” （线程组 ID）。min - 该 pid 的用户模式+系统模式时间的最小样本，取自 /proc/pid/stat。比率是 CPU 的百分比。max - 该 pid 的用户模式+系统模式时间的最大样本，取自 /proc/pid/stat。usr - 在汇总期间该 pid 的平均用户模式运行时间，取自 /proc/pid/stat。sys - 在汇总期间该 pid 的平均系统模式运行时间，取自 /proc/pid/stat。nice - 表示该进程的当前 “nice” 值，取自 /proc/pid/stat。值越高表示越好（nicer）。runq - 进程和它所有线程可运行但等待运行的时间，通过 netlink 取自 taskst…

pyDash：一个基于 web 的 Linux 性能监测工具
type: item
date: 2017-04-30T15:09:00+08:00
description: pyDash 是一个轻量且基于 web 的 Linux 性能监测工具，它是用 Python 和 Django 加上 Chart.js 来写的。经测试，在下面这些主流 Linux 发行版上可运行：CentOS、Fedora、Ubuntu、Debian、Raspbian 以及 Pidora 。你可以使用这个工具来监视你的 Linux 个人电脑/服务器资源，比如 CPU、内存、网络统计，包括在线用户的进程以及更多。仪表盘完全由主要的 Python 发行版本所提供的 Python 库开发，因此它的依赖关系很少，你不需要安装许多包或库来运行它。在这篇文章中，我将展示如何安装 pyDash 来监测 Linux 服务器性能。如何在 Linux 系统下安装 pyDash1、首先，像下面这样安装需要的软件包 git 和 Python pip：-------------- 在 Debian/Ubuntu 上 -------------- $ sudo apt-get install git python-pip -------------- 在 CentOS/RHEL 上 -------------- # yum install epel-release # yum install git python-pip -------------- 在 Fedora 22+ 上 -------------- # dnf install git python-pip 2、如果安装好了 git 和 Python pip，那么接下来，像下面这样安装 virtualenv，它有助于处理针对 Python 项目的依赖关系：# pip install virtualenv 或 $ sudo pip install virtualenv 3、现在，像下面这样使用 git 命令，把 pyDash 仓库克隆到 home 目录中：# git clone https://github.com/k3oni/pydash.git # cd pydash 4、下一步，使用下面的 virtualenv 命令为项目创建一个叫做 pydashtest 虚拟环境：$ virtualenv pydashtest #give a name for your virtual environment like pydashtest 创建虚拟环境重要：请注意，上面的屏幕截图中，虚拟环境的 bin 目录被高亮显示，你的可能和这不一样，取决于你把 pyDash 目录克隆到什么位置。5、创建好虚拟环境（pydashtest）以后，你需要在使用前像下面这样激活它：$ source /home/aaronkilik/pydash/pydashtest/bin/activate 激活虚拟环境从上面的屏幕截图中，你可以注意到，提示字符串 1（PS1）已经发生改变，这表明虚拟环境已经被激活，而且可以开始使用。6、现在，安装 pydash 项目 requirements；如何你好奇的话，可以使用 cat 命令查看 requirements.txt 的内容，然后像下面所示那样进行安装：$ cat requirements.txt $ pip install -r requirements.txt 7、现在，进入 pydash 目录，里面包含一个名为 settings.py 的文件，也可直接运行下面的命令打开这个文件，然后把 SECRET_KEY 改为一个特定值：$ vi pydash/settings.py 设置密匙保存文件然后退出。8、之后，运行下面的命令来创建一个项目数据库和安装 Django 的身份验证系统，并创建一个项目的超级用户：$ python manage.py syncdb 根据你的情况回答下面的问题：Would you like to create one now? (yes/no): yes Username (leave blank to use 'root'): admin Email address: aaronkilik@gmail.com Password: ########### Password (again): ############ 创建项目数据库9、这个时候，一切都设置好了，然后，运行下面的命令来启用 Django 开发服务器：$ python manage.py runserver 10、接下来，打开你的 web 浏览器，输入网址：http://127.0.0.1:8000/ 进入 web 控制台登录界面，输入你在第 8 步中创建数据库和安装 Django 身份验证系统时创建的超级用户名和密码，然后点击登录。pyDash 登录界面11、登录到 pydash 主页面以后，你将会…

Python 是慢，但我无所谓
type: item
date: 2017-04-25T19:14:00+08:00
description: 为牺牲性能追求生产率而呐喊让我从关于 Python 中的 asyncio 这个标准库的讨论中休息一会，谈谈我最近正在思考的一些东西：Python 的速度。对不了解我的人说明一下，我是一个 Python 的粉丝，而且我在我能想到的所有地方都积极地使用 Python。人们对 Python 最大的抱怨之一就是它的速度比较慢，有些人甚至拒绝尝试使用 Python，因为它比其他语言速度慢。这里说说为什么我认为应该尝试使用 Python，尽管它是有点慢。速度不再重要过去的情形是，程序需要花费很长的时间来运行，CPU 比较贵，内存也很贵。程序的运行时间是一个很重要的指标。计算机非常的昂贵，计算机运行所需要的电也是相当贵的。对这些资源进行优化是因为一个永恒的商业法则：优化你最贵的资源。在过去，最贵的资源是计算机的运行时间。这就是导致计算机科学致力于研究不同算法的效率的原因。然而，这已经不再是正确的，因为现在硅芯片很便宜，确实很便宜。运行时间不再是你最贵的资源。公司最贵的资源现在是它的员工时间。或者换句话说，就是你。把事情做完比把它变快更加重要。实际上，这是相当的重要，我将把它再次放在这里，仿佛它是一个引文一样（给那些只是粗略浏览的人）:把事情做完比快速地做事更加重要。你可能会说：“我的公司在意速度，我开发一个 web 应用程序，那么所有的响应时间必须少于 x 毫秒。”或者，“我们失去了客户，因为他们认为我们的 app 运行太慢了。”我并不是想说速度一点也不重要，我只是想说速度不再是最重要的东西；它不再是你最贵的资源。速度是唯一重要的东西当你在编程的背景下说 速度 时，你通常是说性能，也就是 CPU 周期。当你的 CEO 在编程的背景下说 速度 时，他指的是业务速度，最重要的指标是产品上市的时间。基本上，你的产品/web 程序是多么的快并不重要。它是用什么语言写的也不重要。甚至它需要花费多少钱也不重要。在一天结束时，让你的公司存活下来或者死去的唯一事物就是产品上市时间。我不只是说创业公司的想法 -- 你开始赚钱需要花费多久，更多的是“从想法到客户手中”的时间期限。企业能够存活下来的唯一方法就是比你的竞争对手更快地创新。如果在你的产品上市之前，你的竞争对手已经提前上市了，那么你想出了多少好的主意也将不再重要。你必须第一个上市，或者至少能跟上。一但你放慢了脚步，你就输了。企业能够存活下来的唯一方法就是比你的竞争对手更快地创新。一个微服务的案例像 Amazon、Google 和 Netflix 这样的公司明白快速前进的重要性。他们创建了一个业务系统，可以使用这个系统迅速地前进和快速的创新。微服务是针对他们的问题的解决方案。这篇文章不谈你是否应该使用微服务，但是至少要理解为什么 Amazon 和 Google 认为他们应该使用微服务。微服务本来就很慢。微服务的主要概念是用网络调用来打破边界。这意味着你正在把使用的函数调用（几个 cpu 周期）转变为一个网络调用。没有什么比这更影响性能了。和 CPU 相比较，网络调用真的很慢。但是这些大公司仍然选择使用微服务。我所知道的架构里面没有比微服务还要慢的了。微服务最大的弊端就是它的性能，但是最大的长处就是上市的时间。通过在较小的项目和代码库上建立团队，一个公司能够以更快的速度进行迭代和创新。这恰恰表明了，非常大的公司也很在意上市时间，而不仅仅只是只有创业公司。CPU 不是你的瓶颈如果你在写一个网络应用程序，如 web 服务器，很有可能的情况会是，CPU 时间并不是你的程序的瓶颈。当你的 web 服务器处理一个请求时，可能会进行几次网络调用，例如到数据库，或者像 Redis 这样的缓存服务器。虽然这些服务本身可能比较快速，但是对它们的网络调用却很慢。这里有一篇很好的关于特定操作的速度差异的博客文章。在这篇文章里，作者把 CPU 周期时间缩放到更容易理解的人类时间。如果一个单独的 CPU 周期等同于 1 秒，那么一个从 California 到 New York 的网络调用将相当于 4 年。那就说明了网络调用是多少的慢。按一些粗略估计，我们可以假设在同一数据中心内的普通网络调用大约需要 3 毫秒。这相当于我们“人类比例” 3 个月。现在假设你的程序是高 CPU 密集型，这需要 100000 个 CPU 周期来对单一调用进行响应。这相当于刚刚超过 1 天。现在让我们假设你使用的是一种要慢 5 倍的语言，这将需要大约 5 天。很好，将那与我们 3 个月的网络调用时间相比，4 天的差异就显得并不是很重要了。如果有人为了一个包裹不得不至少等待 3 个月，我不认为额外的 4 天对他们来说真的很重要。上面所说的终极意思是，尽管 Python 速度慢，但是这并不重要。语言的速度（或者 CPU 时间）几乎从来不是问题。实际上谷歌曾…

深入解析面向数据的哈希表性能
type: item
date: 2017-04-17T19:16:00+08:00
description: 最近几年中，面向数据的设计已经受到了很多的关注 —— 一种强调内存中数据布局的编程风格，包括如何访问以及将会引发多少的 cache 缺失。由于在内存读取操作中缺失所占的数量级要大于命中的数量级，所以缺失的数量通常是优化的关键标准。这不仅仅关乎那些对性能有要求的 code-data 结构设计的软件，由于缺乏对内存效益的重视而成为软件运行缓慢、膨胀的一个很大因素。高效缓存数据结构的中心原则是将事情变得平滑和线性。比如，在大部分情况下，存储一个序列元素更倾向于使用普通数组而不是链表 —— 每一次通过指针来查找数据都会为 cache 缺失增加一份风险；而普通数组则可以预先获取，并使得内存系统以最大的效率运行如果你知道一点内存层级如何运作的知识，下面的内容会是想当然的结果——但是有时候即便它们相当明显，测试一下任不失为一个好主意。几年前 Baptiste Wicht 测试过了 std::vector vs std::list vs std::deque，（后者通常使用分块数组来实现，比如：一个数组的数组）。结果大部分会和你预期的保持一致，但是会存在一些违反直觉的东西。作为实例：在序列链表的中间位置做插入或者移除操作被认为会比数组快，但如果该元素是一个 POD 类型，并且不大于 64 字节或者在 64 字节左右（在一个 cache 流水线内），通过对要操作的元素周围的数组元素进行移位操作要比从头遍历链表来的快。这是由于在遍历链表以及通过指针插入/删除元素的时候可能会导致不少的 cache 缺失，相对而言，数组移位则很少会发生。（对于更大的元素，非 POD 类型，或者你已经有了指向链表元素的指针，此时和预期的一样，链表胜出）多亏了类似 Baptiste 这样的数据，我们知道了内存布局如何影响序列容器。但是关联容器，比如 hash 表会怎么样呢？已经有了些权威推荐：Chandler Carruth 推荐的带局部探测的开放寻址（此时，我们没必要追踪指针），以及Mike Acton 推荐的在内存中将 value 和 key 隔离（这种情况下，我们可以在每一个 cache 流水线中得到更多的 key）， 这可以在我们必须查找多个 key 时提高局部性能。这些想法很有意义，但再一次的说明：测试永远是好习惯，但由于我找不到任何数据，所以只好自己收集了。测试我测试了四个不同的 quick-and-dirty 哈希表实现，另外还包括 std::unordered_map 。这五个哈希表都使用了同一个哈希函数 —— Bob Jenkins 的 SpookyHash（64 位哈希值）。（由于哈希函数在这里不是重点，所以我没有测试不同的哈希函数；我同样也没有检测我的分析中的总内存消耗。）实现会通过简短的代码在测试结果表中标注出来。UM： std::unordered_map 。在 VS2012 和 libstdc++-v3 （libstdc++-v3: gcc 和 clang 都会用到这东西）中，UM 是以链表的形式实现，所有的元素都在链表中，bucket 数组中存储了链表的迭代器。VS2012 中，则是一个双链表，每一个 bucket 存储了起始迭代器和结束迭代器；libstdc++ 中，是一个单链表，每一个 bucket 只存储了一个起始迭代器。这两种情况里，链表节点是独立申请和释放的。最大负载因子是 1 。Ch：分离的、链状 bucket 指向一个元素节点的单链表。为了避免分开申请每一个节点，元素节点存储在普通数组池中。未使用的节点保存在一个空闲链表中。最大负载因子是 1。OL：开地址线性探测 —— 每一个 bucket 存储一个 62 bit 的 hash 值，一个 2 bit 的状态值（包括 empty，filled，removed 三个状态），key 和 value 。最大负载因子是 2/3。DO1：“data-oriented 1” —— 和 OL 相似，但是哈希值、状态值和 key、values 分离在两个隔离的平滑数组中。DO2：“data-oriented 2” —— 与 OL 类似，但是哈希/状态，keys 和 values 被分离在 3 个相隔离的平滑数组中。在我的所有实现中，包括 VS2012 的 UM 实现，默认使用尺寸为 2 的 n 次方。如果超出了最大负载因子，则扩展两倍。在 libstdc++ 中，UM 默认尺寸是一个素数。如果超出了最大负载因子，则扩展为下一个素数大小。但是我不认为这些细节对性能很重要。素数是一种对低 bit 位上没有足够熵的低劣 hash 函数的挽救手段，但是我们正在用的是一个很好的 hash 函数。OL，DO1 和 DO2 的实现将共同的被称为 OA（open addressing）——稍后我们将发现它们在…