0%

一、最早的Web服务器

最早的Web服务器简单地响应浏览器发来的HTTP静态文件请求,并将存储在服务器上的静态文件(例如: jpg、htm、html)返回给浏览器。如图是处理流程

比如我访问:http://www.example.com/index.html,那么网络服务器就会去对应目录中找到 index.html这个文件,并返回给浏览器。

二、CGI的出现

首先说明:CGI是一种协议

事物总是不断发展,网站也越来越复杂,所以出现动态技术。但是Web服务器并不能直接运行 php/asp 这样的文件,自己不能做,外包给别人吧,但是要与第三做个约定,我给你什么,然后你给我什么,就是我把请求参数发送给你,然后我接收你的处理结果再给客户端。这个约定就是 CGI协议(Common Gateway Interface),协议只是一个“规定、规则”,理论上用什么语言都能实现,比如用 vb/c/perl/php/python 来实现。

在2000年或更早的时候,CGI 比较盛行。那时,Perl 是编写 CGI 的主流语言,以至于一般的 CGI 程序(遵循 CGI 协议的程序)就是 Perl 程序(例如世界上80%的网站所采用的编程语言 php 语言刚开始的版本就是用Perl语言写的)。

CGI 是 “Common Gateway Interface” 的缩写,翻成中文叫“公共网关接口”,它是 web 服务器与外部应用程序(CGI 程序)之间传递信息的接口标准。通过 CGI 接口,web 服务器就能够获取客户端提交的信息,并转交给服务器端的 CGI 程序处理,最后返回结果给客户端。也就是说,CGI 实际上是一个接口标准。我们通常所说的 CGI 是指 CGI 程序,即实现了 CGI 接口标准的程序。只要某种语言具有标准输入、输出和环境变量,如 perl/PHP/C 等,就可以用来编写 CGI 程序。CGI 只是接口协议,根本不是什么语言。

阅读全文 »

Version

PHP version 7.4

问题呈现

最小化分析代码:

1
2
3
4
5
6
7
8
9
$data = ['foo', 'bar'];

foreach ($data as &$item) {
}

foreach ($data as $item) {
}

print_r($data);

输出结果:

1
2
3
4
5
Array
(
[0] => 'foo'
[1] => 'foo'
)

我们可以发现,$data的值莫名奇妙变了,而它只是经过了两个空循环而已,发生了什么?!

先总结一下 PHP 中两条关于引用的两个规则:

  • 给引用变量赋值,实际上是给引用所指向的变量赋值
  • 一个引用变量可以被修改为对另外一个变量的引用

下面我来一行行代码分析产生这个问题的原因:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$data = ['foo', 'bar'];

// 循环开始,$item 变量不存在,新建一个$item 变量,且是一个引用变量,它不指向任何变量地址
foreach ($data as &$item) {
// loop 1: 执行了 $item = &$data[0];$item 指向 $data[0] 的地址
// loop 2: 执行了 $item = &$data[1];$item 指向 $data[1] 的地址
}
// 提示:这个循环没有改变 $data 的数据,只是 $item 依然指向第二个元素 的地址

// 循环开始,$item 变量存在,不会新建变量
foreach ($data as $item) {
// loop 1: 执行了 $item = $data[0];$item 所指向的变量(即 第二个元素)的值被修改为$data[0](即'foo'),这里已经导致了$data 两个元素都等于 'foo'
// loop 2: 执行了 $item = $data[1];由于$item 指向的是$data[1],实际上相当于执行$data[1] = $data[1],没有任何意义
}
// 最后$data 中的两个元素都是 'foo'

如何避免这个问题1:

1
2
3
4
5
foreach ($data as &$item) {

// 每次 loop 销毁$item (实际上只要在最后一次 loop 销毁即可,因此你可以把 unset 写到 foreach 后面,就是不是很好看)
unset($item);
}

如何避免这个问题2:

不使用引用

Version

mysql version 8.0.13

事务隔离级别概述

mysql 中,InnoDB 所提供的事务符合 ACID 的要求,而事务通过事务日志中的 redo log 和 undo log 满足了原子性、一致性、持久性,事务还会通过锁机制满足隔离性,在 InnoDB 存储引擎中,有不同的隔离级别,它们有着不同的隔离性。

什么是事务的隔离级别?如果只是从概念上理解的话可能比较模糊,咱们直接看看不同隔离级别下的实际表现是什么样子的,再结合理论去理解,就会明了很多。首先,打开两个终端,同时连接到当前数据库,如下图所示,我们对两个回话进行编号,并且以颜色区分,1号会话使用黄色进行标识,2号会话使用红色进行标识。

两个会话使用相同的数据库。

两个会话中同时各自开启一个事务。

由于下面的所有操作会在两个会话中来回切换,所以,为了方便描述,我们为每个操作的顺序进行编号,例如下图中,我们先在会话1的事务1中执行了更新操作,然后在事务1中执行了查询操作,最后又在会话2中的事务2中执行了查询操作,按照操作顺序,为各个操作进行了顺序编号。

阅读全文 »

系统环境介绍

Win 10 2004
WSL2(Ubuntu 20.04)
Docker 19.03.13

启用 Linux 子系统

打开 控制面板 -> 程序 -> 启用或关闭Windows功能。找到适用于Linux的Windows子系统虚拟机平台,勾选这两项之后确定,并重新启动计算机。

切换系统 WSL 默认版本到 2

使用管理员用户打开 Windows PowerShell,运行:

1
wsl --set-default-version 2

注意,有可能会出现如下提示:

WSL 2 需要更新其内核组件。有关信息,请访问 https://aka.ms/wsl2kernel

出现这个提示,说明需要更新 WSL2 的内核。按照提示打开链接。点击下图中的下载链接,下载并安装 WSL2 内核。

阅读全文 »

背景

为了更好的说明几种算法,我们举个例子,下文就这个例子分别几种算法实现。

  • 如何限制每分钟访问 /api/books 接口不能超过 120 次 ?

我们先定义一个接口:

1
2
3
4
interface RateLimiter
{
public function access();
}

固定时间窗口算法

固定时间窗口算法又叫计数器算法,逻辑就是对固定时间段内的访问次数进行计数,如果计数结果超过次数限制,则拒绝访问。

固定时间窗口算法的劣势就在于其只关心时间段内的总访问次数,而忽略了瞬间集中请求的问题,换而言之,这种统计方法的粒度太粗了,然而我们无法保证请求在时间段内的分布是平均的。

举个例子,如果 A 用户访问接口的时间分布如下:

时间段 访问次数
00:00 ~ 00:30 20
00:30 ~ 01:00 100
01:00 ~ 01:30 100
01:30 ~ 02:00 20

显然在第一分钟,我们有 120 次请求,第二分钟也是 120 次请求,但是 00:30 ~ 01:30 这一分钟时间内,显然是请求书超过 120 次的,所以,这种情况虽然实现了需求,但是很勉强,粒度不够细。

阅读全文 »

简介

在命令行中是没有 redis pipeline 功能的,但 redis 是支持 pipeline 的,而且在各个语言版的 client 中都有相应的实现。

简单概括 redis pipeline 的功能就是将单次请求变为批量请求。

由于网络开销延迟,就算 redis server 端有很强的处理能力,也会由于收到的 client 消息少,而造成吞吐量小。当 client 使用 pipelining 发送命令时,redis server 会将请求放到队列中(使用内存),执行完毕后一次性发送结果。

Pipeline 在某些场景下非常有用,比如有多个 command 需要被“及时的”提交,而且他们对相应结果没有互相依赖,对结果响应也无需立即获得,那么 pipeline 就可以充当这种“批处理”的工具;而且在一定程度上,可以较大的提升性能,性能提升的原因主要是 TCP 连接中减少了“交互往返”的时间。

管道(pipeline)可以一次性发送多条命令并在执行完后一次性将结果返回,pipeline 通过减少客户端与 redis 的通信次数来实现降低往返延时时间,而且 Pipeline 实现的原理是队列,而队列的原理是时先进先出,这样就保证数据的顺序性。 Pipeline 的默认的同步的个数为 53 个,也就是说 arges 中累加到 53 条数据时会把数据提交。

需要注意到是用 pipeline 方式打包命令发送,redis 必须在处理完所有命令前先缓存起所有命令的处理结果。打包的命令越多,缓存消耗内存也越多。所以并不是打包的命令越多越好。具体多少合适需要根据具体情况测试。

适用场景

有些系统可能对可靠性要求很高,每次操作都需要立马知道这次操作是否成功,是否数据已经写进 redis 了,那这种场景就不适合。

还有的系统,可能是批量的将数据写入 redis,允许一定比例的写入失败,那么这种场景就可以使用了,比如 10000 条一下进入 redis,可能失败了 2 条无所谓,后期有补偿机制就行了,比如短信群发这种场景,如果一下群发 10000 条,按照第一种模式去实现,那这个请求过来,要很久才能给客户端响应,这个延迟就太长了,如果客户端请求设置了超时时间 5 秒,那肯定就抛出异常了,而且本身群发短信要求实时性也没那么高,这时候用 pipeline 最好了。

概述

概念: 可以一次执行多个命令,本质是一组命令的集合。一个事务中的所有命令都会序列化,按顺序地串行化执行而不会被其它命令插入,不许加塞。

Redis 部分支持事务,不支持的是:强一致性

能干嘛: 一个队列中,一次性、顺序性、排他性的执行一系列命令

常用命令:

  • MULTI:开启一个事务,MULTI 执行之后,客户端可以继续向服务器发送任意多条命令,这些命令不会立即被执行,而是被放到一个队列中。
  • EXEC:执行队列中所有的命令
  • DISCARD:清空事务队列,并放弃执行事务
  • UNWATCH:取消 WATCH 命令对所有 key 的监视
  • WATCH key1 key2 ... :监视一个(或多个) key ,如果在事务执行之前这个(或这些) key 被其他命令所改动,那么事务将被打断。

使用

正常执行:

阅读全文 »

Version

Hexo 5.2.0
NexT 8.0.1

这几天将博客主题从 NexT-7.7.0 升级到了 8.0.1,在重新安装插件的时候顺便记录了本博客当前使用的插件

鼠标点击特效

下面是四个比较常用的鼠标点击特效脚本,我们可以把它们放置在 source/js/cursor/ 目录下:

  • 礼花特效代码:
阅读全文 »

1、全局升级hexo-cli,先 hexo version 查看当前版本,然后 npm i hexo-cli -g,再次 hexo version 查看是否升级成功。

2、使用 npm install -g npm-checknpm-check,检查系统中的插件是否有升级的,可以看到自己前面都安装了那些插件

3、使用 npm install -g npm-upgradenpm-upgrade,升级系统中的插件

4、使用 npm update -g和npm update --save

PS:第四步遇到了错误,错误提示如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
> fsevents@1.2.11 install /Users/lanvnal/Files/blog/node_modules/hexo/node_modules/fsevents
> node-gyp rebuild

xcode-select: error: tool 'xcodebuild' requires Xcode, but active developer directory '/Library/Developer/CommandLineTools' is a command line tools instance

xcode-select: error: tool 'xcodebuild' requires Xcode, but active developer directory '/Library/Developer/CommandLineTools' is a command line tools instance

No receipt for 'com.apple.pkg.CLTools_Executables' found at '/'.

No receipt for 'com.apple.pkg.DeveloperToolsCLILeo' found at '/'.

No receipt for 'com.apple.pkg.DeveloperToolsCLI' found at '/'.
gyp: No Xcode or CLT version detected!

其实已经安装过了xcode cli,但是这里还是报错了,估计和苹果新系统有关,重装就好了,操作如下:

如果像以前一样执行 xcode-select --install 会有如下报错:

1
xcode-select: error: command line tools are already installed, use "Software Update" to install updates

解决办法:

1
2
sudo rm -rf /Library/Developer/CommandLineTools
xcode-select --install

原文链接:Hexo版本升级指南

如果 1G 内存要装 MySQL 5.7,这篇文章也是适用的。

宝塔 6.9.8

宝塔面板在编译安装 MySQL 8.0 时,要求 4个核心的 CPU,8G 内存,实在是太高了,小站长的服务器一般都不会有如此高的配置。这时候,我们要使用 MySQL 8.0,可以选择极速安装,或者,如果一定要自己编译的话,可以使用命令行来跳过配置检测。不过,MySQL 编译过程中,需要 5G 以上的内存,以及 9G 以上的数据盘空间。如果我们的内存实在不够,可以创建 swap 虚拟内存。

在宝塔面板里的 Linux 工具箱(如果没有可以去软件商店里面安装) 修改 Swap/虚拟内存,输入 0,然后手动设置 swap 到系统盘:

1
2
3
4
5
6
fallocate -l 4G /swap
chown root:root /swap
chmod 0600 /swap
mkswap /swap
swapon /swap
echo '/swap swap swap defaults 0 0' >> /etc/fstab

查看一下 swap 是否开启成功:

1
2
3
4
swapon -s

Filename Type Size Used Priority
/swap file 4194300 9480 -2

现在内存有 5933M,应该够了,我们还要检查一下,/www 所在的磁盘够不够,建议剩余空间不小于 10G。如果不够,把不需要的文件删一下,或者扩容磁盘,这里不赘述。

阅读全文 »