齐市北关献彩票3d字谜:文章 – 伯乐在线 - 山西十一选五手机版▁山西11选五前三组遗漏▁山西十一选五任七遗漏▁山西11选五遗漏top10▁山西体彩十一选5一定牛 //www.brhi.net Wed, 19 Dec 2018 12:49:07 +0000 zh-CN hourly 1 https://wordpress.org/?v=4.5.16 Linux 搜索文件和文件夹的 4 种简单方法 - 山西十一选五手机版▁山西11选五前三组遗漏▁山西十一选五任七遗漏▁山西11选五遗漏top10▁山西体彩十一选5一定牛 //www.brhi.net/114561/ //www.brhi.net/114561/#respond Wed, 19 Dec 2018 12:49:07 +0000 //www.brhi.net/?p=114561 Linux 管理员一天都不能离开搜索文件,因为这是他们的日?;疃?。

Linux 搜索文件和文件夹的 4 种简单方法,首发于山西十一选五手机版。

]]>

Linux 管理员一天都不能离开搜索文件,因为这是他们的日?;疃?。了解一些搜索的东西是不错的,因为这能帮助你在命令行服务器中工作。这些命令记忆起来不复杂,因为它们使用的是标准语法。

可以通过四个 Linux 命令啦执行此操作,每个命令都有自己独特的功能。

方法 1:使用 find 命令在 Linux 中搜索文件和文件夹

find 命令被广泛使用,并且是在 Linux 中搜索文件和文件夹的著名命令。它搜索当前目录中的给定文件,并根据搜索条件递归遍历其子目录。

它允许用户根据大小、名称、所有者、组、类型、权限、日期和其他条件执行所有类型的文件搜索。

运行以下命令以在系统中查找给定文件。

# find / -iname "sshd_config"
/etc/ssh/sshd_config

运行以下命令以查找系统中的给定文件夹。要在 Linux 中搜索文件夹,我们需要使用 -type 参数。

# find / -type d -iname "ssh"
/usr/lib/ssh
/usr/lib/go/src/cmd/vendor/golang.org/x/crypto/ssh
/usr/lib/go/pkg/linux_amd64/cmd/vendor/golang.org/x/crypto/ssh
/etc/ssh

使用通配符搜索系统上的所有文件。我们将搜索系统中所有以 .config 为扩展名的文件。

# find / -name "*.config"
/usr/lib/mono/gac/avahi-sharp/1.0.0.0__4d116c78973743f5/avahi-sharp.dll.config
/usr/lib/mono/gac/avahi-ui-sharp/0.0.0.0__4d116c78973743f5/avahi-ui-sharp.dll.config
/usr/lib/python2.7/config/Setup.config
/usr/share/git/mw-to-git/t/test.config
/var/lib/lightdm/.config
/home/daygeek/.config
/root/.config
/etc/skel/.config

使用以下命令格式在系统中查找空文件和文件夹。

# find / -empty

使用以下命令组合查找 Linux 上包含特定文本的所有文件。

# find / -type f -exec grep "Port 22" '{}' \; -print
# find / -type f -print | xargs grep "Port 22"
# find / -type f | xargs grep 'Port 22'
# find / -type f -exec grep -H 'Port 22' {} \;

方法 2:使用 locate 命令在 Linux 中搜索文件和文件夹

locate 命令比 find 命令运行得更快,因为它使用 updatedb 数据库,而 find 命令在真实系统中搜索。

它使用数据库而不是搜索单个目录路径来获取给定文件。

locate 命令未在大多数发行版中预安装,因此,请使用你的包管理器进行安装。

数据库通过 cron 任务定期更新,但我们可以通过运行以下命令手动更新它。

$ sudo updatedb

只需运行以下命令即可列出给定的文件或文件夹。在 locate 命令中不需要指定特定选项来打印文件或文件夹。

在系统中搜索 ssh 文件夹。

# locate --basename '\ssh'
/etc/ssh
/usr/bin/ssh
/usr/lib/ssh
/usr/lib/go/pkg/linux_amd64/cmd/vendor/golang.org/x/crypto/ssh
/usr/lib/go/src/cmd/go/testdata/failssh/ssh
/usr/lib/go/src/cmd/vendor/golang.org/x/crypto/ssh

在系统中搜索 ssh_config 文件。

# locate --basename '\sshd_config'
/etc/ssh/sshd_config

方法 3:在 Linux 中搜索文件使用 which 命令

which 返回在终端输入命令时执行的可执行文件的完整路径。

当你想要为可执行文件创建桌面快捷方式或符号链接时,它非常有用。

which 命令搜索当前用户而不是所有用户的 $PATH 环境变量中列出的目录。我的意思是,当你登录自己的帐户时,你无法搜索 root 用户文件或目录。

运行以下命令以打印 vim 可执行文件的完整路径。

# which vi
/usr/bin/vi

或者,它允许用户一次执行多个文件搜索。

# which -a vi sudo
/usr/bin/vi
/bin/vi
/usr/bin/sudo
/bin/sudo

方法 4:使用 whereis 命令在 Linux 中搜索文件

whereis 命令用于搜索给定命令的二进制、源码和手册页文件。

# whereis vi
vi: /usr/bin/vi /usr/share/man/man1/vi.1p.gz /usr/share/man/man1/vi.1.gz

 

Linux 搜索文件和文件夹的 4 种简单方法,首发于山西十一选五手机版。

]]>
//www.brhi.net/114561/feed/ 0
学会这两件事,让你成为 Git 老司机 - 山西十一选五手机版▁山西11选五前三组遗漏▁山西十一选五任七遗漏▁山西11选五遗漏top10▁山西体彩十一选5一定牛 //www.brhi.net/114551/ //www.brhi.net/114551/#respond Tue, 18 Dec 2018 15:34:25 +0000 //www.brhi.net/?p=114551 “我在提交中犯了个错误,我如何修正它?”,“我的提交历史一团糟,我该如何让它更整洁?”如果你曾经有上述问题,那么这篇文章很适合你。这篇文章介绍了一个让你成为 Git 老司机的清单。

学会这两件事,让你成为 Git 老司机,首发于山西十一选五手机版。

]]>

  • 我在提交中犯了个错误,我如何修正它?
  • 我的提交历史一团糟,我该如何让它更整洁?

如果你曾经有上述问题,那么这篇文章很适合你。这篇文章介绍了一个让你成为 Git 老司机的清单。

我在提交中犯了个错误,我该怎么办?

情景 1

假设你已经提交了一堆文件,并发现输入的提交信息实际上并不清晰。现在你要更改提交消息。为此,你可以使用 git commit --amend

git commit --amend -m “New commit message”

场景 2

假设你要提交六个文件,但你最终错误地只提交了五个文件。你可能认为可以创建新提交并将第六个文件添加到该提交。

这种方法没错。但是,为了保持整洁的提交历史,如果你可以以某种方式将此文件加入到你之前的提交本身,那岂不是更好?这也可以通过 git commit --amend 完成:

git commit --amend -m “New commit message”

--no-edit 表示提交信息不会更改。

场景 3

无论你何时在 Git 进行提交,提交都会附上作者名称和作者电子邮箱。通常,当你第一次配置 Git 时,就需要设置作者和电子邮箱。你无需担心每次提交的作者详细信息。

也就是说,对于特定项目,你可能希望使用不同的电子邮箱 ID。你需要使用以下命令为该项目配置电子邮箱 ID:

git config user.email “your email id”

假设你忘记配置电子邮箱,并且已经完成了第一次提交。amend 命令也可以用于更改先前提交的作者消息??梢允褂靡韵旅罡奶峤坏淖髡咝畔ⅲ?/p>

git commit --amend --author "Author Name <Author Email>"

注意事项

应该仅在本地仓库使用 amend 命令。在远端仓库使用 amend 命令会制造大量混乱。

我的提交历史一团糟,我该如何处理?

假设你正在处理一段代码。你知道代码大约需要十天完成。在这十天内,其他开发人员也将提交代码到远程仓库。

将本地仓库代码与远程仓库代码保持同步是个很好的做法。这在你拉取请求时会避免许多合并冲突的操作。因此,你应该每两天从远程仓库中拉取一个变更。

每次将代码从远程仓库拉取到本地仓库时,都会在本地操作中创建新的合并提交。这意味着你的本地历史提交记录会有大量的合并提交,这会让审阅人员头大。

上面是历史提交记录在本地仓库中的显示方式。

如何让历史提交记录看起来更整洁?

这就需要用到 rebase 了。

什么是变基(rebase)?

举个🌰。

此图显示了发布(release)分支和功能(feature)分支中的提交。

  1. 发布分支有三个提交:Rcommit1、Rcommit2 和 Rcommit3。
  2. 你在发布分支中仅有一个提交(即 Rcommit1)时,创建了功能分支。
  3. 你已向功能分支添加了两个提交。它们是 Fcommit1 和 Fcommit2。
  4. 你希望从发布分支提交到功能分支中。
  5. 你可以使用变基来完成该操作。
  6. 让发布分支命名为 release,让功能分支命名为 feature。
  7. 可以使用以下命令进行变基:

git checkout feature
git rebase release

变基

当执行变基时,你的目标是确保功能分支从发布分支获取最新代码。

变基命令尝试逐个添加每个提交,并检查冲突。这听起来是不是有点头大?

让我画个图帮助理解。

这显示了变基内部实际做的事情:

第 1 步

  1. 运行该命令的那一刻,功能分支指向发布分支的头部。
  2. 现在,功能分支有三个提交,Rcommit1、Rcommit2 和 Rcommit3。
  3. 你可能想知道 Rcommit1 和 Rcommit2 发生了什么?
  4. 提交仍然存在,将在下面步骤中使用。

第 2 步

  1. 现在 Git 尝试将 Fcommit1 添加到功能分支上。
  2. 如果没有冲突,则在 Rcommit3 之后添加 Fcommit1;
  3. 如果存在冲突,Git 会通知你,你必须手动解决冲突。解决冲突后,使用以下命令继续变基:

git add fixedfile
git rebase --continue

第 3 步

  1. 一旦添加了 Fcommit1,Git 将尝试添加 Fcommit2。
  2. 同样,如果没有冲突,则在 Fcommit1 之后添加 Fcommit2,并且变基成功。
  3. 如果存在冲突,Git 会通知你,你必须手动解决。解决冲突后,使用第 2 步提到的相同命令。
  4. 整个变基完成后,你会发现功能分支有 Rcommit1、Rcommit2、Rcommit3、Fcommit1 和 Fcommit2。

注意事项

  1. 变基和合并(merge)在 Git 中都很有用。两种并无优劣之分。
  2. 在合并的情况下,你将有个合并提交。在变基的情况下,不会像合并提交那样有额外的提交。
  3. 一种最佳的实践是一分为二。使用远端仓库中的最新代码更新本地仓库时,请使用变基。在处理拉取请求,以将功能分支和发布分支或主分支合并时,请使用合并。
  4. 使用变基会更改历史提交记录(使其更整洁)。但话虽如此,改变历史提交存在风险。因此,请确保永远不要对远程存储仓库的代码使用变基。始终仅对本地仓库代码使用变基,来更改历史提交记录。
  5. 如果对远端仓库进行变基,会制造许多混乱,因为其他开发人员无法识别新的历史记录。
  6. 此外,如果在远端仓库上完成变基,则当其他开发人员尝试从远端仓库中拉取最新代码时,就可能会出问题。所以,我再重申一遍,变基总是仅在本地仓库中进行。😃

恭喜

你现在是个 Git 老司机了。😃

在这篇文章中,你了解到:

  • 修改提交记录
  • 变基

这两个都是非常实用的概念。探索 Git 的世界,继续学习吧。

学会这两件事,让你成为 Git 老司机,首发于山西十一选五手机版。

]]>
//www.brhi.net/114551/feed/ 0
神奇的 Linux 命令行字符形状工具 boxes - 山西十一选五手机版▁山西11选五前三组遗漏▁山西十一选五任七遗漏▁山西11选五遗漏top10▁山西体彩十一选5一定牛 //www.brhi.net/114549/ //www.brhi.net/114549/#respond Sun, 16 Dec 2018 13:08:05 +0000 //www.brhi.net/?p=114549 本文将教你如何在 Linux 命令行终端中使用 boxes 工具绘制字符形状图形来包装你的文字让其更突出。

神奇的 Linux 命令行字符形状工具 boxes,首发于山西十一选五手机版。

]]>

本文将教你如何在 Linux 命令行终端中使用 boxes 工具绘制字符形状图形来包装你的文字让其更突出。

现在正值假期,每个 Linux 终端用户都该得到一点礼物。无论你是庆祝圣诞节还是庆祝其他节日,或者什么节日也没有,都没有关系。我将在接下来的几周内介绍 24 个 Linux 命令行小玩具,供你把玩或者与朋友分享。让我们享受乐趣,让这个月过得快乐一点,因为对于北半球来说,这个月有点冷并且沉闷。

对于我要讲述的内容,可能你之前就有些了解。但是,我还是希望我们都有机会学到一些新的东西(我做了一点研究,确??梢苑窒?24 个小玩具)。

24 个 Linux 终端小玩具中的第一个是叫做 boxes 的小程序。为何从 boxes 说起呢?因为在没有它的情况下很难将所有其他命令礼物包装起来!

在我的 Fedora 机器上,默认没有安装 boxes 程序,但它在我的普通仓库中可以获取到,所以用如下命令就可安装:

$ sudo dnf install boxes -y

如果你在使用其他 Linux 发行版,一般也都可以在默认仓库中找到 boxes。

boxes 是我真正希望在高中和大学计算机课程中就使用的实用程序,因为善意的老师要求我在每个源文件、函数、代码块等开头添加一些特定外观的备注信息。

/***************/
/* Hello World */
/***************/

事实证明,一旦你需要在框内添加几行文字,并且格式化的将它们统一风格就会变得很乏味。而 boxes 是一个简单实用程序,它使用 ASCII 艺术风格的字符形状框来包围文本。其字符形状默认风格是源代码注释风格,但也提供了一些其他选项。

它真的很容易使用。使用管道,便可以将一个简短问候语塞进字符形状盒子里。

$ cat greeting.txt | boxes -d diamonds -a c

上面的命令输出结果如下:

? ? ? ?/ ? ? ? ? ?/ ? ? ? ? ?/
? ? ///\/ ? ?///\/ ? ?///\/
?///\///\///\///\///\///\/
//\///\///\///\///\///\///\
\/// ? ? ? ? ? ? ? ? ? ? ? ? ? ?/\//
?/ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?/
?/ ? ? ?I'm wishing you all a ? ? ? /
//\ ? ? joyous holiday season ? ? ?//\
\// ? ? and a Happy Gnu Year! ? ? ?\//
?/ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?/
?/ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?/
//\/ ? ? ? ? ? ? ? ? ? ? ? ? ? ?///\
\///\///\///\///\///\///\//
?/\///\///\///\///\///\///
? ? /\/// ? ?/\/// ? ?/\///
? ? ? ?/ ? ? ? ? ?/ ? ? ? ? ?/

或者玩点更有趣的,比如:

echo "I am a dog" | boxes -d dog -a c

不要惊讶,它将会输出如下:

? ? ? ? ? __ ? _,--="=--,_ ? __
? ? ? ? ?/ ?." ? ?.-. ? ?"./ ?
? ? ? ? / ?,/ ?_ ? : : ? _ ?/` 
? ? ? ?  ?`| /o ?:_: ?/o |__/
? ? ? ? ?`-'| :="~` _ `~"=: |
? ? ? ? ? ? ` ? ? (_) ? ? `/
? ? ?.-"-. ?  ? ? ?| ? ? ?/ ? .-"-.
.---{ ? ? }--| ?/,.-'-., ?|--{ ? ? }---.
?) ?(_)_)_) ?_/`~-===-~`_/ ?(_(_(_) ?(
( ? ? ? ? ? ? ?I am a dog ? ? ? ? ? ? ? )
?) ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? (
'---------------------------------------'

boxes 程序提供了很多选项 用于填充、定位甚至处理正则表达式。你可以在其 项目主页 上了解更多有关 boxes 的信息,或者转到 GitHub 去下载源代码或者贡献你自己的盒子形状。说到此,如果你想给你的提交找个好点子,我已经有了一个想法:为什么不能是一个节日礼物盒子?

? ? ? ? ?_ ?_
? ? ? ? /_/_
?________/_/_______
| ? ? ? ///\ ? ? ? |
| ? ? ?/// ?\ ? ? ?|
| ? ? ? ? ? ? ? ? ? ?|
| ? ? "Happy pull ? ?|
| ? ? ? request!" ? ?|
|____________________|

boxes 是基于 GPLv2 许可证的开源项目。

你有特别喜欢的命令行小玩具需要我介绍的吗?这个系列要介绍的小玩具大部分已经落实,但还预留了几个空位置。如果你有特别想了解的可以评论留言,我会查看的。如果还有空位置,我会考虑介绍它的。即使要介绍的小玩具已经有 24 个了,但如果我得到了一些很好的意见,我会在最后做一些有价值的提及。

你可以通过 Drive a locomotive through your Linux terminal 来查看明天会介绍的命令行小玩具。


 

神奇的 Linux 命令行字符形状工具 boxes,首发于山西十一选五手机版。

]]>
//www.brhi.net/114549/feed/ 0
关于 top 工具的 6 个替代方案 - 山西十一选五手机版▁山西11选五前三组遗漏▁山西十一选五任七遗漏▁山西11选五遗漏top10▁山西体彩十一选5一定牛 //www.brhi.net/114546/ //www.brhi.net/114546/#respond Tue, 11 Dec 2018 12:55:00 +0000 //www.brhi.net/?p=114546 我并不会说它们比 top 更好或者可以完全替代 top,但多了解一些类似的工具总是好的。

关于 top 工具的 6 个替代方案,首发于山西十一选五手机版。

]]>
在 GitHub 和 GitLab 上,不断有来自世界各地的开源应用程序和工具涌现。其中有全新的应用程序,也有针对现有各种被广泛使用的 Linux 程序的替代方案。在本文档中,我会介绍一些针对 top 工具(也就是命令行任务管理器程序)的替代方案。

top 工具的替代方案

在本文中,将会介绍以下 6 种 top 工具的替代方案:

  1. Htop
  2. Vtop
  3. Gtop
  4. Gotop
  5. Ptop
  6. Hegemon

如果后续有更多类似的工具,原作者会在原文进行更新。如果你对此有兴趣,可以持续关注。

Htop

htop 是一个流行的开源跨平台交互式进程管理器,也是我最喜欢的系统活动监控工具。htop 是对原版 top 工具的扩展。它最初只是用于 Linux 系统,后来开发者们不断为其添加对其它类 Unix 操作系统的支持,包括 FreeBSD 和 Mac OS。htop 还是一个自由开源软件,它基于 ncurses 并按照 GPLv2 发布。

和原版的 top 工具相比,htop 工具有这些优势:

  • htoptop 启动更快
  • htop 支持横向滚动和纵向滚动浏览进程列表,以便看到所有的进程和完整的命令行
  • top 工具中进行杀死进程、更改进程优先级这些操作时,需要输入进程 ID,而在 htop 工具中则不需要输入
  • htop 中可以同时杀死多个进程
  • top 中每次输入一个未预设的键都要等待一段时间,尤其是在多个键组成转义字符串的时候就更麻烦了

在很多 Linux 发行版的默认软件仓库中,都带有了 htop。

在基于 Arch 的操作系统中则可以执行以下命令来安装 htop

$ sudo pacman -S htop

在基于 Debian 的操作系统使用以下命令:

$ sudo apt install htop

在使用 RPM 软件管理的操作系统使用以下命令:

$ sudo dnf install htop

或者

$ sudo yum install htop

在 openSUSE 系统中:

$ sudo zypper in htop

用法

不带任何参数执行 htop 时,会显示如下画面:

$ htop

从图上可以看出,htop 会在界面顶部显示内存、交换空间、任务总数、系统平均负载、系统正常运行时间这些常用指标,在下方则和 top 一样显示进程列表,并且将进程的 ID、用户、进程优先级、进程 nice 值、虚拟内存使用情况、CPU 使用情况、内存使用情况等信息以多列显示出来。如果你想详细了解这些数据的含义,可以在这里阅读参考。

top 不同的是,htop 支持对不同的操作使用专有的按键。以下列出一些用于与 htop 交互的快捷键:

  • F1、h、?:进入帮助界面。
  • F2、Shift+s:进入设置界面。在设置界面中可以配置仪表板界面顶部显示哪些数据,以及设置颜色方案、显示列、显示顺序等等多种参数。
  • F3、/:在进程列表中进行搜索。
  • F4、\:进入筛选模式。输入一个字符串,筛选出包含这个字符串的进程。进入筛选模式后再按一次 F4 或者 ESC 可以退出筛选模式。
  • F5、t:切换默认显示模式和树型显示模式,在树型显示模式下按 + 可以查看子树。
  • F6、<、>:依次按照进程 ID、用户、进程优先级、进程 nice 值、CPU 使用率、内存使用率排序显示。
  • F7、]:提高所选进程的优先级。
  • F8、[:降低所选进程的优先级。
  • F9、k:杀死所选进程??梢杂? / 键选择不同的进程并按 F9 杀死进程。
  • F10、q: 退出 htop

以上这些快捷键都在 htop 界面底部显示。

需要注意的是,这其中有一些快捷键可能会与已有的快捷键发生冲突。例如按 F2 之后可能没有进入 htop 的设置界面,而是开始了对终端窗口的重命名。在这种情况下,你可能要更改一下快捷键的设置。

除了以上列出的快捷键以外,还有一些带有其它功能的快捷键,例如:

  • u 可以选择显示某个用户的进程。
  • Shift+m 可以按照内存使用量对进程列表排序。
  • Shift+p 可以按照 CPU 使用量对进程列表排序。
  • Shit+t 可以按照进程启动时间对进程列表排序。
  • CTRL+l 刷新界面。

htop 的所有功能都可以在启动后通过快捷键来调用,而不需要在启动的时候带上某个参数。当然,htop 也支持带参数启动。

例如按照以下方式启动 htop 就可以只显示某个用户的进程:

$ htop -u

更改界面自动刷新的时间间隔:

$ htop -d 10

看,htop 确实比 top 好用多了。

想了解 htop 的更多细节,可以查阅它的手册页面:

$ man htop

也可以查看它的项目主页GitHub 仓库。

Vtop

vtoptop 工具的另一个替代方案。它是一个使用 NodeJS 编写的、自由开源的命令行界面系统活动监视器,并使用 MIT 许可证发布。vtop 通过使用 unicode 中的盲文字符来绘制 CPU 和内存使用情况的可视化图表。

在安装 vtop 之前,需要先安装 NodeJS。如果还没有安装 NodeJS,可以按照这个教程进行安装。

NodeJS 安装完毕之后,执行以下命令安装 vtop

$ npm install -g vtop

安装好 vtop 就可以执行以下命令开始监控了。

$ vtop

显示界面如下:

如上图所示,vtop 界面和 top、htop 都有所不同,它将不同的内容分别以多个框的布局显示。另外在界面底部也展示了用于与 vtop 交互的所有快捷键。

vtop 有这些快捷键:

  • dd :杀死一个进程。
  • 、k:向上移动。
  • 、j:向下移动。
  • 、h :放大图表。
  • 、l:缩小图表。
  • g :跳转到进程列表顶部。
  • Shift+g :跳转到进程列表底部。
  • c :以 CPU 使用量对进程排序。
  • m :以内存使用量对进程排序。

想要了解更多关于 vtop 的细节,可以查阅它的项目主页或者 GitHub 仓库。

Gtop

gtopvtop 一样,都是一个使用 NodeJS 编写、在 MIT 许可下发布的系统活动监视器。

执行以下命令安装 gtop

$ npm install gtop -g

然后执行以下命令启动:

$ gtop

显示界面如下:

gtop 有一个优点,就是它会以不同的颜色来显示不同的???,这种表现形式非常清晰明了。

主要的快捷键包括:

  • p:按照进程 ID 对进程排序。
  • c:按照 CPU 使用量对进程排序。
  • m:按照内存使用量对进程排序。
  • q、Ctrl+c:退出。

想要了解更多关于 gtop 的细节,可以查阅它的 GitHub 仓库。

Gotop

gotop 也是一个完全自由和开源的图表式系统活动监视器。顾名思义,它是在受到 gtopvtop 的启发之后用 Go 语言编写的,因此也不再对其展开过多的赘述了。如果你有兴趣了解这个项目,可以阅读《gotop:又一个图表式系统活动监视器》这篇文章。

Ptop

有些人对 NodeJS 和 Go 语言的项目可能不太感冒。如果你也是其中之一,你可以试一下使用 Python 编写的 ptop。它同样是一个自由开源的、在 MIT 许可下发布的系统活动监视器。

ptop 同时兼容 Python2.x 和 Python3.x,因此可以使用 Python 的软件包管理器 pip 轻松安装。如果你没有安装 pip,也可以参考这个教程进行安装。

安装 pip 之后,执行以下命令就可以安装 ptop

$ pip install ptop

又或者按照以下方式通过源代码安装:

$ git clone https://github.com/darxtrix/ptop
$ cd ptop/
$ pip install -r requirements.txt # install requirements
$ sudo python setup.py install

如果需要对 ptop 进行更新,可以这样操作:

$ pip install --upgrade ptop

即使你不执行更新,ptop 也会在第一次启动的时候提示你是否需要更新到最新的版本。

现在可以看一下启动 ptop 后的界面。

$ ptop

就像下面这样:

ptop 的快捷键包括以下这些:

  • Ctrl+k:杀死一个进程。
  • Ctrl+n:按照内存使用量对进程排序。
  • Ctrl+t:按照进程启动时间对进程排序。
  • Ctrl+r:重置所有数据。
  • Ctrl+f:对进程进行筛选,输入进程的名称就能够筛选出符合条件的进程。
  • Ctrl+l:查看所选进程的详细信息。
  • g:跳转到进程列表顶部。
  • Ctrl+q:退出。

ptop 还支持更改显示主题。如果你想让 ptop 更好看,可以选择你喜欢的主题??捎玫闹魈獍ㄒ韵抡庑?/p>

  • colorful
  • elegant
  • simple
  • dark
  • light

如果需要更换主题(例如更换到 colorful 主题),可以执行以下命令:

$ ptop -t colorful

使用 -h 参数可以查看帮助页面:

$ ptop -h

想要了解更多关于 ptop 的细节,可以查阅它的 GitHub 仓库。

Hegemon

hegemon 是一个使用 Rust 编写的系统活动监视器,如果你对 Rust 感兴趣,也可以了解一下。我们最近有一篇关于 hegemon文章,想要详细了解的读者不妨阅读。

总结

以上就是关于 top 工具的 6 个替代方案。我并不会说它们比 top 更好或者可以完全替代 top,但多了解一些类似的工具总是好的。你有使用过这些工具吗?哪个是你最喜欢的?欢迎在评论区留言。

 

关于 top 工具的 6 个替代方案,首发于山西十一选五手机版。

]]>
//www.brhi.net/114546/feed/ 0
正则表达式的隐藏陷阱,你都了解么? - 山西十一选五手机版▁山西11选五前三组遗漏▁山西十一选五任七遗漏▁山西11选五遗漏top10▁山西体彩十一选5一定牛 //www.brhi.net/114536/ //www.brhi.net/114536/#comments Thu, 06 Dec 2018 15:55:18 +0000 //www.brhi.net/?p=114536 想不到,一行不起眼的正则表达式,竟然会让你的CPU挂死,这个正则表达式的陷阱你遇到过吗?

正则表达式的隐藏陷阱,你都了解么?,首发于山西十一选五手机版。

]]>
几天前,一个在线项目的监控系统突然报告了一个异常。在检查了相关资源的使用率后,我们发现 CPU 利用率接近 100%。然后,我们用 Java 附带的线程转储工具导出了这个异常相关的堆栈信息。

我们发现,所有堆栈信息都指向一个名为 “validateUrl” 的方法,它在堆栈上有超过 100 个错误消息。通过检查代码,我们发现该方法的主要功能是验证 URL 的合法性。

一个正则表达式是如何导致如此高的 CPU 利用率的呢?为了重现这个错误,我们提取了关键代码,并进行了简单的单元测试。

public static void main(String[] args) {
    String badRegex = "^([hH][tT]{2}[pP]://|[hH][tT]{2}[pP][sS]://)(([A-Za-z0-9-~]+).)+([A-Za-z0-9-~\\\\/])+$";
    String bugUrl = "//www.fapiao.com/dddp-web/pdf/download?request=6e7JGxxxxx4ILd-kExxxxxxxqJ4-CHLmqVnenXC692m74H38sdfdsazxcUmfcOH2fAfY1Vw__%5EDadIfJgiEf";
    if (bugUrl.matches(badRegex)) {
        System.out.println("match!!");
    } else {
        System.out.println("no match!!");
    }
}

当我们运行上面的示例时,资源监视器显示,一个名为 Java 的进程 CPU 利用率已经飙升到 91.4%。

现在我们几乎可以判断,正则表达式是导致 CPU 利用率飙升的原因。

所以,让我们聚焦于正则表达式:

^([hH][tT]{2}[pP]://|[hH][tT]{2}[pP][sS]://)(([A-Za-z0-9-~]+).)+([A-Za-z0-9-~\\/])+$

这个正则表达式看起来并没有什么异常。它可以分为三部分:

第一部分用于匹配 httphttps 协议。 第二部分用于匹配 www. 字符。第三部分用于匹配剩余字符。我盯着这个正则表达式看了很久,也没发现什么大问题。

事实上,Java 用来处理正则表达式所用的 NFA 引擎是引起高 CPU 利用率的关键。当进行字符匹配时, NFA 会使用一种称为“回朔法”(backtracking)的方法。一旦发生回溯,所花费的时间将变得非常长??赡苁羌阜种?,也可能长达数小时。所需时间的长短取决于发生回溯的次数和回溯的复杂度。

也许有些人还不太清楚回溯是什么。没关系,让我们从正则表达式的原理开始。

正则表达式引擎

正则表达式是一组便于匹配的符号。为了实现如此复杂且强大的匹配语法,我们必须有一组算法,算法的实现称为正则表达式引擎。简而言之,正则表达式的实现引擎有两种:一种是 DFA (有穷确定自动机 Deterministic Final Automata),另一种是 NFA (有穷非确定自动机 Non deterministic Finite Automaton).

这是两种不同的自动机。在这里,我们不会深入讨论它们的原理。简单地说,DFA 的时间复杂度是线性的。它更稳定,但功能有限。NFA 的时间复杂度相对不稳定。 根据正则表达式的不同,时间有时长,有时短。NFA 的优点是它的功能更强大,所以被 Java、.NET、Perl、Python、Ruby 和 PHP 用来处理正则表达式。

NFA 是怎样进行匹配的呢?我们用下面的字符串和表达式作为例子。

text="Today is a nice day."
regex="day"

记住,NFA 匹配是基于正则表达式的。也就是说,NFA 将依次读取正则表达式的匹配符,并将其与目标字符串进行匹配。如果匹配成功,它将转到正则表达式的下一个匹配符。否则,它将继续与目标字符串的下一个字符进行比较。

让我们一步一步地来看一下上面的例子。

  • 首先,提取正则表达式的第一个匹配符:d。然后,将它与字符串的第一个字符 T 进行比较。不匹配,所以转到下一个。第二个字符是 o,也不匹配。继续转到下一个,也就是 d。匹配成功。于是,读取正则表达式的第二个字符: a。
  • 正则表达式的第二个匹配符是:a。将它与字符串的第四个字符 a 进行比较。又匹配了。于是继续读取正则表达式的第三个字符 y。
  • 正则表达式的第三个匹配符是 y。让我们继续与字符串的第五个字符比较。匹配成功。接着,尝试读取正则表达式的下一个字符,发现没有字符了,因此匹配结束。

以上是 NFA 的匹配过程。实际的匹配过程要复杂得多。不过,匹配的原理都是一样的。

NFA 回溯法

现在,你已经了解了 NFA 是如何进行字符串匹配的。下面,让我们来看一下本文的重点:回溯法。我们将使用下面的例子,以便更好的解释回朔法。

text="abbc"
regex="ab{1,3}c"

这是一个比较简单的例子。正则表达式以 a 开始,以 c 结束。它们之间有以 1-3 个 b 组成的字符串。NFA 的匹配过程如下:

  • 首先,读取正则表达式的第一个匹配符 a,并将其与字符串的第一个字符 a 进行比较。两者匹配,所以,移动到正则表达式的第二个字符。
  • 读取正则表达式的第二个匹配符 b{1,3},将它与字符串的第二个字符 b 进行比较。它们又匹配了。b{1,3} 代表 1-3 个 b,基于 NFA 的贪婪特性(即,尽可能地进行匹配),此时它不会读取正则表达式的下一个匹配符,而是仍然使用b{1,3} 与字符串的第三个字符 b 进行比较。它们匹配了。于是继续用 b{1,3} 与字符串的第四个字符 c 进行比较。它们不匹配。 回溯 就出现在这里
  • 回溯是如何进行的?回溯后,字符串中已被读取的第四个字符 c 将被放弃。指针将返回到字符串的第三个字符。接着,正则表达式的下一个匹配符 c 会被用来与待匹配字符串当前指针的下一个字符 c 进行对比。两者是匹配的。这时,字符串最后一个字符已经被读取。匹配结束。

让我们回过头来看看用于验证 URL 的正则表达式。

^([hH][tT]{2}[pP]://|[hH][tT]{2}[pP][sS]://)(([A-Za-z0-9-~]+).)+([A-Za-z0-9-~\\/])+$

出现问题的 URL 如下:

//www.fapiao.com/dzfp-web/pdf/download?request=6e7JGm38jfjghVrv4ILd-kEn64HcUX4qL4a4qJ4-CHLmqVnenXC692m74H5oxkjgdsYazxcUmfcOH2fAfY1Vw__%5EDadIfJgiEf

我们将正则表达式分为三个部分:

  • 第1部分:验证协议。 ^([hH][tT]{2}[pP]://|[hH][tT]{2}[pP][sS]://)。
  • 第2部分:验证域。(([A-Za-z0-9-~]+).)+。
  • 第3部分:验证参数。([A-Za-z0-9-~\\/])+$。

可以发现,验证 // 协议这部分的正则表达式没有什么问题。但是,当用 xxxx. 验证 www.fabiao.com 时,匹配过程如下:

  • 匹配 www。
  • 匹配 fapiao。
  • 匹配 com/dzfp-web/pdf/download?request=6e7JGm38jf.....。由于“贪婪”的性质,程序会一直试图读取下一个字符进行匹配,直至上述一长串字符串读取完毕,发现找不到点号。此时,程序开始一个字符一个字符进行回溯。

这是正则表达式中的第一个问题。

另一个问题出现在正则表达式的第三部分??梢钥吹?,有问题的 URL 具有下划线(_)和百分号(),但是与第三部分对应的正则表达式中则没有。因此,只有在匹配完一长串字符之后,程序才发现两者不匹配,然后进行回溯。

这是这个正则表达式中的第二个问题。

解决方案

你已经知道回溯是导致问题的原因。所以,解决问题的方法就是减少回溯。事实上,你会发现,如果把下划线和百分比符号添加到第三部分,程序就会变得正常。

public static void main(String[] args) {
    String badRegex = "^([hH][tT]{2}[pP]://|[hH][tT]{2}[pP][sS]://)(([A-Za-z0-9-~]+).)+([A-Za-z0-9-~_%\\\\/])+$";
    String bugUrl = "//www.fapiao.com/dddp-web/pdf/download?request=6e7JGxxxxx4ILd-kExxxxxxxqJ4-CHLmqVnenXC692m74H38sdfdsazxcUmfcOH2fAfY1Vw__%5EDadIfJgiEf";
    if (bugUrl.matches(badRegex)) {
        System.out.println("match!!");
    } else {
        System.out.println("no match!!");
    }
}

运行上面的程序,它会打印出“ match!! ”。

如果未来其他的 URL 中含有别的混乱字符怎么办? 再次修正代码? 当然不现实!

事实上,正则表达式有三种模式:贪婪模式 ,勉强模式独占模式。

如果你在正则表达式中添加一个 ? 标志,贪婪模式将变成勉强模式。此时,它将尽可能少地匹配。然而,勉强模式下回溯仍可能出现。例如:

text="abbc"
regex="ab{1,3}?c"

正则表达式的第一个字符 a 与字符串的第一个字符 a 相匹配。正则表达式的第二个运算符 b{1,3}? 匹配了字符串的第二个字符 b 。由于最小匹配的原则,正则表达式将读取第三个运算符 c,并与字符串第三个字符 b 进行比较。两者不匹配。因此,程序进行回溯并将正则表达式的第二个运算符 b{1,3}? 与字符串的第三个字符 b 进行比较。现在匹配成功了。之后,正则表达式的第三个匹配符 c 与字符串的第四个字符 c 正相匹配。匹配结束。

如果添加 +标志,则原来的贪婪模式将变成独占模式。也就是说,它将匹配尽可能多的字符,但不会回溯。

因此,如果你想将这个问题完全解决。你必须保证表达式能正确的行使它的功能,同时确保没有回溯发生。我在上述验证 URL 的正则表达式的第二部分增添了一个加号:

 

^([hH][tT]{2}[pP]:\/\/|[hH][tT]{2}[pP][sS]:\/\/)
(([A-Za-z0-9-~]+).)++    --->>> (added + here)(“+”添加在这里)
([A-Za-z0-9-~_%\\\/])+$

现在,程序运行没有问题了。

最后,我推荐一个网站。它可以检查你写的正则表达式以及相应的匹配字符串是否存在问题。

例如,本文中存在问题的 URL 在使用上述网站检测后,会弹出如下提示:灾难性的回溯。

当你单击左下角的 “regex debugger” 时,它将告诉你已经进行了多少步匹配,列出所有的匹配步骤,并指出发生回溯的地方。

本文中的正则表达式在 110,000 次尝试之后自动停止。这表明,正则表达式存在一定的问题并需要改进。

`但是,当我用如下修改后的正则表达式测试时:

^([hH][tT]{2}[pP]:\/\/|[hH][tT]{2}[pP][sS]:\/\/)(([A-Za-z0-9-~]+).)++([A-Za-z0-9-~\\\/])+$

网站提示,仅用了 58 步就完成了匹配。

一个字符的差异导致了巨大的性能差距。

一些补充

一个小小的正则表达式也能神奇的让 CPU 卡死。这给我们提了一个醒。当遇到正则表达式的时候,一定要注意“贪婪模式”以及回溯问题。

正则表达式的隐藏陷阱,你都了解么?,首发于山西十一选五手机版。

]]>
//www.brhi.net/114536/feed/ 2
在 Linux 上自定义 bash 命令提示符 - 山西十一选五手机版▁山西11选五前三组遗漏▁山西十一选五任七遗漏▁山西11选五遗漏top10▁山西体彩十一选5一定牛 //www.brhi.net/114528/ //www.brhi.net/114528/#respond Tue, 27 Nov 2018 13:16:30 +0000 //www.brhi.net/?p=114528 尽管很多插件或工具都可以很轻易地满足这一需求,但我们也可以不使用插件和工具,自己手动自定义一些基本的显示方式,例如添加或者修改某些元素、更改前景色、更改背景色等等。

在 Linux 上自定义 bash 命令提示符,首发于山西十一选五手机版。

]]>

众所周知,bash(the Bourne-Again Shell)是目前绝大多数 Linux 发行版使用的默认 shell。本文将会介绍如何通过添加颜色和样式来自定义 bash 命令提示符的显示。尽管很多插件或工具都可以很轻易地满足这一需求,但我们也可以不使用插件和工具,自己手动自定义一些基本的显示方式,例如添加或者修改某些元素、更改前景色、更改背景色等等。

在 Linux 中自定义 bash 命令提示符

在 bash 中,我们可以通过更改 $PS1 环境变量的值来自定义 bash 命令提示符。

一般情况下,bash 命令提示符会是以下这样的形式:

在上图这种默认显示形式当中,“sk” 是我的用户名,而 “ubuntuserver” 是我的主机名。

只要插入一些以反斜杠开头的特殊转义字符串,就可以按照你的喜好修改命令提示符了。下面我来举几个例子。

在开始之前,我强烈建议你预先备份 ~/.bashrc 文件。

$ cp ~/.bashrc ~/.bashrc.bak

更改 bash 命令提示符中的 username@hostname 部分

如上所示,bash 命令提示符一般都带有 “username@hostname” 部分,这个部分是可以修改的。

只需要编辑 ~/.bashrc 文件:

$ vi ~/.bashrc

在文件的最后添加一行:

PS1="ostechnix> "

将上面的 “ostechnix” 替换为任意一个你想使用的单词,然后按 ESC 并输入 :wq 保存、退出文件。

执行以下命令使刚才的修改生效:

$ source ~/.bashrc

你就可以看见 bash 命令提示符中出现刚才添加的 “ostechnix” 了。

再来看看另一个例子,比如将 “username@hostname” 替换为 “Hello@welcome>”。

同样是像刚才那样修改 ~/.bashrc 文件。

export PS1="Hello@welcome> "

然后执行 source ~/.bashrc 让修改结果立即生效。

以下是我在 Ubuntu 18.04 LTS 上修改后的效果。

仅显示用户名

如果需要仅显示用户名,只需要在 ~/.bashrc 文件中加入以下这一行。

export PS1="\u "

这里的 \u 就是一个转义字符串。

下面提供了一些可以添加到 $PS1 环境变量中的用以改变 bash 命令提示符样式的转义字符串。每次修改之后,都需要执行 source ~/.bashrc 命令才能立即生效。

显示用户名和主机名

export PS1="\u\h "

命令提示符会这样显示:

skubuntuserver

显示用户名和完全限定域名

export PS1="\u\H "

在用户名和主机名之间显示其它字符

如果你还需要在用户名和主机名之间显示其它字符(例如 @),可以使用以下格式:

export PS1="\u@\h "

命令提示符会这样显示:

sk@ubuntuserver

显示用户名、主机名,并在末尾添加 $ 符号

export PS1="\u@\h\\$ "

综合以上两种显示方式

export PS1="\u@\h> "

命令提示符最终会这样显示:

sk@ubuntuserver>

相似地,还可以添加其它特殊字符,例如冒号、分号、星号、下划线、空格等等。

显示用户名、主机名、shell 名称

export PS1="\u@\h>\s "

显示用户名、主机名、shell 名称以及 shell 版本

export PS1="\u@\h>\s\v "

bash 命令提示符显示样式:

显示用户名、主机名、当前目录

export PS1="\u@\h\w "

如果当前目录是 $HOME ,会以一个波浪线(~)显示。

在 bash 命令提示符中显示日期

除了用户名和主机名,如果还想在 bash 命令提示符中显示日期,可以在 ~/.bashrc 文件中添加以下内容:

export PS1="\u@\h>\d "

在 bash 命令提示符中显示日期及 12 小时制时间

export PS1="\u@\h>\d\@ "

显示日期及 hh:mm:ss 格式时间

export PS1="\u@\h>\d\T "

显示日期及 24 小时制时间

export PS1="\u@\h>\d\A "

显示日期及 24 小时制 hh:mm:ss 格式时间

export PS1="\u@\h>\d\t "

以上是一些常见的可以改变 bash 命令提示符的转义字符串。除此以外的其它转义字符串,可以在 bash 的 man 手册 PROMPTING 章节中查阅。

你也可以随时执行以下命令查看当前的命令提示符样式。

$ echo $PS1

在 bash 命令提示符中去掉 username@hostname 部分

如果我不想做任何调整,直接把 username@hostname 部分整个去掉可以吗?答案是肯定的。

如果你是一个技术方面的博主,你有可能会需要在网站或者博客中上传自己的 Linux 终端截图?;蛐砟愕挠没椭骰?、太另类,不想让别人看到,在这种情况下,你就需要隐藏命令提示符中的 “username@hostname” 部分。

如果你不想暴露自己的用户名和主机名,只需要按照以下步骤操作。

编辑 ~/.bashrc 文件:

$ vi ~/.bashrc

在文件末尾添加这一行:

PS1="\W> "

输入 :wq 保存并关闭文件。

执行以下命令让修改立即生效。

$ source ~/.bashrc

现在看一下你的终端,“username@hostname” 部分已经消失了,只保留了一个 ~> 标记。

如果你想要尽可能简单的操作,又不想弄乱你的 ~/.bashrc 文件,最好的办法就是在系统中创建另一个用户(例如 “user@example”、“admin@demo”)。用带有这样的命令提示符的用户去截图或者录屏,就不需要顾虑自己的用户名或主机名被别人看见了。

警告:在某些情况下,这种做法并不推荐。例如像 zsh 这种 shell 会继承当前 shell 的设置,这个时候可能会出现一些意想不到的问题。这个技巧只用于隐藏命令提示符中的 “username@hostname” 部分,仅此而已,如果把这个技巧挪作他用,也可能会出现异常。

为 bash 命令提示符着色

目前我们也只是变更了 bash 命令提示符中的内容,下面介绍一下如何对命令提示符进行着色。

通过向 ~/.bashrc 文件写入一些配置,可以修改 bash 命令提示符的前景色(也就是文本的颜色)和背景色。

例如,下面这一行配置可以令某些文本的颜色变成红色:

export PS1="\u@

\[\e[31m\]

\h

\[\e[m\]

"

添加配置后,执行 source ~/.bashrc 立即生效。

你的 bash 命令提示符就会变成这样:

类似地,可以用这样的配置来改变背景色:

export PS1="\u@

\[\e[31;46m\]

\h

\[\e[m\]

"

添加 emoji

大家都喜欢 emoji?;箍梢园凑找韵屡渲冒?emoji 插入到命令提示符中。

PS1="\W ? >"

需要注意的是,emoji 的显示取决于使用的字体,因此某些终端可能会无法正常显示 emoji,取而代之的是一些乱码或者单色表情符号。

自定义 bash 命令提示符有点难,有更简单的方法吗?

如果你是一个新手,编辑 $PS1 环境变量的过程可能会有些困难,因为命令提示符中的大量转义字符串可能会让你有点晕头转向。但不要担心,有一个在线的 bash $PS1 生成器可以帮助你轻松生成各种 $PS1 环境变量值。

就是这个网站

EzPrompt

只需要直接选择你想要的 bash 命令提示符样式,添加颜色、设计排序,然后就完成了。你可以预览输出,并将配置代码复制粘贴到 ~/.bashrc 文件中。就这么简单。顺便一提,本文中大部分的示例都是通过这个网站制作的。

我把我的 ~/.bashrc 文件弄乱了,该如何恢复?

正如我在上面提到的,强烈建议在更改 ~/.bashrc 文件前做好备份(在更改其它重要的配置文件之前也一定要记得备份)。这样一旦出现任何问题,你都可以很方便地恢复到更改之前的配置状态。当然,如果你忘记了备份,还可以按照下面这篇文章中介绍的方法恢复为默认配置。

这篇文章是基于 ubuntu 的,但也适用于其它的 Linux 发行版。不过事先声明,这篇文章的方法会将 ~/.bashrc 文件恢复到系统最初时的状态,你对这个文件做过的任何修改都将丢失。

感谢阅读!

 

在 Linux 上自定义 bash 命令提示符,首发于山西十一选五手机版。

]]>
//www.brhi.net/114528/feed/ 0
网络应用优化——时延与带宽 - 山西十一选五手机版▁山西11选五前三组遗漏▁山西十一选五任七遗漏▁山西11选五遗漏top10▁山西体彩十一选5一定牛 //www.brhi.net/114523/ //www.brhi.net/114523/#comments Thu, 22 Nov 2018 10:04:51 +0000 //www.brhi.net/?p=114523 本文网络应用优化中最重要的两个目标:时延与带宽。通过定义并区分两者的关系,并引申出网络服务优化的几种基本方法。

网络应用优化——时延与带宽,首发于山西十一选五手机版。

]]>
1. 用户感知的“速度”
用户体验能给网站带来更多的收益,因此人们也投入了更多精力去研究它。用户体验中,除了好的交互,精美的界面,用户感知的“速度”也是重要的一环。从网络角度来说,时延(latency)和带宽(bindwidth)是决定“速度”的重要环节。
不同的应用对时延和带宽需求的侧重点往往不同:
  • 网络游戏需要更低的时延。在一些对抗激烈的FPS、MOBA类的游戏中,单次数据传输的量并不大,因此带宽要求不高。但是若你顶着延迟和别人进行对抗,那么这局比赛可能已经输了一半;
  • 流媒体需要更高的带宽。高速带宽能让你观看高清电影,而延时就显得不那么重要,带来问题无非是在加载前等待一段时间罢了;
  • 视频聊天需要更低的时延。更低的时延意味着你能看到更流畅的实时画面,而不会掉帧。也许只有当你想要切换更高清晰度的时候才需要选择更高的带宽。
  • 浏览网页需要更低的时延。因为没人愿意在一个空白页面上花上几秒钟。更高的带宽常常无关紧要,除非你需要流量高分辨率的图片或者高清的视频。

2. 时延与带宽

2.1.糖果包装问题

某厂某天生产了N颗糖果,需要进行包装和验收。流水线一端的工人A负责包装,包装速度为N1颗/小时,另一端B的验收速度为N2颗/小时,两者通过协调达成某一相同的速度MIN(N1,N2)颗/小时。通过传送带传送到目的地。传送带长L米,速度为V 米/小时。从A开始计时到B验收完成,所需时间T为多少?
答:T = L / V + N / MIN(N1,N2) + 1 / MIN(N1,N2)
时间T反映了完成糖果包装并验收完成的总时间。如果糖果想象成可以需要传输的文件,那么就可以把糖果包装问题转换为一个简化的网络传输问题。
假设服务器A向用户B发送一个大小为100KB的图片(假设HTTP连接已经建立),服务器上行带宽为1Mbps,用户所在下行带宽为100Mbps。已知端对端物理距离为2000 km,光信号在光纤中的传播速度是200000 km/s,求图片从A发出到B完整接收的时间T。代入公式可得: T = 2000/200 + 100 * 8 / 1 = 810 ms(最后一项太小可以被忽略)
这个时间就是时延,具体的说是单向时延,即一个数据文件从传输到完整接收所花费的时间。

2.2.时延是什么

2.1中图片传输的时间叫做时延。时延并没有一个确切的定义。多数情况下是指单向时延,就是在数据通信过程中从A发送数据的第一个比特开始到B接受到数据的最后一个比特为结束产生的时间消耗,在某些场景下也指双向时延,即从网络请求发出到收到完整响应为结束经历的时间。时延常以毫秒为单位来衡量。数据包的大小、链路上传下行速率、通信距离、通信介质的种类、路由器的处理能力都会影响时延。常说的时延是下列这些不同时延的总和:
  • 传播时延。信号在信道中传输的时间=通信距离/传播速度。
  • 处理时延。路由器路由、差错控制以及数据包头信息处理的时间。
  • 队列时延。数据包在队列中等待路由器处理的时间。
  • 发送时延。将数据包发送到信道中的时间=数据包大小/信道带宽。
减少时延往往比增加带宽需要更多的成本。2015年9月,Hibernia网络公司为了最大程度上确保纽约和伦敦的通信延时,部署了一条名为“Hibernia Express”的海底光缆,总计耗费达3亿美元。采用新光缆之后,纽约伦敦两地的延时为58.95ms,比现存的所有大西洋光缆少了5ms。这意味着节约的每1毫秒,价值近6千万美元。

2.3.带宽是什么

带宽是指数据通信最大的吞吐量,根据传输方向的不同可以分为上行带宽和下行带宽,常用Mbps来进行衡量。对于互联网上的用户,运营商(ISP)提供的带宽就是数据通信的最大吞吐量,并且上下行带宽往往不对称。如中国电信百兆宽带最大下行速度为100Mbps,而最大上行速度只有20Mbps。
一般来说,核心网络(如海底光缆)的带宽往往可以达到几百Tbps。而终端用户实际可用的带宽,往往是网络服务所在服务器的上行带宽与用户下行带宽的最小值。
若某一网站部署在上行带宽为1Mbps服务器上,那么即使访问者拥有100Mbps的下行带宽,用户仍然只能以1Mbps的速度下载网页上的内容。

2.4.联系与区别

对终端用户而言,延时可以理解为某一网络服务的响应速度,而带宽可以理解为上传下载文件的最大速度,而实际可用的带宽,往往又是由网络服务所在服务器的上行带宽与用户下行带宽的最小值所决定。
以浏览网页为例子,若响应速度快,用户实际可用的带宽(见2.3节的定义)小,就可能导致页面上的图片以肉眼可见的速度一点点显示出来;若响应速度慢,用户实际可用的带宽大,就可能导致页面上的内容需要等待很久才能有显示,在此之前都是空白。但是当响应完成,会立即显示网页内容。
有人说带宽和时延没有关系,这句话是有问题的。因为在2.2节中介绍了发送延时,它通常由服务器的上行带宽与用户下行带宽的最小值所决定。准确的说是,目前现实场景中大部分的时延不是由带宽决定,而往往是由传播距离、网络状况等所决定。

3.性能优化

了解了带宽和时延,那么就可以更好地理解网站性能优化背后的本质——减少延时,增加带宽。常见的性能优化的方式有合并请求和建立内容分发网络(CDN):
合并请求。从优化角度来说,合并请求就是在减少总时延。一个100KB的文件和 10个10KB大小的文件大小相同。若D为传播时延,T为发送10KB文件的发送时延,那么一次发送100KB文件的时延为 D + 10T,而发送10次单个10KB文件的延时为 10D+10T。相同情况下,请求次数越少,总时延就越少。
建立内容分发网络。内容分发网络通过将网站内容服务器分布在靠近用户的位置,从而使用户就近获取所需内容,减少传播延时,进而显著提升网站的响应速度。
举例来说,高质量的视频网站必须租用高速的上行带宽,确保能够承担大规模的视频流量,因为没人愿意等待几分钟缓冲一个流媒体视频。同时它也要在各地建立大规模的内容分发网络(CDN)来降低视频内容的传播延迟,这样才不会让用户等待很久才能获得网站的响应。

4.总结

本文网络应用优化中最重要的两个目标:时延与带宽。通过定义并区分两者的关系,并引申出网络服务优化的几种基本方法。和所有的教程一样,本文不可能涵盖到网络优化的所有细节,但是若能对你有所启发,那就是再好不过了。

5.参考链接

网络应用优化——时延与带宽,首发于山西十一选五手机版。

]]>
//www.brhi.net/114523/feed/ 1
程序员神器 StackOverflow 10 岁了,它长大后想成为什么? - 山西十一选五手机版▁山西11选五前三组遗漏▁山西十一选五任七遗漏▁山西11选五遗漏top10▁山西体彩十一选5一定牛 //www.brhi.net/114499/ //www.brhi.net/114499/#comments Tue, 20 Nov 2018 03:20:53 +0000 //www.brhi.net/?p=114499 今年 9 月,程序员必备神器之一的 Stack Overflow 正式成立 10 周年了。截至目前为止,SO 用户量高达 930 万,也许你经常在 SO 上找解决方案。但你可能还不真正了解 SO。来看看 SO 创始人 Jeff Atwood 是怎么说的。

程序员神器 StackOverflow 10 岁了,它长大后想成为什么?,首发于山西十一选五手机版。

]]>
【伯乐在线导读】:今年 9 月,程序员必备神器之一的 Stack Overflow 正式成立 10 周年了。截至目前为止,SO 用户量高达 930 万,也许你经常在 SO 上找解决方案。但你可能还不真正了解 SO。来看看 SO 创始人 Jeff Atwood 是怎么说的。


 

现实生活中常常有人问我,我的工作是什么,对此我有一个 15 秒的回答:

我们创建了一个类似维基百科的网站,程序员们可以在上面发表或者解答问题。网站的名字叫?Stack Overflow。

截至 2018 年 9 月,Joel Spolsky 与我共同创建的 Stack Overflow?已经走过了?10 个年头。从 2012 年开始我就在做其他的工作了,但是能让人们在我过世之后还能想起我的东西,那肯定还是我的老伙伴 Stack Overflow。

这里我好像应该滔滔不绝地说?Stack Overflow 有多么优秀,而我作为创始人是有多么伟大。

但I这些我都不在乎。

我真正在乎的是,Stack Overflow 对程序员们是不是有帮助。对此,让我们看看如今最牛叉的开发者之一,我的偶像?John Carmack 是怎么评价的。

Stack Overflow为提升开发者的效率事业差不多贡献了好几亿美元 在为提升开发者的效率方面,Stack Overflow 可能贡献了好几十亿美元

说实话,2013 年 9 月 17 日是很美好的一天。我读到这条推的时候吓了一跳,不光是因为我经常用 Carl Sagan 的方式读 Billions 这个词。我在 Twitter 每隔几天就会读到一些残酷无尽的人间疾苦,以及人们在网络上的互相叫骂。与此相反,那一天是我感觉到的只有喜悦。这也提醒了我,我该查查 Twitter,看看如今谁还对网络抱有不同的理解。

Stack Overflow 有着如此多用户,也帮助了一个时代的开发者,对此我感到既荣幸又谦卑。但是,实现这一成就的并不是我。

  • 是你们,对 Stack Overflow 贡献了经过深入研究后想到的提问;
  • 是你们,对 Stack Overflow 贡献出了简洁而清晰的答案;
  • 是你们,编辑了 Stack Overflow 的提问或答案,并使其变得更好;

世界各地开发者们所贡献的那些大大小小的提问与回答,把 Stack Overflow 变成了一个在开发领域能与维基百科抗衡的创意共享知识库。这实在是…非常的不可思议。

不过成功的故事都很无聊。这个世界上有很多人,本身运气好,但还时不时的告诉别人是自己的努力以及喝活力汽水换来了成功。我觉得失败的故事更有教育意义,在建立业务与规划未来时,我把自己想象成深渊专家,并开始一场比赛。这是我自己做事的习惯。

abyss-oc

当你在凝视深渊的时候,深渊也正在凝视着你 – Friedrich Nietzsche

由此,我现在要与耀眼的深渊对视,预测一下Stack Overflow未来十年会遇到的挑战。这之前,我要先澄清以下事实。

1、从 2012 年 2 月开始,我就没有再为 Stack Overflow 做事了,也没有对其运营有过任何建议。你问我对如何运作Stack Overflow 竟然能没有建议?额,那你可能不认识我。你问我难道我不会时不时给员工发邮件告诉他们我的想法?我也许会吧,但是我为数不多的归档邮件可以证明,这个事情很少发生。

2、Stack 有着优秀的员工,他们中的大多数(包括我离开之前的 Stack Overflow 社区成员)都能对我们的使命给出更好的,不像我那样胡思乱想的阐述。我会用生命信任他们吗?不会。但是我会用 Joel 的生命信任他们!

3、Stack Overflow并不属于我或者 Joel,或者其他一些优秀的开发者。Stack Overflow 的运作靠的是世界各地日复一日做开发的人们,就像你或我一样。我觉得 Stack Overflow 就像个家长,它的目标是让孩子们最终能离开家长身边,成为可以独当一面的大人。

4、作为 Stack Overflow 的创始人,我在社区成立的最初四年里,花了非常多的时间参与制定规则与规范。你现在阅读的是我所强观点,弱坚持。这只是我的一些想法,我也希望自己的预测是准确的,但是这并不意味着我可以预测未来,或者我有资格去预测未来。不过我并不会以自己是否具有资格而不去做一些事情。

Stack Overflow首先是一个 wiki

Stack Overflow不仅是个论坛,它跟维基百科有很多相似之处。我们衡量问题和答案是否有意义的方式,不是看那些问题和答案对特定几个人的帮助,而是看随着时间的推移,这些问题和答案能不能帮助到越来越多的人。我从?2008 年 Stack Overflow 上线后就在强调这个关系。来看看下面谁的地位最高。

为了强调这一核心价值,Stack Overflow添加了一个简洁的功能。那就是在用户资料里会显示,你所贡献的问题与回答帮助到了多少人。

这些问答内容到底服务于谁?回答问题为何有如此严格的审核过程?对于 Stack Overflow 最常见的抱怨通常来自于对前面这两个问题的误解。

我希望更多的人能明白,Stack Overflow并不是一个“回答我的问题”的地方,它是“让我们合作建立一个对未来的开发者们有益的地方”。也许Stack Overflow应该更加努力去帮助用户理解这件事。 我希望更多的人能明白,Stack Overflow并不是一个“回答我的问题”的地方,它是“让我们合作建立一个对未来的开发者们有益的地方”。也许 Stack Overflow 应该更加努力去帮助用户理解这件事。

如今很多用户,甚至泡在 Hacker News 上的技术圈网友,都不知道 Stack Overflow 上有个功能,那就是每一个问题都是可以修改的,即使是没有登录的匿名用户也可以修改。对此我深表惊讶。这个功能不奇怪,对吧,因为 Stack Overflow 就是一种维基百科,这也是维基百科的运行模式,任何人都可以修改任何内容。不信的话,现在就去试试吧,找一个你认为可以提高的问题或者回答,点击“改善这个回答(improve this answer)”或者“改善这个问题(improve this question)”,然后写下你的改良版。

Stack Overflow 有很多功能(甚至也包括我自己在 2012 年之前的一些所作所为)都容易导致用户误解其核心价值。理论上,“如今每一个开发者都听过,用过以及了解 Stack Overflow”,但我觉得这个假设不准确。毕竟每时每刻都有新的开发者诞生。说得更复杂一点,Stack Overflow 的使用模式有三种,从大到小,以倒金字塔的形式排列如下:

1、我在需要的时候去搜索答案

用户直接上网搜索,搜索引擎会直接显示出 Stack Overflow 中的高票答案。出现在搜索引擎第一页,这也是Stack Overflow的主要目标。如Stack Overflow正常运行,98%的开发者在他们的整个职业生涯中,不需要主动提出或者回答问题。只要通过网络搜索就可以找Stack Overflow上到他们需要的结果。这是个好事,非常好的事。

2、我遇到很困难的问题时会参与Stack Overflow的讨论,因为单纯的搜索找不到我想要的答案

只在遇到难以解决的困难时,参与Stack Overflow的讨论,这很合理。然而,我觉得这个阶层的用户最容易感觉到Stack Overflow不是那么容易使用,因为这类用户可能对Stack Overflow很熟悉,但是并不清楚发布问题的流程。并且在他们急切想寻找答案的时候,他们没有时间或心思去应对Stack Overflow对于问题背景、格式、描述以及引用要求。

3、为了自己的职业发展,我主动参与Stack Overflow的问题讨论

这个阶层的用户很有经验,他们贡献了很多答案,也了解什么样的问题是好问题,是他们感兴趣、愿意回答的问题。他们不经常提问,因为他们知道如何去全面搜索他们想要的答案。但是他们一旦提问,那一定是个示范性的好问题。

(理论上这里还有个第四阶层用户,他们无私的贡献了很多提问与回答,目的只是为了推动软件开发行业的发展,造福于新一代的开发者们。但是我们没空提这些大神,你们只会让我们显得更加平凡,所以我们就此打住吧)

第一阶层的用户在社区里开心地逛了好几年,却在变为第二阶层用户时,一下子有了不开心的用户体验。对此我一点儿也不惊讶。我认为解决这个问题最主要的方式,就是改变并提高提问页面的用户体验。另外值得注意的一点是,用户在提出了某个问题后,可能收到关于问题信息不足的负面反馈,但是他们也许并不知道,你的问题应该是“有益于其他用户而并不只是你自己”。

Stack Overflow采用了维基百科的模式,也使其自身受到了很多限制。即使用户在提问前就知道这些,很多时候到底什么是“有用的信息”也很难判断。同理,很多时候我们也不确定到底什么样的话题,人群或者地点需要一份维基百科。Henrietta Lacks?有自己的维基百科页面,这毫无争议,但是他住在奥哈马市的表兄 Dave,那个提出了一个关于 PHP 5.6 的奇怪问题的人,是不是该被写入维基百科呢?

随着时间的推移,重复内容像地雷一样遍地都是

这事我很早就预料到了。老实说,我有点庆幸自己在 2012 年离开了 Stack Overflow,这样我就不用去处理这个难以置信的技术性难题:重复性内容。在我听到的关于 Stack Overflow 的所有抱怨里,重复内容是我觉得最有共鸣的。

如果你接受Stack Overflow是个类似于维基百科系统这一前提,那同理你显然不能接受,在维基百科中,对于意大利有五个不同的词条。Stack Overflow不允许对于同一个技术问题有重复的提问。我们确实有很多避免重复问题的功能,比如输入问题时的同步搜索,以及提交问题前,你会看到一个很明显的,鼓励用户先去搜索相关问题的搜索框。

… 如何查找并判断重复内容是个非常有难度的问题,即使是Google这样的公司,有着名副其实世界最聪明的工程师团队,专攻了20年也没有解决这个问题。

当你在一个不允许重复问题的网站中提问时,系统去重的难度取决于总问题数量,处理一百万的问题总量的去重与一千万甚至一亿相比,是非常不同的。系统处理问题去重的难度,会从不太难处理变为最终的完全无法处理。比如你提出了一个与艺术类相关的问题,那么系统需要根据你的提问内容,在不胜枚举的已有问题中进行筛选,以确保没有看起来相似的提问。

等会儿,还有个更难的问题!

  • 相似问题中有一点内容变化也是可以的,因为十个不同的人在提出同一个问题时,完全可能使用毫不相关的词语来形容这个问题。我知道这听起来很疯狂,但是相信我:人类极其擅长做这样的事。我们希望保留这些重复的问题,并且让他们都指向同一个主问题,以便于用户更好的搜索他们需要的内容,即使这些用户使用了那些平常不太会被用到的词语去描述问题。
  • 如何判断你提出的问题是不是重复,这是个不小的挑战。多少词语的重叠才能决定一个问题是不是与另一个重复?谁来决定?不同人有不同理论。这是个以人类语言为标准的解析,然后人类吧……不可预知。这个系统无法做到让所有人满意,去重的缺陷会一直存在于系统之中。

我对于越来越严重的重复问题并没有一个好的解决方案。但是我想指出,早期在?Stack Exchange?有很多先例,它们把网站分为“初级”和“高级”区域,不同区域的规则不同。我们在别的地方也能找到类似的例子,比如 Math 和 MathOverflow,English 和 English Learners, Unix 和 Ubuntu,也许是时候搞一个以初级用户为主的 Stack Overflow了,在那里我们可以允许多一些重复,少一些规则。

Stack Overflow是个可以同行评审的竞争性系统

Stack Overflow确实是个相当明确的竞争性系统,它的一大标志就是“总会有更好的解决办法”。根据我的多年观察,激励开发者最有效的方式就是…巧妙地暗示出别人的解决方案也许比你的更好。

- 你好Randall。医生说你能听到我说话,虽然你看起来像植物人。我是来告诉你,别着急慢慢康复。因为Ross接替了你的工作,并且做的非常好。他甚至找到了你代码里的瓶颈,还说他改过的代码变快了两倍。 - 这不可能?。。。?!我现在就回办公室! – 你好Randall。医生说你能听到我说话,虽然你看起来像植物人。我是来告诉你,别着急慢慢康复。因为Ross接替了你的工作,并且做的非常好。他甚至找到了你代码里的瓶颈,还说他改过的代码变快了两倍。

– 这不可能?。。。?!我现在就回办公室!

Stack Overflow的竞争性质体现在了它的公开声望系统上,就是用户名旁边那个拥有神奇力量的数字。所有的声望值都来源于其他用户,而不是所谓的系统。

每当你提出问题或者提交回答时,你的问题或回答都可以被其他用户指指点点,他们可以编辑、标记、关闭、打开、顶、踩或者收起。这样做的目的是让 Stack Overflow 成为一个同行评审和友好竞争的系统,就像在公司里,你的代码被你从没见过的另一个部门的人来评审。有人以友好的方式去质疑你所提问题的提论,也是完全合理的,比如,你真的想用这个正则表达式去匹配 HTML 吗?

我完全清楚这种竞争性质的同行评审系统,并不适合每一个人。Stack Overflow 采用维基百科的模式,导致它存在不能接受重复内容这样的限制。那么根据你的情况与背景,同行评审时,你收到的评价可能会让你觉得不舒服。

我听部分用户反应,在 Stack Overflow 提问的过程中会感觉到焦虑。对我来说,在 Stack Overflow上提问,应该感受到一种 ”我要展示出我最好的一面“ 的正常焦虑:

  • 在你的同事面前演讲的焦虑
  • 考试要取得好成绩的焦虑
  • 开始新工作,与你尊敬的优秀同事们一起工作的焦虑
  • 第一天去学校报到,即将见到新同学的焦虑

至于那种完全不会感到焦虑的地方,我唯一能想到的就是,从事了很久的工作,已经不再关注与工作本身,因此也没有那种担心有一天就会丢了工作的焦虑。这样怎么会好呢?所以说我不喜欢零焦虑的系统。

也许你不喜欢竞争。那么能不能有个少量竞争模式的问答系统呢?一个没有投支持或者反对票功能的系统,这样无论发表什么内容都不会感觉焦虑。这就像是一个全是你的支持者的网络,大家都相信你,希望你成功。这当然也是可以的。我认为应该有类似这样的网站,用户可以根据自己的需求与目标来选择适合自己的体验。那么 Stack 应该建立一个这样模式的社区吗?这样的社区已经有了吗?这是个开放题。也请随意在留言区发表你的看法。

Stack Overflow是为了日??⒄叨杓频?/h2>

Stack Overflow的目标用户到底是谁,这也是经常容易被混淆的一点。这个回答很直观,而且从从未改变过:

一个为专业和热情的程序员而存在的问答平台。这是指:

当前正在从事程序开发职业的人,或者如果愿意就能立即胜任程序开发工作的人。

如果你觉得好奇,这个定义的一部分是公开的商业决策。为了盈利,你的用户群体必须要有一部分拿着开发者薪水的人,或者在找开发者的工作的人。整个 Stack Overflow 社区也许有着知识共享的标签,但是它并不是个非营利组织。我们的出发点是可持续经营,这也是为什么我们在 Stack Overflow 上线一年之后,就成立?Stack Overflow Careers 招聘平台的原因,回顾一下,成立的确实有点过早了。为了实现比 2009 好很多的集成化用户体验,招聘平台被归入了 Stack Overflow,放在了?stackoverflow.com/jobs下面。

用户的选择定位并不是说要排斥非开发者,但是 Stack Overflow 确实是一个有着严格同行评审,对已经在从事相关行业的人来说非常优秀的功能,但同时也是对于学生或者初学者来说很不友好的功能。这也是为什么,我每次在推特上,看到有人推荐学生去 Stack Overflow 找答案时,我会小心翼翼的建议不要这样。对于开发领域的新手或者学生来说,他们需要的,与 Stack Overflow 所提供的是完全相反的。他们需要的是:

  • 一对一的指导
  • 实时屏幕共享协作
  • 实时语音
  • 理论背景知识课程
  • 初学者练习
  • 一个练习与实验的场所

这些都是对初学者来说,很好很合理的事情,但是 Stack Overflow 一个也不做。你可以通过 Stack Overflow 来从头学习如何编程吗?理论上你可以通过任何软件做任何事情,你甚至可以通过 Reddit 与人进行日常交流,如果你是受虐狂的话。但是答案还是肯定的,理论上你可以通过 Stack Overflow 学习如何编程,如果你是喜欢竞争模式(声望、被关闭、被踩)的神童,也完全能接受要去帮助别人而不只是自己学习知识这一观点。但是我强烈不推荐这样做。对初学者来说,除了 Stack Overflow 外还有很多更好更合适的平台。那么 Stack Overflow 能不能成为一个适合新手和学生的平台呢?我不清楚,我也不能决定。

这些就是我要说的。我们可以不再与深渊对视。

我希望我的观点对 Stack Overflow 不会有什么负面影响。总的来说,我认为目前的 Stack Overflow 很强大。但是,无论是?2008 年还是2018 年,我怎么想有关系吗?

Stack Overflow 是你们的。 Stack Overflow 将信念赌在了这一点:信任你的同行。Stack Overflow 的成长离不开那些积极参与社区讨论的开发者们。是你们让我相信开发者社区是最好的学习与成长的地方。是你们让我收获了如此多的对于 Stack Overflow 的赞誉。这不是我的功劳,而是你们的。 很久之前我在 Code Horror 上就知道了合作的力量是多么强大。目前我们的社区已经达到我今生难以企及的高度。我唯一能要求的,或者是我们能要求的,就是大家互相帮助互相成长。 如果有人认可了你的付出,那么你值得为此感到骄傲。

开发者社区的力量能够创造以及终结 Stack Overflow。Stack Overflow 长大了会成为什么?它的未来将由我们共同创造。

PS:Stack Overflow 十周年快乐!

程序员神器 StackOverflow 10 岁了,它长大后想成为什么?,首发于山西十一选五手机版。

]]> //www.brhi.net/114499/feed/ 1 在 Linux 命令行中使用 tcpdump 抓包 - 山西十一选五手机版▁山西11选五前三组遗漏▁山西十一选五任七遗漏▁山西11选五遗漏top10▁山西体彩十一选5一定牛 //www.brhi.net/114505/ //www.brhi.net/114505/#comments Tue, 13 Nov 2018 13:37:54 +0000 //www.brhi.net/?p=114505 tcpdump 是一款灵活、功能强大的抓包工具,能有效地帮助排查网络故障问题。

在 Linux 命令行中使用 tcpdump 抓包,首发于山西十一选五手机版。

]]>

tcpdump 是一款灵活、功能强大的抓包工具,能有效地帮助排查网络故障问题。

以我作为管理员的经验,在网络连接中经常遇到十分难以排查的故障问题。对于这类情况,tcpdump 便能派上用场。

tcpdump 是一个命令行实用工具,允许你抓取和分析经过系统的流量数据包。它通常被用作于网络故障分析工具以及安全工具。

tcpdump 是一款强大的工具,支持多种选项和过滤规则,适用场景十分广泛。由于它是命令行工具,因此适用于在远程服务器或者没有图形界面的设备中收集数据包以便于事后分析。它可以在后台启动,也可以用 cron 等定时工具创建定时任务启用它。

本文中,我们将讨论 tcpdump 最常用的一些功能。

1、在 Linux 中安装 tcpdump

tcpdump 支持多种 Linux 发行版,所以你的系统中很有可能已经安装了它。用下面的命令检查一下是否已经安装了 tcpdump

$ which tcpdump
/usr/sbin/tcpdump

如果还没有安装 tcpdump,你可以用软件包管理器安装它。 例如,在 CentOS 或者 Red Hat Enterprise 系统中,用如下命令安装 tcpdump

$ sudo yum install -y tcpdump

tcpdump 依赖于 libpcap,该库文件用于捕获网络数据包。如果该库文件也没有安装,系统会根据依赖关系自动安装它。

现在你可以开始抓包了。

2、用 tcpdump 抓包

使用 tcpdump 抓包,需要管理员权限,因此下面的示例中绝大多数命令都是以 sudo 开头。

首先,先用 tcpdump -D 命令列出可以抓包的网络接口:

$ sudo tcpdump -D
1.eth0
2.virbr0
3.eth1
4.any (Pseudo-device that captures on all interfaces)
5.lo [Loopback]

如上所示,可以看到我的机器中所有可以抓包的网络接口。其中特殊接口 any 可用于抓取所有活动的网络接口的数据包。

我们就用如下命令先对 any 接口进行抓包:

$ sudo tcpdump -i any
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on any, link-type LINUX_SLL (Linux cooked), capture size 262144 bytes
09:56:18.293641 IP rhel75.localdomain.ssh > 192.168.64.1.56322: Flags [P.], seq 3770820720:3770820916, ack 3503648727, win 309, options [nop,nop,TS val 76577898 ecr 510770929], length 196
09:56:18.293794 IP 192.168.64.1.56322 > rhel75.localdomain.ssh: Flags [.], ack 196, win 391, options [nop,nop,TS val 510771017 ecr 76577898], length 0
09:56:18.295058 IP rhel75.59883 > gateway.domain: 2486+ PTR? 1.64.168.192.in-addr.arpa. (43)
09:56:18.310225 IP gateway.domain > rhel75.59883: 2486 NXDomain* 0/1/0 (102)
09:56:18.312482 IP rhel75.49685 > gateway.domain: 34242+ PTR? 28.64.168.192.in-addr.arpa. (44)
09:56:18.322425 IP gateway.domain > rhel75.49685: 34242 NXDomain* 0/1/0 (103)
09:56:18.323164 IP rhel75.56631 > gateway.domain: 29904+ PTR? 1.122.168.192.in-addr.arpa. (44)
09:56:18.323342 IP rhel75.localdomain.ssh > 192.168.64.1.56322: Flags [P.], seq 196:584, ack 1, win 309, options [nop,nop,TS val 76577928 ecr 510771017], length 388
09:56:18.323563 IP 192.168.64.1.56322 > rhel75.localdomain.ssh: Flags [.], ack 584, win 411, options [nop,nop,TS val 510771047 ecr 76577928], length 0
09:56:18.335569 IP gateway.domain > rhel75.56631: 29904 NXDomain* 0/1/0 (103)
09:56:18.336429 IP rhel75.44007 > gateway.domain: 61677+ PTR? 98.122.168.192.in-addr.arpa. (45)
09:56:18.336655 IP gateway.domain > rhel75.44007: 61677* 1/0/0 PTR rhel75. (65)
09:56:18.337177 IP rhel75.localdomain.ssh > 192.168.64.1.56322: Flags [P.], seq 584:1644, ack 1, win 309, options [nop,nop,TS val 76577942 ecr 510771047], length 1060

---- SKIPPING LONG OUTPUT -----

09:56:19.342939 IP 192.168.64.1.56322 > rhel75.localdomain.ssh: Flags [.], ack 1752016, win 1444, options [nop,nop,TS val 510772067 ecr 76578948], length 0
^C
9003 packets captured
9010 packets received by filter
7 packets dropped by kernel
$

tcpdump 会持续抓包直到收到中断信号。你可以按 Ctrl+C 来停止抓包。正如上面示例所示,tcpdump 抓取了超过 9000 个数据包。在这个示例中,由于我是通过 ssh 连接到服务器,所以 tcpdump 也捕获了所有这类数据包。-c 选项可以用于限制 tcpdump 抓包的数量:

$ sudo tcpdump -i any -c 5
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on any, link-type LINUX_SLL (Linux cooked), capture size 262144 bytes
11:21:30.242740 IP rhel75.localdomain.ssh > 192.168.64.1.56322: Flags [P.], seq 3772575680:3772575876, ack 3503651743, win 309, options [nop,nop,TS val 81689848 ecr 515883153], length 196
11:21:30.242906 IP 192.168.64.1.56322 > rhel75.localdomain.ssh: Flags [.], ack 196, win 1443, options [nop,nop,TS val 515883235 ecr 81689848], length 0
11:21:30.244442 IP rhel75.43634 > gateway.domain: 57680+ PTR? 1.64.168.192.in-addr.arpa. (43)
11:21:30.244829 IP gateway.domain > rhel75.43634: 57680 NXDomain 0/0/0 (43)
11:21:30.247048 IP rhel75.33696 > gateway.domain: 37429+ PTR? 28.64.168.192.in-addr.arpa. (44)
5 packets captured
12 packets received by filter
0 packets dropped by kernel
$

如上所示,tcpdump 在抓取 5 个数据包后自动停止了抓包。这在有些场景中十分有用 —— 比如你只需要抓取少量的数据包用于分析。当我们需要使用过滤规则抓取特定的数据包(如下所示)时,-c 的作用就十分突出了。

在上面示例中,tcpdump 默认是将 IP 地址和端口号解析为对应的接口名以及服务协议名称。而通常在网络故障排查中,使用 IP 地址和端口号更便于分析问题;用 -n 选项显示 IP 地址,-nn 选项显示端口号:

$ sudo tcpdump -i any -c5 -nn
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on any, link-type LINUX_SLL (Linux cooked), capture size 262144 bytes
23:56:24.292206 IP 192.168.64.28.22 > 192.168.64.1.35110: Flags [P.], seq 166198580:166198776, ack 2414541257, win 309, options [nop,nop,TS val 615664 ecr 540031155], length 196
23:56:24.292357 IP 192.168.64.1.35110 > 192.168.64.28.22: Flags [.], ack 196, win 1377, options [nop,nop,TS val 540031229 ecr 615664], length 0
23:56:24.292570 IP 192.168.64.28.22 > 192.168.64.1.35110: Flags [P.], seq 196:568, ack 1, win 309, options [nop,nop,TS val 615664 ecr 540031229], length 372
23:56:24.292655 IP 192.168.64.1.35110 > 192.168.64.28.22: Flags [.], ack 568, win 1400, options [nop,nop,TS val 540031229 ecr 615664], length 0
23:56:24.292752 IP 192.168.64.28.22 > 192.168.64.1.35110: Flags [P.], seq 568:908, ack 1, win 309, options [nop,nop,TS val 615664 ecr 540031229], length 340
5 packets captured
6 packets received by filter
0 packets dropped by kernel

如上所示,抓取的数据包中显示 IP 地址和端口号。这样还可以阻止 tcpdump 发出 DNS 查找,有助于在网络故障排查中减少数据流量。

现在你已经会抓包了,让我们来分析一下这些抓包输出的含义吧。

3、理解抓取的报文

tcpdump 能够抓取并解码多种协议类型的数据报文,如 TCP、UDP、ICMP 等等。虽然这里我们不可能介绍所有的数据报文类型,但可以分析下 TCP 类型的数据报文,来帮助你入门。更多有关 tcpdump 的详细介绍可以参考其 帮助手册。tcpdump 抓取的 TCP 报文看起来如下:

08:41:13.729687 IP 192.168.64.28.22 > 192.168.64.1.41916: Flags [P.], seq 196:568, ack 1, win 309, options [nop,nop,TS val 117964079 ecr 816509256], length 372

具体的字段根据不同的报文类型会有不同,但上面这个例子是一般的格式形式。

第一个字段 08:41:13.729687 是该数据报文被抓取的系统本地时间戳。

然后,IP 是网络层协议类型,这里是 IPv4,如果是 IPv6 协议,该字段值是 IP6。

192.168.64.28.22 是源 ip 地址和端口号,紧跟其后的是目的 ip 地址和其端口号,这里是 192.168.64.1.41916。

在源 IP 和目的 IP 之后,可以看到是 TCP 报文标记段 Flags [P.]。该字段通常取值如下:

标志类型 描述
S SYN Connection Start
F FIN Connection Finish
P PUSH Data push
R RST Connection reset
. ACK Acknowledgment

该字段也可以是这些值的组合,例如 [S.] 代表 SYN-ACK 数据包。

接下来是该数据包中数据的序列号。对于抓取的第一个数据包,该字段值是一个绝对数字,后续包使用相对数值,以便更容易查询跟踪。例如此处 seq 196:568 代表该数据包包含该数据流的第 196 到 568 字节。

接下来是 ack 值:ack 1。该数据包是数据发送方,ack 值为 1。在数据接收方,该字段代表数据流上的下一个预期字节数据,例如,该数据流中下一个数据包的 ack 值应该是 568。

接下来字段是接收窗口大小 win 309,它表示接收缓冲区中可用的字节数,后跟 TCP 选项如 MSS(最大段大?。┗蛘叽翱诒壤?。更详尽的 TCP 协议内容请参考 Transmission Control Protocol(TCP) Parameters。

最后,length 372 代表数据包有效载荷字节长度。这个长度和 seq 序列号中字节数值长度是不一样的。

现在让我们学习如何过滤数据报文以便更容易的分析定位问题。

4、过滤数据包

正如上面所提,tcpdump 可以抓取很多种类型的数据报文,其中很多可能和我们需要查找的问题并没有关系。举个例子,假设你正在定位一个与 web 服务器连接的网络问题,就不必关系 SSH 数据报文,因此在抓包结果中过滤掉 SSH 报文可能更便于你分析问题。

tcpdump 有很多参数选项可以设置数据包过滤规则,例如根据源 IP 以及目的 IP 地址,端口号,协议等等规则来过滤数据包。下面就介绍一些最常用的过滤方法。

协议

在命令中指定协议便可以按照协议类型来筛选数据包。比方说用如下命令只要抓取 ICMP 报文:

$ sudo tcpdump -i any -c5 icmp
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on any, link-type LINUX_SLL (Linux cooked), capture size 262144 bytes

然后再打开一个终端,去 ping 另一台机器:

$ ping opensource.com
PING opensource.com (54.204.39.132) 56(84) bytes of data.
64 bytes from ec2-54-204-39-132.compute-1.amazonaws.com (54.204.39.132): icmp_seq=1 ttl=47 time=39.6 ms

回到运行 tcpdump 命令的终端中,可以看到它筛选出了 ICMP 报文。这里 tcpdump 并没有显示有关 opensource.com 的域名解析数据包:

09:34:20.136766 IP rhel75 > ec2-54-204-39-132.compute-1.amazonaws.com: ICMP echo request, id 20361, seq 1, length 64
09:34:20.176402 IP ec2-54-204-39-132.compute-1.amazonaws.com > rhel75: ICMP echo reply, id 20361, seq 1, length 64
09:34:21.140230 IP rhel75 > ec2-54-204-39-132.compute-1.amazonaws.com: ICMP echo request, id 20361, seq 2, length 64
09:34:21.180020 IP ec2-54-204-39-132.compute-1.amazonaws.com > rhel75: ICMP echo reply, id 20361, seq 2, length 64
09:34:22.141777 IP rhel75 > ec2-54-204-39-132.compute-1.amazonaws.com: ICMP echo request, id 20361, seq 3, length 64
5 packets captured
5 packets received by filter
0 packets dropped by kernel

主机

host 参数只抓取和特定主机相关的数据包:

$ sudo tcpdump -i any -c5 -nn host 54.204.39.132
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on any, link-type LINUX_SLL (Linux cooked), capture size 262144 bytes
09:54:20.042023 IP 192.168.122.98.39326 > 54.204.39.132.80: Flags [S], seq 1375157070, win 29200, options [mss 1460,sackOK,TS val 122350391 ecr 0,nop,wscale 7], length 0
09:54:20.088127 IP 54.204.39.132.80 > 192.168.122.98.39326: Flags [S.], seq 1935542841, ack 1375157071, win 28960, options [mss 1460,sackOK,TS val 522713542 ecr 122350391,nop,wscale 9], length 0
09:54:20.088204 IP 192.168.122.98.39326 > 54.204.39.132.80: Flags [.], ack 1, win 229, options [nop,nop,TS val 122350437 ecr 522713542], length 0
09:54:20.088734 IP 192.168.122.98.39326 > 54.204.39.132.80: Flags [P.], seq 1:113, ack 1, win 229, options [nop,nop,TS val 122350438 ecr 522713542], length 112: HTTP: GET / HTTP/1.1
09:54:20.129733 IP 54.204.39.132.80 > 192.168.122.98.39326: Flags [.], ack 113, win 57, options [nop,nop,TS val 522713552 ecr 122350438], length 0
5 packets captured
5 packets received by filter
0 packets dropped by kernel

如上所示,只抓取和显示与 54.204.39.132 有关的数据包。

端口号

tcpdump 可以根据服务类型或者端口号来筛选数据包。例如,抓取和 HTTP 服务相关的数据包:

$ sudo tcpdump -i any -c5 -nn port 80
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on any, link-type LINUX_SLL (Linux cooked), capture size 262144 bytes
09:58:28.790548 IP 192.168.122.98.39330 > 54.204.39.132.80: Flags [S], seq 1745665159, win 29200, options [mss 1460,sackOK,TS val 122599140 ecr 0,nop,wscale 7], length 0
09:58:28.834026 IP 54.204.39.132.80 > 192.168.122.98.39330: Flags [S.], seq 4063583040, ack 1745665160, win 28960, options [mss 1460,sackOK,TS val 522775728 ecr 122599140,nop,wscale 9], length 0
09:58:28.834093 IP 192.168.122.98.39330 > 54.204.39.132.80: Flags [.], ack 1, win 229, options [nop,nop,TS val 122599183 ecr 522775728], length 0
09:58:28.834588 IP 192.168.122.98.39330 > 54.204.39.132.80: Flags [P.], seq 1:113, ack 1, win 229, options [nop,nop,TS val 122599184 ecr 522775728], length 112: HTTP: GET / HTTP/1.1
09:58:28.878445 IP 54.204.39.132.80 > 192.168.122.98.39330: Flags [.], ack 113, win 57, options [nop,nop,TS val 522775739 ecr 122599184], length 0
5 packets captured
5 packets received by filter
0 packets dropped by kernel

IP 地址/主机名

同样,你也可以根据源 IP 地址或者目的 IP 地址或者主机名来筛选数据包。例如抓取源 IP 地址为 192.168.122.98 的数据包:

$ sudo tcpdump -i any -c5 -nn src 192.168.122.98
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on any, link-type LINUX_SLL (Linux cooked), capture size 262144 bytes
10:02:15.220824 IP 192.168.122.98.39436 > 192.168.122.1.53: 59332+ A? opensource.com. (32)
10:02:15.220862 IP 192.168.122.98.39436 > 192.168.122.1.53: 20749+ AAAA? opensource.com. (32)
10:02:15.364062 IP 192.168.122.98.39334 > 54.204.39.132.80: Flags [S], seq 1108640533, win 29200, options [mss 1460,sackOK,TS val 122825713 ecr 0,nop,wscale 7], length 0
10:02:15.409229 IP 192.168.122.98.39334 > 54.204.39.132.80: Flags [.], ack 669337581, win 229, options [nop,nop,TS val 122825758 ecr 522832372], length 0
10:02:15.409667 IP 192.168.122.98.39334 > 54.204.39.132.80: Flags [P.], seq 0:112, ack 1, win 229, options [nop,nop,TS val 122825759 ecr 522832372], length 112: HTTP: GET / HTTP/1.1
5 packets captured
5 packets received by filter
0 packets dropped by kernel

注意此处示例中抓取了来自源 IP 地址 192.168.122.98 的 53 端口以及 80 端口的数据包,它们的应答包没有显示出来因为那些包的源 IP 地址已经变了。

相对的,使用 dst 就是按目的 IP/主机名来筛选数据包。

$ sudo tcpdump -i any -c5 -nn dst 192.168.122.98
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on any, link-type LINUX_SLL (Linux cooked), capture size 262144 bytes
10:05:03.572931 IP 192.168.122.1.53 > 192.168.122.98.47049: 2248 1/0/0 A 54.204.39.132 (48)
10:05:03.572944 IP 192.168.122.1.53 > 192.168.122.98.47049: 33770 0/0/0 (32)
10:05:03.621833 IP 54.204.39.132.80 > 192.168.122.98.39338: Flags [S.], seq 3474204576, ack 3256851264, win 28960, options [mss 1460,sackOK,TS val 522874425 ecr 122993922,nop,wscale 9], length 0
10:05:03.667767 IP 54.204.39.132.80 > 192.168.122.98.39338: Flags [.], ack 113, win 57, options [nop,nop,TS val 522874436 ecr 122993972], length 0
10:05:03.672221 IP 54.204.39.132.80 > 192.168.122.98.39338: Flags [P.], seq 1:643, ack 113, win 57, options [nop,nop,TS val 522874437 ecr 122993972], length 642: HTTP: HTTP/1.1 302 Found
5 packets captured
5 packets received by filter
0 packets dropped by kernel

多条件筛选

当然,可以使用多条件组合来筛选数据包,使用 and 以及 or 逻辑操作符来创建过滤规则。例如,筛选来自源 IP 地址 192.168.122.98 的 HTTP 数据包:

$ sudo tcpdump -i any -c5 -nn src 192.168.122.98 and port 80
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on any, link-type LINUX_SLL (Linux cooked), capture size 262144 bytes
10:08:00.472696 IP 192.168.122.98.39342 > 54.204.39.132.80: Flags [S], seq 2712685325, win 29200, options [mss 1460,sackOK,TS val 123170822 ecr 0,nop,wscale 7], length 0
10:08:00.516118 IP 192.168.122.98.39342 > 54.204.39.132.80: Flags [.], ack 268723504, win 229, options [nop,nop,TS val 123170865 ecr 522918648], length 0
10:08:00.516583 IP 192.168.122.98.39342 > 54.204.39.132.80: Flags [P.], seq 0:112, ack 1, win 229, options [nop,nop,TS val 123170866 ecr 522918648], length 112: HTTP: GET / HTTP/1.1
10:08:00.567044 IP 192.168.122.98.39342 > 54.204.39.132.80: Flags [.], ack 643, win 239, options [nop,nop,TS val 123170916 ecr 522918661], length 0
10:08:00.788153 IP 192.168.122.98.39342 > 54.204.39.132.80: Flags [F.], seq 112, ack 643, win 239, options [nop,nop,TS val 123171137 ecr 522918661], length 0
5 packets captured
5 packets received by filter
0 packets dropped by kernel

你也可以使用括号来创建更为复杂的过滤规则,但在 shell 中请用引号包含你的过滤规则以防止被识别为 shell 表达式:

$ sudo tcpdump -i any -c5 -nn "port 80 and (src 192.168.122.98 or src 54.204.39.132)"
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on any, link-type LINUX_SLL (Linux cooked), capture size 262144 bytes
10:10:37.602214 IP 192.168.122.98.39346 > 54.204.39.132.80: Flags [S], seq 871108679, win 29200, options [mss 1460,sackOK,TS val 123327951 ecr 0,nop,wscale 7], length 0
10:10:37.650651 IP 54.204.39.132.80 > 192.168.122.98.39346: Flags [S.], seq 854753193, ack 871108680, win 28960, options [mss 1460,sackOK,TS val 522957932 ecr 123327951,nop,wscale 9], length 0
10:10:37.650708 IP 192.168.122.98.39346 > 54.204.39.132.80: Flags [.], ack 1, win 229, options [nop,nop,TS val 123328000 ecr 522957932], length 0
10:10:37.651097 IP 192.168.122.98.39346 > 54.204.39.132.80: Flags [P.], seq 1:113, ack 1, win 229, options [nop,nop,TS val 123328000 ecr 522957932], length 112: HTTP: GET / HTTP/1.1
10:10:37.692900 IP 54.204.39.132.80 > 192.168.122.98.39346: Flags [.], ack 113, win 57, options [nop,nop,TS val 522957942 ecr 123328000], length 0
5 packets captured
5 packets received by filter
0 packets dropped by kernel

该例子中我们只抓取了来自源 IP 为 192.168.122.98 或者 54.204.39.132 的 HTTP (端口号80)的数据包。使用该方法就很容易抓取到数据流中交互双方的数据包了。

5、检查数据包内容

在以上的示例中,我们只按数据包头部的信息来建立规则筛选数据包,例如源地址、目的地址、端口号等等。有时我们需要分析网络连接问题,可能需要分析数据包中的内容来判断什么内容需要被发送、什么内容需要被接收等。tcpdump 提供了两个选项可以查看数据包内容,-X 以十六进制打印出数据报文内容,-A 打印数据报文的 ASCII 值。

例如,HTTP 请求报文内容如下:

$ sudo tcpdump -i any -c10 -nn -A port 80
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on any, link-type LINUX_SLL (Linux cooked), capture size 262144 bytes
13:02:14.871803 IP 192.168.122.98.39366 > 54.204.39.132.80: Flags [S], seq 2546602048, win 29200, options [mss 1460,sackOK,TS val 133625221 ecr 0,nop,wscale 7], length 0
E..<..@.@.....zb6.'....P...@......r............
............................
13:02:14.910734 IP 54.204.39.132.80 > 192.168.122.98.39366: Flags [S.], seq 1877348646, ack 2546602049, win 28960, options [mss 1460,sackOK,TS val 525532247 ecr 133625221,nop,wscale 9], length 0
E..<..@./..a6.'...zb.P..o..&...A..q a..........
.R.W.......     ................
13:02:14.910832 IP 192.168.122.98.39366 > 54.204.39.132.80: Flags [.], ack 1, win 229, options [nop,nop,TS val 133625260 ecr 525532247], length 0
E..4..@.@.....zb6.'....P...Ao..'...........
.....R.W................
13:02:14.911808 IP 192.168.122.98.39366 > 54.204.39.132.80: Flags [P.], seq 1:113, ack 1, win 229, options [nop,nop,TS val 133625261 ecr 525532247], length 112: HTTP: GET / HTTP/1.1
E.....@.@..1..zb6.'....P...Ao..'...........
.....R.WGET / HTTP/1.1
User-Agent: Wget/1.14 (linux-gnu)
Accept: */*
Host: opensource.com
Connection: Keep-Alive
................
13:02:14.951199 IP 54.204.39.132.80 > 192.168.122.98.39366: Flags [.], ack 113, win 57, options [nop,nop,TS val 525532257 ecr 133625261], length 0
E..4.F@./.."6.'...zb.P..o..'.......9.2.....
.R.a....................
13:02:14.955030 IP 54.204.39.132.80 > 192.168.122.98.39366: Flags [P.], seq 1:643, ack 113, win 57, options [nop,nop,TS val 525532258 ecr 133625261], length 642: HTTP: HTTP/1.1 302 Found
E....G@./...6.'...zb.P..o..'.......9.......
.R.b....HTTP/1.1 302 Found
Server: nginx
Date: Sun, 23 Sep 2018 17:02:14 GMT
Content-Type: text/html; charset=iso-8859-1
Content-Length: 207
X-Content-Type-Options: nosniff
Location: https://opensource.com/
Cache-Control: max-age=1209600
Expires: Sun, 07 Oct 2018 17:02:14 GMT
X-Request-ID: v-6baa3acc-bf52-11e8-9195-22000ab8cf2d
X-Varnish: 632951979
Age: 0
Via: 1.1 varnish (Varnish/5.2)
X-Cache: MISS
Connection: keep-alive
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>302 Found</title>
</head><body>
<h1>Found</h1>
<p>The document has moved <a >here</a>.</p>
</body></html>
................
13:02:14.955083 IP 192.168.122.98.39366 > 54.204.39.132.80: Flags [.], ack 643, win 239, options [nop,nop,TS val 133625304 ecr 525532258], length 0
E..4..@.@.....zb6.'....P....o..............
.....R.b................
13:02:15.195524 IP 192.168.122.98.39366 > 54.204.39.132.80: Flags [F.], seq 113, ack 643, win 239, options [nop,nop,TS val 133625545 ecr 525532258], length 0
E..4..@.@.....zb6.'....P....o..............
.....R.b................
13:02:15.236592 IP 54.204.39.132.80 > 192.168.122.98.39366: Flags [F.], seq 643, ack 114, win 57, options [nop,nop,TS val 525532329 ecr 133625545], length 0
E..4.H@./.. 6.'...zb.P..o..........9.I.....
.R......................
13:02:15.236656 IP 192.168.122.98.39366 > 54.204.39.132.80: Flags [.], ack 644, win 239, options [nop,nop,TS val 133625586 ecr 525532329], length 0
E..4..@.@.....zb6.'....P....o..............
.....R..................
10 packets captured
10 packets received by filter
0 packets dropped by kernel

齐市北关献彩票3d字谜:Found

The document has moved here.

................
13:02:14.955083 IP 192.168.122.98.39366 > 54.204.39.132.80: Flags [.], ack 643, win 239, options [nop,nop,TS val 133625304 ecr 525532258], length 0
E..4..@.@.....zb6.'....P....o..............
.....R.b................
13:02:15.195524 IP 192.168.122.98.39366 > 54.204.39.132.80: Flags [F.], seq 113, ack 643, win 239, options [nop,nop,TS val 133625545 ecr 525532258], length 0
E..4..@.@.....zb6.'....P....o..............
.....R.b................
13:02:15.236592 IP 54.204.39.132.80 > 192.168.122.98.39366: Flags [F.], seq 643, ack 114, win 57, options [nop,nop,TS val 525532329 ecr 133625545], length 0
E..4.H@./.. 6.'...zb.P..o..........9.I.....
.R......................
13:02:15.236656 IP 192.168.122.98.39366 > 54.204.39.132.80: Flags [.], ack 644, win 239, options [nop,nop,TS val 133625586 ecr 525532329], length 0
E..4..@.@.....zb6.'....P....o..............
.....R..................
10 packets captured
10 packets received by filter
0 packets dropped by kernel

这对定位一些普通 HTTP 调用 API 接口的问题很有用。当然如果是加密报文,这个输出也就没多大用了。

6、保存抓包数据

tcpdump 提供了保存抓包数据的功能以便后续分析数据包。例如,你可以夜里让它在那里抓包,然后早上起来再去分析它。同样当有很多数据包时,显示过快也不利于分析,将数据包保存下来,更有利于分析问题。

使用 -w 选项来保存数据包而不是在屏幕上显示出抓取的数据包:

$ sudo tcpdump -i any -c10 -nn -w webserver.pcap port 80
[sudo] password for ricardo:
tcpdump: listening on any, link-type LINUX_SLL (Linux cooked), capture size 262144 bytes
10 packets captured
10 packets received by filter
0 packets dropped by kernel

该命令将抓取的数据包保存到文件 webserver.pcap。后缀名 pcap 表示文件是抓取的数据包格式。

正如示例中所示,保存数据包到文件中时屏幕上就没有任何有关数据报文的输出,其中 -c10 表示抓取到 10 个数据包后就停止抓包。如果想有一些反馈来提示确实抓取到了数据包,可以使用 -v 选项。

tcpdump 将数据包保存在二进制文件中,所以不能简单的用文本编辑器去打开它。使用 -r 选项参数来阅读该文件中的报文内容:

$ tcpdump -nn -r webserver.pcap
reading from file webserver.pcap, link-type LINUX_SLL (Linux cooked)
13:36:57.679494 IP 192.168.122.98.39378 > 54.204.39.132.80: Flags [S], seq 3709732619, win 29200, options [mss 1460,sackOK,TS val 135708029 ecr 0,nop,wscale 7], length 0
13:36:57.718932 IP 54.204.39.132.80 > 192.168.122.98.39378: Flags [S.], seq 1999298316, ack 3709732620, win 28960, options [mss 1460,sackOK,TS val 526052949 ecr 135708029,nop,wscale 9], length 0
13:36:57.719005 IP 192.168.122.98.39378 > 54.204.39.132.80: Flags [.], ack 1, win 229, options [nop,nop,TS val 135708068 ecr 526052949], length 0
13:36:57.719186 IP 192.168.122.98.39378 > 54.204.39.132.80: Flags [P.], seq 1:113, ack 1, win 229, options [nop,nop,TS val 135708068 ecr 526052949], length 112: HTTP: GET / HTTP/1.1
13:36:57.756979 IP 54.204.39.132.80 > 192.168.122.98.39378: Flags [.], ack 113, win 57, options [nop,nop,TS val 526052959 ecr 135708068], length 0
13:36:57.760122 IP 54.204.39.132.80 > 192.168.122.98.39378: Flags [P.], seq 1:643, ack 113, win 57, options [nop,nop,TS val 526052959 ecr 135708068], length 642: HTTP: HTTP/1.1 302 Found
13:36:57.760182 IP 192.168.122.98.39378 > 54.204.39.132.80: Flags [.], ack 643, win 239, options [nop,nop,TS val 135708109 ecr 526052959], length 0
13:36:57.977602 IP 192.168.122.98.39378 > 54.204.39.132.80: Flags [F.], seq 113, ack 643, win 239, options [nop,nop,TS val 135708327 ecr 526052959], length 0
13:36:58.022089 IP 54.204.39.132.80 > 192.168.122.98.39378: Flags [F.], seq 643, ack 114, win 57, options [nop,nop,TS val 526053025 ecr 135708327], length 0
13:36:58.022132 IP 192.168.122.98.39378 > 54.204.39.132.80: Flags [.], ack 644, win 239, options [nop,nop,TS val 135708371 ecr 526053025], length 0
$

这里不需要管理员权限 sudo 了,因为此刻并不是在网络接口处抓包。

你还可以使用我们讨论过的任何过滤规则来过滤文件中的内容,就像使用实时数据一样。 例如,通过执行以下命令从源 IP 地址 54.204.39.132 检查文件中的数据包:

$ tcpdump -nn -r webserver.pcap src 54.204.39.132
reading from file webserver.pcap, link-type LINUX_SLL (Linux cooked)
13:36:57.718932 IP 54.204.39.132.80 > 192.168.122.98.39378: Flags [S.], seq 1999298316, ack 3709732620, win 28960, options [mss 1460,sackOK,TS val 526052949 ecr 135708029,nop,wscale 9], length 0
13:36:57.756979 IP 54.204.39.132.80 > 192.168.122.98.39378: Flags [.], ack 113, win 57, options [nop,nop,TS val 526052959 ecr 135708068], length 0
13:36:57.760122 IP 54.204.39.132.80 > 192.168.122.98.39378: Flags [P.], seq 1:643, ack 113, win 57, options [nop,nop,TS val 526052959 ecr 135708068], length 642: HTTP: HTTP/1.1 302 Found
13:36:58.022089 IP 54.204.39.132.80 > 192.168.122.98.39378: Flags [F.], seq 643, ack 114, win 57, options [nop,nop,TS val 526053025 ecr 135708327], length 0

下一步做什么?

以上的基本功能已经可以帮助你使用强大的 tcpdump 抓包工具了。更多的内容请参考 tcpdump 网站 以及它的 帮助文件。

tcpdump 命令行工具为分析网络流量数据包提供了强大的灵活性。如果需要使用图形工具来抓包请参考 Wireshark。

Wireshark 还可以用来读取 tcpdump 保存的 pcap 文件。你可以使用 tcpdump 命令行在没有 GUI 界面的远程机器上抓包然后在 Wireshark 中分析数据包。

 

在 Linux 命令行中使用 tcpdump 抓包,首发于山西十一选五手机版。

]]>
//www.brhi.net/114505/feed/ 5
5 个适合系统管理员使用的告警可视化工具 - 山西十一选五手机版▁山西11选五前三组遗漏▁山西十一选五任七遗漏▁山西11选五遗漏top10▁山西体彩十一选5一定牛 //www.brhi.net/114503/ //www.brhi.net/114503/#respond Mon, 12 Nov 2018 13:24:16 +0000 //www.brhi.net/?p=114503 这些开源的工具能够通过输出帮助用户了解系统的运行状况,并对可能发生的潜在问题作出告警。

5 个适合系统管理员使用的告警可视化工具,首发于山西十一选五手机版。

]]>

这些开源的工具能够通过输出帮助用户了解系统的运行状况,并对可能发生的潜在问题作出告警。

你大概已经知道(或猜到)告警可视化alerting and visualization工具是用来做什么的了。下面我们就要来说一下,为什么要讨论这样的工具,甚至某些系统专门将可视化作为特有的功能。

可观察性Observability的概念来自控制理论control theory,这个概念描述了我们通过对系统的输入和输出来了解其的能力。本文将重点介绍具有可观察性的输出组件。

告警可视化工具可以对其它系统的输出进行分析,进而对输出的信息进行结构化表示。告警实际上是对系统异常状态的描述,而可视化则是让用户能够直观理解的结构化表示。

常见的可视化告警

告警

首先要明确一下告警alert的含义。在人员无法响应告警内容情况下,不应该发送告警 —— 包括那些发给多个人但只有其中少数人可以响应的告警,以及系统中的每个异常都触发的告警。因为这样会产生告警疲劳,告警接收者也往往会对这些过多的告警采取忽视的态度 —— 直到系统恶化到以少见的方式告警。

例如,如果管理员每天都会收到告警系统发来的数百封告警邮件,他就很容易会忽略告警系统的所有邮件。除非他真的看到问题发生,或者受到了客户或上级的询问时,管理员才会重新重视告警信息。在这种情况下,告警已经失去了原有的意义和用途。

告警不是一个持续的信息流或者状态更新。告警的目的在于暴露系统无法自动恢复的问题,而且告警应该只发送给最有可能解决问题的人员。超出这个定义的内容都不应该作为告警,否则将会对实际工作造成不良的影响。

不同的告警体系都会有各自的告警类型,因此不能用优先级(P1-P5)或者诸如“信息”、“警告”、“严重”之类的字眼来一概而论,下面我会介绍一些新兴的复杂系统的事件响应中出现的通用分类方式。

刚才我提到了一个“信息”这个告警类型,但实际上告警不应该是一个信息,尽管有些人可能会不这样认为。但我觉得如果一个告警没有发送给任何一个人,它就不应该是警报,而只是一些在许多系统中被视为警报的数据点,代表了一些应该知晓但不需要响应的事件。它更应该作为告警可视化工具的一部分,而不是会导致触发告警的事件?!?a >实用监控》是这个领域的必读书籍,其作者 Mike Julian 在书中就介绍了他自己关于告警的看法。

而非信息警报则代表告警需要被响应以及需要相关的操作。我将这些告警大致分为内部故障和外部故障两种类型,而对于大多数公司来说,通?;嵊辛礁鲆陨系募侗鹄慈范ㄏ煊Ω婢挠畔燃?。系统性能下降就是一种故障,因为其对用户的影响通常都是未知的。

内部故障比外部故障的优先级低,但也需要快速响应。内部故障通常包括公司员工使用的内部系统或仅对公司员工可见的应用故障。

外部故障则包括任何马上会产生业务影响的系统故障,但不包括影响系统更新的故障。外部故障一般包括客户所面临的应用故障、数据库故障和导致系统可用性或一致性失效的网络故障,这些都会影响用户的正常使用。对于不直接影响用户的依赖组件故障也属于外部故障,随着应用程序的不断运行,一旦依赖组件发生故障,系统的性能也会受到波及。这种情况对于使用某些外部服务或数据源的系统来说很常见,尽管这些外部服务或数据源对于可能不涉及到系统的主要功能,但是当系统在处理相关依赖组件的错误时可能会出现较明显的延迟。

可视化

可视化的种类有很多,我就不一一赘述了。这是一个有趣的研究领域,在我这些年的数据分析经历当中,学习和应用可视化方面的知识可以说是相当有挑战性。我们需要将复杂的系统输出通过直观的方式来向他人展示,才能有效地把信息传播出去。Google ChartsTableau 都提供了很多可视化方面的工具。下面将会介绍一些最常见的可视化创新解决方案。

折线图

折线图可能是最常见的可视化方式了,它可以让用户很直观地按照时间维度了解系统的情况。系统中每个单一或聚合的指标都会以一条折线在图表中体现。但当同一个图表中同时存在多条折线时,就可能会对阅读有所影响(如下图所示),所以大多数情况下都可以选择仅查看其中的少数几条折线,而不是让所有折线同时显示。如果某个指标的数值产生了大于正常范围的波动,就会很容易发现。例如下图中异常的紫线、黄线、浅蓝线。

折线图的另一个用法是可以将多条折线堆叠起来以显示它们之间的关系。例如对于通过折线图反映服务器的请求数量,可以单独看到每台服务器上的请求,也可以聚合在一起看。这就可以在同一个图表中灵活查看整个系统以及每个实例的情况了。

热力图

另一种常见的可视化方式是热力图。热力图与条形图比较类似,还可以在条形图的基础上显示某部分在整体中占比的变化情况。例如在查看网络请求延时的时候,就可以使用热力图快速查看到所有网络请求的总体趋势和分布情况,另外,它可以使用不同颜色来表示不同部分的数值。

在以下这个热力图中,通过竖直方向上每个时间段的色块数量分布,可以清楚地看到大部分数据集中在整个范围的中心位置。我们还可以发现,大多数时间段的色块分布都是比较宽松的,而 14:00 到 15:00 这一段则分布得很密集,这样的分布有可能意味着一种不健康的状态。

仪表图

还有一种常见的可视化方式是仪表图,用户可以通过仪表图快速了解单个指标。仪表一般用于单个指标的显示,例如车速表代表汽车的行驶速度、油量表代表油箱中的汽油量等等。大多数的仪表图都有一个共通点,就是会划分出所示指标的对应状态。如下图所示,绿色表示正常的状态,橙色表示不良的状态,而红色则表示极差的状态。下图中间一行模拟了真实仪表的显示情况。

上面图表中,除了常规仪表样式的显示方式之外,还有较为直接的数据显示方式,配合相同的配色方案,一眼就可以看出各个指标所处的状态,这一点与和仪表的特点类似。所以,最下面一行可能是仪表图的最佳显示方式,用户不需要仔细阅读,就可以大致了解各个指标的不同状态。这种类型的可视化是我最常用的类型,在数秒钟之间,我就可以全面地总览系统各方面地运行情况。

火焰图

Netflix 的 Brendan Gregg 在 2011 年开始使用的火焰图是一种较为少见地可视化方式。它不像仪表图那样可以从图表中快速得到关键信息,通常只会在需要解决某个应用的问题的时候才会用到这种图表?;鹧嫱贾饕糜?CPU、内存和相关帧方面的表示,X 轴按字母顺序将帧一一列出,而 Y 轴则表示堆栈的深度。图中每个矩形都是一个标明了调用的函数的堆栈帧。矩形越宽,就表示它在堆栈中出现越频繁。在分析系统性能问题的时候,火焰图能够起到很大的作用,大家不妨尝试一下。

工具的选择

在告警工具方面,有几个商用的工具相当不错。但由于这是一篇介绍开源技术的文章,我只会介绍那些已经被广泛使用的免费工具。希望你也能够为这些工具贡献你自己的代码,让它们更加完善。

告警工具

Bosun

如果你的电脑出现问题,得多亏 Stack Exchange 你才能在网上查到解决办法。Stack Exchange 以众包问答的模式运营着很多不同类型的网站。其中就有广受开发者欢迎的 Stack Overflow,以及运维方面有名的 Super User。除此以外,从育儿经验到科幻小说、从哲学讨论到单车论坛,Stack Exchange 都有涉猎。

Stack Exchange 开源了它的告警管理系统 Bosun,同时也发布了 Prometheus 及其 AlertManager 系统。这两个系统有共通点。Bosun 和 Prometheus 一样使用 Golang 开发,但 Bosun 比 Prometheus 更为强大,因为它可以使用指标聚合metrics aggregation以外的方式与系统交互。Bosun 还可以从日志和事件收集系统中提取数据,并且支持 Graphite、InfluxDB、OpenTSDB 和 Elasticsearch。

Bosun 的架构包括一个单一的服务器的二进制文件,一个诸如 OpenTSDB 的后端、Redis 以及 scollector 代理。 scollector 代理会自动检测主机上正在运行的服务,并反馈这些进程和其它的系统资源的情况。这些数据将发送到后端。随后 Bosun 的二进制服务文件会向后端发起查询,确定是否需要触发告警。也可以通过 Grafana 这些工具通过一个通用接口查询 Bosun 的底层后端。而 Redis 则用于存储 Bosun 的状态信息和元数据。

Bosun 有一个非常巧妙的功能,就是可以根据历史数据来测试告警。这是我几年前在使用 Prometheus 的时候就非常需要的功能,当时我有一个异常的数据需要产生告警,但没有一个可以用于测试的简便方法。为了确保告警能够正常触发,我不得不造出对应的数据来进行测试。而 Bosun 让这个步骤的耗时大大缩短。

Bosun 更是涵盖了所有常用过的功能,包括简单的图形化表示和告警的创建。它还带有强大的用于编写告警规则的表达式语言。但 Bosun 默认只带有电子邮件通知配置和 HTTP 通知配置,因此如果需要连接到 Slack 或其它工具,就需要对配置作出更大程度的定制化(其文档中有)。类似于 Prometheus,Bosun 还可以使用模板通知,你可以使用 HTML 和 CSS 来创建你所需要的电子邮件通知。

Cabot

CabotArachnys 公司开发。你或许对 Arachnys 公司并不了解,但它很有影响力:Arachnys 公司构建了一个基于云的先进解决方案,用于防范金融犯罪。在之前的公司时,我也曾经参与过类似“了解你的客户(KYC)”的工作。大多数公司都认为与恐怖组织产生联系会造成相当不好的影响,因为恐怖组织可能会利用自己的系统来筹集资金。而这些解决方案将有助于防范欺诈类犯罪,尽管这类犯罪情节相对较轻,但仍然也会对机构产生风险。

Arachnys 公司为什么要开发 Cabot 呢?其实只是因为 Arachnys 的开发人员对 Nagios 不太熟悉。Cabot 的出现对很多人来说都是一个好消息,它基于 Django 和 Bootstrap 开发,因此如果想对这个项目做出自己的贡献,门槛并不高。(另外值得一提的是,Cabot 这个名字来源于开发者的狗。)

与 Bosun 类似,Cabot 也不对数据进行收集,而是使用监控对象的 API 提供的数据。因此,Cabot 告警的模式是拉取而不是推送。它通过访问每个监控对象的 API,根据特定的指标检索所需的数据,然后将告警数据使用 Redis 缓存,进而持久化存储到 Postgres 数据库。

Cabot 的一个较为少见的特点是,它原生支持 Graphite,同时也支持 Jenkins。Jenkins 在这里被视为一个集中式的定时任务,它会以对待故障的方式去对待构建失败的状况。构建失败当然没有系统故障那么紧急,但一旦出现构建失败,还是需要团队采取措施去处理,毕竟并不是每个人在收到构建失败的电子邮件时都会亲自去检查 Jenkins。

Cabot 另一个有趣的功能是它可以接入 Google 日历安排值班人员,这个称为 Rota 的功能用处很大,希望其它告警系统也能加入类似的功能。Cabot 目前仅支持安排主备联系人,但还有继续改进的空间。它自己的文档也提到,如果需要全面的功能,更应该考虑付费的解决方案。

StatsAgg

Pearson 作为一家开发了 StatsAgg 告警平台的出版公司,这是极为罕见的,当然也很值得敬佩。除此以外,Pearson 还运营着另外几个网站以及和 O’Reilly Media 合资的企业。但我仍然会将它视为出版教学书籍的公司。

StatsAgg 除了是一个告警平台,还是一个指标聚合平台,甚至也有点类似其它系统的代理。StatsAgg 支持通过 Graphite、StatsD、InfluxDB 和 OpenTSDB 输入数据,也支持将其转发到各种平台。但随着中心服务的负载不断增加,风险也不断增大。尽管如此,如果 StatsAgg 的基础架构足够强壮,即使后端存储平台出现故障,也不会对它产生告警的过程造成影响。

StatsAgg 是用 Java 开发的,为了尽可能降低复杂性,它仅包括主服务和一个 UI。StatsAgg 支持基于正则表达式匹配来发送告警,而且它更注重于服务方面的告警,而不是服务器基础告警。我认为它填补了开源监控工具方面的空白,而这正式它自己的目标。

可视化工具

Grafana

Grafana 的知名度很高,它也被广泛采用。每当我需要用到数据面板的时候,我总是会想到它,因为它比我使用过的任何一款类似的产品都要好。Grafana 由 Torkel ?degaard 开发的,像 Cabot 一样,也是在圣诞节期间开发的,并在 2014 年 1 月发布。在短短几年之间,它已经有了长足的发展。Grafana 基于 Kibana 开发,Torkel 开启了新的分支并将其命名为 Grafana。

Grafana 着重体现了实用性以及数据呈现的美观性。它天生就可以从 Graphite、Elasticsearch、OpenTSDB、Prometheus 和 InfluxDB 收集数据。此外有一个 Grafana 商用版插件可以从更多数据源获取数据,但是其他数据源插件也并非没有开源版本,Grafana 的插件生态系统已经提供了各种数据源。

Grafana 能做什么呢?Grafana 提供了一个中心化的了解系统的方式。它通过 web 来展示数据,任何人都有机会访问到相关信息,当然也可以使用身份验证来对访问进行限制。Grafana 使用各种可视化方式来提供对系统一目了然的了解。Grafana 还支持不同类型的可视化方式,包括集成告警可视化的功能。

现在你可以更直观地设置告警了。通过 Grafana,可以查看图表,还可以查看由于系统性能下降而触发告警的位置,单击要触发报警的位置,并告诉 Grafana 将告警发送何处。这是一个对告警平台非常强大的补充。告警平台不一定会因此而被取代,但告警系统一定会由此得到更多启发和发展。

Grafana 还引入了很多团队协作的功能。不同用户之间能够共享数据面板,你不再需要为 Kubernetes 集群创建独立的数据面板,因为由 Kubernetes 开发者和 Grafana 开发者共同维护的一些数据面板已经可用了。

团队协作过程中一个重要的功能是注释。注释功能允许用户将上下文添加到图表当中,其他用户就可以通过上下文更直观地理解图表。当团队成员在处理某个事件,并且需要沟通和理解时,这个功能就十分重要了。将所有相关信息都放在需要的位置,可以让整个团队中快速达成共识。在团队需要调查故障原因和定位事件责任时,这个功能就可以发挥作用了。

Vizceral

Vizceral 由 Netflix 开发,用于在故障发生时更有效地了解流量的情况。Grafana 是一种通用性更强的工具,而 Vizceral 则专用于某些领域。 尽管 Netflix 表示已经不再在内部使用 Vizceral,也不再主动对其展开维护,但 Vizceral 仍然会定期更新。我在这里介绍这个工具,主要是为了介绍它的的可视化机制,以及如何利用它来协助解决问题。你可以在样例环境中用它来更好地掌握这一类系统的特性。

 

5 个适合系统管理员使用的告警可视化工具,首发于山西十一选五手机版。

]]>
//www.brhi.net/114503/feed/ 0
软件工程师生存指南:面试准备、工作经验和实用工具 - 山西十一选五手机版▁山西11选五前三组遗漏▁山西十一选五任七遗漏▁山西11选五遗漏top10▁山西体彩十一选5一定牛 //www.brhi.net/114496/ //www.brhi.net/114496/#comments Fri, 09 Nov 2018 03:12:50 +0000 //www.brhi.net/?p=114496 软件工程师是令人羡慕的职业。但是如何才能拿到这份工作?又如何才能做好这份工作呢?拥有相关经验的Valeri Alexiev提供了相关建议和工具。其中包括了如何准备面试、如何以软件工程师的身份工作以及如何持续改进方面的经验之谈。

软件工程师生存指南:面试准备、工作经验和实用工具,首发于山西十一选五手机版。

]]>
编者按:软件工程师是令人羡慕的职业。但是如何才能拿到这份工作?又如何才能做好这份工作呢?拥有相关经验的 Valeri Alexiev 提供了相关建议和工具。其中包括了如何准备面试、如何以软件工程师的身份工作以及如何持续改进方面的经验之谈。

我刚开始工作的头几年是紧张学习的时间。

我得面对现实,成为软件工程师需要有很多技能,这些我之前都不知道?;毓斯?,显然学会那些东西是很好的。

所以我就根据自己及其他人的经验写了这篇指南来帮助入行的新人。

本文将覆盖以下内容:

  1. 如何尽力做好面试
  2. 如何在软件工程师的角色中生存(及发展)
  3. 考虑持续改进时可以参考的资源

  面试

当你开始软件工程职业生涯时,你得面对一个无可争议的事实。面试很恶心。

参与其中的每个人都觉得很恶心。既被人面试过又面试过别人的我可以证明,面试是一项极其耗时、极其有压力的工作,并且面试其实并不是将来工作表现一个的好的指示器。但不管怎样,这都是一个必要之恶,你和你的简历最好还是做好准备为妥。

  做好战斗准备

如果你考虑做软件过程,确保了解一些最常见的编程面试问题,比如“FizzBuzz”:

写一个程序打印从 1 到 100 的数字。但是如果数字是 3 的倍数的话则打印“Fizz”,如果数字是 5 的倍数则打印“Buzz”。如果同时是 3 和 5 的倍数则打印“FizzBuzz”。

来自 Coding Horror

听起来很简单,是吧?

好吧,但其实绝大部分面试者都没能通过这一简单的测试,且不说更复杂的变种了。

我个人曾经见过很多角逐资深岗位的候选人在拥有完全互联网访问的情况下没能通过这一测试。所以如果你的简历上面列有编程语言的话,确保你知道如何用它来编写实现 FizzBuzz 程序。否则的话,你只不过是在浪费所有人的时间,包括你自己的。

当然,为了在面试过后生存,你需要知道的不仅仅只有 FizzBuzz。你还需要确保你知道:

  • 基础的数据结构和算法:比如链表、数组、树以及排序。
  • 要知道所选择语言的常见解决办法,比如字符串是否恒定,内存是如何管理的。
  • 类似类与对象,以及继承等面向对象编程的概念。

在职业生涯开始时,你需要就这些问题做好准备,因为你并没有经历去证明自己能做好这份工作。在准备面试的时候有两个资源我会经常推荐:

  • Cracking the Coding Interview(破解面试代码)》,这是一本非常好的书,里面介绍了很多的编码问题和解决方案,同时还总结了解决这些问题需要了解的东西。
  • CodeWars?,这个网站收集了大量的编程问题,你可以运用各种语言在浏览器里面去解决这些问题。最有用的部分是看看别的用户是如何解决同样问题的。这样你就可以看到解决相同问题的不同办法,并且学到你所选语言的新工具。

  赋予自身额外优势

为了让自己取得那点额外优势,有几件事情你可以去做。

首先,学会如何沟通你的经验。你应该进行一次电梯演讲来将你的简历总结成连贯的、打动人的个人介绍。

此外,要了解自己的简历!听起来很蠢是吧,但我就见过很多面试者连解释清楚自己简历上的特定事项都很困难。你应该能够回答任何有关你列上简历的经历方面的问题,并且解释清楚这一经历如何让你成为本工作更好的候选人。

接着,要在 GitHub(或者其他的公共代码库)上面有一些编码的例子。

眼见为实,面试官能够看到你的代码将创造奇迹。此外,这还证明了你对版本控制系统有了解。

你的代码例子不需要太复杂,但是一定要整洁,能够显示出好的编码实践。这是你展示自己在没有编码面试所带来的时间压力情况下代码写得如何的机会。

一旦你做完了上面的事情后,就得考虑参与一个开源项目了。参加开源项目能表明你能够在已有代码库基础上工作并且可以与其他程序员一些协作。

这是你在无需实际进入一个行业环境的情况下最接近在行业环境下编程的方式了。这也是目前为止最难最耗时的一项任务,所以等到你把前面我提到的比较容易取得的果实都摘完之后再干这件事。

  面试你的面试官

在找工作的匆忙与压力之下,很多候选人都忘了面试是一个双向的过程。在公司努力寻找这份工作的合适人选时,你也应该设法弄清楚这家公司适不适合你。

确保你也要提出以下一些问题,哪怕对方是以电子邮件的形式回复你。要意识到公司经常把不遵循最佳实践说成是一项技能,所以要体会其言外之意。

以下是一些你可以去提问的例子:

  “对我来说典型的工作日会是什么样的?”

知道特定岗位预期的样子很重要,因为软件工程工作差别相当大。比方说你的工作既可能是维护服务器,也可能是直接跟客户沟通。

危险信号:“我不大肯定?!?→?意味着面试你的那个人不在你的团队,或者他们对为什么要招你并没有明确的想法。

 “你们是如何测试软件的?”

理想情况下,验证代码质量应该是单元测试、人工测试以及自动化测试的结合。

危险信号:“我们都写不出 bug,哈哈?!?→?那些人正是会写出 bug 的人。

 “你们使用什么样的版本控制系统?”

版本控制系统对于协作极其有用,在职业环境下没有理由不使用。

危险信号 #1:“额,版本控制系统?” →?快跑,跑得越远越好。

永远记得使用版本控制。

危险信号 #2:“<插入不知名的或者定制的 VCS>” →?这表明他们很有可能没有跟上时代并且很久没有升级自己的基础设施了。

  “你们进行同行评审吗?”

同行评审,或者让别人看看你的代码再把它放进代码库,这是识别愚蠢错误的极好办法,同时也是开始你的职业生涯时一个关键的培训机会。

危险信号:“我们相互信任!”→很有可能那些资深开发者对自己的代码非常警惕不想给人看也不擅长接受反馈。

  “你们的继续教育计划是什么样的?”

作为一名软件工程师意味着当新技术出现、成熟并以令人眼花缭乱的速度走向过时的时候要不断学习。因此,很多公司都有培训预算用来买大学和在线课程、会议或者内部交流。

危险信号:“你是说在闲暇时间读读网上的东西?” →这家公司要么资金紧张,要么把开发者视为可替代的,而不是长期投资。

  “你们采用的软件开发流程是什么?”

无论实际的细节是什么,流程对于软件工程都至关重要。至于哪些东西对于优化流程做出了贡献可能大家会有不同的看法,但仅就项目的工作方式达成一致就能将混乱最小化并且确保每个人都能达成共识。

危险信号:“我们的流程受到了自由风格的爵士的影响?!?→ 很有可能整个部门都处在救火模式,总是不断地从紧急跳到另一个紧急状态而缺乏任何明确的目标。

  “你们是如何处理技术债务的?”

技术债务是过时技术以及代码库中临时应急的解决方案的累积。处理好技术债务对于代码的长期健康很重要,这件事情应该持续地做。

危险信号:“我们只关注新功能?!?→ 他们的代码库一团糟或者很快就会一团糟。

  “你们的公司文化是什么样的?”

公司文化也许是个非常含糊的概念,但即便像开放办公室还是小隔间这样的小事情都会显著改变你与同事的日?;ザ?。这方面没有普遍性的危险信号,但是要确保他们的答案是你可以按照每周 40+ 小时的节奏持续相处数年的东西。

  以软件工程师的身份工作

在这个阶段,如果你面试过程中表现不错并且喜欢面试官回答你问题的方式,你被录用的可能性就很高了。

祝贺,你正式成为一名工程师了!

那现在又该如何呢?好吧,现在是时候重新学习大量编码和工作方面的东西了。既然我们是程序员,我们就从讨论代码开始。

  好的行业代码

好的行业代码有以下属性,依序是:

  1. 可读性,因为代码用来读和维护的频次要高于写。代码的意图必须清晰,让其他开发者在多年后依然理解。
  2. 防御性,就是要遵循防御性编码的最佳实践。防御性编码本身就是一个课题,不过其要义是:你必须确保自己所写的类和方法的不恰当使用不会导致你的代码搞得软件都崩溃。
  3. 优化,位列清单的最后未知,因为大多数时候你并不需要真正去担心这个。这并不意味着你应该编写糟糕代码,在存在线性解决方案的情况下以O(n3)的效率去做某个东西。但开发者通??释⑹圆⑶一嵩诓恍枰那榭鱿鹿扔呕?,却牺牲了代码的可读性和防御性。你永远都应该能够证明牺牲了这些属性的特定优化是值得的。

现在你了解了如何去编写良好的行业代码了。

  编码的工作你不会干太多的

说出来也许有点令人吃惊,但是大多数时候你都不用写新代码,而是相反,要做:

  • 调试
  • 读已有代码
  • 开会或者写电子邮件
  • 研究该怎么做以便不用写代码

因此编码以外的技能对你的职业一样关键。

调试和阅读代码

  • 调试远不仅仅是用打印语句。一切使用广泛的语言和技术栈都有各种强大的工具。学会使用它们,因为这些会让调试轻而易举,节省你无数的时间。
  • 理解代码库。大多数技术栈都有某种代码图谱生成工具来帮助你理解代码库的结构。企业级的 IDE 通常都内置了那种功能。你还可以利用 ReSharper、grep?或者 Sourcegraph 之类的工具来探索代码。
  • 理解产品。你会对居然有这么多开发者在试图“修复”软件前不知道软件应该是怎么工作的感到惊讶。先看看文档再说吧。

  组织你的思路

既然你的大量时间都是用在沟通、研究和多任务上,你需要一些工具来帮助一切井然有序。

  • TODO 清单/任务工具:你的公司应该已经有了某种任务管理软件了,但你自己也有类似的个人系统是有帮助的。使用便利贴或者像 Trello 或者 Todoist 之类的软件。
  • 笔记:开会一定要记笔记,要致力于改进现有文档并且建立个人的知识库。使用 Evernote、OneNote 或者笔记本。使用这些工具似乎有用力过度之嫌,但日后在回顾这一耗掉了你 3 天时间才想清楚的晦涩的开发过程时你会感谢自己的。不做丰富笔记的好的软件开发者我一个都没见过。
  • 图表/可视化:人是视觉动物,创建流程图和架构可帮助你和其他人理解复杂的话题。在跟非技术人员沟通时图解尤其有用??墒褂?Lucidchart、?Visio 或者白板。

  知道何时使用库

简短回答:随时都要。

详细回答:99% 的时间内你都不应该重新发明轮子。在大多数的软件工程岗位,实现特定类型的东西都属于纯粹浪费时间。这并不意味着你不应该知道所使用的算法和数据结构是怎么工作的,因为这可以帮助你决定用什么以及什么时候用。

为了成为一名高效的软件工程师,你需要理解自己可以任意支配使用的那些库。大多数流行语言的标准库都是极其有用的,其规模比你想象的要大。此外,代码库也许也会利用了额外的特殊库。阅读其文档,知道什么使用去使用它们。

你还应该不要害怕去建议额外的库,如果它们将节省时间的话。然而,你需要确保自己选择了一个好的库供行业使用。好的库的标准是:

  • 开源,这样你就可以验证自身代码的质量,并有可能修补对应用非常关键的 bug。
  • 按照 MIT 和 BSD 等方式进行的授权,这样你的公司使用起来就不会遇到任何问题。要小心 GPL,因为它会让你不小心就将整个代码库都开源出去。
  • 成熟,比方说出来已经有一段时间了,并且功能集非常丰富。
  • 维护性强,新版本推出很密集。
  • 别的公司或者项目也使用,这个可以充当品质认证确保有行业支持,能持续维护下去。

  持续改进

为了替自己创建新的职业机会,除了学习会让你更擅长日常工作的技能以外,你还需要持续改进自身技能并且学习新技能。

其实学习的机会有很多,而且其中很多都是你可以负担得起的:

  • 在线课程:向领域内最好的教授学习的机会,而且方式灵活,不容错过。现有技能的补充性教程可以去可以看看?Coursera、?Udacity 以及 edX?等。
  • 在线硕士学位:在线硕士学位是最近在顶级大学流行起来的一个趋势,这种方式可以灵活地继续你的正规教育。相比之下,这种继续教育方式费用没那么昂贵,修完整个学位大多数在 1 万美元左右。乔治亚理工大学、UT 以及加州大学圣地亚哥分校等大学均提供此类学位。我个人推荐乔治亚理工大学的在线硕士虚伪,我去年刚从这里毕业。
  • 博客:博客是开发者社区的重要组成部分。诸如 Coding Horror、Joel on Software 等博客或者甚至更加诙谐的网站如 The Daily WTF 等都可以为你提供信息,了解到作为软件工程师该干什么不该干什么。浏览 Medium、r/programming, HackerNews 等新闻流也能让你找到好博客和好文章。
  • 会议:最后但并非最不重要的一个,会议时令人赞叹的学习机会,你绝对应该利用公司的培训预算去参加会议。以下是不完全的好会议清单:GOTO(通用),?Strange Loop(通用),?PyCon?(Pytho),CPPCon?(C++),DEF CON?(安全),Fluent?(Web 开发)。上述所有的会议在 YouTube 上都有视频,所以你哪怕不出席也能学到东西!

希望这篇文章能够用相关知识把你武装起来,让你了解到作为软件工程师的职业生涯伊始应该期待什么,并且提供合适的工具给你在开启这段令人兴奋的旅程中助你一臂之力!

软件工程师生存指南:面试准备、工作经验和实用工具,首发于山西十一选五手机版。

]]>
//www.brhi.net/114496/feed/ 1
Python 数据科学入门 - 山西十一选五手机版▁山西11选五前三组遗漏▁山西十一选五任七遗漏▁山西11选五遗漏top10▁山西体彩十一选5一定牛 //www.brhi.net/114493/ //www.brhi.net/114493/#comments Thu, 08 Nov 2018 12:46:16 +0000 //www.brhi.net/?p=114493 不需要昂贵的工具即可领略数据科学的力量,从这些开源工具起步即可。

Python 数据科学入门,首发于山西十一选五手机版。

]]>

不需要昂贵的工具即可领略数据科学的力量,从这些开源工具起步即可。

无论你是一个具有数学或计算机科学背景的资深数据科学爱好者,还是一个其它领域的专家,数据科学提供的可能性都在你力所能及的范围内,而且你不需要昂贵的,高度专业化的企业级软件。本文中讨论的开源工具就是你入门时所需的全部内容。

Python,其机器学习和数据科学库(pandas、 Keras、 TensorFlow、 scikit-learn、 SciPy、 NumPy 等),以及大量可视化库(Matplotlib、pyplot、 Plotly 等)对于初学者和专家来说都是优秀的自由及开源软件工具。它们易于学习,很受欢迎且受到社区支持,并拥有为数据科学而开发的最新技术和算法。它们是你在开始学习时可以获得的最佳工具集之一。

许多 Python 库都是建立在彼此之上的(称为依赖项),其基础是 NumPy 库。NumPy 专门为数据科学设计,经常被用于在其 ndarray 数据类型中存储数据集的相关部分。ndarray 是一种方便的数据类型,用于将关系表中的记录存储为 cvs 文件或其它任何格式,反之亦然。将 scikit 函数应用于多维数组时,它特别方便。SQL 非常适合查询数据库,但是对于执行复杂和资源密集型的数据科学操作,在 ndarray 中存储数据可以提高效率和速度(但请确保在处理大量数据集时有足够的 RAM)。当你使用 pandas 进行知识提取和分析时,pandas 中的 DataFrame 数据类型和 NumPy 中的 ndarray 之间的无缝转换分别为提取和计算密集型操作创建了一个强大的组合。

作为快速演示,让我们启动 Python shell 并在 pandas DataFrame 变量中加载来自巴尔的摩的犯罪统计数据的开放数据集,并查看加载的一部分 DataFrame:

>>> ?import pandas as pd
>>> ?crime_stats =?pd.read_csv('BPD_Arrests.csv')
>>> ?crime_stats.head()

我们现在可以在这个 pandas DataFrame 上执行大多数查询,就像我们可以在数据库中使用 SQL 一样。例如,要获取 Description 属性的所有唯一值,SQL 查询是:

$ SELECT unique(“Description”) from crime_stats;

利用 pandas DataFrame 编写相同的查询如下所示:

>>>  crime_stats['Description'].unique()
['COMMON   ASSAULT'   'LARCENY'   'ROBBERY   - STREET'   'AGG.   ASSAULT'
'LARCENY   FROM   AUTO'   'HOMICIDE'   'BURGLARY'   'AUTO   THEFT'
'ROBBERY   - RESIDENCE'   'ROBBERY   - COMMERCIAL'   'ROBBERY   - CARJACKING'
'ASSAULT   BY  THREAT'   'SHOOTING'   'RAPE'   'ARSON']

它返回的是一个 NumPy 数组(ndarray 类型):

>>>  type(crime_stats['Description'].unique())
<class 'numpy.ndarray'>

接下来让我们将这些数据输入神经网络,看看它能多准确地预测使用的武器类型,给出的数据包括犯罪事件,犯罪类型以及发生的地点:

>>>  from   sklearn.neural_network   import   MLPClassifier
>>>  import   numpy   as np
>>>
>>>  prediction   =  crime_stats[[‘Weapon’]]
>>>  predictors   =  crime_stats['CrimeTime',   ‘CrimeCode’,   ‘Neighborhood’]
>>>
>>>  nn_model   =  MLPClassifier(solver='lbfgs',   alpha=1e-5,   hidden_layer_sizes=(5,
2),   random_state=1)
>>>
>>>predict_weapon   =  nn_model.fit(prediction,   predictors)

现在学习模型准备就绪,我们可以执行一些测试来确定其质量和可靠性。对于初学者,让我们输入一个训练集数据(用于训练模型的原始数据集的一部分,不包括在创建模型中):

>>>  predict_weapon.predict(training_set_weapons)
array([4,   4,   4,   ..., 0,   4,   4])

如你所见,它返回一个列表,每个数字预测训练集中每个记录的武器。我们之所以看到的是数字而不是武器名称,是因为大多数分类算法都是用数字优化的。对于分类数据,有一些技术可以将属性转换为数字表示。在这种情况下,使用的技术是标签编码,使用 sklearn 预处理库中的 LabelEncoder 函数:preprocessing.LabelEncoder()。它能够对一个数据和其对应的数值表示来进行变换和逆变换。在这个例子中,我们可以使用 LabelEncoder()inverse_transform 函数来查看武器 0 和 4 是什么:

>>>  preprocessing.LabelEncoder().inverse_transform(encoded_weapons)
array(['HANDS',   'FIREARM',   'HANDS',   ..., 'FIREARM',   'FIREARM',   'FIREARM']

这很有趣,但为了了解这个模型的准确程度,我们将几个分数计算为百分比:

>>>  nn_model.score(X,   y)
0.81999999999999995

这表明我们的神经网络模型准确度约为 82%。这个结果似乎令人印象深刻,但用于不同的犯罪数据集时,检查其有效性非常重要?;褂衅渌馐岳醋稣飧?,如相关性、混淆、矩阵等。尽管我们的模型有很高的准确率,但它对于一般犯罪数据集并不是非常有用,因为这个特定数据集具有不成比例的行数,其列出 FIREARM 作为使用的武器。除非重新训练,否则我们的分类器最有可能预测 FIREARM,即使输入数据集有不同的分布。

在对数据进行分类之前清洗数据并删除异常值和畸形数据非常重要。预处理越好,我们的见解准确性就越高。此外,为模型或分类器提供过多数据(通常超过 90%)以获得更高的准确度是一个坏主意,因为它看起来准确但由于过度拟合而无效。

Jupyter notebooks 相对于命令行来说是一个很好的交互式替代品。虽然 CLI 对于大多数事情都很好,但是当你想要运行代码片段以生成可视化时,Jupyter 会很出色。它比终端更好地格式化数据。

这篇文章 列出了一些最好的机器学习免费资源,但是还有很多其它的指导和教程。根据你的兴趣和爱好,你还会发现许多开放数据集可供使用。作为起点,由 Kaggle 维护的数据集,以及在州政府网站上提供的数据集是极好的资源。

Python 数据科学入门,首发于山西十一选五手机版。

]]>
//www.brhi.net/114493/feed/ 1
awk 入门教程 - 山西十一选五手机版▁山西11选五前三组遗漏▁山西十一选五任七遗漏▁山西11选五遗漏top10▁山西体彩十一选5一定牛 //www.brhi.net/114490/ //www.brhi.net/114490/#respond Wed, 07 Nov 2018 14:18:16 +0000 //www.brhi.net/?p=114490 对于日志、CSV 那样的每行格式相同的文本文件,awk 可能是最方便的工具。

awk 入门教程,首发于山西十一选五手机版。

]]>
awk是处理文本文件的一个应用程序,几乎所有 Linux 系统都自带这个程序。

它依次处理文件的每一行,并读取里面的每一个字段。对于日志、CSV 那样的每行格式相同的文本文件,awk可能是最方便的工具。

awk其实不仅仅是工具软件,还是一种编程语言。不过,本文只介绍它的命令行用法,对于大多数场合,应该足够用了。

一、基本用法

awk的基本用法就是下面的形式。

# 格式
$ awk 动作 文件名

# 示例
$ awk '{print $0}' demo.txt

上面示例中,demo.txtawk所要处理的文本文件。前面单引号内部有一个大括号,里面就是每一行的处理动作print $0。其中,print是打印命令,$0代表当前行,因此上面命令的执行结果,就是把每一行原样打印出来。

awk也可以处理标准输入(stdin)。

$ echo 'this is a test' | awk '{print $0}'
this is a test

上面代码中,print $0就是把标准输入this is a test,重新打印了一遍。

awk会根据空格和制表符,将每一行分成若干字段,依次用$1、$2、$3代表第一个字段、第二个字段、第三个字段等等。

$ echo 'this is a test' | awk '{print $3}'
a

上面代码中,$3代表this is a test的第三个字段a。

下面,为了便于举例,我们把/etc/passwd文件保存成demo.txt。

root:x:0:0:root:/root:/usr/bin/zsh
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync

这个文件的字段分隔符是冒号(:),所以要用-F参数指定分隔符为冒号。然后,才能提取到它的第一个字段。

$ awk -F ':' '{ print $1 }' demo.txt
root
daemon
bin
sys
sync

二、变量

除了$ + 数字表示某个字段,awk还提供其他一些变量。

变量NF表示当前行有多少个字段,因此$NF就代表最后一个字段。

$ echo 'this is a test' | awk '{print $NF}'
test

$(NF-1)代表倒数第二个字段。

$ awk -F ':' '{print $1, $(NF-1)}' demo.txt
root /root
daemon /usr/sbin
bin /bin
sys /dev
sync /bin

上面代码中,print命令里面的逗号,表示输出的时候,两个部分之间使用空格分隔。

变量NR表示当前处理的是第几行。

$ awk -F ':' '{print NR ") " $1}' demo.txt
1) root
2) daemon
3) bin
4) sys
5) sync

上面代码中,print命令里面,如果原样输出字符,要放在双引号里面。

awk的其他内置变量如下。

  • FILENAME:当前文件名
  • FS:字段分隔符,默认是空格和制表符。
  • RS:行分隔符,用于分割每一行,默认是换行符。
  • OFS:输出字段的分隔符,用于打印时分隔字段,默认为空格。
  • ORS:输出记录的分隔符,用于打印时分隔记录,默认为换行符。
  • OFMT:数字输出的格式,默认为%.6g。

三、函数

awk还提供了一些内置函数,方便对原始数据的处理。

函数toupper()用于将字符转为大写。

$ awk -F ':' '{ print toupper($1) }' demo.txt
ROOT
DAEMON
BIN
SYS
SYNC

上面代码中,第一个字段输出时都变成了大写。

其他常用函数如下。

  • tolower():字符转为小写。
  • length():返回字符串长度。
  • substr():返回子字符串。
  • sin():正弦。
  • cos():余弦。
  • sqrt():平方根。
  • rand():随机数。

awk内置函数的完整列表,可以查看手册。

四、条件

awk允许指定输出条件,只输出符合条件的行。

输出条件要写在动作的前面。

$ awk '条件 动作' 文件名

请看下面的例子。

$ awk -F ':' '/usr/ {print $1}' demo.txt
root
daemon
bin
sys

上面代码中,print命令前面是一个正则表达式,只输出包含usr的行。

下面的例子只输出奇数行,以及输出第三行以后的行。

# 输出奇数行
$ awk -F ':' 'NR % 2 == 1 {print $1}' demo.txt
root
bin
sync

# 输出第三行以后的行
$ awk -F ':' 'NR >3 {print $1}' demo.txt
sys
sync

下面的例子输出第一个字段等于指定值的行。

$ awk -F ':' '$1 == "root" {print $1}' demo.txt
root

$ awk -F ':' '$1 == "root" || $1 == "bin" {print $1}' demo.txt
root
bin

五、if 语句

awk提供了if结构,用于编写复杂的条件。

$ awk -F ':' '{if ($1 > "m") print $1}' demo.txt
root
sys
sync

上面代码输出第一个字段的第一个字符大于m的行。

if结构还可以指定else部分。

$ awk -F ':' '{if ($1 > "m") print $1; else print "---"}' demo.txt
root
---
---
sys
sync

六、参考链接

(完)

awk 入门教程,首发于山西十一选五手机版。

]]>
//www.brhi.net/114490/feed/ 0
反对薪酬保密,一程序员公开了硅谷秘密 - 山西十一选五手机版▁山西11选五前三组遗漏▁山西十一选五任七遗漏▁山西11选五遗漏top10▁山西体彩十一选5一定牛 //www.brhi.net/114488/ //www.brhi.net/114488/#respond Wed, 07 Nov 2018 07:31:29 +0000 //www.brhi.net/?p=114488 讨论报酬水平是职场的大忌。因为这样可能会被公司炒鱿鱼。但是硅谷的软件工程师 Jackie Luo 提出,为了报酬的公平性需要提高透明度,因为只有员工才能提供公司所需的技能和经验,公司不能一手遮天。而透明性的提高需要所有员工的积极参与。她的呼吁得到了很多技术员工的响应,这篇文章就是她发现的硅谷员工的薪酬秘密。

反对薪酬保密,一程序员公开了硅谷秘密,首发于山西十一选五手机版。

]]>
讨论报酬水平是职场的大忌。因为这样可能会被公司炒鱿鱼。但是硅谷的软件工程师 Jackie Luo?提出,为了报酬的公平性需要提高透明度,因为只有员工才能提供公司所需的技能和经验,公司不能一手遮天。而透明性的提高需要所有员工的积极参与。她的呼吁得到了很多技术员工的响应,这篇文章就是她发现的硅谷员工的薪酬秘密。

我是一名软件工程师,有 3 年的工作经验,在 Square 工作,这是一家总部位于旧金山的上市公司。我每年能赚 13 万美元,外加价值 47500 美元的股票,也就是每年 177500 美元。

基本工资我没有跟他们谈。不过我的确把 4 年股票赠与从 15 万美元谈到了 19 万美元。我是在 2 月 5 号入职的。那笔赠与目前的价值是 412390.02 美元(煤炭都会波动)。如果按照这个股价行权第一年的话,我真正的报酬是 233097.51 美元。

透露这一切令我感到害怕。陌生人和同行看到我挣的钱后认为我拿得太多了。(“开玩笑吧?她都干了什么能拿到这样的工资水平?”)要么他们也许会认为我拿得太少。(“如果她拿这么少的话那一定是工作不怎样?!保┙创蛩愎臀业墓颈厝欢蓟峥吹轿抑暗男剿缓蠼椅蠢吹男剿ㄖ暗乃?,从而限制了我换工作时的涨薪水平,或者因为害怕我这个人太贵而将我排除在面试名单之外。

既然这样我为什么还要分享这些数字?因为我们需要更多地讨论有关我们拿多少报酬的事情。公平报酬始于更大的透明度。

在今天,性别、种族、阶层以及无数其他的身份标识在技术业的系统性偏见中都扮演着自己的角色。2018 年的一份雇佣报告发现,男性在技术业拿到的报酬要高于女性,在同一家公司担任相同角色的情况下 63% 的时候男性都要高于女性。54% 的技术女性报告说自己拿到的钱要比担任同一角色的男性要少。

但我们有一个有关报酬的真诚对话可以缩小差距的乐观理由。意识到存在报酬差异的人当中有 66% 者只是在跟同事聊到报酬的情况时才知道这件事情的存在。

硅谷真正的财富是通过股权产生的。

通常当大家讨论报酬——该接受什么,该拒绝什么,如何协商的时候,建议总是“知道你的价值?!钡趺床拍苤??对于大多数员工来说,报酬被锁在一个黑箱里面,而处在职场最上层阶梯的人掌握着所有的信息。只需要把他们支付的报酬数据给收集众多客户相关数字的机构,他们通常能获取到有关市场给特定角色开出的平均薪酬的信息,并且还能拿到聚合的分析。这种信息不对称造成了权力的失衡,只有一端,也即是更有权力的一方能够做出关于报酬支付的知情决定。

典型的场景是这样的:你接受了一家公司的面试,在电话筛选上花费了几个小时,并且完成了现场面试。你表现很好。准备拿到 offer。当然了,招聘人员会打电话给你,问你想开出的报酬是多少。

这个时候你就开始恐慌了。如果你报出的数字太高怎么办?你不希望公司因此不给你这个 offer 了——你需要一份工作并且已经走完了整个面试流程,所以你不希望破坏这个机会??扇绻惚ǖ锰湍??你不希望贱卖自己,而你现在协商的报酬,在你拿到那份工作之前,将决定你未来几年的报酬。拥有类似资格的其他人拿到的报酬如何?你完全就是在黑暗中乱开枪。

纠正这种不平衡的努力的确有(比如 Glassdoor、Comparably 以及 Levels 这类的服务),但是聚合报酬数据的匿名平台并不能替代我们的真正需要:一种将公开讨论报酬正?;奈幕?。

因为有感于作家 Carina Hsieh 以及#talkpay 运动,在三八国际妇女节那天我发了一条推特。它向技术界的男性发出来公开邀请,请他们与我分享自己的工资好让我可以匿名地发布出去。

即便在今天,相对于自己的同行,女性以及被忽视的少数族裔还是频繁地拿到过低的报酬,而他们甚至都没有意识到这一点,因为他们没有太多的比较点。我以为会有少数人愿意直接给我发信息。

迄今为止,已经有 50 万人看到了那条推特。成千上万的人已经直接私信我。大家发送了很多的工资信息给我,多到我仍然还没有把我收到的数据公布完,差得还远呢。

我们保守薪水的秘密是因为我们害怕会因为分享这些数据而受到惩罚。

全世界各种角色的技术员工都把自己的薪水数据发给了我,但因为我是一名湾区的软件工程师,所以我最大的数据集来自这里。那么,湾区的男性软件工程师拿到的薪水有多少呢?以下就是我对这场讨论的贡献:

软件工程师开发了你每天使用的各种网站和 app。湾区的软件工程角色往往从 6 位数起步:120000 美元是 4 年大学生涯刚刚毕业的计算机科学专业拿到的典型的基本工资,这是由大型上市技术公司设定的标准。新毕业生去到小一点的初创企业能拿到的薪水可能会比这要低一点,但通常哪怕是初创企业也会支付 6 位数的工资。早期阶段初创企业给的钱最少,而真正令人安逸之心的薪酬数字只会出现在最大型的“初创企业”那里,比如 Uber、Lyft 以及 AirBnb。

加州技术业的工资概况

初创企业和上市公司的一大差异化因素是股权。初创企业的股权到头来往往一文不值,但是上市公司的股权则代表着报仇的一大部分?;镜墓ぷ屎苌倩嵴堑?40 万美元以上——实际上我还没有见过——但股票则可以令工程师的整体薪酬翻番或者甚至翻 3 番。而且跟工资不一样的是,股票在价值上可以飙涨,如果你是目睹了股价坐火箭的 Google 员工或者你是一家初创企业的第一名工程师而那家公司后来被高价收购的话这一点是真的。硅谷的真正财富是通过股权产生的。

尤其是 Facebook 和 Google 对于迫切需要的人才开出的薪酬是最丰厚的。尽管市场竞争激烈,但如果你听说一位工程师的总报酬达到 75 万美元的话,那一定是非常不典型的。很有可能他们是在 Facebook 或者 Google 工作,而且是全世界稍有的几个具备行业经验与专业知识能从事相关工作的人。他们就是戴着“金手套”的人:理论上他们可以在任何地方找到一份工作,但是他们无法离开(或者至少他们认为自己不能离开),因为没有一个竞争对手能配得上他们的报酬。

大家通?;岬P淖约夯嵋蛭窒碜约旱氖杖攵怀傣嫌?。

如果让我来猜测湾区软件工程师的平均总薪酬(基本工资、股权加奖金)的话,我想大概在 150000 美元到 200000 美元之间。这个估计得到了我从 Twitter 收到的数据的支持,其中位数是 183750 美元。根据 Glassdoor,工程师的平均基本工资是 137000 美元,奖金为 11000 美元,这还没有包括股票奖励。

美国技术工资概况

这个数字已经不少了,所以这个话题的敏感性也不足为奇。尽管如此,我对披露报酬数字给我的人的害怕程度仍然准备不足,很多人一而再再而三地向我强调这一信息只能匿名发出。好几位甚至还要求自己的工作城市和职位细节信息要尽可能写得含糊,以防自己正好被对上号。大家往往会担心自己因为分享收入信息而被炒鱿鱼。

对待透明性的态度是文化已经受到严重破坏的迹象。我们如何得到报酬塑造了我们得日常生活的一切:我们可以在哪里生活,可以做什么,可以有多大的自由。在收入方面更清楚了解到我们所处的位置完全是我们的利益所在,但是我们还是要保守这一信息秘密,因为我们害怕会由于分享而受到惩罚。在一个本该极其重视透明性的行业里,我们在最需要透明性的地方却恰恰存在不足。

让我们改变这一权力格局吧。跟你的同事讨论,跟你的业界同行讨论,跟你的朋友讨论自己拿到了多少报酬。跟你团队里面的女性和少数族裔讨论。不要仅仅讨论工资,要讨论整体报酬包括股权和奖金在内。讨论相关过程,比如你的报酬如何改变了自己的职业生涯路径以及协商报酬最后对拿到 offer 的影响会怎样。邀请他们也做同样的事情。

大家的共同看法是公司在就业市场拥有一切权力因为就业机会是它们赋予的。但员工才是提供公司所需技能和经验的人。知道自己应该拿多少让你在一个通常不钟爱于你的体系里面多少有一点权力——而你应该运用这种权力。

反对薪酬保密,一程序员公开了硅谷秘密,首发于山西十一选五手机版。

]]>
//www.brhi.net/114488/feed/ 0
Ubuntu 上更改 MySQL 数据库数据存储目录 - 山西十一选五手机版▁山西11选五前三组遗漏▁山西十一选五任七遗漏▁山西11选五遗漏top10▁山西体彩十一选5一定牛 //www.brhi.net/114485/ //www.brhi.net/114485/#respond Wed, 07 Nov 2018 07:12:38 +0000 //www.brhi.net/?p=114485 之前写过一篇博客“MySQL更改数据库数据存储目录”,当时的测试环境是RHEL和CentOS,谁想最近在Ubuntu下面更改MySQL数据库数据存储目录时遇到了之前未遇到的问题,之前的经验用不上了(或者说之前的总结不是太全面),修改完MySQL数据库数据存储目录后重启MySQL,发现MySQL服务无法启动。

Ubuntu 上更改 MySQL 数据库数据存储目录,首发于山西十一选五手机版。

]]>
之前写过一篇博客“MySQL更改数据库数据存储目录”,当时的测试环境是RHEL和CentOS,谁想最近在Ubuntu下面更改MySQL数据库数据存储目录时遇到了之前未遇到的问题,之前的经验用不上了(或者说之前的总结不是太全面),修改完MySQL数据库数据存储目录后重启MySQL,发现MySQL服务无法启动。

root@mylnx2:/etc/mysql/mysql.conf.d# service mysql start
 
Job for mysql.service failed because the control process exited with error code. See "systemctl status mysql.service" and "journalctl -xe" for details.

连MySQL的错误日志也未生成,使用service mysql status命令可以输出一些较详细的信息,如下所示:

root@mylnx2:/etc/mysql/mysql.conf.d# service mysql status
● mysql.service - MySQL Community Server
   Loaded: loaded (/lib/systemd/system/mysql.service; enabled; vendor preset: enabled)
   Active: activating (start-post) (Result: exit-code) since Mon 2018-10-15 22:33:00 CST; 28s ago
  Process: 12947 ExecStart=/usr/sbin/mysqld (code=exited, status=1/FAILURE)
  Process: 12932 ExecStartPre=/usr/share/mysql/mysql-systemd-start pre (code=exited, status=0/SUCCESS)
 Main PID: 12947 (code=exited, status=1/FAILURE);         : 12948 (mysql-systemd-s)
    Tasks: 2
   Memory: 1.9M
      CPU: 367ms
   CGroup: /system.slice/mysql.service
           └─control
             ├─12948 /bin/bash /usr/share/mysql/mysql-systemd-start post
             └─13045 sleep 1
 
Oct 15 22:33:00 mylnx2 systemd[1]: Starting MySQL Community Server...
Oct 15 22:33:01 mylnx2 mysqld[12947]: 2018-10-15T14:33:01.013763Z 0 [Warning] Changed limits: max_open_files: 1024 (requested 5000)
Oct 15 22:33:01 mylnx2 mysqld[12947]: 2018-10-15T14:33:01.013836Z 0 [Warning] Changed limits: table_open_cache: 431 (requested 2000)
Oct 15 22:33:01 mylnx2 mysqld[12947]: 2018-10-15T14:33:01.207533Z 0 [Warning] TIMESTAMP with implicit DEFAULT value is deprecated. Please use --explicit
Oct 15 22:33:01 mylnx2 mysqld[12947]: 2018-10-15T14:33:01.207663Z 0 [Warning] Can't create test file /mysql_data/mysql/mylnx2.lower-test
Oct 15 22:33:01 mylnx2 mysqld[12947]: 2018-10-15T14:33:01.207717Z 0 [Note] /usr/sbin/mysqld (mysqld 5.7.23-0ubuntu0.16.04.1-log) starting as process 129
Oct 15 22:33:01 mylnx2 mysqld[12947]: 2018-10-15T14:33:01.215413Z 0 [Warning] Can't create test file /mysql_data/mysql/mylnx2.lower-test
Oct 15 22:33:01 mylnx2 mysqld[12947]: 2018-10-15T14:33:01.215445Z 0 [Warning] Can't create test file /mysql_data/mysql/mylnx2.lower-test
Oct 15 22:33:01 mylnx2 systemd[1]: mysql.service: Main process exited, code=exited, status=1/FAILURE

错误信息为“[Warning] Can’t create test file /mysql_data/mysql/mylnx2.lower-test”。其实这里是踩到了“AppArmor”这个坑,之前对Ubuntu了解不多,所以直到遇到这个问题,才了解、知道这么个概念。下面是百科对AppArmor的介绍:

AppArmor是一个高效和易于使用的Linux系统安全应用程序。AppArmor对操作系统和应用程序所受到的威胁进行从内到外的?;?,甚至是未被发现的0day漏洞和未知的应用程序漏洞所导致的攻击。AppArmor安全策略可以完全定义个别应用程序可以访问的系统资源与各自的特权。AppArmor包含大量的默认策略,它将先进的静态分析和基于学习的工具结合起来,AppArmor甚至可以使非常复杂的应用可以使用在很短的时间内应用成功。

AppArmor对MySQL所能使用的目录权限做了限制,如下截图所示,规定了MySQL使用的数据文件路径权限。

# cat /etc/apparmor.d/usr.sbin.mysqld

clip_image001

我将MySQL的数据库数据存储目录从/var/lib/mysql 切换到/mysql_data/mysql下面。所以就遇到了上面错误,需要修改或新增两条记录,从而使mysqld可以使用/mysql_data/mysql这个目录

/mysql_data/mysql/ r,

/mysql_data/mysql/** rwk,

然后重启AppArmor服务后,然后就可以重启MySQL服务了。

sudo service apparmor restart

当然/etc/apparmor.d/usr.sbin.mysqld还有Allow plugin access需要调整,这个不是重点,在此略过。

犹豫了一会,还是记录一下这个小小案例!虽然网上已有不少人总结这个,但是自己动手总结一下,印象也深刻一点!

Ubuntu 上更改 MySQL 数据库数据存储目录,首发于山西十一选五手机版。

]]>
//www.brhi.net/114485/feed/ 0
SQL优化指南 - 山西十一选五手机版▁山西11选五前三组遗漏▁山西十一选五任七遗漏▁山西11选五遗漏top10▁山西体彩十一选5一定牛 //www.brhi.net/114482/ //www.brhi.net/114482/#respond Tue, 06 Nov 2018 06:18:34 +0000 //www.brhi.net/?p=114482 从order by、group by、子查询和limit分页等方面介绍SQL优化方式。

SQL优化指南,首发于山西十一选五手机版。

]]>

慢查询日志 开启撒网模式

开启了MySQL慢查询日志之后,MySQL会自动将执行时间超过指定秒数的SQL统统记录下来,这对于搜罗线上慢SQL有很大的帮助。

SHOW VARIABLES LIKE 'slow%'

以我刚安装的mysql5.7为例 查询结果是这样子的:

slow_launch_time:表示如果建立线程花费了比这个值更长的时间,slow_launch_threads 计数器将增加
slow_query_log:是否开启慢查询日志 ON开启,OFF关闭 默认没有开启
slow_query_log_file:日志保存路径

SHOW VARIABLES LIKE 'long%'

long_query_time:达到多少秒的sql就记录日志

客户端可以用set设置变量的方式让慢查询开启,但是个人不推荐,因为真实操作起来会有一些问题,比如说,重启MySQL后就失效了,或者是开启了慢查询,我又去改变量值,它就不生效了。

编辑MySQL的配置文件:

vim /etc/my.cnf

加入如下三行:

  slow_query_log=ON
  slow_query_log_file=/var/lib/mysql/localhost-centos-slow.log
  long_query_time=3

我这里设置的是3秒

重启MySQL

systemctl restart mysqld;

服务器开一个监控:

tail -f /var/lib/mysql/localhost-centos-slow.log

客户端走一条SQL:

SELECT SLEEP(3)

此时发现sql已经被记录到日志里了。(有时候不一定,我看到很多博客讲的是超过指定秒数,但我实验得出的结果是达到指定秒数)

EXPLAIN 点对点分析你

explain是一个神奇的命令,可以查看sql的具体的执行计划。

以一条联查sql为例:

SELECT a.id,a.cn_name,a.role_id,r.name
FROM tb_usr_admins a
INNER JOIN tb_base_roles r ON r.id=a.role_id
WHERE a.cn_name="接单人员"

查询结果是:

加上explain命令来执行:

EXPLAIN
SELECT a.id,a.cn_name,a.role_id,r.name
FROM tb_usr_admins a
INNER JOIN tb_base_roles r ON r.id=a.role_id
WHERE a.cn_name="接单人员"

查询结果是:

这就是这条SQL的执行计划,下面来说明一下这个执行计划怎么看

id:代表优先级? id值越大,越先执行,id值相同,从上往下执行。(比如示例的这条sql的执行计划,就是先执行第一行,再执行第二行)

select_type:表示select类型 取值如下

simple 简单表 即不使用表连接或者子查询
primary 包含union或者子查询的主查询 即外层的查询
union UNION中的第二个或者后面的查询语句
subquery 一般子查询中的子查询被标记为subquery,也就是位于select列表中的查询
derived 派生表 该临时表是从子查询派生出来的
等等

type:表示MySQL在表中查找数据的方式,或者叫访问类型,以下对于type取值的说明 从上往下性能由最差到最好

all:全表扫描,MySQL遍历全表来找到匹配的行
index:索引全扫描,MySQL遍历挣个索引来查询匹配的行
range:索引范围扫描,常见于<、<=、>、>=、between等操作符
ref:使用非唯一索引或唯一索引的前缀扫描,返回匹配的单行数据
eq_ref:类似ref,区别就在于使用的索引是唯一索引,简单来说,就是多表连接中使用primary key或者unique index作为关联条件。
const/system:单表中最多有一个匹配行,查询起来非常迅速,常见于根据primary key或者唯一索引unique index进行的单表查询
null:mysql不用访问表或者索引,直接就能够得到查询的结果,例如select 1+2 as result。

possible_keys:表示查询时可能使用的索引

key:表示实际使用的索引

key_len:使用到索引字段的长度

rows:扫描数量

Extra:执行情况的说明和描述,包含不适合在其他列中显示但是对执行计划非常重要的额外信息,常用取值如下:

Using index:直接访问索引就取到了数据,高性能的表现。
Using where:直接在主键索引上过滤数据,必带where子句,而且用不上索引
Using index condition:先条件过滤索引,再查数据,
Using filesort:使用了外部文件排序 只要见到这个 就要优化掉
Using temporary:创建了临时表来处理查询 只要见到这个 也要尽量优化掉

优化争议无数的count()

统计列与统计行?

COUNT()是一个特殊的函数,有两种不同的作用,它可以统计某个列值的数量,也可以统计行数。

在统计列值的时候要求列值是非空的,也就是不统计null。

当我们统计行的时候,常见的是COUNT(*),这种情况下,通配符*并不会像我们猜想的那样扩展成所有的列,实际上,它会忽略所有的列而直接统计所有的行数

解密MyiSAM的‘快’

这是一个容易产生误解的事情:MyiSAM的count()函数总是非???。

不过它是有前提条件的,条件是没有任何where条件的count(*)才非???,因为此时无须实际的去计算表的行数,mysql可以利用存储引擎的特性直接获得这个值,如果mysql知道某列不可能有null值,那么mysql内部会将count(列)表达式优化为count(*)。

当统计带有where条件的查询,那么mysql的count()和其他存储引擎就没有什么不同了。

COUNT(1)、COUNT(*)、COUNT(列)

(先提前申明,本人是在innodb库里做的实验。)

1.count(1)和count(*)直接就是统计主键,他们两个的效率是一样的。如果删除主键,他们都走全表扫描。

2.如果count(列)中的字段是索引的话,count(列)和count(*)一样快,否则count(列)走全表扫描。

优化order by 语句

MySQL的排序方式

优化order by语句就不得不了解mysql的排序方式。

1.第一种通过有序索引返回数据,这种方式的extra显示为Using Index,不需要额外的排序,操作效率较高。

2.第二种是对返回的数据进行排序,也就是通??吹降腢sing filesort,filesort是通过相应的排序算法,将数据放在sort_buffer_size系统变量设置的内存排序区中进行排序,如果内存装载不下,它就会将磁盘上的数据进行分块,再对各个数据块进行排序,然后将各个块合并成有序的结果集。

filesort的优化

了解了MySQL排序的方式,优化目标就清晰了:尽量减少额外的排序,通过索引直接返回有序数据。where条件和order by使用相同的索引。

1.创建合适的索引减少filesort的出现。

2.查询时尽量只使用必要的字段,select 具体字段的名称,而不是select * 选择所有字段,这样可以减少排序区的使用,提高SQL性能。

优化group by 语句

为什么order by后面不能跟group by ?

事实上,MySQL在所有的group by 后面隐式的加了order by ,也就是说group by语句的结果会默认进行排序。

如果你要在order by后面加group by ,那结果执行的SQL是不是这样:select * from tb order by … group by … order by … ? 这不是搞笑吗?

禁止排序

既然知道问题了,那么就容易优化了,如果查询包括group by但又不关心结果集的顺序,而这种默认排序又导致了需要文件排序,则可以指定order by null 禁止排序。

例如:

select * from tb group by name order by null;

优化limit 分页

一个非常常见又非常头痛的场景:‘limit 1000,20’。

这时MySQL需要查询1020条记录然后只返回最后20条,前面的1000条都将被抛弃,这样的代价非常高。如果所有页面的访问频率都相同,那么这样的查询平均需要访问半个表的数据。

第一种思路 在索引上分页

在索引上完成分页操作,最后根据主键关联回原表查询所需要的其他列的内容。

例如:

SELECT * FROM tb_user LIMIT 1000,10

可以优化成这样:

SELECT * FROM tb_user u 
INNER JOIN (SELECT id FROM tb_user LIMIT 1000,10) AS b ON b.id=u.id

第二种思路 将limit转换成位置查询

这种思路需要加一个参数来辅助,标记分页的开始位置:

SELECT * FROM tb_user WHERE id > 1000 LIMIT 10

优化子查询

子查询,也就是查询中有查询,常见的是where后面跟一个括号里面又是一条查询sql

尽可能的使用join关联查询来代替子查询。

当然 这不是绝对的,比如某些非常简单的子查询就比关联查询效率高,事实效果如何还要看执行计划。

只能说大部分的子查询都可以优化成Join关联查询。

改变执行计划

提高索引优先级

use index 可以让MySQL去参考指定的索引,但是无法强制MySQL去使用这个索引,当MySQL觉得这个索引效率太差,它宁愿去走全表扫描。。。

SELECT * FROM tb_user USE INDEX (user_name)

注意:必须是索引,不能是普通字段,(亲测主键也不行)。

忽略索引

ignore index 可以让MySQL忽略一个索引

SELECT * FROM tb_user IGNORE INDEX (user_name) WHERE user_name="张学友"

强制使用索引

force index 使用了force index 之后 尽管效率非常低,MySQL也会照你的话去执行

SELECT * FROM tb_user FORCE INDEX (user_name) WHERE user_name="张学友"

个人分享

查看执行计划时建议依次观察以下几个要点:

1.SQL内部的执行顺序。
2.查看select的查询类型。
3.实际有没有使用索引。
4.Extra描述信息

PS:一定要养成查看执行计划的习惯,这个习惯非常重要。

SQL优化指南,首发于山西十一选五手机版。

]]>
//www.brhi.net/114482/feed/ 0
MySQL 更改数据库数据存储目录 - 山西十一选五手机版▁山西11选五前三组遗漏▁山西十一选五任七遗漏▁山西11选五遗漏top10▁山西体彩十一选5一定牛 //www.brhi.net/114479/ //www.brhi.net/114479/#respond Mon, 05 Nov 2018 13:43:15 +0000 //www.brhi.net/?p=114479 MySQL 数据库默认的数据库文件位于 /var/lib/mysql 下,有时候由于存储规划等原因,需要更改 MySQL 数据库的数据存储目录。下文总结整理了实践过程的操作步骤。

MySQL 更改数据库数据存储目录,首发于山西十一选五手机版。

]]>
MySQL数据库默认的数据库文件位于/var/lib/mysql下,有时候由于存储规划等原因,需要更改MySQL数据库的数据存储目录。下文总结整理了实践过程的操作步骤。

1:确认MySQL数据库存储目录

[root@DB-Server tmp]# mysqladmin -u root -p variables | grep datadir
Enter password: 
| datadir | /var/lib/mysql/

2:关闭MySQL服务

在更改MySQL的数据目录前,必须关闭MySQL服务。

方式1

[root@DB-Server ~]# service mysql status
 
MySQL running (9411)[ OK ]
 
[root@DB-Server ~]# service mysql stop
 
Shutting down MySQL..[ OK ]
 
[root@DB-Server ~]#

clip_image001

 

方式2

[root@DB-Server ~]# /etc/rc.d/init.d/mysql status
 
MySQL running (8900)[ OK ]
 
[root@DB-Server ~]# /etc/rc.d/init.d/mysql stop
 
Shutting down MySQL..[ OK ]
 
[root@DB-Server ~]#

3:创建新的数据库存储目录

[root@DB-Server ~]# cd /u01
[root@DB-Server u01]# mkdir mysqldata

 

4:移动MySQL数据目录到新位置

[root@DB-Server ~]# mv /var/lib/mysql /u01/mysqldata/

 

5修改配置文件my.cnf

并不是所有版本都包含有my.cnf这个配置文件,在MySQL 5.5版本,我就找不到my.cnf这个配置文件, 而有些MySQL版本该文件位于/usr/my.cnf,如果/etc/目录下没有my.cnf配置文件,请到/usr/share/mysql/下找到*.cnf文件,拷贝其中一个到/etc/并改名为my.cnf中。命令如下:

clip_image003

[root@DB-Server mysql]# cp /usr/share/mysql/my-medium.cnf /etc/my.cnf

编辑/etc/my.cnf文件,修改参数socket

???????????????????????? MySQL 5.5 版本

clip_image004

# The following options will be passed to all MySQL clients
[client]
#password       = your_password
port            = 3306
socket          = /u01/mysqldata/mysql/mysql.sock
 
# Here follows entries for some specific programs
 
# The MySQL server
[mysqld]
port            = 3306
socket          = /u01/mysqldata/mysql/mysql.sock
skip-external-locking
key_buffer_size = 16M
max_allowed_packet = 1M
table_open_cache = 64
sort_buffer_size = 512K
net_buffer_length = 8K
read_buffer_size = 256K
read_rnd_buffer_size = 512K
myisam_sort_buffer_size = 8M

clip_image005

 

6:修改启动脚本/etc/init.d/mysql

将参数datadir修改为datadir=/u01/mysqldata/mysql/

clip_image006

 

7:启动MySQL服务并验证MySQL数据库路径

[root@DB-Server ~]# service mysql start
Starting MySQL..[  OK  ]
[root@DB-Server ~]# mysqladmin -u root -p variables | grep datadir
Enter password: 
| datadir        | /u01/mysqldata/mysql/

我的疑问:

1: 在修改数据库的存储目录前,/var/lib/mysql/目录下根本没有mysql.sock文件,安装上面配置后,就会生成mysql.sock文件。

关于mysql.sock文件,搜索了一下资料:mysql.sock是用于socket连接的文件。也就是只有你的守护进程启动起来这个文件才存在。但是你的mysql程序(这个程序是客户端,服务器端是mysqld)可以选择是否使用mysql.sock文件来连接(因为这个方法只适合在Unix主机上面连接本地的mysqld),对于非本地的任何类型的主机。那么这个文件是否一定需要的呢? 这个需要进一步了解清楚。

2:我在网上看有些网友总结的修改MySQL数据路径,有些需要给新建的目录的权限做一些处理,而有些有不用对目录权限进行授权,我没有处理,也没有什么问题。到底要不要对新的数据库目录授权呢?

3:我在MySQL_5.6.20这个版本测试时,不修改my.cnf,只修改启动脚本/etc/init.d/mysql,也完全没有啥问题。也没有myssql.sock文件生成。

4: 注意如果没有禁用selinux, 修改MySQL的数据路径后启动MySQL服务会遇到一些错误。关于这个的解释是后台服务都需要有对相应目录的对应权限,而 mysql 的默认路径/var/lib/mysql 已经添加了相应的策略,修改路径后由于没有相应的策略,导致后台进程读取文件被selinux阻止,从而出现权限错误。 所以要么关闭Selinux或修改文件安全上下文。

[root@DB-Server mysql]# /etc/init.d/mysql start
 
Starting MySQL....The server quit without updating PID file (/u01/mysqldata/mysql//DB-Server.localdomain.pid).[FAILED]
 
[root@DB-Server mysql]# 
 
[root@DB-Server mysql]# chcon -R -t mysqld_db_t /u01/mysqldata/mysql/
 
[root@DB-Server mysql]# /etc/init.d/mysql start
 
Starting MySQL.[ OK ]
 
[root@DB-Server mysql]#

参考资料:

//database.ctocio.com.cn/tips/449/7566949.shtml

www.linuxidc.com/Linux/2012-12/75647.htm

//blog.csdn.net/hellyhe/article/details/8309470

MySQL 更改数据库数据存储目录,首发于山西十一选五手机版。

]]>
//www.brhi.net/114479/feed/ 0
人人都能读懂的编译器原理 - 山西十一选五手机版▁山西11选五前三组遗漏▁山西十一选五任七遗漏▁山西11选五遗漏top10▁山西体彩十一选5一定牛 //www.brhi.net/114466/ //www.brhi.net/114466/#comments Thu, 01 Nov 2018 07:16:37 +0000 //www.brhi.net/?p=114466 理解编译器内部原理,可以让你更高效利用它。按照编译的工作顺序,逐步深入编程语言和编译器是怎样工作的。本文有大量的链接、样例代码和图表帮助你理解编译器。

人人都能读懂的编译器原理,首发于山西十一选五手机版。

]]>
编程语言是怎样工作的

理解编译器内部原理,可以让你更高效利用它。按照编译的工作顺序,逐步深入编程语言和编译器是怎样工作的。本文有大量的链接、样例代码和图表帮助你理解编译器。

作者注:

这是我在 Medium 上的第二篇文章的再版,上一版有超过 21000 的阅读量。很高兴我能够帮助到各位的学习,因此我根据上一版的评论,完完全全重写了。

我选择 Rust 作为这篇文章的主要语言。它是一种详尽的、高效的、现代的而且看起来特意使得设计编译器变得简单。我很喜欢使用它。 https://www.rust-lang.org/

写这篇文章的目的主要是吸引读者的注意力,而不是提供 20 多页的令人头皮发麻的阅读材料。对于那些你感兴趣的更深层次的话题,文章中有许多链接会引导你找到相关的资料。大多数链接到维基百科 。

感谢你的关注,我希望你能够喜欢这些我花费了超过 20 个小时的写出的文章?;队谖恼碌撞科缆鄞α粝氯魏挝侍饣蛘呓ㄒ?。

简单介绍

编译器是什么?

你口中所说的编程语言本质上只是一个软件,这个软件叫做编译器,编译器读入一个文本文件,经过大量的处理,最终产生一个二进制文件。 编译器的语言部分就是它处理的文本样式。因为电脑只能读取 1 和 0 ,而人们编写 Rust 程序要比直接编写二进制程序简单地多,因此编译器就被用来把人类可读的文本转换成计算机可识别的机器码。

编译器可以是任何可以把文本文件转换成其他文件的程序。例如,下面有一个用 Rust 语言写的编译器把 0 转换成 1,把 1 转换成 0 :

// An example compiler that turns 0s into 1s, and 1s into 0s.

fn main() {
    let input = "1 0 1 A 1 0 1 3";

    // iterate over every character `c` in input
    let output: String = input.chars().map(|c|
        if c == '1' { '0' }
        else if c == '0' { '1' }
        else { c } // if not 0 or 1, leave it alone
    ).collect();

    println!("{}", output); // 0 1 0 A 0 1 0 3
}

编译器是做什么的?

简言之,编译器获取源代码,产生一个二进制文件。因为从复杂的、人类可读的代码直接转化成0/1二进制会很复杂,所以编译器在产生可运行程序之前有多个步骤:

  1. 从你给定的源代码中读取单个词。
  2. 把这些词按照单词、数字、符号、运算符进行分类。
  3. 通过模式匹配从分好类的单词中找出运算符,明确这些运算符想进行的运算,然后产生一个运算符的树(表达式树)。
  4. 最后一步遍历表达式树中的所有运算符,产生相应的二进制数据。

尽管我说编译器直接从表达式树转换到二进制,但实际上它会产生汇编代码,之后汇编代码会被汇编/编译到二进制数据?;惚喑绦蚓秃帽仁且恢指呒兜?、人类可读的二进制。更多关于汇编语言的阅读资料在这里。

解释器是什么?

解释器 非常像编译器,它也是读入编程语言的代码,然后处理这些代码。尽管如此,解释器会跳过了代码生成,然后即时编译并执行 AST。 解释器最大的优点就在于在你 debug 期间运行程序所消耗的时间。编译器编译一个程序可能在一秒到几分钟不等,然而解释器可以立即开始执行程序,而不必编译。解释器最大的缺点在于它必须安装在用户电脑上,程序才可以执行。

虽然这篇文章主要是关于编译器的,但是对于编译器和解释器之间的区别和编译器相关的内容一定要弄清楚。

1. 词法分析

第一步是把输入一个词一个词的拆分开。这一步被叫做 词法分析,或者说是分词。这一步的关键就在于 我们把字符组合成我们需要的单词、标识符、符号等等。 词法分析大多都不需要处理逻辑运算像是算出 2+2 – 其实这个表达式只有三种 标记:一个数字:2,一个加号,另外一个数字:2。

让我们假设你正在解析一个像是 12+3 这样的字符串:它会读入字符 1,2,+,和 3。我们已经把这些字符拆分开了,但是现在我们必须把他们组合起来;这是分词器的主要任务之一。举个例子,我们得到了两个单独的字符 12,但是我们需要把它们放到一起,然后把它们解析成为一个整数。至于 +也需要被识别为加号,而不是它的字符值 – 字符值是43 。

如果你可以阅读过上面的代码,并且弄懂了这样做的含义,接下来的 Rust 分词器会组合数字为32位整数,加号就最后了标记值 Plus(加).

rust playground

你可以点击 Rust playgroud 左上角的 “Run” 按钮来编译和执行你浏览器中的代码。

在一种编程语言的编译器中,词法解析器可能需要许多不同类型的标记。例如:符号,数字,标识符,字符串,操作符等。想知道要从源文件中提取怎样的标记完全取决于编程语言本身。

int main() {
    int a;
    int b;
    a = b = 4;
    return a - b;
}

Scanner production:
[Keyword(Int), Id("main"), Symbol(LParen), Symbol(RParen), Symbol(LBrace), Keyword(Int), Id("a"), Symbol(Semicolon), Keyword(Int), Id("b"), Symbol(Semicolon), Id("a"), Operator(Assignment), Id("b"),
Operator(Assignment), Integer(4), Symbol(Semicolon), Keyword(Return), Id("a"), Operator(Minus), Id("b"), Symbol(Semicolon), Symbol(RBrace)]

C 语言的样例代码已经进行过词法分析,并且输出了它的标记。

2. 解析

解析器确实是语法解析的核心。解析器提取由词法分析器产生的标记,并尝试判断它们是否符合特定的模式,然后把这些模式与函数调用,变量调用,数学运算之类的表达式关联起来。 解析器逐词地定义编程语言的语法。

int a = 3a: int = 3 的区别在于解析器的处理上面。解析器决定了语法的外在形式是怎样的。它确保括号和花括号的左右括号是数量平衡的,每个语句结尾都有一个分号,每个函数都有一个名称。当标记不符合预期的模式时,解析器就会知道标记的顺序不正确。

你可以写好几种不同类型的解析器。最常见的解析器之一是从上到下的,递归降解的解析器。递归降解的解析器是用起来最简单也是最容易理解的解析器。我写的所有解析器样例都是基于递归降解的。

解析器解析的语法可以使用一种 语法 表示出来。像 EBNF 这样的语法就可以描述一个解析器用于解析简单的数学运算,像是这样 12+3 :

expr = additive_expr ;
additive_expr = term, ('+' | '-'), term ;
term = number ;

简单加法和减法表达式的 EBNF 语法。
请记住语法文件并不是解析器,但是它确实是解析器的一种表达形式。你可以围绕上面的语法创建一个解析器。语法文件可以被人使用并且比起直接阅读和理解解析器的代码要简单许多。

那种语法的解析器应该是 expr 解析器,因为它直接与所有内容都相关的顶层。唯一有效的输入必须是任意数字,加号或减号,任意数字。expr 需要一个 additive_expr,这主要出现在加法和减法表达式中。additive_expr 首先需要一个 term (一个数字),然后是加号或者减号,最后是另一个 term 。

 


解析 12+3 产生的样例 AST
解析器在解析时产生的树状结构被称为 抽象的语法树,或者称之为 AST。 ast 中包含了所有要进行操作。解析器不会计算这些操作,它只是以正确的顺序来收集其中的标记。

我之前补充了我们的词法分析器代码,以便它与我们的语法想匹配,并且可以产生像图表一样的 AST。我用 // BEGIN PARSER //// END PARSER // 的注释标记出了新的解析器代码的开头和结尾。

rust playground

我们可以再深入一点。假设我们想要支持只有数字没有运算符的输入,或者添加除法和乘法,甚至添加优先级。只要简单地修改一下语法文件,这些都是完全有可能的,任何调整都会直接反映在我们的解析器代码中。

expr = additive_expr ;
additive_expr = multiplicative_expr, { ('+' | '-'), multiplicative_expr } ;
multiplicative_expr = term, { ("*" | "/"), term } ;
term = number ;

新的语法。
https://play.rust-lang.org/?gist=1587a5dd6109f70cafe68818a8c1a883&version=nightly&mode=debug&edition=2018

 

针对 C 语言语法编写的解析器(又叫做词法分析器)和解析器样例。从字符序列的开始 “if(net>0.0)total+=net(1.0+tax/100.0);”,扫描器组成了一系列标记,并且对它们进行分类,例如,标识符,保留字,数字,或者运算符。后者的序列由解析器转换成语法树,然后由其他的编译器分阶段进行处理。扫描器和解析器分别处理 C 语法中的规则和与上下文无关的部分。引自:Jochen Burghardt.来源.

3. 生成代码

代码生成器 接收一个 AST ,然后生成相应的代码或者汇编代码。代码生成器必须以递归下降的顺序遍历AST中的所有内容-就像是解析器的工作方式一样-之后生成相应的内容,只不过这里生成的不再是语法树,而是代码了。

https://godbolt.org/z/K8416_

如果打开上面的链接,你就可以看到左侧样例代码产生的汇编代码?;惚啻氲牡谌泻偷谒男姓故玖吮嘁肫髟贏ST中遇到常量的时候是怎样为这些常量生成相应的代码的。

Godbolt Compiler Explorer 是一个很棒的工具,允许你用高级语言编写代码,并查看它产生的汇编代码。你可以有点晕头转向了,想知道产生的是哪种代码,但不要忘记给你的编程语言编译器添加优化选项来看看它到底有多智能。(对于 Rust 是 -O

如果你对于编译器是在汇编语言中怎样把一个本地变量保存到内存中感兴趣的话,这篇文章 (“代码生成”部分)非常详细地解释了堆栈的相关知识。大多数情况下,当变量不是本地变量的时候,高级编译器会在堆区为变量分配空间,并把它们保存到堆区,而不是栈区。你可以从这个 StackOverflow 的回答上阅读更多关于变量存储的内容。

因为汇编是一个完全不同的,而且复杂的主题,因此这里我不会过多地讨论它。我只是想强调代码生成器的重要性和它的作用。此外,代码生成器不仅可以产生汇编代码。Haxe 编译器有一个可以产生 6 种以上不同的编程语言的后端:包括 C++,Java,和 Python。

后端指的是编译器的代码生成器或者表达式解析器;因此前端是词法分析器和解析器。同样也有一个中间端,它通常与优化和 IR 有关,这部分会在稍后解释。后端通常与前端无关,后端只关心它接收到的 AST。这意味着可以为几种不同的前端或者语言重用相同的后端。大名鼎鼎的 GNU Compiler Collection 就属于这种情况。

我找不到比我的 C 编译器后端更好的代码生成器示例了;你可以在这里查看。

在生成汇编代码之后,这些汇编代码会被写入到一个新的汇编文件中 (.s.asm)。然后该文件会被传递给汇编器,汇编器是汇编语言的编译器,它会生成相应的二进制代码。之后这些二进制代码会被写入到一个新的目标文件中 (.o) 。

目标文件是机器码,但是它们并不可以被执行。 为了让它们变成可执行文件,目标文件需要被链接到一起。链接器读取通用的机器码,然后使它变为一个可执行文件、共享库或是 静态库。更多关于链接器的知识在这里。

链接器是因操作系统而不同的应用程序。随便一个第三方的链接器都应该可以编译你后端产生的目标代码。因此在写编译器的时候不需要创建你自己的链接器。

编译器可能有 中间表示,或者简称 IR 。IR 主要是为了在优化或者翻译成另一门语言的时候,无损地表示原来的指令。 IR 不再是原来的代码;IR 是为了寻找代码中潜在的优化而进行的无损简化。循环展开向量化 都是利用 IR 完成的。更多关于 IR 相关的优化可以在这个 PDF 中找到。

总结

当你理解了编译器的时候,你就可以更有效地使用你的编程语言?;蛐碛幸惶炷慊岫源唇阕约旱谋喑逃镅愿行巳??我希望这能够帮到你。

资源&更深入的阅读资料

人人都能读懂的编译器原理,首发于山西十一选五手机版。

]]>
//www.brhi.net/114466/feed/ 2
2018 年最好的 Linux 发行版 - 山西十一选五手机版▁山西11选五前三组遗漏▁山西十一选五任七遗漏▁山西11选五遗漏top10▁山西体彩十一选5一定牛 //www.brhi.net/114473/ //www.brhi.net/114473/#comments Sun, 28 Oct 2018 13:49:37 +0000 //www.brhi.net/?p=114473 Jack Wallen 分享他挑选的 2018 年最好的 Linux 发行版。

2018 年最好的 Linux 发行版,首发于山西十一选五手机版。

]]>
Linux distros 2018

Jack Wallen 分享他挑选的 2018 年最好的 Linux 发行版。

这是新的一年,Linux 仍有无限可能。而且许多 Linux 发行版在 2017 年都带来了许多重大的改变,我相信在 2018 年它在服务器和桌面上将会带来更加稳定的系统和市场份额的增长。

对于那些期待迁移到开源平台(或是那些想要切换到)的人对于即将到来的一年,什么是最好的选择?如果你去 Distrowatch 找一下,你可能会因为众多的发行版而感到头晕,其中一些的排名在上升,而还有一些则恰恰相反。

因此,哪个 Linux 发行版将在 2018 年得到偏爱?我有我的看法。事实上,我现在就要和你们分享它。

跟我做的 去年清单 相似,我将会打破那张清单,使任务更加轻松。普通的 Linux 用户,至少包含以下几个类别:系统管理员,轻量级发行版,桌面,为物联网和服务器发行的版本。

根据这些,让我们开始 2018 年最好的 Linux 发行版清单吧。

对系统管理员最好的发行版

Debian 不常出现在“最好的”列表中。但它应该出现,为什么呢?如果了解到 Ubuntu 是基于 Debian 构建的(其实有很多的发行版都基于 Debian),你就很容易理解为什么这个发行版应该在许多“最好”清单中。但为什么是对管理员最好的呢?我想这是由于两个非常重要的原因:

  • 容易使用
  • 非常稳定

因为 Debain 使用 dpkg 和 apt 包管理,它使得使用该环境非常简单。而且因为 Debian 提供了最稳定的 Linux 平台之一,它为许多事物提供了理想的环境:桌面、服务器、测试、开发。虽然 Debian 可能不包括去年本分类的优胜者 Parrot Linux 所带有的大量应用程序,但添加完成任务所需的任何或全部必要的应用程序都非常容易。而且因为 Debian 可以根据你的选择安装不同的桌面(Cinnamon、GNOME、KDE、LXDE、Mate 或者 Xfce),肯定可以满足你对桌面的需求。

debian

图 1:在 Debian 9.3 上运行的 GNOME 桌面。

同时,Debain 在 Distrowatch 上名列第二。下载、安装,然后让它为你的工作而服务吧。Debain 尽管不那么华丽,但是对于管理员的工作来说十分有用。

最轻量级的发行版

轻量级的发行版有其特殊的用途:给予一些老旧或是性能低下的机器以新生。但是这不意味着这些特别的发行版仅仅只为了老旧的硬件机器而生。如果你想要的是运行速度,你可能会想知道在你的现代机器上这类发行版的运行速度能有多快。

在 2018 年上榜的最轻量级的发行版是 Lubuntu。尽管在这个类别里还有很多选择,而且尽管 Lubuntu 的资源占用与 Puppy Linux 一样小,但得益于它是 Ubuntu 家庭的一员,其易用性为它加了分。但是不要担心,Lubuntu 对于硬件的要求并不高:

  • CPU:奔腾 4 或者奔腾 M 或者 AMD K8 以上
  • 对于本地应用,512 MB 的内存就可以了,对于网络使用(Youtube、Google+、Google Drive、Facebook),建议 1 GB 以上。

Lubuntu 使用的是 LXDE 桌面(图 2),这意味着新接触 Linux 的用户在使用这个发行版时不会有任何问题。这份简短清单中包含的应用(例如:Abiword、Gnumeric 和 Firefox)都是非常轻量的,且对用户友好的。

Lubuntu

图 2:LXDE桌面。

Lubuntu 能让十年以上的电脑如获新生。

最好的桌面发行版

Elementary OS 连续两年都是我清单中最好的桌面发行版。对于许多人,Linux Mint (也是一个非常棒的分支)都是桌面发行版的领袖。但是,于我来说,它在易用性和稳定性上很难打败 Elementary OS。例如,我确信是 Ubuntu 17.10 的发布让我迁移回了 Canonical 的发行版。迁移到新的使用 GNOME 桌面的 Ubuntu 不久之后,我发现我缺少了 Elementary OS 外观、可用性和感觉(图 3)。在使用 Ubuntu 两周以后,我又换回了 Elementary OS。

Elementary OS

图 3:Pantheon 桌面是一件像艺术品一样的桌面。

使用 Elementary OS 的任何一个人都会觉得宾至如归。Pantheon 桌面是将操作顺滑和用户友好结合的最完美的桌面。每次更新,它都会变得更好。

尽管 Elementary OS 在 Distrowatch 页面访问量中排名第六,但我预计到 2018 年末,它将至少上升至第三名。Elementary 开发人员非常关注用户的需求。他们倾听并且改进,这个发行版目前的状态是如此之好,似乎他们一切都可以做的更好。 如果您需要一个具有出色可靠性和易用性的桌面,Elementary OS 就是你的发行版。

能够证明自己的最好的发行版

很长一段时间内,Gentoo 都稳坐“展现你技能”的发行版的首座。但是,我认为现在 Gentoo 是时候让出“证明自己”的宝座给 Linux From Scratch(LFS)。你可能认为这不公平,因为 LFS 实际上不是一个发行版,而是一个帮助用户创建自己的 Linux 发行版的项目。但是,有什么能比你自己创建一个自己的发行版更能证明自己所学的 Linux 知识的呢?在 LFS 项目中,你可以从头开始构建自定义的 Linux 系统,而且是从源代码开始。 所以,如果你真的想证明些什么,请下载 Linux From Scratch Book 并开始构建。

对于物联网最好的发行版

Ubuntu Core 已经是第二年赢得了该项的冠军。Ubuntu Core 是 Ubuntu 的一个小型的、事务型版本,专为嵌入式和物联网设备而构建。使 Ubuntu Core 如此完美支持物联网的原因在于它将重点放在 snap 包上 —— 这种通用包可以安装到一个平台上而不会干扰其基本系统。这些 snap 包包含它们运行所需的所有内容(包括依赖项),因此不必担心安装它会破坏操作系统(或任何其他已安装的软件)。 此外,snap 包非常容易升级,并运行在隔离的沙箱中,这使它们成为物联网的理想解决方案。

Ubuntu Core 内置的另一个安全领域是登录机制。Ubuntu Core 使用Ubuntu One ssh密钥,这样登录系统的唯一方法是通过上传的 ssh 密钥到 Ubuntu One帐户(图 4)。这为你的物联网设备提供了更高的安全性。

 Ubuntu Core

图 4:Ubuntu Core屏幕指示通过Ubuntu One用户启用远程访问。

最好的服务器发行版

这里有点意见不统一。主要原因是支持。如果你需要商业支持,乍一看,你最好的选择可能是 Red Hat Enterprise Linux。红帽年复一年地证明了自己不仅是全球最强大的企业服务器平台之一,而且是单一最赚钱的开源业务(年收入超过 20 亿美元)。

但是,Red Hat 并不是唯一的服务器发行版。 实际上,Red Hat 甚至并不能垄断企业服务器计算的各个方面。如果你关注亚马逊 Elastic Compute Cloud 上的云统计数据,Ubuntu 就会打败红帽企业 Linux。根据云市场的报告,EC2 统计数据显示 RHEL 的部署率低于 10 万,而 Ubuntu 的部署量超过 20 万。

最终的结果是,Ubuntu 几乎已经成为云计算的领导者。如果你将它与 Ubuntu 对容器的易用性和可管理性结合起来,就会发现 Ubuntu Server 是服务器类别的明显赢家。而且,如果你需要商业支持,Canonical 将为你提供 Ubuntu Advantage。

对使用 Ubuntu Server 的一个警告是它默认为纯文本界面(图 5)。如果需要,你可以安装 GUI,但使用 Ubuntu Server 命令行非常简单(每个 Linux 管理员都应该知道)。

Ubuntu server

图 5:Ubuntu 服务器登录,通知更新。

你怎么看

正如我之前所说,这些选择都非常主观,但如果你正在寻找一个好的开始,那就试试这些发行版。每一个都可以用于非常特定的目的,并且比大多数做得更好。虽然你可能不同意我的个别选择,但你可能会同意 Linux 在每个方面都提供了惊人的可能性。并且,请继续关注下周更多“最佳发行版”选秀。

通过 Linux 基金会和 edX 的免费“Linux 简介”课程了解有关Linux的更多信息。

 

2018 年最好的 Linux 发行版,首发于山西十一选五手机版。

]]>
//www.brhi.net/114473/feed/ 1
一文带你了解 Vim 的起源 - 山西十一选五手机版▁山西11选五前三组遗漏▁山西十一选五任七遗漏▁山西11选五遗漏top10▁山西体彩十一选5一定牛 //www.brhi.net/114461/ //www.brhi.net/114461/#respond Wed, 24 Oct 2018 09:07:16 +0000 //www.brhi.net/?p=114461 Vim 有着「编辑器之神」的称号,在程序员圈子有很多忠实的粉丝。但可能很多人并不了解 Vim 的来源,本文带你溯源。

一文带你了解 Vim 的起源,首发于山西十一选五手机版。

]]>
我最近偶然发现了一种名为 Intel HEX 的文件格式。据我所知,Intel HEX 文件(使用.hex 扩展名)通过将二进制图像编码成十六进制数字行,使二进制图像不那么晦涩难懂。显然,当人们需要对微控制器进行编程或者将数据烧录进 ROM 时会用到这种文件。无论如何,当我第一次在 Vim 中打开一个 HEX 文件时,我发现了一些震惊的东西。至少对我来说,这种文件格式是非常深奥难懂的,但 Vim 已经掌握了它。HEX 文件的每一行都是一条被划分为不同字段的记录—— Vim 已经预先将每个字段显示成不同的颜色。set ft 吗? 我充满敬畏地发问。filetype=hex,Vim 得意地回答。

Vim 无所不在且受众极其广泛,以至于其支持 HEX 文件也应该在预料之中。Mac OS 中预装了 Vim,同时,Linux 世界中也有很多 Vim 的支持者。即使那些讨厌 Vim 的人也对它很熟悉,因为太多的流行命令行工具默认使用 Vim,不熟悉 Vim 的用户往往身陷其中,这已经变成了一个?meme。包括 Facebook 在内的一些大型网站,当你按下?j?键时,会向下滚动,而当你按下?k?键时,会向上滚动——这意味着 Vim 通过数字文化传播达到了难以想象的高水准。

然而,Vim 也是谜一般的存在。例如,与人尽皆知的由 Facebook 开发和维护的 React 不同,Vim没有明显的发起人。尽管它如此常见和重要,但是似乎没有任何委员会或组织为 Vim 做出决策。你可以花几分钟去浏览 Vim 网站,但却无法得知是谁创建了 Vim 或者为什么创建。如果只启动 Vim 不打开任何文件,你会看到 Vim 的启动消息,表明 Vim 是由”Bram Moolenaar 等人“开发的。但这并不能说明什么,Bram Moolenaar 到底是谁,他的神秘同伙又是谁?

当我们求索上述问题的时候,也许更重要的是,为什么退出 Vim 需要输入:wq?当然,这是一个“写”操作,然后是一个“退出”操作,但这不是一个特别容易直观理解的约定。谁决定了复制文本应该被称为“ yanking ”?为什么:%s/foo/bar/gc是“查找和替换”的缩写?Vim 的特性如此武断,不可能是被编造出来的,那么它们又从何而来呢?

就像众多情况一样,答案是从那个古老的计算机熔炉——贝尔实验室开始。从某种意义上说,Vim 只是一款被称为“ wq 文本编辑器”软件的最新版本。自 Unix 时代诞生以来,这个软件一直在不断地被开发和改进。

Ken Thompson 创建了行编辑器

1966 年,贝尔实验室聘用了 Ken Thompson 。Thompson 刚刚在加州大学伯克利分校完成了电气工程和计算机科学的硕士学位。在伯克利他使用一个名为 QED 的文本编辑器,该编辑器在 1965 到 1966 年间被开发用于伯克利分时系统。1 Thompson 到达贝尔实验室后做的第一件事就是为麻省理工学院兼容分时系统重写 QED。他后来又为 Multics 项目写了另一个版本的QED。在重写过程中,他对程序进行了扩展,以便用户可以在文件中搜索某一行,并使用正则表达式进行替换。2

与伯克利的分时系统一样,由麻省理工学院、通用电气和贝尔实验室合作的 Multics 项目试图创建一个可行的商业分时操作系统。最终,AT&T 认为这个项目毫无进展并退出。在没有分时系统的情况下,Thompson 和贝尔实验室资深研究员 Dennis Ritchie,开始怀念分时系统所提供的“交互式计算的感觉”,并着手创建他们自己的版本,该版本最终发展成为 Unix。3 1969 年 8 月,在妻子和幼子外出去加州度假时,Thompson “给操作系统、shell、编辑器和汇编程序分别分配了一个星期”,将新系统的基本组件组合在一起。4

这个编辑器被称为 ed 。它是基于 QED 的,但并不完全是 QED 的复现。 Thompson 决定放弃某些 QED 的功能,弱化了对常规的表达式的支持,因此 ed 只能理解相对简单的正则表达式。QED 允许用户打开多个缓冲区同时编辑多个文件,但是 ed 一次只使用一个缓冲区。QED 可以执行包含命令的缓冲区,而 ed 则不能。这些简化可能是必要的。Dennis Ritchie 曾说过,去掉 QED 的高级正则表达式是“并不大的损失”。5

ed 现在是 POSIX 规范的一部分,所以如果你有一个符合 POSIX 的系统,你的电脑上就安装了 ed 。现在,许多 ed 命令都是 Vim 的一部分,因此,这就值得摆弄一番了。例如,你必须使用 w 命令来写入磁盘缓冲区,必须使用 q 命令来退出编辑器。这两个命令可以写在同一行命令中,也就是 wq。ed 与 Vim 一样,是一个模态编辑器;若要从命令模式进入输入模式,取决于你试图如何转换文本,需使用 insert 命令(i)、append 命令(a)或 change 命令(c)。ed 还引入了s/foo/bar/g语法来查找和替换或“替换”文本。

考虑到所有这些相似之处,你可能会认为大部分 Vim 用户可以流畅地使用 ed。但 ed 在另一个重要方面,和 Vim 一点也不相似。ed 是一个真正的行编辑。它被广泛应用于电传打字机时代。当 Ken Thompson 和 Dennis Ritchie 在 Unix 上调试程序时看起来是这样的:

Ken Thompson interacting with a PDP-11 via teletype.

ed 不允许你编辑开放缓冲区中那些被其他行围绕的行,也不允许移动光标,因为 ed 在每次修改的时候都必须重新打印整个文件。在1969年, ed 没有任何机制来“清除”屏幕上的内容,因为”屏幕“就是一张纸,所有已经输出的东西都像是已经用墨水打印出来了。在必要的时候,你可以使用列表命令(l)要求 ed 打印出一系列的行,但是大多数时候,你都是在你看不到的文本上操作。因此,使用 ed 就像是尝试用一个低电量的手电筒在黑暗房间中摸索。每次你只能看到那么一点儿,所以必须尽最大努力去记住每件东西的位置。

下面有一个 ed 会话的例子。我添加了注释(在字符 #之后)来解释了每一行,不过如果这些注释真的被输入,ed 并不会把它们当作注释并且会报错:

[sinclairtarget 09:49 ~]$ ed
i                           # Enter input mode
Hello world!

Isn't it a nice day?
.                           # Finish input
1,2l                        # List lines 1 to 2
Hello world!$
$
2d                          # Delete line 2
,l                          # List entire buffer
Hello world!$
Isn't it a nice day?$
s/nice/terrible/g           # Substitute globally
,l
Hello world!$
Isn't it a terrible day?$
w foo.txt                   # Write to foo.txt
38                          # (bytes written)
q                           # Quit
[sinclairtarget 10:50 ~]$ cat foo.txt
Hello world!
Isn't it a terrible day?

正如你所看到的,ed 并不是一个特别友好的程序。

Bill Joy 创建了文本编辑器

对 Thompson 和 Ritchie 来说, ed 已经足够好了。但是其他人则认为它很难用,而且它作为一个淋漓尽致地表现 Unix 对新手敌意的例子而臭名昭著。6在 1975 年,一个名叫 George Coulouris 的人在伦敦玛丽皇后学院的 Unix 系统上开发了一个改进版 ed 。Coulouris 利用他在玛丽女王学院的视频显示器开发他的编辑器。与 ed 不同的是,Coulouris 的程序允许用户编辑在屏幕中的一行代码,通过一次次击键的方式来操作行(想象一下在 Vim 中每次编辑一行)。 Thompson 拜访玛丽女王学院时,看到 Coulouris 已经写好的程序,驳斥道他不需要在编辑文件的时候看到它的状态。受此启发,Coulouris 将他的程序命名为 em,或者“为凡人而生的编辑器”。7

Portrait of George Coulouris (computer scientist).jpg

George Coulouris

1976年,Coulouris 把 em 引入了加州大学伯克利分校,在那里他用了一个夏天的时间在 CS 系访学。这是 Ken Thompson 离开伯克利去贝尔实验室工作十年之后的事了。在伯克利,Coulouris 遇到了 Bill Joy,一名伯克利软件发行公司(BSD)的研究生。Coulouris 斯向Joy 展示了 em, Joy 以 Coulouris 的源代码为基础,为扩展 ed 建立了一个名为 ex 的改进版 ed。1978年,1.1 版本的 ex 与第 1 个版本的 BSD Unix 捆绑在一起。ex 在很大程度上与 ed 兼容,但它增加了两种模式:一种“开放”模式,这种模式可以使 em 单行编辑成为可能,还有一种“可见”模式,这种模式会占据整个屏幕,并且可以像我们今天所习惯的那样,对整个文件进行实时编辑。

Bill joy.jpg

Bill Joy

1979 年的第 2 版 BSD 引入了一个名为 vi 的可执行文件,它只在可视模式下打开 ex 。8

ex/vi (后来称为 vi)建立了我们现在使用的 Vim 中大多数的约定,但这些约定当时并不是 ed 的一部分。Bill Joy 使用的视频终端是 Lear Siegler ADM-3A,它的键盘没有光标键。而是,h、j、k?和?l?上绘制光标键,所以 Bill Joy 在vi 中就使用这些键来进行光标移动。ADM-3A 键盘上 escape 键位置是今天我们所使用的键盘上的 tab 键,这也就解释了为什么这样一个难以够着的键会被用来实现像退出当前模式这么常见的操作。前缀命令的?:?字符同样也来自 i,它在常规模式下(即运行 ex 进入的模式)使用 : 作为提示。这解决了一个 ed 中被长期诟病的问题,也就是一旦启动之后,没有任何反馈信息向用户致以问候。在可见模式下,保存和退出需要使用现在仍在使用的经典 wq?!癥anking”和“puttng”、标记、以及用于设置选项的 set 命令都是原始 vi 的一部分。我们今天在 Vim 中使用的的基本文本编辑过程,都是 vi 中使用的特性。

A Lear Siegler ADM-3A keyboard.

vi 是除 ed?之外唯一与 BSD Unix 捆绑的文本编辑器。在那个时候,Emacs 可能会花费数百美元(这是在 GNU Emacs 之前),所以 vi 变得非常流行。但是 vied 的直接衍生版本,这意味着如果没有 AT&T 的源代码,源代码就不能被修改。这促使一些人创建了 vi 的开源版本。 STEVIE (专门为 VI 爱好者的 ST 编辑器)出现于1987年,Elvis 出现于 1990 年,nvi 出现于 1994 年。其中一些克隆版本添加了额外的功能,如语法高亮和窗口分离。尤其是 Elvis ,它的许多功能被整合到 Vim 中,因为许多 Elvis 用户推动了这些功能的加入。9)

Bram Moolenaar 创建了 Vim

“Vim”现在是“改进版 Vi”的缩写,而最初代表的是“模拟版 Vi”。和其他许多“vi克隆版本”一样,Vim 始于在一个无法使用 vi 的平台上复现 vi 的一个尝试。在荷兰 Venlo 一家影印公司工作的软件工程师 Bram Moolenaar 想要为他全新的 Amiga 2000 准备一款类似于 vi 的编辑器。Moolenaar 已经习惯了在大学时使用的 Unix 系统上的 vi ,当时他 已经对vi了如指掌。10 所以在 1988 年,Moolenaar 使用当时的 STEVIE vi克隆版本开始在 Vim 上工作。

Bram Moolenaar,2006 年加入 Google)

Moolenaar 接触到 STEVIE 缘于其曾经出现在一个叫 Fred Fish 的磁盘上。Fred Fish 是一名美国程序员,每个月都会寄出一张软盘,内含为 Amiga 平台提供的精选可用开源软件。任何人只要支付邮费就可以得到一张这样的磁盘。有若干版本的 STEVIE 曾在 Fred Fish 磁盘上发布。Moolenaar 使用的 STEVIE 版本在 Fred Fish 256 号磁盘上发布。11(令人失望的是,Fred Fish 磁盘似乎与 Freddi Fish 没有任何关系。)

Moolenaar 喜欢 STEVIE,但很快就注意到其缺失了很多 vi 命令。12 因此,在第一次发布 Vim 时,Moolenaar 优先考虑了 vi 的兼容性。当时已经有其他人编写了一系列的 vi 宏,当运行一个合适的 vi 兼容编辑器时,可以求解一个随机生成的迷宫。Moolenaar 能够让这些宏在 Vim 中运行。1991年,Vim 以 Vi模拟为名第一次发布于 Fred Fish 591 号磁盘。13 Moolenaar 添加了一些特性(包括多级撤销和解决编译器错误的“quickfix”模式),这意味着 Vim 已经完成了对 Vi 的超越。在 1993 年通过 FTP 发布 Vim 2.0 之前,Vim 都仍以 Vi模拟 的身份存在。

在众多互联网合作者的帮助下,Moolenaar 稳健地在 Vim 中加入了一些功能。Vim 2.0 引入了对wrap选项的支持,以及对长行文本进行水平滚动的支持。受到了vi克隆nvi的启发,Vim 3.0 增加了对分割窗口和缓冲区的支持。Vim 现在还将每个缓冲区保存到交换文件中以避免程序崩溃造成文件丢失。Vimscript 支持语法高亮显示,第一次出现是在 Vim 5.0 中。与此同时,Vim 的受欢迎程度也在不断增长。它被移植到 MS-DOS、 Windows、Mac,甚至被移植到 Unix 与原来的?vi竞争。

2006 年,Vim 被 Linux Journal 读者评为最受欢迎的编辑器。14 如今,根据 2018 年 Stack Overflow 的开发者调查,Vim 是最受欢迎的文本模式(即终端模拟器)编辑器,受用于 25.8% 的软件开发人员(和 40% 的 Sysadmin / DevOps 人员)。15 在 1980 年代末和整个 1990 年代,程序员一度发起了“编辑器战争”,将 Emacs 用户与 vi (即最终的 Vim )用户进行了对比。虽然 Emacs 肯定仍有一些追随者,但有些人认为编辑器战争已经以 Vim 获胜而结束。16 2018年 Stack Overflow 的开发者调查显示只有 4.1% 的受访者使用 Emacs,也验证了这个事实。

Vim 是如何变得如此成功的?显然,人们喜欢 Vim 所提供的特性。但我认为,Vim 背后的悠久历史表明了它的优势远不仅仅体现在其功能集上。Vim 的代码库可以追溯到 1988 年,当时 Moolenaar 开始研究它。另一方面,“ wq 文本编辑器”——关于 Unix-y 文本编辑器应该如何工作的更广泛的愿景——可以追溯到半个世纪以前?!?wq 文本编辑器”有一些不同的具体表达方式,但在某种程度上要感谢 Bill Joy 和 Bram Moolenaar 对向后兼容性非比寻常的关注,才使好的想法逐渐积累起来。从这个意义上说,“ wq 文本编辑器”是运行时间最长、最成功的开源项目之一,得益于计算机世界中一些最伟大的思想贡献。我不认为“创业公司无视所有先例来创造颠覆性的新软件”的开发方式都是不妥的,但 Vim 提醒我们,这种协作和增量的方式同样能产生奇迹。

 


@TwoBitHistory 每两周更新一次类似文章,如果你喜欢本文请在 Twitter 上关注或者订阅 RSS,以便及时知晓更新发布。伯乐在线已获授权同步翻译中文版,敬请关注

  1. Butler Lampson, “Systems,” Butler Lampson, accessed August 5, 2018, //bwlampson.site/Systems.htm.
  2. Dennis Ritchie, “An Incomplete History of the QED Editor,” accessed August 5, 2018, https://www.bell-labs.com/usr/dmr/www/qed.html.
  3. Peter Salus, “The Daemon, the GNU, and the Penguin,” Groklaw, April 14, 2005, accessed August 5, 2018, //www.groklaw.net/article.php?story=20050414215646742.
  4. ibid.
  5. Dennis Ritchie, “An Incomplete History of the QED Editor,” accessed August 5, 2018, https://www.bell-labs.com/usr/dmr/www/qed.html.
  6. Donald Norman, “The Truth about Unix: The User Interface Is Horrid,” Datamation, accessed August 5, 2018, //www.ceri.memphis.edu/people/smalley/ESCI7205_misc_files/The_truth_about_Unix_cleaned.pdf.
  7. George Coulouris, “George Coulouris: A Bit of History,” George Coulouris’ Homepage, September 1998, accessed August 5, 2018, //www.eecs.qmul.ac.uk/~gc/history/index.html.
  8. “Second Berkeley Software Distribution Manual,” Roguelife, accessed August 5, 2018, //roguelife.org/~fujita/COOKIES/HISTORY/2BSD/vi.u.html.
  9. Sven Guckes, “VIM Wishlist,” Vmunix, May 15, 1995, accessed August 5, 2018, https://web.archive.org/web/20080520075925///www.vmunix.com/vim/wish.html.
  10. Bram Moolenaar, “Vim 25” (lecture, Zurich, November 2, 2016), December 13, 2016, accessed August 5, 2018, https://www.youtube.com/watch?v=ayc_qpB-93o&t=4m58s
  11. ibid. (?t=6m15s)
  12. ibid. (?t=7m6s)
  13. “Fish Disks 1 – 1120,” Amiga Stuff, accessed August 5, 2018, //www.amiga-stuff.com/pd/fish.html.
  14. “2005 Linux Journal Reader’s Choice Awards,” Linux Journal, September 28, 2005, accessed August 5, 2018, https://www.linuxjournal.com/article/8520#N0x850cd80.0x87983bc.
  15. “Stack Overflow Developer Survey 2018,” Stack Overflow, accessed August 5, 2018, https://insights.stackoverflow.com/survey/2018/#development-environments-and-tools.
  16. Bruce Byfield, “The End of the Editor Wars,” Linux Magazine, May 11, 2015, accessed August 5, 2018, //www.linux-magazine.com/Online/Blogs/Off-the-Beat-Bruce-Byfield-s-Blog/The-End-of-the-Editor-Wars.

山西十一选五手机版,首发于山西十一选五手机版。

]]>
//www.brhi.net/114461/feed/ 0