作者归档:mzh

Python标准库小窥[2]: memoryview

要讲memoryview,就要讲它的主要应用场合—-缓冲区(buffer)
要讲buffer前就要讲讲Python的字符处理:Python中的字符是不能修改的 例如
当你需要收集从socket.recv上来的代码时,大部分的人都选择了拼接字符串

while not self.sock.closed:
data = ''
while len(data) < 1024:
d = self.sock.recv(12)
if not d: return;
data += d

殊不知,由于Python字符串的特点,这实际上是将data复制一份,然后于d进行拼接,然后再赋值给data。
当字符大小有1M左右的时候,这种复制的效率会下降10%左右(其他大小没有测试过,但是应该是字符越大,复制的效率就越低,毕竟要重新分配内存区域并填满是很费事的)
而且网络传输有个特点,就是客户端想传多大都可以,所以就会出现只传输部分数据的情况,这时,socket.recv循环次数增多,导致字符缓冲区复制的操作次数增多。
所以,对于已知缓冲区大小下,可以先分配大小的缓冲区,然后依次写入相应数据即可(不需要复制了)。 改装上面的栗子,我们假定已知缓冲区应该有1KB

buf = bytearray(1024)
mv = memoryview(buf)
i = 0
while i < 1024:
i = self.sock.recv_into(mv)
if not i: return; # remote closed
if i < 1024:
mv = mv[i:1024]
i += i

即可

OpenSSL TLS cipher性能横向对比

使用的是Python的SSL/TLS库(反正也是用OpenSSL的)

  • Ubuntu 14.10 Python 2.7.8/Gevent 1.0.1
  • OpenSSl 1.0.1j
  • CPU: 双核I5
  • 内存:4G
  • 网络:1000Mbps网卡
  • 没有使用特殊的加速硬件

  • 交换算法:ECDSA虐哭了RSA
  • 加密算法:
    • RC4-MD5完胜其他(但是不安全),
    • DES系的性能集体阵亡
    • AES还是有不错的性能

详情就看图吧(数值越低越好)

屏幕快照 2014-11-23 21.28.45

加密传输次数增加 对于 总完成时间影响

屏幕快照 2014-11-28 21.58.43

加密数据总量增加 对于 总完成时间影响

屏幕快照 2014-11-28 21.59.08

并发数 对于 总完成时间影响

[具体数据表格在这里](https://docs.google.com/spreadsheets/d/1kvt8NOHFZR0yNhl9pUxm-
Lgn5EnHVmRBTvYQGCHTcso/edit?usp=sharing)

OpenSSL 笔记

2014-11-17

准备知识
  • 私钥/公钥签名算法 之后要说的RSA、ECC(椭圆曲线加密算法)都是其中的一种。
  • 迪菲-赫尔曼密钥交换 简写就是DH
  • ECDH 椭圆曲线DH 使用椭圆曲线签名算法用来进行密钥交换
  • SHA 1-N 、MD5 都是摘要算法,运算出的值进行校验
  • AES DES 3DES RC4 都是加密算法,用来加密传输用的数据

所以ECDH-ECDSA-AES256-GCM-SHA384 意思是: 使用ECDH协议交换以ECDSA为加密算法的公钥,
AES256-GCM加密算法加密传输数据 SHA算法384位强度进行校验

证书制作流程

一般流程是:

  1. 生成自己的私钥
  2. 用私钥生成csr(Certificate Signing Request 验证签名申请)
  3. 将csr提交CA(Certificate authority 验证管理局)
  4. CA发回一个crt(Certificate 验证文件)
  5. 将CA发回的crt和CA公开的crt进行叠加(先后顺序不能颠倒)
  6. 在应用程序中设置keyfile为自己的私钥
  7. 在应用程序中设置certfile为叠加后的crt文件

+-----+ +-----+
| You | | CA |
+-----+ +-----+
-------------------------------\ | |
| Generate private key and CSR |-| |
|------------------------------| | |
| |
| give CSR |
|------------>|
| | ------------\
| |-| check CSR |
| | |-----------|
| |
| give CRT |
|< ------------|
-------------------------------\ | |
| Set your CRT and private key |-| |
|------------------------------| | |
| |

自签名流程:

  1. 生成自己的私钥
  2. 用自己的私钥生成CA crt
  3. 如果需要自签署其他csr,需要执行命令
命令cheatsheat

生成RSA私钥:

openssl genrsa -out myrsa.key 2048

解释: genrsa (generate rsa), 2048是位数 生成ECC私钥:

openssl ecparam -name secp256k1 -genkey -noout -out myecdsa.private.key

解释: secp256k1是曲线的名称 可以用openssl ecparam -list_curves找想要的曲线 生成csr文件:

openssl req -new -sha256 -key [私钥地址] -out [想要csr的地址]

解释: sha256是之前说的摘要算法,默认的sha1已经不再安全了 生成自签名crt文件:

openssl req -new -nodes -x509 -key [私钥地址] -out [想要的crt的地址] -days [想要的天数]

自签名csr文件:

openssl x509 -req -in [CSR地址] -signkey [签署用的私钥] -out [想要的CRT地址] -days [想要的天数]

验证签名文件信息:

openssl x509 -in [CRT文件] -text -noout

如何正确发送Email—SPF,DKIM介绍与配置

对很多管理员来说,添加邮件服务无非就是安装个exim4.就能用了.殊不知,其实现代的邮件为了防止垃圾邮件,已经走得太远太远了.
搜索中文圈,压根没有相关资料,这里我就当抛砖了.

SPF

全名Sender Policy Framework,用来鉴别发送邮件的服务器或者IP,是否为该域允许的范围。
这需要在发送邮件的域名下添加一条TXT记录,举个例子: example.net. TXT "v=spf1 mx a:pluto.example.net include:aspmx.googlemail.com -all" v=spf1做开头为必须,spf1说明这是第一版spf协议 SPF规定有6种机制:

  • ALL 匹配所有的结果,一般放在最后
  • A 匹配所有该域的A记录
  • MX 匹配所有该域的MX记录
  • IP4 所有之后的IPv4地址,可以用mask匹配多项,比如:192.168.0.0/24
  • IP6 所有之后的IPv6地址,同IPv4
  • INCLUDE 去之后对应地址查找,比如INCLUDE:spf.34nm.com,就是去spf.34nm.com继续查找TXT/SPF记录

还有四种修饰符分别意义是:

  • +":允许,默认记录都是允许
  • -":不允许
  • ~":中立,也就是没有相关策略
  • ?":同样是中立,但是为debug

这样例子中 example.net. TXT "v=spf1 mx a:pluto.example.net include:aspmx.googlemail.com -all" 的意思是

mx 允许所有MX记录
a:pluto.example.net pluto.example.net的A记录也允许
include:aspmx.googlemail.com 其余记录参考aspmx.googlemail.com
-all 拒绝所有其他记录

DKIM

由于SPF天生只验证是否可以发信, 不保证这个发信人是验证的,因此,SPF验证通过的仍然可能是伪造的邮件. 这就需要DKIM来进一步保证这封邮件不是伪造的.
在特殊的子域名”_domainkey”(例如:_domainkey.example.com)的TXT记录中插入一对RSA密钥中的公钥,
而RSA的私钥用来加密邮件的部分字段. 收到邮件的服务器发现有DKIM-SIGNATURE字段时,会自动校验DKIM的公钥, 按照匹配程度进行处理.
这样就完成了验证.

+---------------+ +-----------------+
| SenderServer | | ReceiverServer |
+---------------+ +-----------------+
| -----------------\ |
|-| Calculate DKIM | |
| |----------------| |
| |
| Send singed mail |
|--------------------------->|
| |
| Check DKIM record |
|< ---------------------------|
| | ---------------------------\
| |-| OK, found key and verify |
| | |--------------------------|
| |

还可以在特殊子域名之上,再建立一堆域名,例如authmail._domainkey.example.com,这样在校验邮件时还可以选择不同的密钥.
协议的内容相对来说就简单很多了,只有三种值:

  • v=DKIM1; 使用DKIM第一版协议
  • k=rsa; 使用RSA加密
  • p=长长的一段公钥

DMARC

该验证的都验证了,还有个DMARC是干吗的呢? 这是为了给域名邮件的拥有者报告垃圾邮件的状况而设定的规则.
和之前的方法一样,在_dmarc.example.com下面设定自己的DMARC规则, 具体就参考Google 提供的文档 吧.

https://support.google.com/a/answer/2466580?hl=zh-Hans&amp;ref_topic=2759254

Linux下Redis内存优化

最近使用Redis,由于它属于内存数据库,所以调优都集中到了内存上。
根据Redis官方说法

  • 需要将vm.overcommit设置为1

    sysctl vm.overcommit_memory=1
    
  • 确保设置了一定量的swap,最好和内存一样大,否则内核的OOM(out-of-memory)killer会干掉Redis进程

  • 若Redis是大量写入的应用,持久化的RDB或者AOF会按比例使用,或很有可能使用redis使用量的一样多的内存.

使用和Redis一样多的内存做持久化,那我岂不是都得让一半的内存出来给它? 还有那个overcommit是几个意思也不解释一样?搞砸了其他进程肿么办?
好吧,得研究一下内存是如何管理的:
内核会将物理内存分割成动态虚拟的内存页(page),然后在malloc时按overcommit_memory和overcommit_ratio的设置来确定是否允许分配虚拟内存页。
翻看Linux Kernel的文档/资料才发现,有三种值:

  • overcommit_memory=0,默认,智能超发,每次要求分配内存时,kernel都会比较请求的空间和空余的空间是否足以分配
  • overcommit_memory=1,请求分配内存时,永远假装还有足够的内存
  • overcommit_memory=2,不允许超发内存,即允许分配的大小小于
overcommit_ratio*物理内存+swap大小

好吧,Redis要大家假装还有空余内存…也就是说会有很大的几率触发Swap造成性能急剧下降,不过,性能下降总比不能用好
说到swap,大家肯定给Redis服务器设定过swappiness=0,然后祈祷奇迹的发生,但是还是触发了swap。 为什么呢?
首先,Linux十分注重读写性能,尽量避免磁盘IO,你从磁盘上读取的文件会被放入内存,就算程序结束了,还是存在的,这部分内存被称为file
buffer(或者file page),是swap重点照顾的回收对象。 其次,Linux上的用户态进程所有页(也就是redis运行时占用的)也是可以回收的。
其实,swap的触发机制是这样的: 根据swap倾向(swap_tendency)决定回收用户态页还是file
buffer,最后把LRU队列中用得最少的放入swap空间中。
摘自LWN
以下是内核计算其 “swap倾向"的公式:

swap_tendency = mapped_ratio/2 + distress + vm_swappiness

其中:

  • distress 值是内核在释放内存时遇到的问题数。当内核第一次决定收回内存页面时, distress将为0;尝试次数越多,这个值也越大。

  • mapped_ratio值是mapped page与总page比例,即

    mapped ratio = (nr mapped * 100) / total memory
    

nr_mapped可以从下面的命令行获得

 grep nr_mapped /proc/vmstat
  • vm_swappiness 就是大家设定的swappniness值

当swap_tendency超过100时,swap就开始收集最近较少用的页。 而且swappiness设置为0,PRFA就不会回收用户态页,
设置为100时,总是回收用户态页,当然这不是我们想看到的。 最后回到之前的问题,怎么避免触发swap?
其实调整好swapiness之后,只需要监测/proc/zoneinfo中的pages free/high
之间的差值即可,high是当前zone中计算出来的高水位值,当pages free低于pages high才会触发swap回收页,就是这么简单啦~
实在担心的话可以用

redis-server --test-memory 需要测试的内存(MB)

测试一下,系统就会在给定的内存下跑测试。