Linkedin-SRE-中文教程-一-

本文涉及的产品
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
容器服务 Serverless 版 ACK Serverless,952元额度 多规格
全局流量管理 GTM,标准版 1个月
简介: Linkedin-SRE-中文教程-一-

Linkedin SRE 中文教程(一)
原文:School of SRE

协议:CC BY-NC-SA 4.0

SRE 学校
原文:https://linkedin.github.io/school-of-sre/

站点可靠性工程师(SREs)位于软件工程和系统工程的交叉点。虽然基础架构和软件组件如何组合以实现目标可能有无限的排列和组合,但专注于基础技能使 sre 能够处理复杂的系统和软件,无论这些系统是专有的、第三方的、开放的系统,还是运行在云/本地基础架构上的系统,等等。尤其重要的是深入了解系统和基础设施的这些领域是如何相互联系和相互作用的。软件和系统工程技能的结合是罕见的,通常是随着时间的推移,通过接触各种各样的基础设施、系统和软件而建立起来的。

SREs 引入工程实践来维护网站。每个分布式系统都是许多组件的集合。sre 验证业务需求,将它们转换为构成分布式系统的每个组件的 SLA,监控和测量 SLA 的遵守情况,重新构建或扩展以减轻或避免 SLA 违反,将这些学习作为反馈添加到新系统或项目中,从而减少运营负担。因此,从系统设计的第一天起,SREs 就起着至关重要的作用。

2019 年初,我们开始访问印度各地的校园,招募最优秀和最聪明的头脑,以确保 LinkedIn 以及构成其复杂技术堆栈的所有服务始终可供每个人使用。LinkedIn 的这一关键功能属于网站工程团队和网站可靠性工程师(SREs)的职责范围,他们是软件工程师,专门研究可靠性。

随着我们继续这一旅程,我们开始收到来自这些校园的许多问题,关于站点可靠性工程角色到底需要什么?而且,一个人怎样才能学到成为一名成功的现场可靠性工程师所需的技能和纪律呢?几个月过去了,一些校园学生以实习生或全职工程师的身份加入了 LinkedIn,成为网站工程团队的一员;我们也有一些加入我们组织的横向雇员,他们没有传统的 SRE 背景。就在那时,我们几个人聚在一起,开始思考如何让新毕业的工程师加入现场工程团队。

很少有资源可以指导一个人作为 SRE 初学者必须掌握的基本技能。由于缺乏这些资源,我们认为个人很难获得该行业的空缺职位。我们创建了 SRE 学院,作为任何想成为 SRE 人的人的起点。在本课程中,我们将重点培养强大的基础技能。本课程的结构提供了更多真实的例子,以及学习这些主题如何在 SRE 的日常工作职责中发挥重要作用。目前,我们在 SRE 学院下涵盖以下主题:

101 级

基础系列
Linux 基础知识

Linux 联网
Python 和 Web
数据
关系数据库(MySQL)
NoSQL 概念
大数据
系统设计
指标和监控
安全
102 级

Linux 中级
Linux 高级
容器和编排
系统调用和信号
联网
系统设计
系统故障排除和性能调优
持续集成和持续交付
我们相信持续学习将有助于获得更深层次的知识和能力,以扩展您的技能组合,每个模块都添加了参考资料,可作为进一步学习的指南。我们希望,通过学习这些模块,我们应该能够掌握现场可靠性工程师所需的基本技能。

在 LinkedIn,我们使用这一课程让我们的非传统雇员和新大学毕业生进入 SRE 的角色。我们与新员工进行了多轮成功的入职培训,该课程帮助他们在很短的时间内提高了工作效率。这促使我们开源内容,以帮助其他组织让新工程师进入角色,并为有抱负的个人进入角色提供指导。我们意识到,我们创建的初始内容只是一个起点,我们希望社区能够在完善和扩展内容的过程中提供帮助。查看投稿指南开始吧。

101 级
基础系列
Linux 基础知识
Linux 基础知识
原文:https://linkedin.github.io/school-of-sre/level101/linux_basics/intro/

介绍
先决条件
应该能够熟练使用任何操作系统,如 Windows、Linux 或 Mac
期望对操作系统有基本的了解
从本课程中可以期待什么
本课程分为三个部分。在第一部分中,我们介绍了 Linux 操作系统的基础知识。我们将讨论 Linux 体系结构、Linux 发行版和 Linux 操作系统的使用。我们还将讨论 GUI 和 CLI 之间的区别。

在第二部分中,我们将介绍 Linux 中使用的一些基本命令。我们将关注用于导航文件系统、查看和操作文件、I/O 重定向等的命令。

在第三部分中,我们将介绍 Linux 系统管理。这包括由 Linux 管理员执行的日常任务,如管理用户/组、管理文件权限、监控系统性能、日志文件等。

在第二和第三部分,我们将举例来理解这些概念。

本课程不包括哪些内容
在本课程中,我们不涉及高级 Linux 命令和 bash 脚本。我们也不会讨论 Linux 的内部机制。

课程内容
本课程涵盖了以下主题:

Linux 简介
什么是 Linux 操作系统
什么是流行的 Linux 发行版
Linux 操作系统的使用
Linux 架构
图形用户界面(GUI)与命令行界面(CLI)
命令行基础知识
实验室环境设置
什么是命令
文件系统组织
导航文件系统
操作文件
查看文件
回显命令
文本处理命令
输入/输出重定向
Linux 系统管理
实验室环境设置
用户/群组管理
成为超级用户
文件权限
SSH 命令
套餐管理
流程管理
内存管理
守护程序和系统 d
日志
结论
SRE 角色中的应用
有用的课程和教程
什么是 Linux 操作系统
我们大多数人都熟悉 75%以上的个人电脑使用的 Windows 操作系统。Windows 操作系统基于 Windows NT 内核。

内核是操作系统中最重要的部分——它执行重要的功能,如进程管理、内存管理、文件系统管理等。

Linux 操作系统基于 Linux 内核。基于 Linux 的操作系统将由 Linux 内核、GUI/CLI、系统库和系统实用程序组成。Linux 内核由 Linus Torvalds 独立开发和发布。Linux 内核是免费和开源的-github.com/torvalds/linux

Linux 是一个内核,而不是一个完整的操作系统。Linux 内核与 GNU 系统结合在一起,构成一个完整的操作系统。因此,基于 linux 的操作系统也被称为 GNU/Linux 系统。GNU 是一个广泛的自由软件集合,如编译器、调试器、C 库等。 Linux 和 GNU 系统

Linux 历史-en.wikipedia.org/wiki/History_of_Linux

什么是流行的 Linux 发行版
Linux 发行版是一个基于 Linux 内核的操作系统和一个软件包管理系统。软件包管理系统由帮助在操作系统上安装、升级、配置和删除软件的工具组成。

软件通常采用发行版,并以发行版特有的格式打包。这些包可以通过发行版特定的库获得。软件包由软件包管理器在操作系统中安装和管理。

流行的 Linux 发行版列表:

一种男式软呢帽

人的本质

一种自由操作系统

摘录

红帽企业版 Linux

苏塞

Arch Linux

包系统 分布 包管理器
Debian 风格(。deb) Debian,Ubuntu 恰当的
红帽风格(。rpm) Fedora、CentOS、Red Hat Enterprise Linux 妙的
Linux 架构

{spa.goldensuntech.com]
{spa.peaktrans.net]
{spa.fjyjsp.com]
{spa.kitanochapel.com]
{spa.tqnet.net]

Linux 内核在本质上是单一的。

系统调用用于与 Linux 内核空间进行交互。

内核代码只能在内核模式下执行。非内核代码在用户模式下执行。

设备驱动程序用于与硬件设备通信。

Linux 操作系统的使用
基于 Linux 内核的操作系统广泛应用于:

个人电脑

服务器

手机——Android 是基于 Linux 操作系统的

嵌入式设备-手表、电视、交通灯等

卫星

网络设备-路由器、交换机等。

图形用户界面(GUI)与命令行界面(CLI)
用户在用户界面的帮助下与计算机交互。用户界面可以是 GUI 或 CLI。

图形用户界面允许用户使用诸如图标和图像的图形与计算机进行交互。当用户点击图标打开计算机上的应用时,他或她实际上是在使用 GUI。使用 GUI 很容易执行任务。

命令行界面允许用户使用命令与计算机进行交互。用户在终端中键入命令,系统帮助执行这些命令。对 GUI 有经验的新用户可能会发现很难与 CLI 交互,因为他/她需要知道执行特定操作的命令。

外壳与终端
Shell 是一个程序,它从用户那里获取命令,并将它们交给操作系统进行处理。Shell 是 CLI(命令行界面)的一个例子。Bash 是 Linux 服务器上最流行的 shell 程序之一。其他流行的 shell 程序有 zsh、ksh 和 tcsh。

终端是一个打开窗口并让你与外壳交互的程序。一些流行的终端例子有 gnome-terminal、xterm、konsole 等。

Linux 用户确实使用外壳、终端、提示符、控制台等术语。可互换。简单来说,这些都是指从用户那里获取命令的方式。

命令行基础
原文:https://linkedin.github.io/school-of-sre/level101/linux_basics/command_line_basics/

实验室环境设置
您可以使用在线 bash 解释器来运行本课程中作为示例提供的所有命令。这也将帮助您获得各种 linux 命令的实践经验。

REPL 是一个流行的运行 linux 命令的在线 bash 解释器。我们将使用它来运行本课程中提到的所有命令。

什么是命令
命令是告诉操作系统执行特定工作的程序。在 linux 中,程序是作为文件存储的。因此,命令也是存储在磁盘某处的文件。

命令也可以接受额外的参数作为用户的输入。这些参数称为命令行参数。知道如何使用命令很重要,在 Linux 中有很多方法可以获得帮助,尤其是命令。几乎每个命令都有某种形式的文档,大多数命令都有一个命令行参数-h 或- help,可以显示合理数量的文档。但是 Linux 中最流行的文档系统叫做 man pages——手册页的缩写。

使用- help 显示 ls 命令的文档。

文件系统组织
linux 文件系统有一个分层(或树状)结构,它的最高层目录称为 root(用/)表示。根目录中的目录存储与系统相关的文件。这些目录又可以存储系统文件、应用文件或用户相关文件。

bin |最常用命令的可执行程序位于 bin 目录中

dev |该目录包含与系统上的设备相关的文件

etc |该目录包含所有系统配置文件

home |此目录包含与用户相关的文件和目录。

lib |该目录包含所有的库文件

mnt |该目录包含与系统上安装的设备相关的文件

proc |该目录包含与系统上正在运行的进程相关的文件

root |此目录包含与 root 用户相关的文件和目录。

sbin |该目录包含用于系统管理的程序。

tmp |该目录用于存储系统中的临时文件

usr |该目录用于存储系统上的应用

用于导航文件系统的命令
有三个常用于导航文件系统的基本命令:

限位开关(Limit Switch)

显示当前工作目录

激光唱片

我们现在将尝试理解每个命令的作用以及如何使用这些命令。您还应该在在线 bash shell 上练习给出的示例。

打印工作目录
在任何给定的时刻,我们都将站在某个目录中。要获得我们所在目录的名称,我们可以在 linux 中使用 pwd 命令。

我们现在将使用 cd 命令移动到不同的目录,然后打印工作目录。

光盘(更改目录)
cd 命令可用于更改工作目录。使用命令,您可以从一个目录移动到另一个目录。

在下面的例子中,我们最初在根目录中。然后,我们使用 cd 命令来更改目录。

ls(列出文件和目录)**
ls 命令用于列出目录的内容。它将列出给定目录中的所有文件和文件夹。

如果我们在 shell 中键入 ls,它将列出当前目录中的所有文件和目录。

我们还可以提供目录名作为 ls 命令的参数。然后,它将列出给定目录中的所有文件和目录。

用于操作文件的命令
有五个常用于操作文件的基本命令:

触控

mkdir

丙酸纤维素

平均变化

空间

我们现在将尝试理解每个命令的作用以及如何使用这些命令。您还应该在在线 bash shell 上练习给出的示例。
{spa.moodbeauty.net]
{spa.enomoto-motor.com]
{spa.momseducesboy.com]
{spa.tuorange.com]
{spa.inqau.com]
{spa.dgjhm.com]
{spa.3baodan.com]
{spa.xiaobaojun.com]
{spa.dcyaoye.com]

触摸(创建新文件)
触摸命令可用于创建一个空的新文件。该命令对于许多其他目的非常有用,但是我们将讨论创建新文件的最简单的用例。

使用触摸命令的一般语法

touch

mkdir(创建新目录)
mkdir 命令用于创建目录。您可以使用 ls 命令来验证新目录是否已创建。

使用 mkdir 命令的一般语法

mkdir

rm(删除文件和目录)
rm 命令可用于删除文件和目录。请务必注意,该命令会永久删除文件和目录。一旦对这些文件和目录成功执行了 rm 命令,就几乎不可能恢复它们。一定要小心运行这个命令。

使用 rm 命令的一般语法:

rm
让我们试着用一个例子来理解 rm 命令。我们将尝试分别删除使用 touch 和 mkdir 命令创建的文件和目录。

复制文件和目录
cp 命令用于将文件和目录从一个位置复制到另一个位置。请注意,cp 命令不会对原始文件或目录做任何更改。成功运行 cp 命令后,原始文件或目录及其副本将共存。

使用 cp 命令的一般语法:

cp
我们目前在“/home/runner”目录中。我们将使用 mkdir 命令创建一个名为“test_directory”的新目录。我们现在将尝试将“_test_runner.py”文件复制到我们刚才创建的目录中。

请注意,原始的“_test_runner.py”文件没有发生任何变化。它仍然在当前目录中。在“test_directory”中创建了一个新的副本。

我们还可以使用 cp 命令将整个目录从一个位置复制到另一个位置。我们试着用一个例子来理解这一点。

我们再次使用 mkdir 命令创建一个名为“another_directory”的新目录。然后,我们使用 cp 命令和一个附加参数'-r '来复制“test_directory”。

mv(移动文件和目录)

mv 命令既可以用于将文件或目录从一个位置移动到另一个位置,也可以用于重命名文件或目录。请注意,移动文件和复制文件是非常不同的。当您移动文件或目录时,原始副本会丢失。

使用 mv 命令的一般语法:

mv
在本例中,我们将使用 mv 命令将“_test_runner.py”文件移动到“test_directory”中。在这种情况下,这个文件已经存在于“test_directory”中。mv 命令将替换它。请注意,mv 命令成功运行后,当前目录中不存在原始文件。

我们还可以使用 mv 命令将目录从一个位置移动到另一个位置。在这种情况下,我们不需要像使用 cp 命令时那样使用'-r '标志。请注意,如果我们使用 mv 命令,原始目录将不存在。

mv 命令的一个重要用途是重命名文件和目录。让我们看看如何使用这个命令进行重命名。

我们首先将我们的位置更改为“test_directory”。然后,我们使用 mv 命令将“_test_runner.py”文件重命名为“test.py”。

查看文件的命令
有五个常用于查看文件的基本命令:

尾巴

更多

较少的

我们现在将尝试理解每个命令的作用以及如何使用这些命令。您还应该在在线 bash shell 上练习给出的示例。

我们将创建一个名为“numbers.txt”的新文件,并在该文件中插入从 1 到 100 的数字。每个数字将在一个单独的行。

现在不要担心上面的命令。这是一个用于生成数字的高级命令。然后,我们使用重定向操作符将这些数字推送到文件中。我们将在后面的章节中讨论 I/O 重定向。


cat 命令最简单的用法是在输出屏幕上打印文件的内容。这个命令非常有用,可以用于许多其他目的。稍后我们将学习其他用例。

你可以试着运行上面的命令,你会在屏幕上看到从 1 到 100 的数字。你需要向上滚动才能看到所有的数字。


默认情况下,head 命令显示文件的前 10 行。我们可以包含额外的参数,从顶部开始显示任意多的行。

在这个例子中,当我们使用 head 命令时,我们只能看到文件的前 10 行。

默认情况下,head 命令将只显示前 10 行。如果我们想要指定我们想要从开始看到的行数,使用'-n '参数来提供输入。

尾巴
默认情况下,tail 命令显示文件的最后 10 行。我们可以包含额外的参数,从文件末尾开始显示任意多的行。

默认情况下,tail 命令将只显示最后 10 行。如果我们想指定我们想从末尾看到的行数,使用'-n '参数来提供输入。

在本例中,当我们使用带有 explicit -n 选项的 tail 命令时,我们只能看到文件的最后 5 行。

更多
More command 显示文件或命令输出的内容,如果文件很大(例如:日志文件),则一次显示一个屏幕。它还允许在文件中向前导航和有限的向后导航。

More command 尽可能多地显示在当前屏幕上,并等待用户输入前进。向前导航可以通过按 Enter 键来完成,这将使输出前进一行,按 Space 键将输出前进一屏。

较少的
Less command 是 more 的改进版本。它显示文件或命令输出的内容,一次显示一页。它允许在文件中向后导航和向前导航,也有搜索选项。我们可以使用箭头键向前或向后移动一行。向前移动一页,按空格键;向后移动一页,按键盘上的 b 键。您可以立即转到文件的开头和结尾。

Linux 中的 Echo 命令
echo 命令是 shell 中使用的最简单的命令之一。这个命令相当于我们在其他编程语言中拥有的。

echo 命令在屏幕上打印给定的输入字符串。

文本处理命令
在上一节中,我们学习了如何查看文件的内容。在许多情况下,我们会对执行以下操作感兴趣:

仅打印包含特定单词的行

用文件中的另一个单词替换特定的单词

按特定顺序对行进行排序

有三个常用于处理文本的基本命令:

可做文件内的字符串查找

一项 Linux 指令

分类

我们现在将尝试理解每个命令的作用以及如何使用这些命令。您还应该在在线 bash shell 上练习给出的示例。

我们将创建一个名为“numbers.txt”的新文件,并在该文件中插入从 1 到 10 的数字。每个数字将在一个单独的行。

可做文件内的字符串查找
grep 命令最简单的形式可以用来搜索文本文件中的特定单词。它将显示包含特定输入的文件中的所有行。我们要搜索的单词作为 grep 命令的输入提供。

使用 grep 命令的一般语法:
{spa.tangshanjz.com]
{spa.handanseo.net]
{spa.kakuyasu-eigo.com]
{spa.dnxy.net]
{spa.yu-yu-papa.com]
{spa.ymzhi.com]
{spa.ip991.com]

grep
在这个例子中,我们试图在这个文件中搜索一个字符串“1”。grep 命令输出找到该字符串的行。

一项 Linux 指令
最简单的 sed 命令可以用来替换文件中的文本。

使用 sed 命令进行替换的一般语法:

sed 's///'
让我们尝试使用 sed 命令将文件中出现的“1”替换为“3”。

在上面的例子中,文件的内容不会改变。为此,我们必须使用一个额外的参数'-i ',以便将更改反映到文件中。

分类
sort 命令可用于对作为参数提供给它的输入进行排序。默认情况下,它将按升序排序。

在尝试对文件进行排序之前,让我们先看看文件的内容。

现在,我们将尝试使用 sort 命令对文件进行排序。sort 命令按字典顺序对内容进行排序。

在上面的例子中,文件的内容不会改变。

输入输出重定向
每个打开的文件被分配一个文件描述符。文件描述符是系统中打开文件的唯一标识符。总是有三个默认文件打开,stdin(键盘)、stdout(屏幕)和 stderr(输出到屏幕的错误消息)。这些文件可以被重定向。

Linux-UNIX . stack exchange . com/questions/225537/everything-is-a-file

到目前为止,我们已经在屏幕上显示了所有的输出,这是标准输出。我们可以使用一些特殊的操作符将命令的输出重定向到文件,甚至重定向到其他命令的输入。I/O 重定向是一个非常强大的功能。

在下面的例子中,我们使用了'>'操作符将 ls 命令的输出重定向到 output.txt 文件。

在下面的例子中,我们将 echo 命令的输出重定向到一个文件。

我们还可以将一个命令的输出重定向为另一个命令的输入。借助管道,这是可能的。

在下面的示例中,我们使用管道(|)操作符将 cat 命令的输出作为输入传递给 grep 命令。

在下面的例子中,我们使用管道(|)操作符将 sort 命令的输出作为输入传递给 uniq 命令。uniq 命令只打印输入中的唯一数字。

输入/输出重定向-tldp.org/LDP/abs/html/io-redirection.html

Linux 服务器管理
原文:https://linkedin.github.io/school-of-sre/level101/linux_basics/linux_server_administration/

在本课程中,将尝试涵盖 linux 服务器管理员执行的一些常见任务。我们将首先尝试理解一个特定的命令做什么,然后尝试使用例子来理解这些命令。请记住,自己练习 Linux 命令是非常重要的。

实验室环境设置
在你的系统上安装 docker-docs.docker.com/engine/install/

我们将在 Red Hat Enterprise Linux (RHEL) 8 系统上运行所有命令。

我们将在上面的 Docker 容器中运行本模块中使用的大多数命令。
多用户操作系统
如果一个操作系统允许多人/用户使用一台计算机,并且不影响彼此的文件和首选项,则该操作系统被认为是多用户的。基于 Linux 的操作系统本质上是多用户的,因为它允许多个用户同时访问系统。典型的计算机只有一个键盘和显示器,但是如果计算机连接到网络,多个用户可以通过 SSH 登录。我们将在后面介绍更多关于 SSH 的内容。

作为服务器管理员,我们最关心的是离我们很远的 Linux 服务器。我们可以借助 SSH 之类的远程登录方法连接到这些服务器。

由于 Linux 支持多用户,我们需要一种方法来保护用户之间的相互保护。一个用户不应该能够访问和修改其他用户的文件

用户/组管理
Linux 中的用户有一个关联的用户 ID,称为 UID。

用户还有一个主目录和一个与之相关联的登录 shell。

组是一个或多个用户的集合。组使得在一组用户之间共享权限变得更加容易。

每个组都有一个与之关联的名为 GID 的组 ID。

id 命令
id命令可用于查找与用户相关联的 uid 和 gid。它还列出了用户所属的组。

与 root 用户关联的 uid 和 gid 为 0。

在 Linux 中找出当前用户的一个好方法是使用 whoami 命令。

“root”用户或超级用户是最有特权的用户,拥有 对系统上所有资源的无限制访问权。它有 UID 0

与用户/组相关的重要文件
/etc/密码 存储用户名、uid、gid、主目录、登录外壳等
/etc/影子 存储与用户相关联的密码
/etc/group 存储系统中不同组的信息

{spa.ip991.com]
{spa.ki-med.com]
{spa.bjzyjsk.com]
{spa.yishunapp.com]
{spa.fantasybaseballstarters.com]
{spa.enjoy-sololife.com]
{spa.csnrg.com]

如果您想了解上述输出中讨论的每个字段,可以浏览以下链接:

tldp . org/LDP/LAME/LAME/Linux-admin-made-easy/shadow-file-formats . html

tldp.org/HOWTO/User-Authentication-HOWTO/x71.html

管理用户的重要命令
下面是一些常用于管理 Linux 上的用户/组的命令:

useradd -创建新用户

passwd -添加或修改用户密码

usermod -修改用户的属性

userdel -删除用户

useradd
useradd 命令在 Linux 中添加新用户。

我们将创建一个新用户“shivam”。我们还将通过在/etc/passwd 文件后面添加后缀来验证用户是否已经创建。对于新创建的用户,uid 和 gid 是 1000。分配给用户的主目录是/home/shivam,分配给用户的登录 shell 是/bin/bash。请注意,稍后可以修改用户主目录和登录 shell。

如果我们没有为主目录或登录 shell 之类的属性指定任何值,默认值将被分配给用户。我们也可以在创建新用户时覆盖这些默认值。

密码
passwd 命令用于为用户创建或修改密码。

在上面的例子中,我们在创建用户“shivam”或“amit”时没有为他们分配任何密码。

"!!"在阴影中的帐户条目意味着用户的帐户已经创建,但还没有给出密码。

现在让我们尝试为用户“shivam”创建一个密码。

请记住密码,因为我们将在后面使用有用的示例。

另外,现在让我们更改 root 用户的密码。当我们从普通用户切换到根用户时,它会要求您输入密码。此外,当您使用 root 用户登录时,将会询问密码。

usermod
usermod 命令用于修改用户的属性,如主目录或 shell。

我们试着将用户“amit”的登录 shell 修改为“/bin/bash”。

同样,您也可以修改用户的许多其他属性。请尝试“usermod -h”以获得您可以修改的属性列表。

你是谁
userdel 命令用于删除 Linux 上的用户。一旦我们删除用户,所有与该用户相关的信息都将被删除。

让我们试着删除用户“amit”。删除用户后,您将不会在“/etc/passwd”或“/etc/shadow”文件中找到该用户的条目。

管理组的重要命令
管理组的命令与管理用户的命令非常相似。这里不详细解释每个命令,因为它们非常相似。您可以尝试在您的系统上运行这些命令。

groupadd 创建一个新组
groupmod 修改组的属性
groupdel 删除一个组
gpasswd 修改组的密码

我们现在将尝试将用户“shivam”添加到我们上面创建的组中。

成为超级用户
在运行以下命令之前,请确保您已经使用上述 passwd 命令为用户“shivam”和用户“root”设置了密码。

su 命令可用于在 Linux 中切换用户。现在让我们尝试切换到用户“shivam”。

现在让我们尝试打开“/etc/shadow”文件。

操作系统不允许用户“shivam”读取“/etc/shadow”文件的内容。这是 Linux 中的一个重要文件,它存储了用户的密码。该文件只能由 root 用户或拥有超级用户权限的用户访问。

sudo 命令允许 用户以根用户的安全权限运行命令。请记住,root 用户拥有系统的所有权限。我们也可以使用 su 命令切换到 root 用户并打开上面的文件,但是这样做需要 root 用户的密码。另一种在大多数现代操作系统上首选的方法是使用 sudo 命令成为超级用户。使用这种方式,用户必须输入他/她的密码,并且他们需要成为 sudo 组的一部分。

如何向其他用户提供超级权限?

让我们首先使用 su 命令切换到 root 用户。请注意,使用下面的命令需要您输入 root 用户的密码。

如果您忘记了为 root 用户设置密码,请键入“exit ”,您将作为 root 用户返回。现在,使用 passwd 命令设置密码。

文件/etc/sudoers 保存了被允许调用 sudo 的用户的名字。在 redhat 操作系统中,默认情况下不存在该文件。我们需要安装 sudo。

{spa.dalaiyiyao.com]
{spa.chinazart.net]
{spa.wbnlw.com]
{spa.hnjqwgk.com]
{spa.vast-med.com]
{spa.zgjxgp.com]
{spa.dn-kp.com]
{spa.weiyekg.com]

我们将在后面的小节中详细讨论 yum 命令。

尝试打开系统上的“/etc/sudoers”文件。这个文件有很多信息。这个文件存储了用户在运行 sudo 命令时必须遵守的规则。例如,允许 root 从任何地方运行任何命令。

向用户提供 root 访问权限的一个简单方法是将他们添加到有权运行所有命令的组中。“wheel”是 redhat Linux 中拥有此类权限的组。

让我们将用户“shivam”添加到这个组,这样它也拥有 sudo 特权。

现在让我们切换回用户“shivam”并尝试访问“/etc/shadow”文件。

我们需要在运行该命令之前使用 sudo,因为它只能用 sudo 特权来访问。我们已经通过将用户“shivam”添加到组“wheel”中,授予了他 sudo 权限。

文件权限
在 Linux 操作系统上,每个文件和目录都被分配给文件所有者、一组相关用户的成员以及其他所有人的访问权限。这是为了确保不允许一个用户访问另一个用户的文件和资源。

要查看文件的权限,我们可以使用 ls 命令。我们来看看/etc/passwd 文件的权限。

让我们看一下输出中与文件权限相关的一些重要字段。

Chmod 命令
chmod 命令用于修改 Linux 中的文件和目录权限。

chmod 命令接受中的权限作为数字参数。我们可以把权限想象成一系列的位,1 代表真或允许,0 代表假或不允许。

许可 rwx 二进制的 小数
读取、写入和执行 rwx One hundred and eleven seven
直读式记录 rw- One hundred and ten six
阅读并执行 r-x One hundred and one five
只读 r - One hundred four
编写并执行 -wx 011 three
只写 -w- 010 Two
仅执行 [加在以-u 结尾的法语词源的名词之后构成复数] 001 one
没有人 - 000 Zero
我们现在将创建一个新文件,并检查该文件的权限。

群组拥有者没有权限写入这个档案。让我们使用 chmod 命令向组所有者或 root 用户授予写权限。

Chmod 命令也可以用来以类似的方式改变目录的权限。

Chown 命令
chown 命令用于在 Linux 中更改文件或目录的所有者。

命令语法:chown

如果我们没有 sudo 权限,我们需要使用 sudo 命令。让我们切换到用户“shivam”并尝试更改所有者。在运行下面的命令之前,我们还将文件的所有者更改为 root。

Chown 命令也可以用来以类似的方式改变目录的所有者。

Chgrp 命令
chgrp 命令可用于在 Linux 中更改文件或目录的组所有权。语法与 chown 命令非常相似。

Chgrp 命令也可以用来以类似的方式更改目录的所有者。

SSH 命令
ssh 命令用于登录远程系统、在系统之间传输文件以及在远程机器上执行命令。SSH 代表 secure shell,用于通过不安全的网络(如互联网)在两台主机之间提供加密的安全连接。

参考:www.ssh.com/ssh/command/

我们现在将讨论无密码认证,这种认证是安全的,并且最常用于 ssh 认证。

使用 SSH 的无密码认证
使用这种方法,我们可以在不输入密码的情况下 ssh 到主机。当我们希望一些脚本执行 ssh 相关的任务时,这种方法也很有用。

无密码身份验证需要使用公钥和私钥对。顾名思义,公钥可以与任何人共享,但私钥应该是私有的。让我们不要进入这个认证如何工作的细节。你可以在这里了解更多信息

使用远程主机设置无密码身份验证的步骤:

生成公钥-私钥对

如果我们已经在~/中存储了一个密钥对。ssh 目录中,我们将不再需要生成密钥。

安装 openssh 包,其中包含所有与 ssh 相关的命令。

使用 ssh-keygen 命令生成一个密钥对。用户可以选择所有提示的默认值。

成功运行 ssh-keygen 命令后,我们应该在~/中看到两个密钥。ssh 目录。Id_rsa 是私钥,id_rsa.pub 是公钥。请注意,私钥只能由您读取和修改。

将公钥传送到远程主机

有多种方法可以将公钥传输到远程服务器。我们将研究使用 ssh-copy-id 命令来完成这项工作的最常见的方法之一。

安装 openssh-clients 包以使用 ssh-copy-id 命令。

使用 ssh-copy-id 命令将您的公钥复制到远程主机。

现在,ssh 使用密码认证进入远程主机。

我们的公钥应该在~/中。ssh/authorized_keys now。

~/.ssh/authorized_key 包含一个公钥列表。与这些公钥相关联的用户可以通过 ssh 访问远程主机。

如何在远程主机上运行命令?
通用语法:ssh @

如何将文件从一台主机传输到另一台主机?
一般语法:scp

包管理
软件包管理是在系统上安装和管理软件的过程。我们可以从 Linux 包发行商那里安装我们需要的包。不同的分销商使用不同的包系统。

包系统 分布
{spa.souluotu.com]
{spa.ramienet.com]
{spa.rbyhairstory.com]
{spa.xingshuojx.com]
{spa.w1f.cn]
{spa.hot40yogalp.com]
{spa.cmifl.net]
{spa.zogps.com]
Debian 风格(。deb) Debian,Ubuntu
红帽风格(。rpm) Fedora、CentOS、Red Hat Enterprise Linux
Linux 中流行的打包系统

命令 描述
yum install 在您的系统上安装软件包
yum upudate 将软件包更新到最新的可用版本
yum remove 从系统中删除软件包
yum search 搜索特定的关键字
DNF 是 YUM 的继承者,现在在 Fedora 中用于安装和管理软件包。DNF 将来可能会在所有基于 RPM 的 Linux 发行版上取代 YUM。

当我们使用 yum search 命令进行搜索时,确实找到了关键字 httpd 的精确匹配。现在让我们安装 httpd 包。

安装 httpd 后,我们将使用 yum remove 命令删除 httpd 包。

进程管理
在这一节中,我们将学习一些有用的命令,它们可以用来监视 Linux 系统上的进程。

ps(流程状态)
ps 命令用于了解进程或进程列表的信息。

如果在运行 ps 命令时出现错误“ps 命令未找到”,请安装 procps 包。

没有任何参数的 ps 用处不大。让我们尝试使用下面的命令列出系统中的所有进程。

参考:UNIX . stack exchange . com/questions/106847/what-does-aux-mean-in-PS-aux

我们可以在 ps 命令中使用一个附加参数来列出带有特定进程 ID 的进程的信息。

我们可以结合使用 grep 和 ps 命令来仅列出特定进程。

顶端
top 命令用于实时显示系统上运行的 Linux 进程的信息。它还显示系统信息的摘要。

对于每个进程,top 列出了进程 ID、所有者、优先级、状态、cpu 利用率、内存利用率和更多信息。它还列出了整个系统的内存利用率和 cpu 利用率,以及系统正常运行时间和 cpu 平均负载。

内存管理
在本节中,我们将学习一些有用的命令,这些命令可用于查看系统内存的信息。

自由的
free 命令用于显示系统的内存使用情况。该命令显示 RAM 中可用的总空闲空间和已用空间,以及缓存/缓冲区占用的空间。

默认情况下,free 命令以千字节为单位显示内存使用情况。我们可以使用一个额外的参数来获取人类可读格式的数据。

vmstat
vmstat 命令可用于显示内存使用情况以及关于 io 和 cpu 使用情况的附加信息。

检查磁盘空间
在这一节中,我们将学习一些有用的命令,它们可以用来在 Linux 上查看磁盘空间。

磁盘空闲
df 命令用于显示每个已装载文件系统的可用空间。

磁盘使用情况(du)
du 命令用于显示系统中文件和目录的磁盘使用情况。

以下命令可用于显示根目录中前 5 个最大的目录。

守护进程
作为后台进程运行的计算机程序称为守护程序。传统上,守护进程的名称以 d - sshd、httpd 等结尾。我们不能与后台进程交互,因为它们在后台运行。

服务和守护进程大部分时间都可以互换使用。

系统
Systemd 是 Linux 操作系统的系统和服务管理器。Systemd 单元是 systemd 的构造块。这些单元由单元配置文件表示。

以下示例显示了/usr/lib/systemd/system 中的单元配置文件,这些文件由安装的 RPM 软件包分发。我们对以 service 结尾的配置文件更感兴趣,因为这些是服务单元。

管理系统服务
服务单位以结尾。服务文件扩展名。Systemctl 命令可用于启动/停止/重新启动由 systemd 管理的服务。

命令 描述
systemctl 启动名称. service 启动服务
系统停止名称.服务 停止服务
systemctl 重新启动名称。服务 重新启动服务
systemctl 状态名称.服务 检查服务的状态
systemctl 重新加载 name.service 重新加载服务的配置
日志
在这一节中,我们将讨论一些重要的文件和目录,它们对于在 Linux 中查看系统日志和应用日志非常有用。当您对系统进行故障诊断时,这些日志非常有用。

总结
原文:https://linkedin.github.io/school-of-sre/level101/linux_basics/conclusion/

我们已经介绍了 linux 操作系统的基础知识和 Linux 中使用的基本命令。我们还讲述了 Linux 服务器管理命令。

我们希望本课程将使您更容易在命令行上操作。

SRE 角色中的应用
作为 SRE,您需要在这些 Linux 服务器上执行一些常规任务。在对问题进行故障排除时,您也将使用命令行。
在文件系统中从一个位置移动到另一个位置需要ls、pwd和cd命令的帮助。
您可能需要在日志文件中搜索一些特定的信息。命令在这里会非常有用。如果您想将输出存储在一个文件中或者将其作为输入传递给另一个命令,I/O 重定向将变得非常方便。
tail命令对于查看日志文件中的最新数据非常有用。
不同的用户将根据他们的角色拥有不同的权限。出于安全原因,我们也不希望公司的每个人都访问我们的服务器。用户权限可以通过chown、chmod和chgrp命令进行限制。
ssh是 SRE 最常用的命令之一。只有当我们能够登录到服务器时,才能登录到服务器并进行故障排除以及执行基本的管理任务。
如果我们想在服务器上运行 apache 服务器或 nginx 怎么办?我们将首先使用软件包管理器安装它。包管理命令在这里变得很重要。
管理服务器上的服务是 SRE 的另一项重要职责。Systemd 相关命令有助于解决问题。如果服务停止,我们可以使用systemctl start命令启动它。如果不需要某项服务,我们也可以停止它。
监控是 SRE 的另一个核心职责。内存和 CPU 是应该监控的两个重要的系统级指标。像top和free这样的命令在这里非常有用。
如果一个服务抛出一个错误,我们如何找出错误的根本原因?我们当然需要检查日志来找出错误的整个堆栈跟踪。日志文件还会告诉我们错误发生的次数以及开始的时间。
有用的课程和教程
Edx 基本 linux 命令课程
Edx 红帽企业版 Linux 课程
{spa.baogaoma.com]
{spa.5thim.com]
{spa.nklwdf.com]
{spa.creca-tips.com]
{spa.hzjxrj.com]
{spa.caigongzi.com]
{spa.kedo5.com]
{spa.daolicai.com]
linuxcommand.org/lc3_learning_the_shell.php
Git
Git
原文:https://linkedin.github.io/school-of-sre/level101/git/git-basics/

先决条件
已经安装了 Gitgit-scm.com/downloads
参加过 git 高级教程或 LinkedIn 学习课程吗
www . LinkedIn . com/learning/git-essential-training-the-basics/
www . LinkedIn . com/learning/git-branch-merges-and-remotes/
Git 官方文档
从本课程中可以期待什么
作为一名计算机科学领域的工程师,拥有版本控制工具的知识几乎成为一项要求。虽然现在有很多版本控制工具,如 SVN、Mercurial 等,但 Git 可能是最常用的工具,本课程我们将使用 Git。虽然本课程不是从 git 101 开始的,并希望将 git 的基础知识作为先决条件,但它将重新介绍您所知道的 Git 概念,并详细介绍在您执行各种 Git 命令时发生的事情。这样下次运行 git 命令时,您就可以更自信地按 enter 键了!

本课程不包括哪些内容
Git 内部实现细节的高级用法和细节。

课程内容
去基数
使用分支
用 Github Git
挂钩
去吧,普西
尽管你可能已经意识到了,让我们再来看看为什么我们需要一个版本控制系统。随着项目的增长和多个开发人员开始工作,需要一种有效的协作方法。Git 有助于团队轻松协作,并且维护代码库发生变化的历史。

创建 Git Repo
任何文件夹都可以转换成 git 存储库。在执行下面的命令后,我们将在文件夹中看到一个.git文件夹,这使得我们的文件夹成为一个 git 存储库。git 做的所有神奇的事情,.git文件夹也是同样的使能器。

creating an empty folder and changing current dir to it

$ cd /tmp
$ mkdir school-of-sre
$ cd school-of-sre/

initialize a git repo

$ git init
Initialized empty Git repository in /private/tmp/school-of-sre/.git/
正如输出所说,在我们的文件夹中已经初始化了一个空的 git repo。让我们看看那里有什么。

$ ls .git/
HEAD config description hooks info objects refs
.git文件夹里有一堆文件夹和文件。正如我所说的,所有这些使 git 能够施展它的魔法。我们将查看其中的一些文件夹和文件。但是现在,我们只有一个空的 git 存储库。

跟踪文件
现在,您可能已经知道,让我们在 repo 中创建新文件(我们现在将该文件夹称为 repo 。)并查看 git 状态

$ echo "I am file 1" > file1.txt
$ git status
On branch master

No commits yet

Untracked files:
(use "git add ..." to include in what will be committed)

   file1.txt

nothing added to commit but untracked files present (use "git add" to track)
当前的 git 状态显示为No commits yet,还有一个未被跟踪的文件。因为我们刚刚创建了这个文件,所以 git 没有跟踪这个文件。我们明确需要让 git 跟踪文件和文件夹。(同时检查 gitignore )我们如何通过上面输出中建议的git add命令来完成。然后,我们继续创建一个提交。

$ git add file1.txt
$ git status
On branch master

No commits yet

Changes to be committed:
(use "git rm --cached ..." to unstage)

   new file:   file1.txt

$ git commit -m "adding file 1"
[master (root-commit) df2fb7a] adding file 1
1 file changed, 1 insertion(+)
create mode 100644 file1.txt
注意添加文件后,git 状态显示为Changes to be committed:。这意味着无论在那里列出什么,都将包含在下一次提交中。然后,我们继续创建一个 commit,并通过-m附加一条消息。

关于提交的更多信息
提交是回购的快照。每当进行提交时,都会拍摄并保存存储库(文件夹)当前状态的快照。每个提交都有一个唯一的 ID。(df2fb7a对于我们在上一步中所做的提交)。随着我们不断添加/更改越来越多的内容并不断提交,所有这些快照都由 git 存储。同样,所有这些神奇的事情都发生在.git文件夹中。这是所有快照或版本以有效方式存储的地方。

添加更多更改
让我们再创建一个文件并提交更改。它看起来和我们之前提交的一样。

$ echo "I am file 2" > file2.txt
$ git add file2.txt
$ git commit -m "adding file 2"
[master 7f3b00e] adding file 2
1 file changed, 1 insertion(+)
create mode 100644 file2.txt
ID 为7f3b00e的新提交已创建。您可以在任何时候发出git status来查看存储库的状态。

IMPORTANT: Note that commit IDs are long string (SHA) but we can refer to a commit by its initial few (8 or more) characters too. We will interchangeably using shorter and longer commit IDs.
现在我们有了两个提交,让我们将它们可视化:

$ git log --oneline --graph

  • 7f3b00e (HEAD -> master) adding file 2
  • df2fb7a adding file 1
    git log,顾名思义,打印所有 git 提交的日志。这里您可以看到两个额外的参数,--oneline打印日志的较短版本,即:只显示提交消息,而不显示提交者和提交时间。--graph以图形格式打印出来。

此时此刻,提交可能看起来每行只有一个,但是所有的提交都被 git 存储为一个树状数据结构。这意味着给定的提交可以有两个或更多的子提交。而不仅仅是一行提交。当我们到达分支部分时,我们将更深入地研究这一部分。现在,这是我们的提交历史:

df2fb7a ===> 7f3b00e
提交真的有联系吗?
正如我刚才所说的,我们刚刚做的两个提交是通过树状数据结构连接的,我们看到了它们是如何连接的。不过还是来实际验证一下吧。git 中的一切都是对象。新创建的文件存储为一个对象。对文件的更改存储为对象,甚至提交也是对象。要查看对象的内容,我们可以使用下面的命令和对象的 ID。我们将看看第二次提交的内容

$ git cat-file -p 7f3b00e
tree ebf3af44d253e5328340026e45a9fa9ae3ea1982
parent df2fb7a61f5d40c1191e0fdeb0fc5d6e7969685a
author Sanket Patel spatel1@linkedin.com 1603273316 -0700
committer Sanket Patel spatel1@linkedin.com 1603273316 -0700

adding file 2
注意上面输出中的parent属性。它指向我们第一次提交的提交 id。所以这证明他们是有联系的!此外,您可以在该对象中看到第二次提交的消息。正如我所说的,所有这些魔法都是通过.git文件夹实现的,我们正在查看的对象也在那个文件夹中。

{spa.xyhmys.com]
{spa.zblpc.com]
{spa.qut7.com]
{spa.shukuhaku-ninsyou-kagoshima.com]
{spa.xxsjfhzs.com]
{spa.cjqgc.com]
{spa.muxianpai.com]
$ ls .git/objects/7f/3b00eaa957815884198e2fdfec29361108d6a9
.git/objects/7f/3b00eaa957815884198e2fdfec29361108d6a9
它存储在.git/objects/文件夹中。所有文件和对它们的更改都存储在这个文件夹中。

Git 的版本控制部分
我们已经可以在 git 日志中看到两个提交(版本)。版本控制工具给你的一个功能是在历史中来回浏览。例如:您的一些用户正在运行旧版本的代码,他们报告了一个问题。为了调试该问题,您需要访问旧代码。您当前回购中的是最新代码。在本例中,您正在进行第二次提交(7f3b00e),有人报告了提交时代码快照的问题(df2fb7a)。这是您在任何较早的提交中访问代码的方式

Current contents, two files present

$ ls
file1.txt file2.txt

checking out to (an older) commit

$ git checkout df2fb7a
Note: checking out 'df2fb7a'.

You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by performing another checkout.

If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -b with the checkout command again. Example:

git checkout -b

HEAD is now at df2fb7a adding file 1

checking contents, can verify it has old contents

$ ls
file1.txt
这就是我们访问旧版本/快照的方式。我们所需要的只是一个对该快照的引用。在执行git checkout ...时,git 为您做的是使用.git文件夹,查看该版本/引用中的事物(文件和文件夹)的状态,并用这些内容替换当前目录的内容。当时存在的内容将不再存在于本地目录(repo)中,但我们可以而且仍然会访问它们,因为它们是通过 git commit 和.git文件夹存储/跟踪的。

参考
我在前面提到我们需要一个引用到这个版本。默认情况下,git repo 由提交树组成。并且每个提交都有一个唯一的 id。但是惟一的 ID 并不是我们唯一可以引用提交的东西。引用提交有多种方式。例如:HEAD是对当前提交的引用。无论你的回购是在哪个提交被签出,HEAD都会指向那个提交。 HEAD~1是对以前提交的引用。因此,在检查上一节中的先前版本时,我们可能已经完成了git checkout HEAD~1。

同样,master 也是(对分支的)引用。因为 git 使用树状结构来存储提交,所以当然会有分支。而默认的分支叫做master。主(或任何分支引用)将指向分支中的最新提交。即使我们在我们的回购中已经签出到前一个提交,master仍然指向最近的提交。我们可以通过在master查阅来获得最新版本

$ git checkout master
Previous HEAD position was df2fb7a adding file 1
Switched to branch 'master'

now we will see latest code, with two files

$ ls
file1.txt file2.txt
注意,在上面的命令中,我们也可以使用提交的 ID 来代替master。

参考文献和魔法
让我们看看事情的状态。两个提交,master和HEAD引用指向最近的提交

$ git log --oneline --graph

  • 7f3b00e (HEAD -> master) adding file 2
  • df2fb7a adding file 1
    魔法?让我们检查这些文件:

$ cat .git/refs/heads/master
7f3b00eaa957815884198e2fdfec29361108d6a9
维奥拉。master 指向的位置存储在一个文件中。每当 git 需要知道 master 引用指向哪里,或者 git 需要更新 master 指向哪里,只需要更新上面的文件。因此,当您创建一个新的提交时,会在当前提交的基础上创建一个新的提交,并使用新提交的 ID 更新主文件。

类似地,供HEAD参考:

$ cat .git/HEAD
ref: refs/heads/master
我们可以看到HEAD指向一个名为refs/heads/master的引用。所以HEAD会指向曾经master指向的地方。

小冒险
我们讨论了 git 如何在我们执行命令时更新文件。但是让我们试着自己动手做,看看会发生什么。

$ git log --oneline --graph

  • 7f3b00e (HEAD -> master) adding file 2
  • df2fb7a adding file 1
    现在,让我们将 master 更改为指向上一次/第一次提交。

$ echo df2fb7a61f5d40c1191e0fdeb0fc5d6e7969685a > .git/refs/heads/master
$ git log --oneline --graph

  • df2fb7a (HEAD -> master) adding file 1

RESETTING TO ORIGINAL

$ echo 7f3b00eaa957815884198e2fdfec29361108d6a9 > .git/refs/heads/master
$ git log --oneline --graph

  • 7f3b00e (HEAD -> master) adding file 2
  • df2fb7a adding file 1
    我们刚刚编辑了master引用文件,现在我们只能在 git 日志中看到第一次提交。撤消对文件的更改会将状态恢复到原始状态。没有那么多魔法,是吗?

使用分支
原文:https://linkedin.github.io/school-of-sre/level101/git/branches/

回到本地回购协议,它有两个提交。到目前为止,我们只有一条历史线索。提交链接在一行中。但是有时您可能需要在同一个 repo 中并行处理两个不同的特性。现在,这里的一个选项可能是用相同的代码创建一个新的文件夹/repo,并将其用于另一个功能开发。但是有更好的方法。使用分支。由于 git 遵循树状结构进行提交,我们可以使用分支来处理不同的特性集。通过提交,可以创建两个或更多分支,也可以合并分支。

使用分支,可以存在多行历史,我们可以签出其中的任何一行并对其进行操作。正如我们前面所讨论的,检出仅仅意味着用检出版本的快照替换目录(repo)的内容。

让我们创建一个分支,看看它看起来像什么:

$ git branch b1
$ git log --oneline --graph

  • 7f3b00e (HEAD -> master, b1) adding file 2
  • df2fb7a adding file 1
    我们创建一个名为b1的分支。Git 日志告诉我们,b1 也指向最后一次提交(7f3b00e ),但是HEAD仍然指向 master。如果你还记得的话,HEAD 会指向提交/引用。所以如果我们结账去b1,头应该指向那个。我们来确认一下:

$ git checkout b1
Switched to branch 'b1'
$ git log --oneline --graph

  • 7f3b00e (HEAD -> b1, master) adding file 2
  • df2fb7a adding file 1
    b1仍然指向同一个提交,但 HEAD 现在指向b1。因为我们在提交7f3b00e时创建了一个分支,所以将有两行历史记录开始这个提交。根据你在哪个分支上被检查,历史的线将会前进。

此时,我们在分支b1上被签出,因此进行新的提交将使分支引用b1前进到该提交,并且当前的b1提交将成为其父提交。就这么办吧。

Creating a file and making a commit

$ echo "I am a file in b1 branch" > b1.txt
$ git add b1.txt
$ git commit -m "adding b1 file"
[b1 872a38f] adding b1 file
1 file changed, 1 insertion(+)
create mode 100644 b1.txt

The new line of history

$ git log --oneline --graph

  • 872a38f (HEAD -> b1) adding b1 file
  • 7f3b00e (master) adding file 2
  • df2fb7a adding file 1
    $
    请注意,master 仍然指向它所指向的旧提交。我们现在可以签出到主分支并在那里提交。这将导致从提交 7f3b00e 开始的另一行历史。

checkout to master branch

$ git checkout master
Switched to branch 'master'

Creating a new commit on master branch

$ echo "new file in master branch" > master.txt
$ git add master.txt
$ git commit -m "adding master.txt file"
[master 60dc441] adding master.txt file
1 file changed, 1 insertion(+)
create mode 100644 master.txt

The history line

$ git log --oneline --graph

  • 60dc441 (HEAD -> master) adding master.txt file
  • 7f3b00e adding file 2
  • df2fb7a adding file 1
    注意分支 b1 在这里是不可见的,因为我们在主节点上。让我们试着将这两者形象化,以了解全貌:

$ git log --oneline --graph --all

  • 60dc441 (HEAD -> master) adding master.txt file
    | * 872a38f (b1) adding b1 file
    |/
  • 7f3b00e adding file 2
  • df2fb7a adding file 1
    上面的树形结构应该把事情说清楚了。注意在提交 7f3b00e 时有一个清晰的分支/分叉。这就是我们创建分支的方式。现在它们都是两条独立的历史线,特性开发可以独立完成。

再次重申,在内部,git 只是一个提交树。分支名称(人类可读)是指向树中那些提交的指针。我们使用各种 git 命令来处理树结构和引用。Git 相应地修改我们的回购内容。

合并
现在假设您在分支b1上工作的特性已经完成,您需要将它合并到主分支上,所有最终版本的代码都放在那里。所以首先你将签出到 branch master,然后你从上游拉最新的代码(例如:GitHub)。然后你需要将你的代码从b1合并到 master 中。有两种方法可以做到这一点。

以下是当前历史:

$ git log --oneline --graph --all

  • 60dc441 (HEAD -> master) adding master.txt file
    | * 872a38f (b1) adding b1 file
    |/
  • 7f3b00e adding file 2
  • df2fb7a adding file 1
    方案一:直接合并分行。将分支 b1 合并到主分支将导致新的合并提交。这将合并两个不同历史行的更改,并创建一个新的结果提交。

$ git merge b1
Merge made by the 'recursive' strategy.
b1.txt | 1 +
1 file changed, 1 insertion(+)
create mode 100644 b1.txt
$ git log --oneline --graph --all

  • 8fc28f9 (HEAD -> master) Merge branch 'b1'
    |\
    | * 872a38f (b1) adding b1 file
  • | 60dc441 adding master.txt file
    |/
  • 7f3b00e adding file 2
  • df2fb7a adding file 1
    您可以看到创建了一个新的合并提交(8fc28f9)。系统将提示您提交消息。如果回购中有许多分支,这个结果将以许多合并提交结束。与单一的发展历史相比,这看起来很丑陋。所以让我们来看看另一种方法

首先让我们重置我们的最后一次合并,回到之前的状态。

$ git reset --hard 60dc441
HEAD is now at 60dc441 adding master.txt file
$ git log --oneline --graph --all

  • 60dc441 (HEAD -> master) adding master.txt file
    | * 872a38f (b1) adding b1 file
    |/
  • 7f3b00e adding file 2
  • df2fb7a adding file 1
    方案二:重定基数。现在,不要合并两个具有相似基础的分支(提交:7f3b00e),让我们将分支 b1 重新基础到当前的主节点上。这意味着取分支b1(从提交 7f3b00e 到提交 872a38f)和 rebase(把它们放在上面)master (60dc441)。

{spa.mopenten.com]
{spa.zzzgt.com]
{spa.0tom.net]
{spa.kentjia.com]
{spa.sxjapp.com]
{spa.zgszm.com]
{spa.goodmatchtw.com]
{spa.rtlike.com]

Switch to b1

$ git checkout b1
Switched to branch 'b1'

Rebase (b1 which is current branch) on master

$ git rebase master
First, rewinding head to replay your work on top of it...
Applying: adding b1 file

The result

$ git log --oneline --graph --all

  • 5372c8f (HEAD -> b1) adding b1 file
  • 60dc441 (master) adding master.txt file
  • 7f3b00e adding file 2
  • df2fb7a adding file 1
    您可以看到有 1 个提交的b1。该提交的父级是7f3b00e。但是既然我们把它重新放在主人(60dc441)身上。它现在成为了父节点。作为一个副作用,你也看到它已经成为历史的一条线。现在,如果我们要将b1合并到master,这仅仅意味着将master改为指向5372c8f,也就是b1。让我们来试试:

checkout to master since we want to merge code into master

$ git checkout master
Switched to branch 'master'

the current history, where b1 is based on master

$ git log --oneline --graph --all

  • 5372c8f (b1) adding b1 file
  • 60dc441 (HEAD -> master) adding master.txt file
  • 7f3b00e adding file 2
  • df2fb7a adding file 1

Performing the merge, notice the "fast-forward" message

$ git merge b1
Updating 60dc441..5372c8f
Fast-forward
b1.txt | 1 +
1 file changed, 1 insertion(+)
create mode 100644 b1.txt

The Result

$ git log --oneline --graph --all

  • 5372c8f (HEAD -> master, b1) adding b1 file
  • 60dc441 adding master.txt file
  • 7f3b00e adding file 2
  • df2fb7a adding file 1
    现在你可以看到b1和master都指向同一个提交。您的代码已经合并到主分支,可以推送了。我们也有干净的历史!😄

使用 GitHub 的 Git
原文:https://linkedin.github.io/school-of-sre/level101/git/github-hooks/

到目前为止,我们所做的所有操作都是在本地 repo 中进行的,而 git 也在协作环境中帮助我们。GitHub 是互联网上的一个地方,在这里你可以集中托管你的 git repos 并与其他开发者合作。

大部分工作流程将与我们讨论的一样,只是增加了一些东西:

Pull:从 github(中央)回购中获取最新的变更
推送:将您的更改推送到 github repo,以便所有人都可以使用
GitHub 已经就此写了很好的指南和教程,你可以在这里参考它们:

GitHub Hello World
Git 手册
钩住
Git 还有另一个很好的特性,叫做 hooks。钩子基本上是当某个事件发生时被调用的脚本。挂钩的位置如下:

$ ls .git/hooks/
applypatch-msg.sample fsmonitor-watchman.sample pre-applypatch.sample pre-push.sample pre-receive.sample update.sample
commit-msg.sample post-update.sample pre-commit.sample pre-rebase.sample prepare-commit-msg.sample
名称是不言自明的。当你想在特定事件发生时做特定的事情时,这些钩子是有用的。如果你想在推送代码之前运行测试,你应该设置pre-push钩子。让我们试着创建一个预提交钩子。

$ echo "echo this is from pre commit hook" > .git/hooks/pre-commit
$ chmod +x .git/hooks/pre-commit
我们基本上是在 hooks 文件夹中创建一个名为pre-commit的文件,并使其可执行。现在,如果我们提交,我们应该看到消息被打印出来。

$ echo "sample file" > sample.txt
$ git add sample.txt
$ git commit -m "adding sample file"
this is from pre commit hook # <===== THE MESSAGE FROM HOOK EXECUTION
[master 9894e05] adding sample file
1 file changed, 1 insertion(+)
create mode 100644 sample.txt
总结
原文:https://linkedin.github.io/school-of-sre/level101/git/conclusion/

接下来会发生什么?
有很多 git 命令和特性我们在这里没有探讨。但是随着基础的建立,一定要探索这样的概念

做出最佳选择
壁球
改进
隐藏物
重置
Linux 网络
Linux 网络基础
原文:https://linkedin.github.io/school-of-sre/level101/linux_networking/intro/

先决条件
具备 TCP/IP 堆栈中常用术语的高级知识,如 DNS、TCP、UDP 和 HTTP
Linux 命令行基础知识
从本课程中可以期待什么
在整个课程中,我们将介绍 SRE 如何优化系统以提高其 web 堆栈性能,并在网络堆栈的任何一层出现问题时进行故障排除。本课程试图深入了解传统 TCP/IP 协议栈的每一层,并期望 SRE 能够从鸟瞰的角度了解互联网的功能。

本课程不包括哪些内容
这门课花时间在基础知识上。我们并没有涵盖像 HTTP/2.0 、 QUIC 、 TCP 拥塞控制协议、 Anycast 、 BGP 、 CDN 、隧道和多播这样的概念。我们期望本课程将提供理解这些概念的相关基础知识

球场鸟瞰图
该课程涵盖的问题是“当你在浏览器中打开 linkedin.com 时会发生什么?”本课程遵循 TCP/IP 协议栈的流程。更具体地说,本课程涵盖了应用层协议 DNS 和 HTTP、传输层协议 UDP 和 TCP、网络层协议 IP 和数据链路层协议的主题

课程内容
DNS
UDP
HTTP
TCP
IP 路由
域名服务器(DNS)
原文:https://linkedin.github.io/school-of-sre/level101/linux_networking/dns/

域名是网站的简单易读的名称。互联网只理解 IP 地址,但由于记忆不连贯的数字并不实用,所以改用域名。这些域名被 DNS 基础设施翻译成 IP 地址。当有人试图在浏览器中打开www.linkedin.com时,浏览器试图将www.linkedin.com转换成 IP 地址。这个过程称为 DNS 解析。描述这一过程的简单伪代码如下

ip, err = getIPAddress(domainName)
if err:
print(“unknown Host Exception while trying to resolve:%s”.format(domainName))
现在让我们试着理解 getIPAddress 函数内部发生了什么。浏览器将拥有自己的 DNS 缓存,在其中检查是否有域名到已经可用的 IP 地址的映射,在这种情况下,浏览器使用该 IP 地址。如果不存在这样的映射,浏览器会调用 gethostbyname syscall 来请求操作系统查找给定域名的 IP 地址

def getIPAddress(domainName):
resp, fail = lookupCache(domainName)
If not fail:
return resp
else:
resp, err = gethostbyname(domainName)
if err:
return null, err
else:
return resp
现在让我们理解当调用 gethostbyname 函数时操作系统内核做什么。Linux 操作系统查看文件 /etc/nsswitch.conf

hosts: files dns
这一行意味着操作系统必须首先在文件(/etc/hosts)中查找,然后如果在/etc/hosts 中没有匹配项,就使用 DNS 协议进行解析。

文件/etc/hosts 的格式为

IP 地址 FQDN [FQDN]。*

127.0.0.1 localhost.localdomain localhost
::1 localhost.localdomain localhost
如果该文件中存在匹配的域,则操作系统会返回该 IP 地址。让我们给这个文件添加一行

127.0.0.1 test.linkedin.com
{spa.kw3888.com]
{spa.rxfunk.com]
{spa.ybble.com]
{spa.acn33.com]
{spa.jlcj.net]
{spa.bjtmm.com]
然后做平 test.linkedin.com

ping test.linkedin.com -n
PING test.linkedin.com (127.0.0.1) 56(84) bytes of data.
64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.047 ms
64 bytes from 127.0.0.1: icmp_seq=2 ttl=64 time=0.036 ms
64 bytes from 127.0.0.1: icmp_seq=3 ttl=64 time=0.037 ms
如前所述,如果/etc/hosts 中不存在匹配,操作系统会尝试使用 DNS 协议进行 DNS 解析。linux 系统向/etc/resolv.conf 中的第一个 IP 发出 DNS 请求。如果没有响应,请求将被发送到 resolv.conf 中的后续服务器。resolv.conf 中的这些服务器称为 DNS 解析器。DNS 解析器由 DHCP 填充或由管理员静态配置。 Dig 是一个用户空间 DNS 系统,它创建并向 DNS 解析器发送请求,并将收到的响应打印到控制台。

run this command in one shell to capture all DNS requests

sudo tcpdump -s 0 -A -i any port 53

make a dig request from another shell

dig linkedin.com
13:19:54.432507 IP 172.19.209.122.56497 > 172.23.195.101.53: 527+ [1au] A? linkedin.com. (41)
....E..E....@.n....z...e...5.1.:... .........linkedin.com.......)........
13:19:54.485131 IP 172.23.195.101.53 > 172.19.209.122.56497: 527 1/0/1 A 108.174.10.10 (57)
....E..U..@.|. ....e...z.5...A...............linkedin.com..............3..l.

..)........
数据包捕获显示向 linkedin.com 的 172.23.195.101:53(这是/etc/resolv.conf 中的解析器)发出请求,并从 IP 地址为 linkedin.com 108.174.10.10 的 172.23.195.101 收到响应

现在让我们试着理解 DNS 解析器是如何找到 linkedin.com 的 IP 地址的。DNS 解析器首先查看其缓存。由于网络中的许多设备都可以查询域名 linkedin.com,因此域名解析结果可能已经存在于缓存中。如果存在缓存未命中,它将启动 DNS 解析过程。DNS 服务器将“linkedin.com”断开为。,“com。”和“linkedin.com .”并从“.”开始 DNS 解析。的“.”被称为根域,DNS 解析软件知道这些 IP。DNS 解析器查询根域名服务器,以找到能够对“com”的详细信息做出响应的正确域名服务器。“com”的权威名称服务器的地址被退回。现在,DNS 解析服务联系“com”的权威名称服务器获取“linkedin.com”的权威名称服务器。一旦知道了“linkedin.com”的权威名称服务器,解析器就联系 linkedin 的名称服务器以提供“linkedin.com”的 IP 地址。这整个过程可以通过运行

dig +trace linkedin.com
linkedin.com. 3600 IN A 108.174.10.10
这个 DNS 响应有 5 个字段,其中第一个字段是请求,最后一个字段是响应。第二个字段是生存时间,表示 DNS 响应的有效时间,以秒为单位。在这种情况下,linkedin.com 的这种映射在 1 小时内有效。这就是解析器和应用(浏览器)维护其缓存的方式。任何超过 1 小时的 linkedin.com 请求都将被视为缓存未命中,因为映射的 TTL 已经过期,整个过程必须重新进行。第 4 个字段表示 DNS 响应/请求的类型。一些不同的 DNS 查询类型是 A、AAAA、NS、TXT、PTR、MX 和 CNAME。- A 记录返回域名的 IPV4 地址- AAAA 记录返回域名的 IPV6 地址- NS 记录返回域名的权威名称服务器- CNAME 记录是域名的别名。一些域指向其他域名,解析后一个域名会给出一个 IP,该 IP 也用作前一个域名的 IP。示例 www.linkedin.com 的 IP 地址与 2-01-2c3e-005a.cdx.cedexis.net 相同。-为简洁起见,我们不讨论其他 DNS 记录类型,这些记录的 RFC 可在此处获得。

dig A linkedin.com +short
108.174.10.10

dig AAAA linkedin.com +short
2620:109:c002::6cae:a0a

dig NS linkedin.com +short
dns3.p09.nsone.net.
dns4.p09.nsone.net.
dns2.p09.nsone.net.
ns4.p43.dynect.net.
ns1.p43.dynect.net.
ns2.p43.dynect.net.
ns3.p43.dynect.net.
dns1.p09.nsone.net.

dig www.linkedin.com CNAME +short
2-01-2c3e-005a.cdx.cedexis.net.
有了 DNS 的这些基础知识,让我们看看 SREs 使用 DNS 的用例。

SRE 角色中的应用
本节涵盖了 SRE 可以从 DNS 中获得的一些常见解决方案

每个公司都必须为内部网站点和内部服务(如数据库和其他内部应用,如 wiki)建立内部 DNS 基础设施。因此,基础设施团队必须为这些域名维护 DNS 基础设施。这种 DNS 基础设施必须进行优化和扩展,以便它不会成为单点故障。内部 DNS 基础设施的故障会导致微服务的 API 调用失败和其他级联效应。
DNS 也可以用于发现服务。例如,主机名 serviceb.internal.example.com 可以列出在 example.com 公司内部运行服务 b 的实例。云提供商提供选项来启用 DNS 发现(示例)
云提供商和 CDN 提供商使用 DNS 来扩展他们的服务。在 Azure/AWS 中,负载平衡器被赋予一个 CNAME,而不是 IPAddress。它们通过更改别名域名的 IP 地址来更新负载平衡器的 IP 地址。这也是为什么此类别名域名的记录只有 1 分钟那么短的原因之一。
DNS 还可以用来使客户获得离他们位置更近的 IP 地址,这样,如果该公司在地理上是分散的,他们的 HTTP 呼叫可以得到更快的响应。
{spa.fshuifeng.net]
{spa.liuyitang.net]
{spa.loldailiang.com]
{spa.kreamood.com]
{spa.riokalog.com]
{spa.gudesgin.com]
{spa.xlgw999.com]
{spa.kayotom.com]
{spa.xxhaoding.com]
SRE 还必须明白,由于 DNS 基础设施中没有验证,这些响应可能是欺骗性的。这受到其他协议的保护,如 HTTPS(稍后讨论)。DNSSEC 保护免受伪造或操纵的 DNS 响应。
过时的 DNS 缓存可能是一个问题。一些应用可能仍在使用过期的 DNS 记录进行 api 调用。这是 SRE 在进行维护时必须警惕的事情。
DNS 负载平衡和服务发现还必须了解 TTL,并且只有在等待 TTL post 对 DNS 记录进行更改后,才能从池中删除服务器。如果不这样做,由于服务器在 TTL 之前被移除,一定部分的流量将会失败。
用户数据报协议(UDP)
原文:https://linkedin.github.io/school-of-sre/level101/linux_networking/udp/

UDP 是传输层协议。DNS 是运行在 UDP 之上的应用层协议(大多数时候)。在进入 UDP 之前,让我们试着理解什么是应用和传输层。DNS 协议由 DNS 客户端(如 dig)和 DNS 服务器(如 named)使用。传输层确保 DNS 请求到达 DNS 服务器进程,同样,响应到达 DNS 客户端进程。多个进程可以在一个系统上运行,它们可以监听任何端口。DNS 服务器通常监听端口号 53。当客户端发出 DNS 请求时,在填充必要的应用负载后,它通过 sendto 系统调用将负载传递给内核。内核随机选取一个端口号( > 1024 )作为源端口号,将 53 作为目的端口号,并将数据包发送到更低层。当服务器端的内核收到数据包时,它检查端口号并将数据包排队到 DNS 服务器进程的应用缓冲区,该进程发出 recvfrom 系统调用并读取数据包。内核的这一过程称为多路复用(将来自多个应用的数据包组合到相同的较低层)和解复用(将来自单个较低层的数据包分离到多个应用)。多路复用和解复用由传输层完成。

UDP 是最简单的传输层协议之一,它只进行复用和解复用。另一个常见的传输层协议 TCP 做许多其他事情,如可靠的通信、流量控制和拥塞控制。UDP 被设计成轻量级的,以很少的开销处理通信。所以除了多路复用和解复用之外,它不做任何事情。如果运行在 UDP 之上的应用需要 TCP 的任何特性,他们必须在他们的应用中实现它

这个来自 python wiki 的示例涵盖了一个示例 UDP 客户端和服务器,其中“Hello World”是一个应用有效负载,它被发送到侦听端口号 5005 的服务器。服务器接收数据包并从客户端打印“Hello World”字符串

SRE 角色中的应用
如果底层网络速度较慢,UDP 层无法将数据包排入网络层,则来自应用的 sendto syscall 将挂起,直到内核发现其缓冲区被释放。这可能会影响系统的吞吐量。使用 sysctl 变量 net.core.wmem_max 和 net.core.wmem_default 增加写内存缓冲值,为来自慢速网络的应用提供一些缓冲
类似地,如果接收方进程消耗缓冲区的速度很慢,内核必须丢弃由于缓冲区已满而无法排队的数据包。由于 UDP 不保证可靠性,这些丢失的数据包可能会导致数据丢失,除非被应用层跟踪。增加 sysctl 变量 rmem_default 和 rmem_max 可以为来自快速发送者的缓慢应用提供一些缓冲。
超文本传输协议(HTTP)
原文:https://linkedin.github.io/school-of-sre/level101/linux_networking/http/

到目前为止,我们只知道 linkedin.com 的 IP 地址。linkedin.com 的 HTML 页面由浏览器渲染的 HTTP 协议提供服务。浏览器向上面确定的服务器 IP 发送 HTTP 请求。Request 有一个动词 GET、PUT、POST,后跟一个路径和查询参数以及键值对行,该键值对提供了有关客户端和客户端功能的信息,如它可以接受的内容和一个主体(通常在 POST 或 PUT 中)

Eg run the following in your container and have a look at the headers

curl linkedin.com -v

  • Connected to linkedin.com (108.174.10.10) port 80 (#0)

    GET / HTTP/1.1
    Host: linkedin.com
    User-Agent: curl/7.64.1
    Accept: /

    < HTTP/1.1 301 Moved Permanently
    < Date: Mon, 09 Nov 2020 10:39:43 GMT
    < X-Li-Pop: prod-esv5
    < X-LI-Proto: http/1.1
    < Location: https://www.linkedin.com/
    < Content-Length: 0
    <

  • Connection #0 to host linkedin.com left intact
  • Closing connection 0
    这里,第一行 GET 是动词,/是路径,1.1 是 HTTP 协议版本。然后是键值对,它们为服务器提供客户机功能和一些细节。服务器用 HTTP 版本、状态码和状态消息进行响应。状态代码 2xx 表示成功,3xx 表示重定向,4xx 表示客户端错误,5xx 表示服务器端错误。

我们现在就来看看 HTTP/1.0 和 HTTP/1.1 之间的区别。

On the terminal type

telnet www.linkedin.com 80

Copy and paste the following with an empty new line at last in the telnet STDIN

GET / HTTP/1.1
HOST:linkedin.com
USER-AGENT: curl
这将获得服务器响应,并等待下一个输入,因为到 www.linkedin.com 的底层连接可以被进一步的查询重用。通过 TCP,我们可以了解它的好处。但是在 HTTP/1.0 中,这个连接将在响应之后立即关闭,这意味着必须为每个查询打开新的连接。在一个开放的连接中,HTTP/1.1 只能有一个进行中的请求,但是该连接可以一个接一个地被多个请求重用。HTTP/2.0 优于 HTTP/1.1 的一个好处是,我们可以在同一个连接上有多个正在进行的请求。我们将我们的范围限制在通用 HTTP 上,而不是跳到每个协议版本的复杂性上,但是它们应该很容易理解。

HTTP 被称为无状态协议。这一节我们将试图理解无状态意味着什么。假设我们登录到 linkedin.com,客户端对 linkedin.com 的每个请求都没有用户的上下文,提示用户登录每个页面/资源是没有意义的。HTTP 的这个问题由 COOKIE 解决。当用户登录时,会为用户创建一个会话。该会话标识符通过 SET-COOKIE 头发送给浏览器。浏览器存储 cookie 直到服务器设置的到期时间,并从现在开始为 linkedin.com 发送每个请求的 COOKIE。更多关于 cookies 的细节可以在这里找到。cookie 是像密码一样的重要信息,由于 HTTP 是纯文本协议,任何中间人都可以捕获密码或 cookie,并可能侵犯用户的隐私。类似地,正如在 DNS 中所讨论的,假冒的 linkedin.com IP 可以对用户造成网络钓鱼攻击,用户可以提供 linkedin 的密码来登录恶意站点。为了解决这两个问题,HTTPs 应运而生,而且 HTTPs 必须是强制性的。

HTTPS 必须提供服务器识别和客户端与服务器之间的数据加密。服务器管理员必须生成私有公钥对和证书请求。此证书请求必须由证书颁发机构签名,该机构将证书请求转换为证书。服务器管理员必须更新 web 服务器的证书和私钥。该证书具有关于服务器的细节(如它所服务的域名、到期日)、服务器的公钥。私钥是服务器的秘密,丢失私钥会失去服务器提供的信任。当客户端连接时,客户端发送一个 HELLO。服务器将其证书发送给客户端。客户端通过查看证书是否在其到期时间内、证书是否由可信机构签名以及证书中的主机名是否与服务器相同来检查证书的有效性。这种验证确保服务器是正确的服务器,并且没有网络钓鱼。一旦通过验证,客户端就通过用服务器的公钥加密协商来与服务器协商对称密钥和密码。除了拥有私钥的服务器之外,没有人能够理解这些数据。一旦协商完成,对称密钥和算法被用于进一步加密,该加密只能由客户机和服务器从中解密,因为它们只知道对称密钥和算法。从非对称加密算法切换到对称算法是为了不使客户端设备的资源紧张,因为对称加密通常比非对称加密的资源密集度低。

Try the following on your terminal to see the cert details like Subject Name(domain name), Issuer details, Expiry date

curl https://www.linkedin.com -v

  • Connected to www.linkedin.com (13.107.42.14) port 443 (#0)
  • ALPN, offering h2
  • ALPN, offering http/1.1
  • successfully set certificate verify locations:
  • CAfile: /etc/ssl/cert.pem
    CApath: none
  • TLSv1.2 (OUT), TLS handshake, Client hello (1):
    } [230 bytes data]
  • TLSv1.2 (IN), TLS handshake, Server hello (2):
    { [90 bytes data]
  • TLSv1.2 (IN), TLS handshake, Certificate (11):
    { [3171 bytes data]
  • TLSv1.2 (IN), TLS handshake, Server key exchange (12):
    { [365 bytes data]
  • TLSv1.2 (IN), TLS handshake, Server finished (14):
    { [4 bytes data]
  • TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
    } [102 bytes data]
  • TLSv1.2 (OUT), TLS change cipher, Change cipher spec (1):
    } [1 bytes data]
  • TLSv1.2 (OUT), TLS handshake, Finished (20):
    } [16 bytes data]
  • TLSv1.2 (IN), TLS change cipher, Change cipher spec (1):
    { [1 bytes data]
  • TLSv1.2 (IN), TLS handshake, Finished (20):
    { [16 bytes data]
  • SSL connection using TLSv1.2 / ECDHE-RSA-AES256-GCM-SHA384
  • ALPN, server accepted to use h2
  • Server certificate:
  • subject: C=US; ST=California; L=Sunnyvale; O=LinkedIn Corporation; CN=www.linkedin.com
  • start date: Oct 2 00:00:00 2020 GMT
  • expire date: Apr 2 12:00:00 2021 GMT
  • subjectAltName: host "www.linkedin.com" matched cert's "www.linkedin.com"
  • issuer: C=US; O=DigiCert Inc; CN=DigiCert SHA2 Secure Server CA
  • SSL certificate verify ok.
  • Using HTTP2, server supports multi-use
  • Connection state changed (HTTP/2 confirmed)
  • Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0
  • Using Stream ID: 1 (easy handle 0x7fb055808200)
  • Connection state changed (MAX_CONCURRENT_STREAMS == 100)!
    0 82117 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0
  • Connection #0 to host www.linkedin.com left intact
    HTTP/2 200
    {spa.sn860.com]
    {spa.6866shop.com]
    {spa.ysfc1688.com]
    {spa.gxgms.com]
    {spa.editorxtw.com]
    {spa.higemegane31.com]
    {spa.weigangan.com]
    {spa.raleyshf.com]
    cache-control: no-cache, no-store
    pragma: no-cache
    content-length: 82117
    content-type: text/html; charset=utf-8
    expires: Thu, 01 Jan 1970 00:00:00 GMT
    set-cookie: JSESSIONID=ajax:2747059799136291014; SameSite=None; Path=/; Domain=.www.linkedin.com; Secure
    set-cookie: lang=v=2&lang=en-us; SameSite=None; Path=/; Domain=linkedin.com; Secure
    set-cookie: bcookie="v=2&70bd59e3-5a51-406c-8e0d-dd70befa8890"; domain=.linkedin.com; Path=/; Secure; Expires=Wed, 09-Nov-2022 22:27:42 GMT; SameSite=None
    set-cookie: bscookie="v=1&202011091050107ae9b7ac-fe97-40fc-830d-d7a9ccf80659AQGib5iXwarbY8CCBP94Q39THkgUlx6J"; domain=.www.linkedin.com; Path=/; Secure; Expires=Wed, 09-Nov-2022 22:27:42 GMT; HttpOnly; SameSite=None
    set-cookie: lissc=1; domain=.linkedin.com; Path=/; Secure; Expires=Tue, 09-Nov-2021 10:50:10 GMT; SameSite=None
    set-cookie: lidc="b=VGST04:s=V:r=V:g=2201:u=1:i=1604919010:t=1605005410:v=1:sig=AQHe-KzU8i_5Iy6MwnFEsgRct3c9Lh5R"; Expires=Tue, 10 Nov 2020 10:50:10 GMT; domain=.linkedin.com; Path=/; SameSite=None; Secure
    x-fs-txn-id: 2b8d5409ba70
    x-fs-uuid: 61bbf94956d14516302567fc882b0000
    expect-ct: max-age=86400, report-uri="https://www.linkedin.com/platform-telemetry/ct"
    x-xss-protection: 1; mode=block
    content-security-policy-report-only: default-src 'none'; connect-src 'self' www.linkedin.com www.google-analytics.com https://dpm.demdex.net/id lnkd.demdex.net blob: https://linkedin.sc.omtrdc.net/b/ss/ static.licdn.com static-exp1.licdn.com static-exp2.licdn.com static-exp3.licdn.com; script-src 'sha256-THuVhwbXPeTR0HszASqMOnIyxqEgvGyBwSPBKBF/iMc=' 'sha256-PyCXNcEkzRWqbiNr087fizmiBBrq9O6GGD8eV3P09Ik=' 'sha256-2SQ55Erm3CPCb+k03EpNxU9bdV3XL9TnVTriDs7INZ4=' 'sha256-S/KSPe186K/1B0JEjbIXcCdpB97krdzX05S+dHnQjUs=' platform.linkedin.com platform-akam.linkedin.com platform-ecst.linkedin.com platform-azur.linkedin.com static.licdn.com static-exp1.licdn.com static-exp2.licdn.com static-exp3.licdn.com; img-src data: blob: ; font-src data: ; style-src 'self' 'unsafe-inline' static.licdn.com static-exp1.licdn.com static-exp2.licdn.com static-exp3.licdn.com; media-src dms.licdn.com; child-src blob: ; frame-src 'self' lnkd.demdex.net linkedin.cdn.qualaroo.com; manifest-src 'self'; report-uri https://www.linkedin.com/platform-telemetry/csp?f=g
    content-security-policy: default-src
    ; connect-src 'self' https://media-src.linkedin.com/media/ www.linkedin.com s.c.lnkd.licdn.com m.c.lnkd.licdn.com s.c.exp1.licdn.com s.c.exp2.licdn.com m.c.exp1.licdn.com m.c.exp2.licdn.com wss://.linkedin.com dms.licdn.com https://dpm.demdex.net/id lnkd.demdex.net blob: https://accounts.google.com/gsi/status https://linkedin.sc.omtrdc.net/b/ss/ www.google-analytics.com static.licdn.com static-exp1.licdn.com static-exp2.licdn.com static-exp3.licdn.com media.licdn.com media-exp1.licdn.com media-exp2.licdn.com media-exp3.licdn.com; img-src data: blob: ; font-src data: ; style-src 'unsafe-inline' 'self' static-src.linkedin.com .licdn.com; script-src 'report-sample' 'unsafe-inline' 'unsafe-eval' 'self' spdy.linkedin.com static-src.linkedin.com .ads.linkedin.com .licdn.com static.chartbeat.com www.google-analytics.com ssl.google-analytics.com bcvipva02.rightnowtech.com www.bizographics.com sjs.bizographics.com js.bizographics.com d.la4-c1-was.salesforceliveagent.com slideshare.www.linkedin.com https://snap.licdn.com/li.lms-analytics/ platform.linkedin.com platform-akam.linkedin.com platform-ecst.linkedin.com platform-azur.linkedin.com; object-src 'none'; media-src blob: ; child-src blob: lnkd-communities: voyager: ; frame-ancestors 'self'; report-uri https://www.linkedin.com/platform-telemetry/csp?f=l
    x-frame-options: sameorigin
    x-content-type-options: nosniff
    strict-transport-security: max-age=2592000
    x-li-fabric: prod-lva1
    x-li-pop: afd-prod-lva1
    x-li-proto: http/2
    x-li-uuid: Ybv5SVbRRRYwJWf8iCsAAA==
    x-msedge-ref: Ref A: CFB9AC1D2B0645DDB161CEE4A4909AEF Ref B: BOM02EDGE0712 Ref C: 2020-11-09T10:50:10Z
    date: Mon, 09 Nov 2020 10:50:10 GMT

  • Closing connection 0
    这里,我的系统在这个文件/etc/ssl/cert.pem 中有一个它信任的证书颁发机构的列表。它还通过查看过期日期来确保证书没有过期。它还使用/etc/ssl/cert.pem 中颁发者 Digicert 的公钥来验证证书上的签名。完成后,它将使用 www.linkedin.com 的公钥与对称密钥协商密码 TLS ECD he RSA WITH AES 256 GCM _ sha 384。包括第一个 HTTP 请求在内的后续数据传输使用相同的密码和对称密钥。

传输控制协议(TCP)
原文:https://linkedin.github.io/school-of-sre/level101/linux_networking/tcp/

TCP 是像 UDP 一样的传输层协议,但是它保证可靠性、流量控制和拥塞控制。TCP 通过使用序列号来保证可靠的传输。TCP 连接是通过三次握手建立的。在我们的例子中,客户机发送一个 SYN 包和它计划使用的起始序列号,服务器确认这个 SYN 包并发送一个 SYN 和它的序列号。一旦客户端确认了 syn 数据包,连接就建立了。一旦相关方收到对该序列的确认,则从此传输的每个数据都被认为是可靠地传递了

3-way handshake

To understand handshake run packet capture on one bash session

tcpdump -S -i any port 80

Run curl on one bash session

curl www.linkedin.com
tcpdump-3way

在这里,客户端发送一个由[S] flag 表示的 syn 标志,序列号为 1522264672。服务器用 ack 确认收到 SYN。]标志和用于其序列号的 Syn 标志。服务器使用序列号 1063230400,并向客户机确认它期望的序列号 1522264673(客户机序列+1)。客户端向服务器发送一个零长度确认数据包(服务器序列+1 ),连接建立。这被称为三次握手。此后,客户端发送一个 76 字节长的数据包,并将其序列号递增 76。服务器发送一个 170 字节的响应并关闭连接。这就是我们所说的 HTTP/1.1 和 HTTP/1.0 之间的区别。在 HTTP/1.1 中,可以重用相同的连接,这减少了每个 HTTP 请求的 3 次握手的开销。如果客户端和服务器之间的数据包丢失,服务器不会向客户端发送 ack,客户端将重试发送数据包,直到收到 ACK。这保证了可靠性。流量控制由每个段中的 win size 字段建立。win 大小表示内核中可用的 TCP 缓冲区长度,可用于缓冲接收到的数据段。大小为 0 意味着接收方需要从套接字缓冲区捕捉大量的延迟,发送方必须暂停发送数据包,以便接收方能够应付。这种流量控制避免了慢速接收者和快速发送者的问题

TCP 还进行拥塞控制,确定在没有 ack 的情况下可以传输多少数据段。Linux 为我们提供了配置拥塞控制算法的能力,我们不在这里讨论。

关闭连接时,客户机/服务器调用 close syscall。让我们假设客户这样做。客户端的内核将发送一个 FIN 包给服务器。在服务器应用调用 close syscall 之前,服务器内核无法关闭连接。一旦服务器应用调用 close,服务器也发送 FIN 数据包,客户端进入 2 * MSS(120 秒)的时间等待状态,以便该套接字在该时间段内不能重复使用,以防止由于分散的陈旧数据包导致任何 TCP 状态损坏。

Connection tearing

用我们的 TCP 和 HTTP 知识武装起来,让我们看看 sre 在他们的角色中是如何使用它的

SRE 角色中的应用
使用负载平衡器扩展 HTTP 性能需要对 TCP 和 HTTP 有一致的了解。有种不同的负载平衡,如 L4、L7 负载平衡、直接服务器返回等。根据性能和合规性需求,HTTPs 卸载可以在负载平衡器上完成,也可以直接在服务器上完成。
像我们对 UDP 那样调整 rmem 和 wmem 的 sysctl 变量可以提高发送方和接收方的吞吐量。
Sysctl 变量 tcp_max_syn_backlog 和 socket 变量 somax_conn 确定在 app 调用 accept syscall 之前内核可以完成 3 次握手的连接数。这在单线程应用中非常有用。一旦积压满了,新的连接就保持在 SYN_RCVD 状态(当您运行 netstat 时),直到应用调用接受 syscall
如果有太多的短期连接,应用可能会用完文件描述符。深入研究 tcp_reuse 和 tcp_recycle 有助于减少处于时间等待状态的时间(它有自己的风险)。让应用重用连接池而不是创建临时连接也会有所帮助
通过查看指标了解性能瓶颈,并分类是应用还是网络方面的问题。示例:太多套接字处于 Close_wait 状态是应用的问题,而重新传输可能是网络或操作系统堆栈的问题,而不是应用本身的问题。理解基本原理可以帮助我们缩小瓶颈所在
IP 路由和数据链路层
原文:https://linkedin.github.io/school-of-sre/level101/linux_networking/ipr/

我们将探究离开客户端的数据包如何到达服务器,反之亦然。当数据包到达 IP 层时,传输层填充源端口、目的端口。IP/网络层填充目的地 IP(从 DNS 发现),然后在路由表中查找到目的地 IP 的路由。

Linux route -n command gives the default routing table

route -n
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
0.0.0.0 172.17.0.1 0.0.0.0 UG 0 0 0 eth0
172.17.0.0 0.0.0.0 255.255.0.0 U 0 0 0 eth0
这里,目的地 IP 与 Genmask 进行逐位 AND 运算,如果答案是表中的目的地部分,则选择该网关和接口进行路由。这里 linkedin.com 的 is 108.174.10.0 与 255.255.255.0 进行 AND 运算,我们得到的答案是 108.174.10.0,它与路由表中的任何目的地都不匹配。然后 Linux 用 0.0.0.0 对目的 IP 进行 AND 运算,我们得到 0.0.0.0。此答案与默认行匹配

路由表按照 genmask 中设置的 1 的多个八位位组的顺序进行处理,如果没有匹配项,genmask 0.0.0.0 是默认路由。在此操作结束时,Linux 发现数据包必须通过 eth0 发送到下一跳 172.17.0.1。数据包的源 IP 将被设置为接口 eth0 的 IP。现在,要将数据包发送到 172.17.0.1,linux 必须计算出 172.17.0.1 的 MAC 地址。MAC 地址是通过查看存储 IP 地址和 MAC 地址之间转换的内部 arp 缓存来计算的。如果存在缓存未命中,Linux 会在内部网络中广播 ARP 请求,询问谁拥有 172.17.0.1。IP 的所有者发送一个 ARP 响应,该响应由内核缓存,内核通过将源 mac 地址设置为 eth0 的 mac 地址和我们刚才获得的目的 mac 地址 172.17.0.1,将数据包发送到网关。在每一跳中都遵循类似的路由查找过程,直到分组到达实际的服务器。传输层及其上层仅在终端服务器上发挥作用。仅在中间跳跃期间,直到涉及 IP/网络层。

Screengrab for above explanation

我们在路由表中看到的一个奇怪的网关是 0.0.0.0。这个网关意味着发送数据包不需要第 3 层(网络层)跳。源和目的都在同一个网络中。内核必须计算出目的地的 mac,并适当地填充源 mac 和目的地 MAC,然后将数据包发送出去,以便它到达目的地时中间没有任何第 3 层跳

正如我们在其他模块中所做的那样,让我们用 SRE 使用案例来结束本次会议

SRE 角色中的应用
一般来说,路由表是由 DHCP 填充的,随意摆弄并不是一个好习惯。可能有这样的原因,人们不得不绕开路由表,但只有在绝对必要时才选择那条路径
更好地理解错误消息,如“没有到主机的路由”错误可能意味着找不到目的主机的 mac 地址,也可能意味着目的主机关闭
在极少数情况下,查看 ARP 表可以帮助我们了解是否存在 IP 冲突,即错误地将相同的 IP 分配给两台主机,从而导致意外行为
总结
原文:https://linkedin.github.io/school-of-sre/level101/linux_networking/conclusion/

至此,我们已经完全遍历了 TCP/IP 协议栈。我们希望当一个人在浏览器中打开任何网站发布课程时,都会有一个不同的视角。
{spa.juyouyouhuiquan.com]
{spa.namakemonozou.com]
{spa.aalango.com]
{spa.dgctdz.com]
{spa.xamssy.com]
{spa.toyotasurebangna.com]
{spa.iyouwanke.com]
{spa.midou365.com]

在本课程中,我们还剖析了 SRE 负责的这一管道中的共同任务。

训练后练习
在开发环境中设置自己的 DNS 解析器,作为 example.com 的权威 DNS 服务器和其他域的转发器。更新 resolv.conf 以使用 localhost 中运行的新 DNS 解析程序
在 localhost 中设置站点 dummy.example.com,并使用自签名证书运行 web 服务器。更新受信任的 CA 或传递自签名 CA 的公钥作为参数,以便 curl https://dummy.example.com-v 正常工作,没有自签名证书警告
更新路由表,使用同一网络中的另一台主机(容器/虚拟机)作为 8.8.8.8/32 的网关,并运行 ping 8.8.8.8 命令。在新网关上捕获数据包,查看 L3 跳是否按预期工作(可能需要禁用 icmp_redirect)
Python 和 Web
Python 和 Web
原文:https://linkedin.github.io/school-of-sre/level101/python_web/intro/

先决条件
对 python 语言的基本理解。
基本熟悉 flask 框架。
从本课程中可以期待什么
本课程分为两个高级部分。在第一部分中,假设熟悉 python 语言的基本操作和语法用法,我们将更深入地理解 python 作为一种语言。我们将 python 与其他编程语言进行比较,比如 Java 和 c。我们还将探索 python 对象的概念,并在此基础上探索 Python 的特性,比如 decorators。

在围绕 web 的第二部分中,假设您熟悉 Flask 框架,我们将从 socket 模块开始,处理 HTTP 请求。这将揭开 flask 这样的框架如何在内部工作的神秘面纱。

为了向课程介绍 SRE 风味,我们将设计、开发和部署(理论上)一个 URL 缩短应用。我们将强调整个过程中作为上述应用/服务的 SRE 更重要的部分。

本课程不包括哪些内容
对 python 内部和高级 python 有广泛的了解。

实验室环境设置
安装最新版本的 python

课程内容
Python 语言
一些 Python 概念
Python 陷阱
Python 和 Web
插座
烧瓶
短网址应用
设计
缩放应用
监控 App
Python 语言
假设你懂一点 C/C++和 Java,让我们试着在这两种语言和 python 的背景下讨论下面的问题。你可能听说过 C/C++是一种编译语言,而 python 是一种解释语言。一般来说,对于编译语言,我们首先编译程序,然后运行可执行文件,而对于 python,我们像python hello_world.py一样直接运行源代码。而 Java 作为一种解释型语言,仍然有一个单独的编译步骤和运行步骤。那么真正的区别是什么呢?

编译与解释
这对你来说可能听起来有点奇怪:python 在某种程度上是一种编译语言!Python 内置了编译器!这在 java 的例子中很明显,因为我们使用一个单独的命令 ie: javac helloWorld.java来编译它,它将产生一个.class文件,我们称之为字节码。python 与此非常相似。这里的一个区别是,运行 python 程序不需要单独的编译命令/二进制文件。

那么,java 和 python 之间有什么区别呢?嗯,Java 的编译器更加严格和复杂。您可能知道 Java 是一种静态类型语言。因此,编译器的编写方式可以在编译时验证与类型相关的错误。虽然 python 是一种动态语言,但在程序运行之前,类型是未知的。所以在某种程度上,python 编译器是哑的(或者说,不那么严格)。但是当 python 程序运行时,确实有一个编译步骤。您可能见过扩展名为.pyc的 python 字节码文件。下面是如何看到给定 python 程序的字节码。

Create a Hello World

$ echo "print('hello world')" > hello_world.py

Making sure it runs

$ python3 hello_world.py
hello world

The bytecode of the given program

$ python -m dis hello_world.py
1 0 LOAD_NAME 0 (print)
2 LOAD_CONST 0 ('hello world')
4 CALL_FUNCTION 1
6 POP_TOP
8 LOAD_CONST 1 (None)
10 RETURN_VALUE
点击阅读更多关于 dis 模块的信息

现在来看 C/C++,当然有一个编译器。但是输出与 java/python 编译器产生的不同。编译一个 C 程序会产生我们所知的机器码。与字节码相反。

运行程序
我们知道编译涉及到我们正在讨论的所有 3 种语言。只是编译器本质上不同,它们输出不同类型的内容。在 C/C++的情况下,输出是可以被你的操作系统直接读取的机器代码。当你执行这个程序时,你的操作系统会知道如何运行它。但是字节码却不是这样。

那些字节码是特定于语言的。Python 有自己定义的字节码集(更多内容在dis模块中), java 也是如此。所以很自然地,你的操作系统将不知道如何运行它。为了运行这个字节码,我们有一个叫做虚拟机的东西。即:JVM 或 Python VM (CPython,Jython)。这些所谓的虚拟机是能够读取字节码并在给定的操作系统上运行的程序。Python 有多个虚拟机可用。Cpython 是用 C 语言实现的 python VM,类似地,Jython 是 python VM 的 Java 实现。最终,他们应该能够理解 python 语言的语法,能够将其编译成字节码,并能够运行该字节码。你可以用任何语言实现 python 虚拟机!(而人们这么做,只是因为可以做到)

The Operating System

                                                          +------------------------------------+
                                                          |                                    |
                                                          |                                    |
                                                          |                                    |

hello_world.py Python bytecode | Python VM Process |
| |
+----------------+ +----------------+ | +----------------+ |
|print(... | COMPILE |LOAD_CONST... | | |Reads bytecode | |
| +--------------->+ +------------------->+line by line | |
| | | | | |and executes. | |
| | | | | | | |
+----------------+ +----------------+ | +----------------+ |
| |
| |
| |
hello_world.c OS Specific machinecode | A New Process |
| |
+----------------+ +----------------+ | +----------------+ |
|void main() { | COMPILE | binary contents| | | binary contents| |
| +--------------->+ +------------------->+ | |
| | | | | | | |
| | | | | | | |
+----------------+ +----------------+ | +----------------+ |
| (binary contents |
| runs as is) |
| |
| |
+------------------------------------+
上图需要注意两点:
{spa.58hqzx.com]
{spa.kdgcjxsj.com]
{spa.hige-usuku.com]
{spa.jfrhbzs.com]
{spa.zstzxl.com]
{spa.wencan888.com]
{spa.majime-f.com]

通常,当我们运行一个 python 程序时,会启动一个 python VM 进程,该进程读取 python 源代码,将其编译成字节码,然后在一个步骤中运行它。编译不是一个单独的步骤。仅出于说明目的示出。
为类 C 语言生成的二进制文件并不完全按照原样运行。由于有多种类型的二进制文件(例如:ELF),运行二进制文件需要更复杂的步骤,但我们不会深入讨论,因为所有这些都是在操作系统级别完成的。

相关实践学习
通过Ingress进行灰度发布
本场景您将运行一个简单的应用,部署一个新的应用用于新的发布,并通过Ingress能力实现灰度发布。
容器应用与集群管理
欢迎来到《容器应用与集群管理》课程,本课程是“云原生容器Clouder认证“系列中的第二阶段。课程将向您介绍与容器集群相关的概念和技术,这些概念和技术可以帮助您了解阿里云容器服务ACK/ACK Serverless的使用。同时,本课程也会向您介绍可以采取的工具、方法和可操作步骤,以帮助您了解如何基于容器服务ACK Serverless构建和管理企业级应用。 学习完本课程后,您将能够: 掌握容器集群、容器编排的基本概念 掌握Kubernetes的基础概念及核心思想 掌握阿里云容器服务ACK/ACK Serverless概念及使用方法 基于容器服务ACK Serverless搭建和管理企业级网站应用
相关文章
|
2月前
|
运维 Serverless UED
谷歌的SRE和开发是如何合作的
谷歌的SRE和开发是如何合作的
75 5
|
5月前
|
程序员 Python
【🔥热闻速递】Google 裁撤 Python研发团队
Google近日决定解散其Python研发团队,原因是寻求更低劳动力成本,可能转向其他国家招聘。此举可能源于美国程序员薪资高昂,相比之下,中国工程师薪资更低且效率更高。谷歌CEO Sundar Pichai已将部分团队迁移至印度。这一决策引发对公司长期可持续性和人才保留问题的讨论,暗示谷歌正面临挑战。
82 5
|
5月前
|
缓存 安全 测试技术
「译文」Google SRE 二十年的经验教训
「译文」Google SRE 二十年的经验教训
|
Android开发
Twitter SVP Chris Fry 谈对工程师团队的管理
在你加入之后,Twitter 的工程师部门发生了些什么变化呢? Twitter 有意思的地方是,它是从各自为营的小团队中发展起来的,关于分散还是集中的讨论一直就没有停过。在 Salesforce 时的问题是有点过于集中,而现在又是有点过于分散。
165 0
Twitter SVP Chris Fry 谈对工程师团队的管理
|
前端开发 JavaScript 程序员
来自Google, Pinterest 等公司顶级程序员的10条最佳实践
编程语言各有不同,不过区别不大。但用语言的人区别就大了。选择了一门语言你就选择了一个群落。
137 0
来自Google, Pinterest 等公司顶级程序员的10条最佳实践
|
机器学习/深度学习 新零售 算法
如何快速上手 AB Testing ?淘系技术专家秘方公开
本文内容大纲: 1、什么是 A/B Testing? 2、A/B 仅仅是分流吗? 3、怎么样才是科学的 A/B 实验。
1261 0
如何快速上手 AB Testing ?淘系技术专家秘方公开
《阿里云SRE技术期刊》2021年02月【电子版】
《阿里云SRE技术期刊》2021年02月【电子版】
《阿里云SRE技术期刊》2021年02月【电子版】
|
数据挖掘 开发工具
如何快速上手 AB Testing ?阿里技术专家秘方公开
作者 | 乔福 A/B 相信大家都或多或少做过,但是你对 A/B 测试的了解有多少,A/B 仅仅是分流吗?怎么样才是科学的 A/B 实验。下面阿里前端技术专家会结合最近的一些学习,系统性和通俗性地说一说 A/B Testing,希望对大家有所帮助。
1299 0
如何快速上手 AB Testing ?阿里技术专家秘方公开