Seth Kenlon 发布的文章

在本文中,我们将讨论网络连接最基本的诊断工具之一:ping 命令。

如今,联网计算机变得十分普遍,以至于我们大多数人都理所当然地认为,房间一侧的计算机可以连接上房间另一侧的计算机,更不用说能连接上世界的另一端的计算机了。如此,网络使互联网、云、文件共享、媒体流、远程管理、打印等服务成为可能。但是当网络出现问题时,有时很难诊断到底是其中哪一环节出现了问题。下面,我们就来介绍:网络连接最基本的诊断工具之一—— ping 命令。

基本的 ping 命令

当你无法访问本地网络上的计算机或互联网上的服务器时,你可以 ping 它的 IP 地址。ping 将 互联网控制报文协议 Internet Control Message Protocol (ICMP)数据包发送到目标 IP 地址。当我们要对网路连接状况进行判断时,ICMP 是个非常有用的协议,本质上 ICMP 是一个响应和应答信号。

让我们由近及远地进行故障排除。请先 ping 你自己的计算机,以确保你的计算机正在运行 网络栈 networking stack 。你正在操作的计算机称为 主机 localhost ,本地回环地址是:127.0.0.1。

ping 命令能用主机的 主机名 hostname 、IP 地址(即 127.0.0.1)或者仅仅用简写 0 来表示 “主机”。

你可以使用 -c 选项,来控制发送数据包的 次数 count 。

$ ping 0 -c 1
PING 0 (127.0.0.1) 56(84) bytes of data.
64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.069 ms

--- 0 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.069/0.069/0.069/0.000 ms

在你确认本地网络栈已启动并运行后,接下来,你可以 ping 你的路由器的 IP 地址。路由器的 IP 地址通常以 192.168 或 10 开头。实际的 IP 地址取决于路由器的配置。

当你没有指定要发送多少次请求时,你可以用 Ctrl+C,来终止 ping 的运行。

$ ping 192.168.0.1 
PING 192.168.0.1 (192.168.0.1) 56(84) bytes of data.
From 192.168.0.100: icmp_seq=2 Redirect Host(New nexthop: 192.168.0.1)
From 192.168.0.100: icmp_seq=3 Redirect Host(New nexthop: 192.168.0.1)
From 192.168.0.100: icmp_seq=4 Redirect Host(New nexthop: 192.168.0.1)
From 192.168.0.100: icmp_seq=5 Redirect Host(New nexthop: 192.168.0.1)
^C

如果你能 ping 通路由器,则表示你的有线或无线连接能正常工作。

对于你的局域网上的其他主机呢?你可以 ping 各种设备,但是并非所有设备都能保证响应,因为一些设备会丢弃 ICMP 数据包,但许多设备会做出响应。例如,我可以 ping 我的打印机:

$ ping 192.168.0.4 

ping 路由器以外的其他服务器

在确定你自己的网络内部都能连通以后,你还可以 ping 通到路由器以外的其他服务器。同样地,并非所有服务器都能接收 ICMP 数据包,更不用说响应 ICMP 数据包了。然而,也有一些服务器可以接收并响应 ICMP 数据包,而在互联网中的一个重要服务器是 域名服务器 nameserver 。

谷歌的 域名解析服务器 DNS server 的 IP 地址很容易记住,而且它会响应 ping 请求:

$ ping -c 2 8.8.8.8
PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.
64 bytes from 8.8.8.8: icmp_seq=1 ttl=116 time=53.3 ms
64 bytes from 8.8.8.8: icmp_seq=2 ttl=116 time=53.5 ms

--- 8.8.8.8 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1000ms
rtt min/avg/max/mdev = 53.304/53.424/53.544/0.120 ms

当你连不上一个网站时,你可以查询全球 DNS 网络,以找出其主机服务器的地址,然后 ping 该服务器。这至少可以告诉你,网站不通的原因是主机已关闭,或者只是 Web 服务器问题。

例如,假设你尝试访问 example.com,但是发现失败了。首先,使用 host 命令找到 example.com 的 IP 地址:

$ host example.com
example.com has address 93.184.216.34
example.com has IPv6 address 2606:2800:220:1:248:1893:25c8:1946
example.com mail is handled by 0

然后,ping 该网站的的 IP 地址:

$ ping 93.184.216.34 -c 1

使用 IPv6

ping 不仅可以使用 IPv4,还能使用 IPv6。可以通过指定 -4 或 -6 选项,来只使用 IPv4 或 IPv6。

设置数据包大小

你可以使用 -s 选项,来更改要发送的 ICMP 数据包的 大小 size 。默认的数据大小为 56 字节,加上 8 字节包头,总共得到 64 字节的 ICMP 数据包。以下的示例将发送的 ICMP 数据包大小修改为 35+8=43 个字节:

$ ping -s 35 -c 5 8.8.8.8

你可以使用 -D 选项,使得在终端中的每个 ping 回复之前,先打印出当前的时间戳。该时间戳为 UNIX 时间戳,加上微秒:

$ ping -D 8.8.8.8 
PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.
[1634013430.297468] 64 bytes from 8.8.8.8: icmp_seq=1 ttl=116 time=53.3 ms
[1634013431.298738] 64 bytes from 8.8.8.8: icmp_seq=2 ttl=116 time=53.1 ms

设置时间间隔/长短

你可以使用 -i 选项,来更改两次 ping 请求之间的 时间间隔 interval 。以下的示例将 ping 间隔更改为 2 秒:

$ ping -i 2 

你也可以使用 -w 选项,来在一段时间后终止 ping,单位为秒。

$ ping -w 6

ping 的变体

ping 有很多变体。例如,iputils 包提供了 ping 命令;Busybox 也有ping 命令;BSD 也有;甚至还有一个图形界面的 ping:gping,它可用于 Linux、macOS 和 Windows。你可以在 GitHub 上找到更多有关 gping 的信息。

一起来学习吧

ping 命令很简单,但它可以帮你诊断网络连接问题。下次再遇到网络连接问题时,让 ping 命令成为你解决问题的第一个工具吧。


via: https://opensource.com/article/21/10/linux-ping-command

作者:Seth Kenlon 选题:lujun9972 译者:chai001125 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

使用这个开源工具,即使是批量校正图像也很容易。

多年前,在翻阅一家旧书店的书架上的内容时,我偶然发现了一本名为 《UNIX System Command Summary for Berkeley 4.2 & 4.3 BSD》 的小册子,由 Specialized Systems Consultants 出版。我买它是出于好奇,因为它已经有将近 20 年的历史了,但仍然在很大程度上适用于现代 Linux 和 BSD。

无论是当时还是现在,我都很开心。一本写于 1986 年的小册子在 2016 年仍然很重要,而同一个书架上关于专有操作系统的书籍并不值得印刷它们的纸张。(想一想:你认为什么技术可以在僵尸末日中幸存下来?)这本小册子已经放在我自己的书架上好几年了,但我突然想到可能值得对这个作品做一点数字保存,所以我决定扫描这本小册子来创建一本 CBZ 电子书。

使用 Skanlite 进行扫描很容易,但很耗时。然而,当我完成后,我发现有些页面不是很平整。

A page of text, including a table of contents and a glossary, that is crooked and distorted

在打印中,这称为配准问题,这意味着打印内容的位置在页面上的方向不正确。

ImageMagick

ImageMagick 是基于终端的非交互式图形编辑器。尝试在无图形环境(如纯文本终端)中编辑图形似乎违反直觉,但实际上很常见。例如,当你将图像上传到 Web 应用用作个人资料图片时,应用服务器上的脚本可能会使用 ImageMagick 或其库处理你的图像。非交互式编辑器的优点是你可以制定需要对示例图像执行的操作,然后只需按一下按钮即可将这些效果应用于数百个其他图像。

ImageMagick 通常与其他图形编辑器一样强大,只要你花时间了解它的许多功能以及如何组合它们以实现所需的效果。在这种情况下,我想旋转歪斜的页面。在搜索了 ImageMagick 的文档后,我发现我需要的解决方案的 ImageMagick 术语称为纠偏。将你的术语与其他人的术语保持一致对于你不知道的任何事情都是一个挑战,因此当你使用 ImageMagick(或其他任何东西)时,请记住,你描述问题或解决方案的用词可能和别人不一样。

要使用 ImageMagick 对带有弯曲文本的图像进行校正:

$ convert page_0052.webp -deskew25% fix_0052.webp

-deskew 选项表示可接受偏差的阈值。通过跟踪看似字母的对象的峰谷来确定倾斜。根据扫描的弯曲程度,你可能需要多于或少于 25% 的阈值。我已经达到了 80%,到目前为止,低于 25% 没用效果。

结果如下:

The same page of text, now with the text properly aligned

修复了!将其应用于文档的剩余 55 页以修复倾斜的页面,而对已经笔直的页面不做任何事情。换句话说,由于我的阈值设置,在不需要调整的页面上运行此命令是安全的。

使用 ImageMagick 裁剪图像

在纠正了歪斜之后,因为我扫描每一页都比必要的范围要多,以防止意外切断单词,我认为裁剪我纠正的页面是有意义的。我很高兴在页边空白处保留一些空间,但没有以前那么多。我经常使用 ImageMagick 的“裁剪”功能来处理这个网站上的图像,所以我很熟悉这个选项。但是,我需要确定如何裁剪每一页。

首先,我需要图像的大小:

$ identify fixed_0052.webp
WEBP 1128x2593 1128x2593+0+08-bit sRGB 114732B 0.020u 0:00.021

知道尺寸后,我能够对我可以承受的丢失多少像素做出一些估计。经过几次试运行,我得到了这个:

convert fix_0052.webp -gravity Center -crop 950x2450+0+0 crop_0052.webp

这并不完全适合,但当我将它应用于册子中的其他图像时,它被证明很重要。这些页面的内容和扫描仪位置各不相同,所以我很高兴给每一页一点空余空间。

这是校正和裁剪的图像:

The same page of text, with the previous fixes applied and crooked white margins around the page cropped out.

使用开源批量编辑图像

ImageMagick 的美妙之处在于,当你确定了修复图像的公式,你就可以将该修复应用于需要相同修复的所有图像。我使用 GNU Parallel 执行此操作,它使用我所有的 CPU 内核来完成数百页的图像校正。这并不需要很长时间,而且结果不言而喻。更重要的是,我已经有了一个 UNIX 历史上有趣作品的数字档案。


via: https://opensource.com/article/22/11/fixing-scanned-images-imagemagick

作者:Seth Kenlon 选题:lkxed 译者:geekpi 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

Lua 是一个有趣而强大的语言,随着各个版本的推进,功能愈发的强大,开发者群体也在不断的增长。这篇文章我们将探索一下它的各种前景。

Lua 是一个脚本语言,它面向过程、函数式编程,甚至可以是 面向对象的。它使用类 C 语言的语法,但却是动态类型,具有自动内存管理和垃圾回收功能,使用基于寄存器的虚拟机来解释字节码。这些特点使得它对于初学者来说是个很好的语言,同时也是经验丰富的程序员的强大工具。

虽然与 Python 和 JavaScript 相比,Lua 现在已经有点儿黯然失色了,但是 Lua 拥有的一些优点使得它在许多的重大软件项目中很受欢迎。Lua 很容易嵌入到其他语言当中, 这意味着你可以在(例如)Java 编写的代码中包含 Lua 文件,就像原生的 Java 代码一样运行。这听起来就像魔法一般,现在有许多项目如 luaj 使得其成为可能,之所以可以实现,正是因为 Lua 就是为此而设计的。部分出于这种灵活性,你可以在许多游戏、图形应用的程序中发现 Lua 脚本的身影。

就像其他任何事情一样,做到完美是需要时间的,但 Lua 是很易于学习(并且有趣)的语言。它是一种一致的语言、一种带有有用的错误消息的友好的语言,并且可以在网上轻松找到许多有用的资料。那么就让我们开始吧!

安装 Lua

在 Linux 下,你可以使用发行版自带的包管理来安装 Lua。例如,在 Fedora、CentOS、 Mageia、OpenMandriva 以及类似发行版中:

$ sudo dnf install lua

在 Debian 以及基于 Debian 的系统中:

$ sudo apt install lua

对于 Mac,你可以使用 MacPorts 或者 Homebrew:

$ sudo port install lua

对于 Windows,可以使用 Chocolatey 安装 Lua。

完成安装后,可以在终端中输入 lua 来在交互式解释器中使用 Lua。

函数

如许多编程语言一样,Lua 的语法通常是一个内建的函数或关键字,后面跟着参数。例如,print 函数显示你传给它的所有参数。

$ lua
Lua 5.4.2  Copyright (C) 1994-2020 Lua.org,PUC-Rio

> print('hello')
hello

Lua 的 string 库可以操作单词(在编程中称为“字符串”)。例如,要统计字符串中的字母数量,你可以使用 string 库中 len 函数:

> string.len('hello')
5

变量

变量允许你在计算机内存中为临时的数据创建一个指定的空间。Lua 中创建变量的方法是赋予变量一个名字,接着将数据放入其中。

> foo = "hello world"
> print(foo)
hello world
> bar = 1+2
> print(bar)
3

表

在编程中,数组的使用频率仅次于变量。“数组”这个词的字面意思就是一种排列,而这就是程序中数组的意义了。它是数据的一种排列,因为有排列,所有数组具有结构化的优势。本质上,数组通常用于和变量相同的目的,只不过数组会给对其中的数据进行排序。在 Lua 中,数组被称为“表”。(LCTT 译注:使用过其它编程语言的同学可以发现,Lua 的表相当于其它语言中的关联数组、哈希。)

创建表和创建变量类似,区别仅在于它的初始化内容被设置为 {}:

> mytable = {}

当往表中增加数据时,它就如同创建变量一样,区别在于这里的变量之前总是以表名开头,中间使用 . 来连接:

> mytable.foo = "hello world"
> mytable.bar = 1+2
> print(mytable.foo)
hello world
> print(mytable.bar)
3

使用 Lua 编写脚本

在终端交互环境中运行 Lua 可以得到良好的反馈,但是将 Lua 作为脚本运行会更为有用。Lua 脚本就是包含 Lua 代码的文本文件,Lua 命令可以解析并执行此文件。

在刚刚开始学习一门编程语言时,一个永恒的问题是你怎么知道该写什么。这篇文章将提供一个不错的开端,截至目前,你仅知道了两三个 Lua 函数。懂得查阅文档是很关键的。Lua 并不是一个复杂的语言,可以通过 Lua 文档网站 很方便的获取关键字以及函数的用法。

下面是一个练习题。

假设你想编写一个 Lua 脚本来统计句子中的单词数量。与众多的编程挑战一样,有许多方法可以解决这个问题,假设你在 Lua 文档中找到的第一个相关的函数是 string.gmatch,此函数可以搜索字符串中的特定字符。单词通常通过空格分隔开来,所以你决定计算空格数并加 1 来作为单词的数量。

下面是实现的代码:

function wc(words,delimiter)
  count=1
  for w in string.gmatch(words,delimiter) do
    count = count + 1
  end

  return count
end

下面是这个样例代码的解释:

  • function:这是声明函数开始的关键字。自定义函数的工作方式与内置函数(如 print 和 string.len)基本相同。
  • words 和 delimiter:这是函数运行所需的参数。正如 print('hello') 当中,hello 是一个参数。
  • counter:一个变量,且被初始化为 1。
  • for:在循环中使用 string.gmatch 作为迭代器遍历 words,并且在其中搜索delimiter。
  • count = count + 1:当搜索到了 delimiter,则对 count 进行自增 1 的操作。
  • end:for 循环的结束关键字。
  • return count:这个函数输出(或返回)count 变量的内容。
  • end:函数结束的关键字。

现在你已经创建了一个函数,你可以使用它。需要记住,函数不会自动运行,而是等待你在代码中调用它。

将下面的代码写入文件并保存为 words.lua:

function wc(words,delimiter)
  count=1
  for w in string.gmatch(words,delimiter) do
    count = count + 1
  end
  return count
end

result = wc('zombie apocalypse',' ')
print(result)

result = wc('ice cream sandwich',' ')
print(result)

result = wc('can you find the bug? ',' ')
print(result)

你现在创建了一个 Lua 脚本。你可以使用 Lua 运行它。随后你会发现统计单词的结果有些问题:

$ lua ./words.lua
2
3
6

你也许已经注意到了最后一个句子的单词统计不正确,因为在句子的最后带有一个额外的空格。Lua正确的检测到了空格,并将其计入 count 中,但是单子的统计是错误的,因为有个空格并没有作为单词的分隔出现。我把这个问题留给你来解决,或者去发现其他方法,即使方法不太理想。编程中有很多需要思考的地方。有时是纯粹学术性的思考,有时也许是应用是否运训正常的思考。

学习 Lua

Lua 是一个有趣且强大的语言,随着版本的推进,功能愈发的强大,开发者群体也在不断的增长。你可以将 Lua 作为实用性的个人脚本使用,或者在工作中使用,或者仅仅是体验一下一个新的语言。尝试一下,看看 Lua 能给你带来什么吧。

(LCTT 译注:顺便问一句,你知道 “Lua” 怎么发音吗? ?)


via: https://opensource.com/article/22/11/lua-worth-learning

作者:Seth Kenlon 选题:lkxed 译者:MuggleWei 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

使用 Lua 配置持久化应用设置。

不是所有的应用都需要配置文件;对很多应用来说,在启动时变得焕然一新对它们更有利。例如,简单的工具就极少需要偏好项和设置在使用过程中保持稳定不变。然而,当你编写一个复杂的应用程序时,如果能让用户设置与应用的交互方式,以及应用与系统交互的方式会很不错。这就是配置文件用来做的事情。本文将讨论一些利用 Lua 进行持久化配置的方法。

选择一种格式

关于配置文件很重要的两点是一致性和可预见性。你不会希望为了保存用户偏好项,将信息转储到文件中,然后再花几天去编码实现“逆向工程”,处理最后出现在文件里的随机信息。

这里用一些常用的 配置文件格式。Lua 有一些库可以处理大多数常用的配置格式;在本文中,我会采用 INI 格式。

安装库

Lua 库的核心仓库是 Luarocks.org。你可以在这个网站搜索库,或者你可以安装并使用 luarocks 终端命令。

Linux 环境中,你可以从发行版的软件仓库中下载它,例如:

$ sudo dnf install luarocks

在 macOS 上,请使用 MacPorts 或者 Homebrew。在 Windows 上,请使用 Chocolatey。

luarocks 安装后,你可以使用 search 子命令来搜索一个恰当的库。如果你不知道库的名字,可以通过关键词来搜索这个库,例如 ini、xml或者json,这取决于你想要用这个库做什么。打个比方,你可以搜索inifile`, 这个库被我用来解析 INI 格式的文本文件。

$ luarocks search inifile
Search results:
inifile
 1.0-2 (rockspec) - https://luarocks.org
 1.0-2 (src) - https://luarocks.org
 1.0-1 (rockspec) - https://luarocks.org
 [...]

一个开发者容易犯的错误是在系统上安装了这个库却忘了把它和应用打包。这会给没有安装这个库的用户带来麻烦。为了防止这个问题发生,可以使用 --tree 选项将它安装在项目的本地文件夹中。如果你没有这个项目文件夹,那就先创建这个文件夹再安装库:

$ mkdir demo
$ cd demo
$ luarocks install --tree=local inifile

--tree 选项指示 luarocks 创建一个新文件夹并在其中安装你的库,例如这个例子中的 local 文件夹。 使用这个简单的技巧,你可以将所有你项目要使用的依赖项直接安装到项目文件夹中。

配置代码

首先,在一个名 myconfig.ini 的文件中创建一些 INI 数据。

[example]
name=Tux
species=penguin
enabled=false

[demo]
name=Beastie
species=demon
enabled=false

将这个文件保存到你的主目录下,命名为 myconfig.ini, 不要 存到项目文件夹下。你通常会希望配置文件独立于你的文件存在,这样当用户卸载你的应用时,使用应用时产生的数据可以保存在系统中。有些用户会删除不重要的配置文件,但大多数不会。最终,如果他们要重装这个应用,还会保留着所有的用户偏好项。

配置文件的位置以技术来说并不重要,但每一个操作系统都有存储它们的特定或者默认的路径。在 Linux 中,这个路径由 Freedesktop 规范 指定。它规定配置文件被保存在一个名为 ~/.config 的隐藏文件夹中。为了操作时更加清晰明确,可以在主目录下存储配置文件,以便于使用和寻找。

创建第二个文件,命名为 main.lua,并在你喜欢的文本编辑器中打开它。

首先,你必须告诉 Lua 你将想要使用的附加库放置在哪里。package.path 变量决定了 Lua 到哪里去寻找这些库。你可以从终端中查看 Lua 默认的包地址:

$ Lua
> print(package.path)
./?.lua;/usr/share/lua/5.3/?.lua;/usr/share/lua/5.3/?/init.lua;/usr/lib64/lua/5.3/?.lua;/usr/lib64/lua/5.3/?/init.lua

在你的 Lua 代码中,将你本地库的路径添加到 package.path 中:

package.path = package.path .. ';local/share/lua/5.3/?.lua

使用 Lua 解析 INI 文件

当包的位置确定以后,下一件事就是引入 inifile 库并处理一些操作系统逻辑。即使这是一个很简单的应用,代码也需要从操作系统获取到用户主目录的路径,并建立在必要时将文件系统路径返回给操作系统的通信方式。

package.path = package.path .. ';local/share/lua/5.3/?.lua
inifile = require('inifile')

-- find home directory
home = os.getenv('HOME')

-- detect path separator
-- returns '/' for Linux and Mac
-- and '\' for Windows
d = package.config:sub(1,1)

现在你可使用 inifile 来从配置文件解析数据到 Lua 表中。一旦这些数据被导入进表中,你可以像查询其他的 Lua 表一样查询它。

-- parse the INI file and
-- put values into a table called conf
conf = inifile.parse(home .. d .. 'myconfig.ini')

-- print the data for review
print(conf['example']['name'])
print(conf['example']['species'])
print(conf['example']['enabled'])

在终端中运行代码可以看见结果:

$ lua ./main.lua
Tux
penguin
false

这看起来是正确的。试试在 demo 块中执行同样的操作。

使用 INI 格式存储数据

不是所有用来解析的库都会读写数据(通常被称为 \_编码 和 解码),但是 inifile 会这样做。这意味着你可以使用它对配置文件进行修改。

为了改变配置文件中的值,你可以对被解析的表中的变量进行设置,然后把表重写回配置文件中。

-- set enabled to true
conf['example']['enabled'] = true
conf['demo']['enabled'] = true

-- save the change
inifile.save(home .. d .. 'myconfig.ini', conf)

现在再来看看配置文件:

$ cat ~/myconfig.ini
[example]
name=Tux
species=penguin
enabled=true

[demo]
name=Beastie
species=demon
enabled=true

配置文件

按照用户的设想来存储数据对程序来说是至关重要的。幸运的是,这对工程师来说是一个很常规的任务,大多数工作可能早已被完成了。只要找到一个好用的库完成开放格式下编码和解码,你就能为用户提供一致且持续的体验。

以下是完整的演示代码,可供参考。

package.path = package.path .. ';local/share/lua/5.3/?.lua'
inifile = require('inifile')

-- find home directory
home = os.getenv('HOME')

-- detect path separator
-- returns '/' for Linux and Mac
-- and '\' for Windows
d = package.config:sub(1,1)

-- parse the INI file and
-- put values into a table called conf
conf = inifile.parse(home .. d .. 'myconfig.ini')

-- print the data for review
print(conf['example']['name'])
print(conf['example']['species'])
print(conf['example']['enabled'])

-- enable Tux
conf['example']['enabled'] = true

-- save the change
inifile.save(home .. d .. 'myconfig.ini', conf)

via: https://opensource.com/article/21/6/parsing-config-files-lua

作者:Seth Kenlon 选题:lujun9972 译者:hadisi1993 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

PostgreSQL 是最灵活的数据库之一,并且它是开源的。

数据库是以一种有组织且灵活的方式存储信息的工具。电子表格在本质上就是一个数据库,但是图形化应用程序这一限制使得大多数的电子表格应用程序对程序员毫无用处。随着 边缘计算 和物联网设备成为重要的平台,开发者们需要更有效且轻量级的方法,来存储、处理、查询大量的数据。我最爱的一种组合是使用 Lua 连接 PostgreSQL 数据库。无论你使用什么编程语言,PostgreSQL 一定是数据库的绝佳选择,但是在使用 PostgreSQL 之前,首先你需要知道一些基本的东西。

安装 PostgreSQL

在 Linux 上安装 PostgreSQL,要使用你的软件库。在 Fedora,CentOS,Megeia 等类似的 Linux 版本上使用命令:

$ sudo dnf install postgresql postgresql-server

在 Debian, Linux Mint, Elementary 等类似的 Linux 版本上使用命令:

$ sudo apt install postgresql postgresql-contrib

在 macOs 和 Windows 上,可以从官网 postgresql.org 下载安装包。

配置 PostgreSQL

大多数发行版安装 PostgreSQL 数据库时没有启动它,但是为你提供了一个脚本或 systemd 服务,能够可靠地启动 PostgreSQL。但是,在启动 PostgreSQL 之前,必须创建一个数据库集群。

Fedora

在 Fedora,CentOS 等类似的版本上,PostgreSQL 安装包中提供了一个 PostgreSQL 配置脚本。运行这个脚本,可以进行简单地配置:

$ sudo /usr/bin/postgresql-setup --initdb
[sudo] password:
 * Initializing database in '/var/lib/pgsql/data'
 * Initialized, logs are in /var/lib/pgsql/initdb_postgresql.log

Debian

在基于 Debian 的发行版上,在安装 Postgres 的过程中,配置会通过 apt 自动完成。

其他版本

最后,如果你是在其他版本上运行的,那么你可以直接使用 PostgreSQL 提供的一些工具。initdb 命令会创建一个数据库集群,但是这个命令必须在 postgres 用户下运行,你可以使用 sudo 来暂时地成为 postgres 用户:

$ sudo -u postgres \
    "initdb -D /var/lib/pgsql/data \
    --locale en_US.UTF-8 --auth md5 --pwprompt"

运行 PostgreSQL

现在,数据库集群已经存在了,使用 initdb 的输出中提供给你的命令或者使用 systemd 启动 PostgreSQL 服务器:

$ sudo systemctl start postgresql

创建一个数据库用户

使用 createuser 命令来创建一个数据库用户。postgres 用户是 Postgres 安装的超级用户。

$ sudo -u postgres createuser --interactive --password bogus
Shall the new role be a superuser? (y/n) n
Shall the new role be allowed to create databases? (y/n) y
Shall the new role be allowed to create more new roles? (y/n) n
Password:

创建一个数据库

使用 createdb 命令来创建一个新的数据库。在这个例子中,我创建了数据库 exampledb,并把该数据库的拥有者分配给用户 bogus。

$ createdb exampledb --owner bogus

与 PostgreSQL 交互

你可以使用 psql 命令来与 PostgreSQL 中的数据库进行交互。这个命令提供了一个交互界面,所以你可以用它来查看和更新你的数据库。你需要指定要使用的用户和数据库,来连接到一个数据库。

$ psql --user bogus exampledb
psql (XX.Y)
Type "help" for help.

exampledb=>

创建一个表

数据库包含很多表。这些表可以可视化为表格,有很多行(在数据库中称为 记录)和很多列。行和列的交集称为 字段。

结构化查询语言(SQL)是以它提供的内容而命名的,它能提供可预测且一致的语法,来查询数据库内容,从而收到有用的结果。

目前,你的数据库是空的,没有任何的表。你可以用 CREATE 语句来创建一个表。结合使用 IF NOT EXISTS 是很有用的,它可以避免破坏现有的表。

在你创建一个表之前,想想看你希望这个表包含哪一种数据(在 SQL 术语中称为“数据类型”)。在这个例子中,我创建了一个表,包含两列,有唯一标识符的一列和最多九个字符的可变长的一列。

exampledb=> CREATE TABLE IF NOT EXISTS my_sample_table(
exampledb(> id SERIAL,
exampledb(> wordlist VARCHAR(9) NOT NULL
);

关键字 SERIAL 并不是一个数据类型。SERIAL 是 PostgreSQL 中的一个特殊的标记,它可以创建一个自动递增的整数字段。关键字 VARCHAR 是一个数据类型,表示限制内字符数的可变字符。在此例中,我指定了最多 9 个字符。PostgreSQL 中有很多数据类型,因此请参阅项目文档以获取选项列表。

插入数据

你可以使用 INSERT 语句来给你的新表插入一些样本数据:

exampledb=> INSERT INTO my_sample_table (wordlist) VALUES ('Alice');
INSERT 0 1

如果你尝试在 wordlist 域中输入超过 9 个字符,则数据输入将会失败:

exampledb=> INSERT INTO my_sample_table (WORDLIST) VALUES ('Alexandria');
ERROR:  VALUE too long FOR TYPE CHARACTER VARYING(9)

改变表或者列

当你需要改变一个域的定义时,你可以使用 ALTER 这一 SQL 关键字。例如,如果你想改变 wordlist 域中最多只能有 9 个字符的限制,你可以重新设置这个数据类型。

exampledb=> ALTER TABLE my_sample_table
ALTER COLUMN wordlist SET DATA TYPE VARCHAR(10);
ALTER TABLE
exampledb=> INSERT INTO my_sample_table (WORDLIST) VALUES ('Alexandria');
INSERT 0 1

查询表中的内容

SQL 是一种查询语言,因此你可以通过查询来查看数据库的内容。查询可以是很简单的,也可以涉及连接多个不同表之间的复杂关系。要查看表中的所有内容,请使用 SELECT 关键字和 *(* 是通配符):

exampledb=> SELECT * FROM my_sample_table;
 id |  wordlist
----+------------
  1 | Alice
  2 | Bob
  3 | Alexandria
(3 ROWS)

更多数据

PostgreSQL 可以处理很多数据,但是对于任何数据库来说,关键之处在于你是如何设计你的数据库的,以及数据存储下来之后你是怎么查询数据的。在 OECD.org 上可以找到一个相对较大的公共数据集,你可以使用它来尝试一些先进的数据库技术。

首先,将数据下载为逗号分隔值格式(CSV)的文件,并将文件另存为 Downloads 文件夹中的 land-cover.csv。

在文本编辑器或电子表格应用程序中浏览数据,来了解有哪些列,以及每列包含哪些类型的数据。仔细查看数据,并留意错误情况。例如,COU 列指的是国家代码,例如 AUS 表示澳大利亚和 GRC 表示希腊,在奇怪的 BRIICS 之前,这一列的值通常是 3 个字符。

在你理解了这些数据项后,你就可以准备一个 PostgreSQL 数据库了。

$ createdb landcoverdb --owner bogus
$ psql --user bogus landcoverdb
landcoverdb=> create table land_cover(
country_code varchar(6),
country_name varchar(76),
small_subnational_region_code varchar(5),
small_subnational_region_name varchar(14),
large_subnational_region_code varchar(17),
large_subnational_region_name varchar(44),
measure_code varchar(13),
measure_name varchar(29),
land_cover_class_code varchar(17),
land_cover_class_name varchar(19),
year_code integer,
year_value integer,
unit_code varchar(3),
unit_name varchar(17),
power_code integer,
power_name varchar(9),
reference_period_code varchar(1),
reference_period_name varchar(1),
value float(8),
flag_codes varchar(1),
flag_names varchar(1));

引入数据

Postgres 可以使用特殊的元命令 \copy 来直接引入 CSV 数据:

landcoverdb=> \copy land_cover from '~/land-cover.csv' with csv header delimiter ','
COPY 22113

插入了 22113 条记录。这是一个很好的开始!

查询数据

用 SELECT 语句可以查询这 22113 条记录的所有列,此外 PostgreSQL 将输出通过管道传输到屏幕上,因此你可以轻松地滚动鼠标来查看输出的结果。更进一步,你可以使用高级 SQL 语句,来获得一些有用的视图。

landcoverdb=> SELECT
    lcm.country_name,
    lcm.year_value,
    SUM(lcm.value) sum_value
FROM land_cover lcm
JOIN (
    SELECT
        country_name,
        large_subnational_region_name,
        small_subnational_region_name,
        MAX(year_value) max_year_value
    FROM land_cover
    GROUP BY country_name,
        large_subnational_region_name,
        small_subnational_region_name
) AS lcmyv
ON
    lcm.country_name = lcmyv.country_name AND
    lcm.large_subnational_region_name = lcmyv.large_subnational_region_name AND
    lcm.small_subnational_region_name = lcmyv.small_subnational_region_name AND
    lcm.year_value = lcmyv.max_year_value
GROUP BY lcm.country_name,
    lcm.large_subnational_region_name,
    lcm.small_subnational_region_name,
    lcm.year_value
ORDER BY country_name,
    year_value;

下面是样例的一些输出:

---------------+------------+------------
 Afghanistan    |       2019 |  743.48425
 Albania        |       2019 |  128.82532
 Algeria        |       2019 |  2417.3281
 American Samoa |       2019 |   100.2007
 Andorra        |       2019 |  100.45613
 Angola         |       2019 |  1354.2192
 Anguilla       |       2019 | 100.078514
 Antarctica     |       2019 |  12561.907
[...]

SQL 是一种很丰富的语言,超出了本文的讨论范围。通读 SQL 的内容,看看你是否可以对上面的查询语句进行修改,以提供不同的数据集。

拓展数据库

PostgreSQL 是伟大的开源数据库之一。有了它,你可以为结构化数据设计存储库,然后使用 SQL 以不同的方式查询它,以便能够获得有关该数据的新视角。PostgreSQL 也能与许多语言集成,包括 Python、Lua、Groovy、Java 等,因此无论你使用什么工具集,你都可以充分利用好这个出色的数据库。


via: https://opensource.com/article/22/9/drop-your-database-for-postgresql

作者:Seth Kenlon 选题:lkxed 译者:chai001125 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

负载均衡就是将资源分配到某一时刻最需要它的地方。

 title=

当个人电脑刚开始发展的时候,一个家庭可能只有一台(或更少)的电脑。孩子们白天玩电脑游戏,家长们晚上在业务支撑系统上做会计、编程,或者漫游。然而,想象一下今天一个只有一台电脑的家庭,你可以预想到这样会产生什么样的冲突。每个人都想使用电脑,而只有一副键盘和鼠标。

随着计算机变得越来越普遍,IT 行业或多或少也出现了同样的情况。对服务和服务器的需求已经增长到了会因为用量过大而停机的程度。幸运的是,我们现在有了负载均衡的概念来帮助我们处理需求。

负载均衡是什么?

负载均衡是一个通用术语,指的是为了确保高效分配所管理的资源而做的事情。对于 Web 服务器的系统管理员来说,负载均衡通常意味着确保 Web 服务器软件(例如 Nginx)配置了足够的工作节点来处理激增的访客。换言之,如果一个网站突然变得非常受欢迎,其访问者在几分钟内增加了四倍,那么运行服务器的软件必须能够响应每个访问者,并不能让任何访问者发现服务质量下降。对于简单的网站,这就像修改一行配置选项一样简单,但对于具有动态内容的复杂站点,每个用户都有多个数据库查询,这可能是一个严重的问题。

这个问题本应随着云计算的发展而解决,但当 Web 应用程序遇到意外激增时,无法扩展也不是不可能。

在进行负载均衡时,需要记住的重要一点是,高效地分配资源并不一定意味着平均地分配资源。并非所有任务都在任何时候都需要所有的可用资源。一个智能的负载均衡策略仅在需要资源时才为用户和任务提供资源。这通常是应用程序开发人员的领域,而不是 IT 基础架构的责任。异步应用程序对于确保离开计算机休息的用户不占用服务器上的宝贵资源至关重要。

负载均衡是怎么工作的?

负载均衡通过在多个计算节点上分配工作负载来避免瓶颈。这些节点可能是数据中心中的物理服务器、云环境中的容器、用于边缘计算而战略性放置的服务器、复杂应用程序框架中的独立 Java 虚拟机(JVM),或在单个 Linux 服务器上运行的守护进程。

这个想法是把一个大问题分成几个小任务,并把每个任务分配给一台专用计算机。例如,对于一个要求用户登录的网站,该网站可能托管在服务器 A 上,而登录页面和所有随附的身份验证查询都托管在服务器 B 上。这样,新用户登录帐户时就不会占用其它使用该站点的用户的资源。

云计算负载均衡

云计算使用 容器,因此通常没有单独的物理服务器来处理不同的任务(实际上,有许多单独的服务器,但它们被聚集在一起作为一个计算“大脑”)。相反,“ 容器荚 pod ” 是由几个容器创建的。当一个容器荚由于其用户或任务负载而开始耗尽资源时,会生成一个相同的容器荚。容器荚共享存储和网络资源,每个容器荚在创建时被分配给一个计算节点。可以根据负载需要创建或销毁容器荚,这样无论有多少用户,用户都可以体验到一致的服务质量。

边缘计算

边缘计算 在负载均衡时考虑到了现实世界。云计算自然是一个分布式系统,但实际上,云计算的节点通常集中在几个数据中心。用户离运行云计算的数据中心越远,他们为获得最佳服务所必须克服的物理障碍就越多。即使有光纤连接和适当的负载均衡,位于 3000 英里外的服务器的响应时间也可能比仅仅 300 英里外的响应时间长。

边缘计算将计算节点带到云计算的“边缘”,试图弥合地理鸿沟,为云计算形成一种卫星网络,因此它也在良好的负载均衡工作中发挥了作用。

什么是负载均衡算法?

有许多负载均衡策略,它们的复杂性取决于所涉及的技术和需求。负载均衡不必复杂,而且从一开始就负载均衡很重要,即使在使用 Kubernetes 和 Keepalived 这样的专用软件时也是如此。

当你可以设计应用程序,自己为它采取简单的预防措施时,不要依赖容器来均衡负载。如果你从一开始就将应用程序设计为模块化和临时性的,那么你将受益于通过巧妙的网络设计、容器编排和其他未来技术带来的负载均衡机会。

可以指导应用程序开发人员或网络工程师工作的一些流行算法包括:

  • 按顺序将任务分配给服务器(这通常被称为轮询调度)。
  • 将任务分配给当前最不繁忙的服务器。
  • 将任务分配给具有响应最快的服务器。
  • 随机分配任务。

举个例子,在分配特别复杂的任务时,可以组合或加权这些原则以分配到组中最强大的服务器。通常使用 编排,这样管理员就不必为负载均衡寻找完美的算法或策略,尽管有时需要由管理员选择使用哪种负载均衡方案组合。

预料意料之外

负载均衡实际上并不是要确保在整个网络中均匀使用所有资源。负载均衡实际上是确保即使发生意外情况也能提供可靠的用户体验。良好的基础设施可以承受计算机崩溃、应用程序过载、网络流量冲击和用户错误。思考你的服务如何才能具有弹性,并从头开始相应地设计负载均衡策略。


via: https://opensource.com/article/21/4/load-balancing

作者:Seth Kenlon 选题:lujun9972 译者:FYJNEVERFOLLOWS 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出