cURL基本使用

指定用户代理

1
2
# -A, --user-agent <name> Send User-Agent <name> to server
curl -A "Mozilla/5.0" http://localhost:8080/validation/basic

设置参照页(referer)

1
2
# -e, --referer <URL> Referrer URL
curl --referer http://google.com http://knopper.org

使用 cURL 进行认证

HTTP Basic 认证

  1. 使用 Authorization 头部
1
2
3
curl -H "Authorization: Basic Z3Vlc3Q6Z3Vlc3Q=" http://localhost:8080/validation/basic

# Authorization Success
  1. 使用 -u 完成 HTTP 或 FTP 认证
1
2
3
4
5
# curl -u user:pass
curl -u "guest:guest" http://localhost:8080/validation/basic

# 提示后输入密码
curl -u guest http://localhost:8080/validation/basic

只打印返回头部信息

1
2
3
curl -I http://localhost:8080/validation/basic

curl --head http://localhost:8080/validation/basic

打印响应头部信息

1
2
# -i, --include       Include protocol response headers in the output
curl -i http://localhost:8080/validation/basic

使用其他 HTTP 方法

1
2
#  -X, --request <command> Specify request command to use
curl -X DELETE http://upload.linuxhandbook.org/files/deleteFile.txt

发送数据到服务器

1
2
# -d, --data <data>   HTTP POST data
curl -i -X POST http://localhost:8080/addPerson -d '{"name":"Jason","age":26,"gender":"male","address"AVE.18"}' -H "Content-Type: application/json"
1
2
#  -c, --cookie-jar <filename> Write cookies to <filename> after operation
curl -c googleCookie.txt http://www.google.com/files

使用Cookie

1
2
3
4
5
6
7
#  -b, --cookie <data> Send cookies from string/file
# 从文件读取或者在命令行中指定

# 多个 cookie 使用分号分割
curl http://example.com --cookie "user=username;pass=hack"

curl -b googleCookie.txt http://www.google.com/files

开启新的会话(Session)

1
2
# -j, --junk-session-cookies Ignore session cookies read from file
curl -b googleCookie.txt http://www.google.com/files -j

Semaphore-信号量

Semaphore - 信号量

1. 什么是信号量

一个信号量是一个整数变量,在多个进程间进行共享. 信号量的主要目的在于 :

  • 处理同步问题
  • 并发环境下用于共享资源的访问控制

信号量的取值取决于遇到的具体问题,通常,会使用可用资源的个数作为信号量的初始值。

2. 信号量操作

信号量包含两个独立的原子操作,也就是 waitsignal. 也被称之为 P (荷兰语Proberen(测试)的首字母) 和 V 荷兰语Verhogen(增加)的首字母.

假设 S 表示一个信号量,他的整数值代表了某种可用资源的数量,那么 waitsignal 操作分表可用如下的伪代码表示

wait

image-20201201204409486

如果 S 的值大于 0,wait 操作会简单的进行减 1 操作,表示仍有资源可以用于分配;如果 S 已经是 0 , 表示没有可用的资源进行分配, 那么调用 wait 操作的进程会进入休眠(sleep)状态

signal

image-20201201204646050

如果没有其它进程等待资源, signal 操作会进行一个加 1 操作;否则,一个等待的进程会被唤醒(操作系统调度器),最终,唤醒的进程获得了资源的访问控制权限。

简单总结

wait: (把信号量减1),若成功,则退出;若失败,则该进程被阻塞;

signal:(把信号量加1),如果发现有被阻塞的进程,则选择一个唤醒之。

3. 信号量的种类

  • Binary Semphore - 二元信号量

    二元信号量的取值只能是 0 或 1, 可以实现互斥的效果(mutex), 可以用来解决临界区(critial section)问题。

binary semphore is not a mutex ?

  • Counting Semphore - 计数信号量

    计数信号量的取值域是不受限制的,可以用来解决资源分配的同步问题。

信号量的实现,通常需要一个整数值来保存信号量的值,以及一个指针指向等待队列中下一个要执行的进程,同时要避免死锁(deadlock)和饥饿 (starvation)

死锁的情况

image-20201201214736878

进程 0 执行了 wait(S) 操作,然后进程被打断,进程 1 开始执行 wait(Q) 操作后,就开始等待信号量 S, 会被阻塞,然后进入休眠状态,当内核开始执行进程 0 时,信号量 Q 已经被使用,所以两个进程互相等待对方的情况,出现了死锁

如何解决 ?

4. 使用信号量的例子

临界区问题

临界区(critical section)是指代码的一部分,必须避免并发访问。 这时,可以使用一个二元信号量来解决这个问题,信号量的值初始化为 1. 保证互斥的执行临界区代码,一旦 signal 操作,内核会将休眠的进程添加到就绪队列,等待内核执行该进程时,就可以继续执行临界的代码。确保在任何时刻,临界区的代码只有一个和进程在执行

image-20201201215432904

以顺序执行

假设要执行代码片段 S1 和 S2 ,但是要求 S1 先执行, S2 后执行

image-20201201220621412

使用一个初始值为 0 的信号量就可以解决这个问题:

image-20201201220908667

生产者/消费者问题

在这个问题中,生产者往缓冲区中生产物品,消费中从缓冲区中拿出来消费,他们分别对应 Producer 进程和 Consumer 进程,这是,使用一个信号量 S 代表换取中的物品个数,初始化为 0.

image-20201201222814601

缓冲区满了,生产者应该停止生产,进入休眠状态,缓冲区空闲了,谁来通知 Producer 进程呢?

使用三个信号量:

empty: 表示缓冲区中剩余空间大小,初始化为缓冲区的大小

full:表示缓冲区中已用空间大小,初始化为 0

S 用来保护缓冲区同时只能被一个进程访问, 初始化 1

![image-20201201223208708](D:\Markdown 目录\Markdown 文档\工作\Java\img-assets\image-20201201223208708.png)·

生产者

如果 empty 信号量变为 0 ,生产者进入休眠状态;否则往缓冲区里进行生产,然后通知 full 信号量,因此会触发唤醒任何可能等待的消费者

消费者

如果 full 信号量变为 0 ,消费者进入休眠状态,否则从缓冲区中取出物品,并通知 empty 信号量,因此会触发唤醒任何需要进程生成的生成者

除非缓冲区中还有空间,否则生产者进入休眠状态;除非缓冲区中还有元素,否则消费者进入休眠状态

还有很多案例,包括哲学家吃饭问题,同一数据集上的读写问题….

工作中的例子

参考文献

[1] What is a Semaphore

[2] 哲学家进餐问题

[3] PV操作

新词汇

login shell

The goal here is to separate the users having a login shell from the others:

1
2
3
4
5
6
7
cat -n inputfile | sed -En -e '
\=(/usr/sbin/nologin|/bin/false)$= { H;d; }
# Append matching lines to the hold buffer
# and continue to next cycle
p # Print other lines
$ { g;p } # On the last line,
# get and print the content of the hold buffer

What is a login shell ?

减少 Redis 中的内存使用

减少 Redis 中的内存使用

Short structures 使用更短的结构

Redis stores a serialized version of the data, which must be decoded for every read, partially re-encoded for every write, and may require moving data around in memory.

Sharded structures 分片的数据结构

Packing bits and bytes 更紧凑的位和字节

社交网站的所有用户都有位置信息,如何在 Redis 中使用更少的内存存储每一个用户的未知信息?而且要能够方便的进行聚合计算

假设用户的 ID 都是连续的数组,且只存储国家,区域/州/省信息两级信息;并使用 ISO3 中的国家代码,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
# 国家代码
COUNTRIES = '''
ABW AFG AGO AIA ALA ALB AND ARE ARG ARM ASM ATA ATF ATG AUS AUT AZE BDI
BEL BEN BES BFA BGD BGR BHR BHS BIH BLM BLR BLZ BMU BOL BRA BRB BRN BTN
'''.splt()

# 美国,加拿大州信息
STATES = {
'CAN':'''AB BC MB NB NL NS NT NU ON PE QC SK YT'''.split(),
'USA':'''AA AE AK AL AP AR AS AZ CA CO CT DC DE FL FM GA GU HI IA ID
IL IN KS KY LA MA MD ME MH MI MN MO MP MS MT NC ND NE NH NJ NM NV NY OH
OK OR PA PR PW RI SC SD TN TX UT VA VI VT WA WI WV WY'''.split(),
}

最直接的方法是直接以字符串的方式直接存储国家和州代码,每个国家代码至少 3 个字节,州信息至少 2 个字节;

解决方法:以分片的形式存储定长大小的数据

实际存储的时候,并不存储实际的国家和州代码,而只存储其在 “表”(数组) 中的索引代表的字符,这样,只用两个字节就可以存储国家和州信息了(数组长度不会超过单个字节的十进制数字表示)。

image-20201018210437144

1
2
3
4
5
6
7
8
9
10
11
12
13
14
def get_code(country, state):
cindex = bisect.bisect_left(COUNTRIES, country)
if cindex > len(COUNTRIES) or COUNTRIES[cindex] != country:
cindex = -1
cindex += 1

sindex = -1
if state and country in STATES:
states = STATES[country]
sindex = bisect.bisect_left(states, state)
if sindex > len(states) or states[sindex] != state:
sindex = -1
sindex += 1)
return chr(cindex) + chr(sindex)

Redis 中 STRING 结构的值大小限制为 512 MB, 所有用户的信息存储在单个 STRING 的值中必然不可取, 通过进行分片,限制每个分片最多存储 2 百万个用户的位置信息,单个 Key 的值占用大概在 2 MB. 通过 SETRANGE, GETRANGE 命令就可以更新和获取单个用户的位置信息

这里没有限制分片的个数,只限制了每个分片的大小,考虑的是用户 ID 都是有序的,通过 ID 和每个分片的大小,就可以计算每个 ID 所属的分片, 以及分片内的偏移量;为了知道当前一共由多少分片,就要存储当前的最大用户 ID.

这样进行存储,要对这些信息进行聚合计算,比如统计所有用户的国家,州分布,就比较容易,遍历所有分片进行统计,当然由于每个分片 STRING 的值比较大,需要分批多次去读取,而不能直接去读取,会阻塞其它客户端

image-20201018211551176

image-20201018211628124

这里虽然使用的是多个字节存储的,但是某些情况下,GETBIT, SETBIT 命令来获取和设置单个二进制位可能更高效,更节省空间。存储 Boolean 型?

存储数据在 Redis 中的方式,会极大地影响所使用地内存。