Nginx优化

参考:https://www.nginx.com/blog/tuning-nginx/ nginx一般用作高性能反向代理。在http七层代理的情况下,它首先接收客户端请求,经过处理后再请求upstream server,因此nginx服务器上的连接数是客户端请求数的2倍,在高并发情况下,建立的连接数非常多,因此系统相关资源如打开文件数、tcp连接、可分配端口等很可能称为其瓶颈。可以从系统内核参数及nginx自身做一些优化。下面提到的相关参数按需调整。 相关内核参数 tcp连接队列调整 在内核中,为tcp连接维护了两个队列。一个是已经建立了连接的accept队列,这时候连接三次握手已经完毕,处于 established 状态;一个是还没有完全建立连接的队列,这个时候三次握手还没完成,处于 syn_rcvd 的状态。过程如下: 当server接收到client的 SYN 报⽂时,会将其加⼊到内核的SYN半连接队列 接着发送SYN+ACK给client,等待client回应ACK报⽂,client收到此包后connect()调用返回,进入establish状态 server接收到ACK报⽂后,把此连接从SYN队列移除并放⼊到Accept队列 此时server端应⽤调⽤accpet() socket接⼝从Accept 队列取出连接用于数据通信 如何查看这两个队列情况? 全连接查看:ss -ant 半连接查看:ss -ant | grep -i syn_recv | wc -l LISTEN: Recv-Q 表示当前socket完成三次握手等待用户进程(此处即nginx)accept的连接个数,即全连接队列使用量。一般我们常常看到此值为0,没有堆积 Send-Q 表示当前socket全连接队列最大长度 非LISTEN: Recv-Q 表示receive queue中已收到未读取的字节大小 Send-Q 表示send queue中已发送未收到确认的字节大小 队列满了的情况 半连接满 此时会发生syn包被丢弃的现象,因而客户端会重试,性能下降。可能是syn攻击导致 1 2 $ netstat -s | grep -i syn 612 SYNs to LISTEN sockets dropped 全连接满 并发量大,server端accept()调用过慢时出现,可能由于服务器负载、应用程序本身等问题导致。 满了后新的连接直接丢弃或者回复reset包,此行为由内核参数tcp_abort_on_overflow控制(为0直接丢弃,为1回reset包),且内核socket统计信息里面listen overflowed数加1。 1 2 $ netstat -s | grep -i overflow 612 times the listen queue of a socket overflowed 调优上可以适当增大全连接和半连接队列...

August 2, 2020 · 2 min · 228 words · erpan

bash中alias不生效

alias不生效 在修改一段shell脚本时,需要将函数里面的kubectl命令替换为kubectl --insecure-skip-tls-verify=True,使得脚本中的所有kubectl命令执行时会自动加上选项--insecure-skip-tls-verify=True。首先想到的就是利用alias别名,示例如下: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 function func1(){ ... kubectl get deployment -n ${NAMESPACE} ${CI_PROJECT_NAME} # 不生效 ... } ... function main(){ ... alias kubectl="kubectl --insecure-skip-tls-verify=True" kubectl get ns # 不生效 ... } 但是用上面方式改来改去kubectl选项不生效。 原因是:alias不能直接在同一个命令解析单元里面定义并使用,必须在定义alias的命令解析单元解析执行完成后,才能生效。 因此,在函数里面使用alias时,可以用下面函数的方式: 1 2 3 4 function main(){ kubectl() { /usr/bin/kubectl --insecure-skip-tls-verify=True "$@"; } kubectl get ns # 此处等同于kubectl加了--insecure-skip-tls-verify=True选项 } 当然也可以把alias放在函数外、脚本的前面。 命令解析单元 解析单元就是一组完整的命令(包括组合命令、循环等)后面跟上换行符。 shellcheck项目的示例: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 # 单个命令跟换行,一个解析单元 unit 1 # 俩命令在同一解析单元,之间无换行 unit 2; unit 2; # 大括号的同一个解析单元 { unit 3 unit 3 } # 也是同一个解析单元,在大括号组之间无换行 { unit 4 }; { unit 4 } 上面示例中,unit1中定义的别名,只能在unit2及后面才能使用。...

June 12, 2020 · 1 min · 117 words · erpan

读redis-py客户端源码

前言 看别人的代码也是对自己思维和经验的学习丰富过程 作为一个初学者,之前写过的代码量较少,很少涉及到完整的项目开发,看完redis-py库后,get到其中的 连接保活机制 连接池的实现 开辟buffer存入从socket接收来的数据及buffer管理 熟悉了RESP协议 多进程多线程的情况下,利用锁确保连接池数据结构安全 我读的过程中觉得值得注意的是,_in_use_connections使用集合结构;此连接池不是在初始化时创建好一定数量的tcp连接;其中用了两个互斥锁,一个保护连接池,一个保护多进程的池;较多的连接重连,确保连接可用 执行过程 该库主要有Redis、Connection、ConnectionPool、PythonParse、SocketBuffer几个类,下面大概理了一下redis-py的执行过程 开始使用redis-py客户端 class Redis实例化 可以关注下面几个参数: socket_timeout=None, socket_connect_timeout=None, socket_keepalive=None, socket_keepalive_options=None, connection_pool=None, retry_on_timeout=False, max_connections=None, single_connection_client=False, # 是否单个连接,不用连接池 health_check_interval=0, class ConnectionPool连接池初始化ConnectionPool(),此时尚未创建连接 # 此处定义连接池最大连接数 max_connections = max_connections or 2 ** 31 # fork_safe,在_checkpid()方法中用到,保护临界区的锁。这个锁是在进程id改变时获得的。比如fork出一个子进程后,子进程id和池对象中保存的id不一致,那么子进程中的多个线程都可能会先获取此锁,第一个获得锁的线程将重置此池的数据结构并最终释放锁对象,后续的线程再执行时,pid已于子线程池中的pid熟悉一致,不再做其他操作,在下面也会有提到 self._fork_lock = threading.Lock() # 定义了并初始化已创建连接数、使用中的链接、可用的连接等数据结构 self._lock = threading.Lock() self._created_connections = 0 self._available_connections = [] self._in_use_connections = set() 注意此处_in_use_connections使用了集合存储池中的连接对象,这个与python数据类型时间复杂度有关,可点此参考官网,集合的内部实现与字典极为相似,此集合对象只用到两个操作,add和remove,时间复杂度均为O(1),(有误烦请指正🤡🤡🤡) 初始化Redis-Client状态信息完毕,此时还没有任何连接被创建 假设开始执行 r.set('foo', 'baiqi'),此方法返回r.excute_command()的结果 首先尝试从池中获取一个Connection对象 pool.get_connection(command_name, **options) 获取时得先执行下_checkpid()方法,再执行get_connection() 在现代操作系统下保证ConnectionPool fork-safe,连接池的所有方法都会先调用此方法再来操纵连接池的状态。如果当前pid和池对象中保存的pid不一致,可以假设当前进程是fork出来的子进程,子进程不能用父进程的文件描述符(比如sockets),因此它会继续调用self.reset()方法重新初始化当前进程的连接池;如果pids都一致那么直接pass。 而self._fork_lock就是确保了在子进程中的多个线程不会多次执行self.reset()方法。因为在子进程中,第一个调用_checkpid的线程调用了reset()方法使得self.pid置为当前子进程的id。 从池中获取连接时加锁保护,如果池中_available_connections.pop()没有连接,那么开始创建连接make_connection(),并将此连接加入到池的已使用连接集合中,即self._in_use_connections集合 创建连接时得先确认下连接数是不是超过了最大连接数配置,没有则继续创建,返回Connection对象。所以这里的tcp连接数不是在应用一初始化就按照池配置中的连接数来直接一次性创建好多少个连接...

March 6, 2020 · 1 min · 208 words · erpan

Jenkins Pipeline初体验

使用jenkins pipeline共享库,各应用都可以引用共享库方法,更改共享库即可应用到所有使用此库的jenkins-job。我目前没有用到vars目录,但完全能够满足我们日常需求,使用方式上可能较low,直接开始体验。 下面列出了定义的部分方法,以作参考。 共享库目录结构: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 jenkins-pipeline-libraries git:(master) ✗ tree . . ├── jenkins-ci │ └── jenkinsfile-java ├── out │ └── production ├── src │ ├── ops │ │ └── jk │ │ ├── appDetail.groovy │ │ └── tools.groovy │ └── pipeline.gdsl └── vars └── pipelineCfg.groovy 7 directories, 6 files appDetail.groovy文件里面部分函数如下: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 // 获取时间 格式:20201208200419 def getTime() { return new Date()....

January 12, 2020 · 6 min · 1266 words · erpan

vim 常用操作及配置

vim常用操作汇总 光标移动 上下左右 k/j/h/l 行首 0 或者 ^ 行尾 $ 单词和字符串间移动 指令 动作 w/W 正向移动到下一个单词开头,大写的忽略特殊字符、符号等 b/B 和w相对应的反向移动,移动到上一个单词开头 e/E 正向移动到下一个单词结尾 ge 反向移动 {num+} f/F+空格 正向/反向移动到本行空格的地方,num相当于移动几次 跳转 指令 动作 ctrl+f 向下翻页 ctrl+b 向上翻页 ctrl+d/u 向下/向上翻半页 gg 文件行首 G 最后一行 行号+gg/G 都是跳到指定行号的行 g+ctrl+g/G 查看光标位置,输出包含行、列、词、字节位置 缩进操作符 指令 动作 » 和 « 或者 :> 和 :< 当前行右缩进和左缩进,后者命令行模式 :line_num1,line_num1+x> 或者 :line_num>x 命令行模式,批量缩进,缩进x行 复制粘贴 复制剪贴内容存于寄存器, :reg可以查看寄存器内容 指令 动作 yy / 8yy 复制/8行 dd / 8dd 剪贴/8行 p/P 粘贴到光标前/后 u 撤销 ctrl+r 重做 yw 复制当前光标单词 y8w / y8W 复制含当前光标的正向8个单词,大写W的含义和W移动含义相同(忽略一些符号) x/4x/X 剪贴单个字符/4个字符,大写就是反向 d{w/h/j/k/l} 可以各种组合 d$/D 删除光标到行尾 d^ 删除光标到行首 插入、查找、替换 插入 指令 动作 I/A i/a 行首、行尾插入,向前向后插入 o/O 下一行、上一行插入 num + (i/I/A/a/o/O) 多次插入,即重复插入多个字符或者多行 转换 指令 动作 ~ 单个字符大小写转换 g~w 单词大小写反转 g~$ 或 g~~ 整行大小写反转 gU或gu + 回车 整行转大写或小写 gU/uw 单词转大写或小写,转换光标到词尾的部分 ’....

June 20, 2019 · 4 min · 704 words · erpan