sqlite3数据库命令及数据库导入导出

1.  sqlite3 dbName.sqlite3  加载数据库,不存载就创建

2.  .help  帮助详解

    

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
sqlite> .help
.backup ?DBFILE      Backup DB (default "main") to FILE
.bail ON|OFF           Stop after hitting an error.  Default OFF
.databases             List names and files of attached databases
.dump ?TABLE? ...      Dump the database in an SQL text format
                         If TABLE specified, only dump tables matching
                         LIKE pattern TABLE.
.echo ON|OFF           Turn command echo on or off
.exit                  Exit this program
.explain ?ON|OFF?      Turn output mode suitable for EXPLAIN on or off.
                         With no args, it turns EXPLAIN on.
.header(s) ON|OFF      Turn display of headers on or off
.help                  Show this message
.import FILE TABLE     Import data from FILE into TABLE
.indices ?TABLE?       Show names of all indices
                         If TABLE specified, only show indices for tables
                         matching LIKE pattern TABLE.
.load FILE ?ENTRY?     Load an extension library
.log FILE|off          Turn logging on or off.  FILE can be stderr/stdout
.mode MODE ?TABLE?     Set output mode where MODE is one of:
                         csv      Comma-separated values
                         column   Left-aligned columns.  (See .width)
                         html     HTML <table> code
                         insert   SQL insert statements for TABLE
                         line     One value per line
                         list     Values delimited by .separator string
                         tabs     Tab-separated values
                         tcl      TCL list elements
.nullvalue STRING      Print STRING in place of NULL values
.output FILENAME       Send output to FILENAME
.output stdout         Send output to the screen
.prompt MAIN CONTINUE  Replace the standard prompts
.quit                  Exit this program
.read FILENAME         Execute SQL in FILENAME
.restore ?DBFILE     Restore content of DB (default "main") from FILE
.schema ?TABLE?        Show the CREATE statements
                         If TABLE specified, only show tables matching
                         LIKE pattern TABLE.
.separator STRING      Change separator used by output mode and .import
.show                  Show the current values for various settings
.stats ON|OFF          Turn stats on or off
.tables ?TABLE?        List names of tables
                         If TABLE specified, only list tables matching
                         LIKE pattern TABLE.
.timeout MS            Try opening locked tables for MS milliseconds
.width NUM1 NUM2 ...   Set column widths for "column" mode
.timer ON|OFF          Turn the CPU timer measurement on or off

3. 应用截图

加载

root@ubuntu:~/workspace/SVN_AUTH/db# sqlite3 development.sqlite3
SQLite version 3.7.2
Enter ".help" for instructions
Enter SQL statements terminated with a ";"

显示数据库

1
2
3
4
sqlite> .databases
seq  name             file                                                     
---  ---------------  ----------------------------------------------------------
0    main             /root/workspace/SVN_AUTH/db/development.sqlite3          

显示表

sqlite> .tables
applies            logs               repositories       users           
deps               permits            schema_migrations

显示表的内容

sqlite> .head on  #显示表头
sqlite> select * from users;
id|name|brief|group|dep_id|created_at|updated_at
1|3B-7-1-16  刘文民|liuwm|superadmin||2011-08-08 08:11:37.283136|2011-08-08 08:11:37.283136
3|3D-1-01  贾延平|jiayp|admin||2011-08-08 08:19:51.745947|2011-08-08 08:19:51.745947
4|3B-7-1-11 杜宏伟|duhw|||2011-08-08 08:33:51.496746|2011-08-08 08:33:51.496746
5|3B-2-14  苑辰|yuanc-a|emplooyee||2011-08-08 08:52:03.229173|2011-08-08 08:52:03.229173
6|3B-2-16  周四维|zhousw|||2011-08-08 08:54:21.134175|2011-08-08 08:54:21.134175
7|3B-2-12  施晟|shis|||2011-08-08 08:56:01.234077|2011-08-08 08:56:01.234077

显示创建表的脚本(不跟参数显示所有的)


sqlite的数据导入 导出

数据导入的来源可以是其他应用程序的输出,也可以是指定的文本文件,这里采用指定的文本文件。



   1. 首先,确定导入的数据源,这里是待导入的,按固定格式的文本文件。

   2. 然后,依照导入的文件格式,确定想导入的目标数据表,这个数据表如果没有,可以依照待导入的文本文件格式,创建一个相对应的数据表。

   3. 最后,执行.import命令,将文本文件中数据导入数据表中。





1. 数据源



   在/home/ywx/yu/sqlite/下,创建一个名为data.txt的文本文件,并输入以下数据,数据之间采用逗号隔开

  1. id,name,age,address,hobby

  2. 1,tom,24,beijing,football
  3. 2,liu,27,heibei,fotball
  4. 3,jim,26,shandong,football
  5. 4,han,28,beijing,football
  6. 5,meng,25,beijing,tennis

 

2. 目标数据表

    这里创建一张目标数据表,通过分析文本格式,这里需要3个字段,分别是id,name,age。但在数据类型选择时存在一个问题,id和age在文本文件中是按字符型存储的,而其实际在数据表中,最好要表示成整型,因此这里要涉及到一个字符型数据类型向整型数据类型转换的问题。

    在创建表时,将id和age的类型定义为整型,进行强制转换,如果在数据导入时,发现转换失败,可以将id和age类型改为文本型。



  1. ywx@ywx:~/yu/sqlite$ sqlite3 test.db

  2. SQLite version 3.7.7.1 20110628 17:39:05
  3. Enter “.help” for instructions
  4. Enter SQL statements terminated with a “;”
  5. sqlite> create table data_txt_table(id char(10),name char(10),age char(10),address varchar(15),hobby varchar (15));
  6. sqlite>



3. 导入命令



  1. sqlite> .separator “,” 

  2. sqlite> .import data.txt data_txt_table
  3. sqlite> select * from data_txt_table;
  4. id,name,age,address,hobby
  5. 1,tom,24,beijing,football
  6. 2,liu,27,heibei,fotball
  7. 3,jim,26,shandong,football
  8. 4,han,28,beijing,football
  9. 5,meng,25,beijing,tennis
  10. sqlite>



   这里需要注意一点,在数据导入之前,先要根据数据的具体分的格式,设置数据导入的间隔符,例如在文本数据中采用的是‘,’来间隔数据,因此应先调用.seperator 设置‘,’ 为间隔符。





2. 查看命令

  

  .schema 命令来查看指定的数据表的结构

  1. sqlite> .schema data_txt_table

  2. CREATE TABLE data_txt_table(id char(10),name char(10),age char(10),address varchar(15),hobby varchar (15));
  3. sqlite>



2. .tables 命令用来查看当前数据库的所有数据表



  1. sqlite> .tables

  2. data_txt_table
  3. sqlite>



3. databases 命令用来查看当前所有数据库



  1. sqlite> .databases

  2. seq name file 
  3.   
  4. 0 main /home/ywx/yu/sqlite/test.db 
  5. 1 temp





3. 数据导出



   数据导出也是一个常用到的操作,可以将指定表中的数据导出成SQL脚本,供其他数据库使用,还可以将指定的数据表中的数据完整定位到标准输出,也可以将指定数据库中的数据完整的导入到另一个指定数据库等,



1. 导出成指定的SQL脚本

   将sqlite中指定的数据表以SQL创建脚本的形式导出,具体命令



  1. ywx@ywx:~/yu/sqlite$ sqlite3 test.db

  2. SQLite version 3.7.7.1 20110628 17:39:05
  3. Enter “.help” for instructions
  4. Enter SQL statements terminated with a “;”
  5. sqlite> .output data.sql
  6. sqlite> .dump
  7. sqlite>

 

  1. ywx@ywx:~/yu/sqlite$ ll

  2. 总计 16
  3. drwxrxrx 2 ywx ywx 4096 20110813 23:15 ./
  4. drwxrxrx 7 ywx ywx 4096 20110813 20:53 ../
  5. rwrr 1 ywx ywx 602 20110813 23:17 data.sql
  6. rwrr 1 ywx ywx 2048 20110813 22:44 test.db



2. 数据库导出



  1. data.sql test.db

  2. ywx@ywx:~/yu/sqlite$ sqlite3 test.db “.dump” | sqlite3 test2.db
  3. ywx@ywx:~/yu/sqlite$ ll
  4. 总计 20
  5. drwxrxrx 2 ywx ywx 4096 20110813 23:20 ./
  6. drwxrxrx 7 ywx ywx 4096 20110813 20:53 ../
  7. rwrr 1 ywx ywx 602 20110813 23:17 data.sql
  8. rwrr 1 ywx ywx 2048 20110813 23:20 test2.db
  9. rwrr 1 ywx ywx 2048 20110813 22:44 test.db



3. 其他格式,如:htm格式输出



  1. ywx@ywx:~/yu/sqlite$ sqlite3 html test.db “select * from data_txt_table” > liu.htm

  2. ywx@ywx:~/yu/sqlite$ ls
  3. data.sql liu.htm test2.db test.db
  4. http://blog.chinaunix.net/uid-22666248-id-2182334.html

使用 Nginx 实现灰度发布

灰度发布是指在黑与白之间,能够平滑过渡的一种发布方式。AB test就是一种灰度发布方式,让一部分用户继续用A,一部分用户开始用B,如果用户对B没有什么反对意见,那么逐步扩大范围,把所有用户都迁移到B上面来。

灰度发布可以保证整体系统的稳定,在初始灰度的时候就可以发现、调整问题,以保证其影响度。

灰度发布常见一般有三种方式:

  • Nginx+LUA方式
  • 根据Cookie实现灰度发布
  • 根据来路IP实现灰度发布

本文主要将讲解根据Cookie和来路IP这两种方式实现简单的灰度发布,Nginx+LUA这种方式涉及内容太多就不再本文展开了。

A/B测试流程

Nginx根据Cookie实现灰度发布

根据Cookie查询Cookie键为version的值,如果该Cookie值为V1则转发到hilinux_01,为V2则转发到hilinux_02。Cookie值都不匹配的情况下默认走hilinux_01所对应的服务器。

两台服务器分别定义为:

1 2 
hilinux_01  192.168.1.100:8080 hilinux_02  192.168.1.200:8080 
  • 用if指令实现
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 
upstream hilinux_01 {  server 192.168.1.100:8080 max_fails=1 fail_timeout=60; }  upstream hilinux_02 {  server 192.168.1.200:8080 max_fails=1 fail_timeout=60; }  upstream default {  server 192.168.1.100:8080 max_fails=1 fail_timeout=60; }  server {  listen 80;  server_name  www.hi-linux.com;  access_log  logs/www.hi-linux.com.log  main;   #match cookie  set $group "default";  if ($http_cookie ~* "version=V1"){  set $group hilinux_01;  }   if ($http_cookie ~* "version=V2"){  set $group hilinux_02;  }   location / {   proxy_pass http://$group;  proxy_set_header   Host             $host;  proxy_set_header   X-Real-IP        $remote_addr;  proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;  index  index.html index.htm;  }  } 
  • 用map指令实现

在Nginx里面配置一个映射,$COOKIE_version可以解析出Cookie里面的version字段。$group是一个变量,{}里面是映射规则。

如果一个version为V1的用户来访问,$group就等于hilinux_01。在server里面使用就会代理到http://hilinux_01上。version为V2的用户来访问,$group就等于hilinux_02。在server里面使用就会代理到http://hilinux_02上。Cookie值都不匹配的情况下默认走hilinux_01所对应的服务器。

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 
upstream hilinux_01 {  server 192.168.1.100:8080 max_fails=1 fail_timeout=60; }  upstream hilinux_02 {  server 192.168.1.200:8080 max_fails=1 fail_timeout=60; }  upstream default {  server 192.168.1.100:8080 max_fails=1 fail_timeout=60; }   map $COOKIE_version $group { ~*V1$ hilinux_01; ~*V2$ hilinux_02; default default; }  server {  listen 80;  server_name  www.hi-linux.com;  access_log  logs/www.hi-linux.com.log  main;   location / {   proxy_pass http://$group;  proxy_set_header   Host             $host;  proxy_set_header   X-Real-IP        $remote_addr;  proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;  index  index.html index.htm;  }  } 

Nginx根据来路IP实现灰度发布

如果是内部IP,则反向代理到hilinux_02(预发布环境);如果不是则反向代理到hilinux_01(生产环境)。

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 
upstream hilinux_01 {  server 192.168.1.100:8080 max_fails=1 fail_timeout=60; }  upstream hilinux_02 {  server 192.168.1.200:8080 max_fails=1 fail_timeout=60; }  upstream default {  server 192.168.1.100:8080 max_fails=1 fail_timeout=60; }  server {  listen 80;  server_name  www.hi-linux.com;  access_log  logs/www.hi-linux.com.log  main;    set $group default;  if ($remote_addr ~ "211.118.119.11") {  set $group hilinux_02;  }  location / {   proxy_pass http://$group;  proxy_set_header   Host             $host;  proxy_set_header   X-Real-IP        $remote_addr;  proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;  index  index.html index.htm;  } } 

如果你只有单台服务器,可以根据不同的IP设置不同的网站根目录来达到相同的目的。

1 2 3 4 5 6 7 8 9 10 11 12 13 14 
server {  listen 80;  server_name  www.hi-linux.com;  access_log  logs/www.hi-linux.com.log  main;   set $rootdir "/var/www/html";  if ($remote_addr ~ "211.118.119.11") {  set $rootdir "/var/www/test";  }   location / {  root $rootdir;  } } 

到此最基本的实现灰度发布方法就讲解完了,如果要做更细粒度灰度发布可参考ABTestingGateway项目。

ABTestingGateway是新浪开源的一个动态路由系统。ABTestingGateway是一个可以动态设置分流策略的灰度发布系统,工作在7层,基于nginx和ngx-lua开发,使用redis作为分流策略数据库,可以实现动态调度功能。

ABTestingGateway:https://github.com/CNSRE/ABTestingGateway

https://www.hi-linux.com/posts/34319.html

linux系统收到SYN但不回SYN+ACK问题排查

wKioL1mKiFzyAHTYAAZzy5AQiS4317.jpg

二,排查

1,发现系统没有任何负载

2,网卡也没有丢包

3,iptables策略也都没问题

4,系统的SYN_RECV连接很少,也没超限

5,系统的文件描述符等资源也都没问题

6,messages和dmesg中没有任何提示或者错误信息

7,通过netstat命令查看系统上协议统计信息,发现很多请求由于时间戳的问题被rejected

# netstat -s |grep reject
    2181 passive connections rejected because of time stamp
    34 packets rejects in established connections because of timestamp

三,通过google来协助

发现有同样的人遇见这个问题:

是通过调整sysctl -w net.ipv4.tcp_timestamps=0或者sysctl -w net.ipv4.tcp_tw_recycle=0来解决这个问题,于是我就顺藤摸瓜继续查。

而在查询这两个参数的过程中,发现问题原因如下:

发现是 Linux tcp_tw_recycle/tcp_timestamps设置导致的问题。 因为在linux kernel源码中发现tcp_tw_recycle/tcp_timestamps都开启的条件下,60s内同一源ip主机的socket connect请求中的timestamp必须是递增的。经过测试,我这边centos6系统(kernel 2.6.32)和centos7系统(kernel 3.10.0)都有这问题。

    源码函数:kernel 2.6.32 tcp_v4_conn_request(),该函数是tcp层三次握手syn包的处理函数(服务端);
    源码片段:
       if (tmp_opt.saw_tstamp &&
            tcp_death_row.sysctl_tw_recycle &&
            (dst = inet_csk_route_req(sk, req)) != NULL &&
            (peer = rt_get_peer((struct rtable *)dst)) != NULL &&
            peer->v4daddr == saddr) {
            if (get_seconds() < peer->tcp_ts_stamp + TCP_PAWS_MSL &&
                (s32)(peer->tcp_ts – req->ts_recent) >
                            TCP_PAWS_WINDOW) {
                NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_PAWSPASSIVEREJECTED);
                goto drop_and_release;
            }
        }
        
        tmp_opt.saw_tstamp:该socket支持tcp_timestamp
        sysctl_tw_recycle:本机系统开启tcp_tw_recycle选项
        TCP_PAWS_MSL:60s,该条件判断表示该源ip的上次tcp通讯发生在60s内
        TCP_PAWS_WINDOW:1,该条件判断表示该源ip的上次tcp通讯的timestamp 大于 本次tcp

总结:

我这边和其它同事通过公司出口(NAT网关只有1个ip地址)访问问题server,由于timestamp时间为系统启动到当前的时间,故我和其它同事的timestamp肯定不相同;根据上述SYN包处理源码,在tcp_tw_recycle和tcp_timestamps同时开启的条件下,timestamp大的主机访问serverN成功,而timestmap小的主机访问失败。并且,我在办公网找了两台机器可100%重现这个问题。

解决:

# echo “0” > /proc/sys/net/ipv4/tcp_tw_recycle

四,扩展

1,net.ipv4.tcp_timestamps

tcp_timestamps的本质是记录数据包的发送时间。基本的步骤如下:

发送方在发送数据时,将一个timestamp(表示发送时间)放在包里面

接收方在收到数据包后,在对应的ACK包中将收到的timestamp返回给发送方(echo back)

发送发收到ACK包后,用当前时刻now – ACK包中的timestamp就能得到准确的RTT

当然实际运用中要考虑到RTT的波动,因此有了后续的(Round-Trip Time Measurement)RTTM机制。

TCP Timestamps Option (TSopt)具体设计如下

Kind: 8             // 标记唯一的选项类型,比如window scale是3
Length: 10 bytes    // 标记Timestamps选项的字节数
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
| Kind=8 | Length=10 | TS Value (TSval) | TS ECho Reply (TSecr) |
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 
   1          1             4                       4
timestamps一个双向的选项,当一方不开启时,两方都将停用timestamps。比如client端发送的SYN包中带有timestamp选项,但server端并没有开启该选项。则回复的SYN-ACK将不带timestamp选项,同时client后续回复的ACK也不会带有timestamp选项。当然,如果client发送的SYN包中就不带timestamp,双向都将停用timestamp。

tcp数据包中timestamps的value是系统开机时间到现在时间的(毫秒级)时间戳。

参数:

0:停用

1:启用(系统默认值)

2,net.ipv4.tcp_tw_recycle

TCP规范中规定的处于TIME_WAIT的TCP连接必须等待2MSL时间。但在linux中,如果开启了tcp_tw_recycle,TIME_WAIT的TCP连接就不会等待2MSL时间(而是rto或者60s),从而达到快速重用(回收)处于TIME_WAIT状态的tcp连接的目的。这就可能导致连接收到之前连接的数据。为此,linux在打开tcp_tw_recycle的情况下,会记录下TIME_WAIT连接的对端(peer)信息,包括IP地址、时间戳等。这样,当内核收到同一个IP的SYN包时,就会去比较时间戳,检查SYN包的时间戳是否滞后,如果滞后,就将其丢掉(认为是旧连接的数据)。这在绝大部分情况下是没有问题的,但是对于我们实际的client-server的服务,访问我们服务的用户一般都位于NAT之后,如果NAT之后有多个用户访问同一个服务,就有可能因为时间戳滞后的连接被丢掉。

参数:

0:停用(系统默认值)

1:启用

参考:

https://serverfault.com/questions/235965/why-would-a-server-not-send-a-syn-ack-packet-in-response-to-a-syn-packet

http://hustcat.github.io/tcp_tw_recycle-and-tcp_timestamp/

linux free 查询可用内存

free工具用来查看系统可用内存:

/opt/app/tdev1$free
             total       used       free     shared    buffers     cached
Mem:       8175320    6159248    2016072          0     310208    5243680
-/+ buffers/cache:     605360    7569960
Swap:      6881272      16196    6865076

解释一下Linux上free命令的输出。

下面是free的运行结果,一共有4行。为了方便说明,我加上了列号。这样可以把free的输出看成一个二维数组FO(Free Output)。例如:

FO[2][1] = 24677460 FO[3][2] = 10321516 1 2 3 4 5 6 1 total used free shared buffers cached 2 Mem: 24677460 23276064 1401396 0 870540 12084008 3 -/+ buffers/cache: 10321516 14355944 4 Swap: 25151484 224188 24927296 

free的输出一共有四行,第四行为交换区的信息,分别是交换的总量(total),使用量(used)和有多少空闲的交换区(free),这个比较清楚,不说太多。

free输出地第二行和第三行是比较让人迷惑的。这两行都是说明内存使用情况的。第一列是总量(total),第二列是使用量(used),第三列是可用量(free)。

第一行的输出时从操作系统(OS)来看的。也就是说,从OS的角度来看,计算机上一共有:

24677460KB(缺省时free的单位为KB)物理内存,即FO[2][1]; 在这些物理内存中有23276064KB(即FO[2][2])被使用了; 还用1401396KB(即FO[2][3])是可用的;

这里得到第一个等式:

FO[2][1] = FO[2][2] + FO[2][3]

FO[2][4]表示被几个进程共享的内存的,现在已经deprecated,其值总是0(当然在一些系统上也可能不是0,主要取决于free命令是怎么实现的)。

FO[2][5]表示被OS buffer住的内存。FO[2][6]表示被OS cache的内存。在有些时候buffer和cache这两个词经常混用。不过在一些比较低层的软件里是要区分这两个词的,看老外的洋文:

A buffer is something that has yet to be "written" to disk. A cache is something that has been "read" from the disk and stored for later use. 

也就是说buffer是用于存放要输出到disk(块设备)的数据的,而cache是存放从disk上读出的数据。这二者是为了提高IO性能的,并由OS管理。

Linux和其他成熟的操作系统(例如windows),为了提高IO read的性能,总是要多cache一些数据,这也就是为什么FO[2][6](cached memory)比较大,而FO[2][3]比较小的原因。我们可以做一个简单的测试:

释放掉被系统cache占用的数据:

echo 3>/proc/sys/vm/drop_caches 

  1. 读一个大文件,并记录时间;
  2. 关闭该文件;
  3. 重读这个大文件,并记录时间;

第二次读应该比第一次快很多。原来我做过一个BerkeleyDB的读操作,大概要读5G的文件,几千万条记录。在我的环境上,第二次读比第一次大概可以快9倍左右。

free输出的第二行是从一个应用程序的角度看系统内存的使用情况。

  • 对于FO[3][2],即-buffers/cache,表示一个应用程序认为系统被用掉多少内存;
  • 对于FO[3][3],即+buffers/cache,表示一个应用程序认为系统还有多少内存;

因为被系统cache和buffer占用的内存可以被快速回收,所以通常FO[3][3]比FO[2][3]会大很多。

这里还用两个等式:

FO[3][2] = FO[2][2] - FO[2][5] - FO[2][6] FO[3][3] = FO[2][3] + FO[2][5] + FO[2][6] 

这二者都不难理解。

free命令由procps.*.rpm提供(在Redhat系列的OS上)。free命令的所有输出值都是从/proc/meminfo中读出的。

在系统上可能有meminfo(2)这个函数,它就是为了解析/proc/meminfo的。procps这个包自己实现了meminfo()这个函数。可以下载一个procps的tar包看看具体实现,现在最新版式3.2.8。

文章出处:

http://www.cnblogs.com/coldplayerest/archive/2010/02/20/1669949.html

free命令可以显示Linux系统中空闲的、已用的物理内存及swap内存,及被内核使用的buffer。在Linux系统监控的工具中,free命令是最经常使用的命令之一。

1.命令格式:

free [参数]

2.命令功能:

free 命令显示系统使用和空闲的内存情况,包括物理内存、交互区内存(swap)和内核缓冲区内存。共享内存将被忽略

3.命令参数:

-b  以Byte为单位显示内存使用情况。 

-k  以KB为单位显示内存使用情况。 

-m  以MB为单位显示内存使用情况。

-g   以GB为单位显示内存使用情况。 

-o  不显示缓冲区调节列。 

-s<间隔秒数>  持续观察内存使用状况。 

-t  显示内存总和列。 

-V  显示版本信息。 

4.使用实例:

实例1:显示内存使用情况

命令:

free

free -g

free –m

输出:

[root@SF1150 service]# free

             total       used       free     shared    buffers     cached

Mem:      32940112   30841684    2098428          0    4545340   11363424

-/+ buffers/cache:   14932920   18007192

Swap:     32764556    1944984   30819572

[root@SF1150 service]# free -g

             total       used       free     shared    buffers     cached

Mem:            31         29          2          0          4         10

-/+ buffers/cache:         14         17

Swap:           31          1         29

[root@SF1150 service]# free -m

             total       used       free     shared    buffers     cached

Mem:         32168      30119       2048          0       4438      11097

-/+ buffers/cache:      14583      17584

Swap:        31996       1899      30097

说明:

下面是对这些数值的解释:

total:总计物理内存的大小。

used:已使用多大。

free:可用有多少。

Shared:多个进程共享的内存总额。

Buffers/cached:磁盘缓存的大小。

第三行(-/+ buffers/cached):

used:已使用多大。

free:可用有多少。

第四行是交换分区SWAP的,也就是我们通常所说的虚拟内存。

区别:第二行(mem)的used/free与第三行(-/+ buffers/cache) used/free的区别。 这两个的区别在于使用的角度来看,第一行是从OS的角度来看,因为对于OS,buffers/cached 都是属于被使用,所以他的可用内存是2098428KB,已用内存是30841684KB,其中包括,内核(OS)使用+Application(X, oracle,etc)使用的+buffers+cached.

第三行所指的是从应用程序角度来看,对于应用程序来说,buffers/cached 是等于可用的,因为buffer/cached是为了提高文件读取的性能,当应用程序需在用到内存的时候,buffer/cached会很快地被回收。

所以从应用程序的角度来说,可用内存=系统free memory+buffers+cached。

如本机情况的可用内存为:

18007156=2098428KB+4545340KB+11363424KB

接下来解释什么时候内存会被交换,以及按什么方交换。 

当可用内存少于额定值的时候,就会开会进行交换.如何看额定值: 

命令:

cat /proc/meminfo 

输出:

[root@SF1150 service]# cat /proc/meminfo

MemTotal:     32940112 kB

MemFree:       2096700 kB

Buffers:       4545340 kB

Cached:       11364056 kB

SwapCached:    1896080 kB

Active:       22739776 kB

Inactive:      7427836 kB

HighTotal:           kB

HighFree:            kB

LowTotal:     32940112 kB

LowFree:       2096700 kB

SwapTotal:    32764556 kB

SwapFree:     30819572 kB

Dirty:             164 kB

Writeback:           kB

AnonPages:    14153592 kB

Mapped:          20748 kB

Slab:           590232 kB

PageTables:      34200 kB

NFS_Unstable:        kB

Bounce:              kB

CommitLimit:  49234612 kB

Committed_AS: 23247544 kB

VmallocTotal: 34359738367 kB

VmallocUsed:    278840 kB

VmallocChunk: 34359459371 kB

HugePages_Total:     0HugePages_Free:      0HugePages_Rsvd:      0Hugepagesize:     2048 kB

交换将通过三个途径来减少系统中使用的物理页面的个数:  

1.减少缓冲与页面cache的大小, 

2.将系统V类型的内存页面交换出去,  

3.换出或者丢弃页面。(Application 占用的内存页,也就是物理内存不足)。 

事实上,少量地使用swap是不是影响到系统性能的。

那buffers和cached都是缓存,两者有什么区别呢?

为了提高磁盘存取效率, Linux做了一些精心的设计, 除了对dentry进行缓存(用于VFS,加速文件路径名到inode的转换), 还采取了两种主要Cache方式:Buffer Cache和Page Cache。前者针对磁盘块的读写,后者针对文件inode的读写。这些Cache有效缩短了 I/O系统调用(比如read,write,getdents)的时间。

磁盘的操作有逻辑级(文件系统)和物理级(磁盘块),这两种Cache就是分别缓存逻辑和物理级数据的。

Page cache实际上是针对文件系统的,是文件的缓存,在文件层面上的数据会缓存到page cache。文件的逻辑层需要映射到实际的物理磁盘,这种映射关系由文件系统来完成。当page cache的数据需要刷新时,page cache中的数据交给buffer cache,因为Buffer Cache就是缓存磁盘块的。但是这种处理在2.6版本的内核之后就变的很简单了,没有真正意义上的cache操作。

Buffer cache是针对磁盘块的缓存,也就是在没有文件系统的情况下,直接对磁盘进行操作的数据会缓存到buffer cache中,例如,文件系统的元数据都会缓存到buffer cache中。

简单说来,page cache用来缓存文件数据,buffer cache用来缓存磁盘数据。在有文件系统的情况下,对文件操作,那么数据会缓存到page cache,如果直接采用dd等工具对磁盘进行读写,那么数据会缓存到buffer cache。

所以我们看linux,只要不用swap的交换空间,就不用担心自己的内存太少.如果常常swap用很多,可能你就要考虑加物理内存了.这也是linux看内存是否够用的标准.

如果是应用服务器的话,一般只看第二行,+buffers/cache,即对应用程序来说free的内存太少了,也是该考虑优化程序或加内存了。

实例2:以总和的形式显示内存的使用信息

命令:

  free -t 

输出:

[root@SF1150 service]#  free -t 

             total       used       free     shared    buffers     cached

Mem:      32940112   30845024    2095088          0    4545340   11364324

-/+ buffers/cache:   14935360   18004752Swap:     32764556    1944984   30819572Total:    65704668   32790008   32914660[root@SF1150 service]#

说明:

实例3:周期性的查询内存使用信息

命令:

free -s 10

输出:

[root@SF1150 service]#  free -s 10

             total       used       free     shared    buffers     cached

Mem:      32940112   30844528    2095584          0    4545340   11364380

-/+ buffers/cache:   14934808   18005304Swap:     32764556    1944984   30819572

             total       used       free     shared    buffers     cached

Mem:      32940112   30843932    2096180          0    4545340   11364388

-/+ buffers/cache:   14934204   18005908Swap:     32764556    1944984   30819572

说明:

每10s 执行一次命令

https://www.cnblogs.com/peida/archive/2012/12/25/2831814.html

linux 百万并发连接之内核优化tcp_mem

在服务端,连接达到一定数量,诸如50W时,有些隐藏很深的问题,就不断的抛出来。 通过查看dmesg命令查看,发现大量TCP: too many of orphaned sockets错误,也很正常,下面到了需要调整tcp socket参数的时候了。

第一个需要调整的是tcp_rmem,即TCP读取缓冲区,单位为字节,查看默认值

  1. cat /proc/sys/net/ipv4/tcp_rmem
  2. 4096 87380 4161536

默认值为87380 byte ≈ 86K,最小为4096 byte=4K,最大值为4064K。

第二个需要调整的是tcp_wmem,发送缓冲区,单位是字节,默认值

  1. cat /proc/sys/net/ipv4/tcp_wmem
  2. 4096 16384 4161536

解释同上

第三个需要调整的tcp_mem,调整TCP的内存大小,其单位是页,1页等于4096字节。系统默认值:

  1. cat /proc/sys/net/ipv4/tcp_mem
  2. 932448 1243264 1864896

tcp_mem(3个INTEGER变量):low, pressure, high

  • low:当TCP使用了低于该值的内存页面数时,TCP不会考虑释放内存。
  • pressure:当TCP使用了超过该值的内存页面数量时,TCP试图稳定其内存使用,进入pressure模式,当内存消耗低于low值时则退出pressure状态。
  • high:允许所有tcp sockets用于排队缓冲数据报的页面量,当内存占用超过此值,系统拒绝分配socket,后台日志输出“TCP: too many of orphaned sockets”。

一般情况下这些值是在系统启动时根据系统内存数量计算得到的。 根据当前tcp_mem最大内存页面数是1864896,当内存为(1864896*4)/1024K=7284.75M时,系统将无法为新的socket连接分配内存,即TCP连接将被拒绝。

实际测试环境中,据观察大概在99万个连接左右的时候(零头不算),进程被杀死,触发out of socket memory错误(dmesg命令查看获得)。每一个连接大致占用7.5K内存(下面给出计算方式),大致可算的此时内存占用情况(990000 * 7.5 / 1024K = 7251M)。

这样和tcp_mem最大页面值数量比较吻合,因此此值也需要修改。

三个TCP调整语句为:

  1. echo “net.ipv4.tcp_mem = 786432 2097152 3145728”>> /etc/sysctl.conf
  2. echo “net.ipv4.tcp_rmem = 4096 4096 16777216”>> /etc/sysctl.conf
  3. echo “net.ipv4.tcp_wmem = 4096 4096 16777216”>> /etc/sysctl.conf

备注: 为了节省内存,设置tcp读、写缓冲区都为4K大小,tcp_mem三个值分别为3G 8G 16G,tcp_rmemtcp_wmem最大值也是16G。

目标达成

经过若干次的尝试,最终达到目标,1024000个持久连接。1024000数字是怎么得来的呢,两台物理机器各自发出64000个请求,两个配置为6G左右的centos测试端机器(绑定7个桥接或NAT连接)各自发出640007 = 448000。也就是 1024000 = (64000) + (64000) + (640007) + (64000*7), 共使用了16个网卡(物理网卡+虚拟网卡)。
终端输出

  1. ……
  2. online user 1023990
  3. online user 1023991
  4. online user 1023992
  5. online user 1023993
  6. online user 1023994
  7. online user 1023995
  8. online user 1023996
  9. online user 1023997
  10. online user 1023998
  11. online user 1023999
  12. online user 1024000

在线用户目标达到1024000个!

服务器状态信息

服务启动时内存占用:

  1. total used free shared buffers cached
  2. Mem: 10442 271 10171 0 22 78
  3. -/+ buffers/cache: 171 10271
  4. Swap: 8127 0 8127

系统达到1024000个连接后的内存情况(执行三次 free -m 命令,获取三次结果):

  1. total used free shared buffers cached
  2. Mem: 10442 7781 2661 0 22 78
  3. -/+ buffers/cache: 7680 2762
  4. Swap: 8127 0 8127
  5. total used free shared buffers cached
  6. Mem: 10442 7793 2649 0 22 78
  7. -/+ buffers/cache: 7692 2750
  8. Swap: 8127 0 8127
  9. total used free shared buffers cached
  10. Mem: 10442 7804 2638 0 22 79
  11. -/+ buffers/cache: 7702 2740
  12. Swap: 8127 0 8127

这三次内存使用分别是7680,7692,7702,这次不取平均值,取一个中等偏上的值,定为7701M。那么程序接收1024000个连接,共消耗了 7701M-171M = 7530M内存, 7530M*1024K / 1024000 = 7.53K, 每一个连接消耗内存在为7.5K左右,这和在连接达到512000时所计算较为吻合。
虚拟机运行Centos内存占用,不太稳定,但一般相差不大,以上数值,仅供参考。

执行top -p 某刻输出信息:

  1. top – 17:23:17 up 18 min, 4 users, load average: 0.33, 0.12, 0.11
  2. Tasks: 1 total, 1 running, 0 sleeping, 0 stopped, 0 zombie
  3. Cpu(s): 0.2%us, 6.3%sy, 0.0%ni, 80.2%id, 0.0%wa, 4.5%hi, 8.8%si, 0.0%st
  4. Mem: 10693580k total, 6479980k used, 4213600k free, 22916k buffers
  5. Swap: 8323056k total, 0k used, 8323056k free, 80360k cached
  6. PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
  7. 2924 yongboy 20 0 82776 74m 508 R 51.3 0.7 3:53.95 server

执行vmstate:

  1. vmstat
  2. procs ———–memory———- —swap– —–io—- –system– —–cpu—–
  3. r b swpd free buff cache si so bi bo in cs us sy id wa st
  4. 0 0 0 2725572 23008 80360 0 0 21 2 1012 894 0 9 89 2 0

获取当前socket连接状态统计信息:

  1. cat /proc/net/sockstat
  2. sockets: used 1024380
  3. TCP: inuse 1024009 orphan 0 tw 0 alloc 1024014 mem 2
  4. UDP: inuse 11 mem 1
  5. UDPLITE: inuse 0
  6. RAW: inuse 0
  7. FRAG: inuse 0 memory 0

获取当前系统打开的文件句柄:

  1. sysctl -a | grep file
  2. fs.file-nr = 1025216 0 1048576
  3. fs.file-max = 1048576

此时任何类似于下面查询操作都是一个慢,等待若干时间还不见得执行完毕。

  1. netstat -nat|grep -i “8000”|grep ESTABLISHED|wc -l
  2. netstat -n | grep -i “8000” | awk ‘/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}’

以上两个命令在二三十分钟过去了,还未执行完毕,只好停止。

小结

本次从头到尾的测试,所需要有的linux系统需要调整的参数也就是那么几个,汇总一下:

  1. echo “* – nofile 1048576” >> /etc/security/limits.conf
  2. echo “fs.file-max = 1048576” >> /etc/sysctl.conf
  3. echo “net.ipv4.ip_local_port_range = 1024 65535” >> /etc/sysctl.conf
  4. echo “net.ipv4.tcp_mem = 786432 2097152 3145728” >> /etc/sysctl.conf
  5. echo “net.ipv4.tcp_rmem = 4096 4096 16777216” >> /etc/sysctl.conf
  6. echo “net.ipv4.tcp_wmem = 4096 4096 16777216” >> /etc/sysctl.conf

其它没有调整的参数,仅仅因为它们暂时对本次测试没有带来什么影响,实际环境中需要结合需要调整类似于SO_KEEPALIVE、tcpmax_orphans等大量参数。

开放DNS速度测试

[root@2 ~]# time for i in `seq 1 100`;do dig @8.8.8.8 www.alidns.com > /dev/null 2>&1; done

real    0m14.733s
user    0m0.227s
sys     0m0.302s
[root@2 ~]# time for i in `seq 1 100`;do dig @119.29.29.29 www.alidns.com > /dev/null 2>&1; done

real    0m14.249s
user    0m0.224s
sys     0m0.327s
[root@2 ~]# time for i in `seq 1 100`;do dig @114.114.114.114 www.alidns.com > /dev/null 2>&1; done

real    0m14.856s
user    0m0.235s
sys     0m0.312s
[root@2 ~]# time for i in `seq 1 100`;do dig @223.5.5.5 www.alidns.com > /dev/null 2>&1; done

real    0m13.729s
user    0m0.235s
sys     0m0.309s
[root@2 ~]# time for i in `seq 1 100`;do dig @180.76.76.76 www.alidns.com > /dev/null 2>&1; done

real    1m8.154s
user    0m0.205s
sys     0m0.326s
[root@2 ~]# time for i in `seq 1 100`;do dig @101.226.4.6 www.alidns.com > /dev/null 2>&1; done

real    0m16.814s
user    0m0.225s
sys     0m0.307s
[root@2 ~]# time for i in `seq 1 100`;do dig @1.2.4.8 www.alidns.com > /dev/null 2>&1; done

real    0m14.493s
user    0m0.215s
sys     0m0.317s
[root@2 ~]# time for i in `seq 1 100`;do dig @208.67.222.222 www.alidns.com > /dev/null 2>&1; done

real    0m47.309s
user    0m0.228s
sys     0m0.326s
[root@2 ~]# time for i in `seq 1 100`;do dig @208.67.222.222 www.alidns.com > /dev/null 2>&1; done
c^C
real    1m36.730s
user    0m0.214s
sys     0m0.320s
[root@2 ~]# time for i in `seq 1 100`;do dig @4.2.2.1 www.alidns.com > /dev/null 2>&1; done

real    0m38.440s
user    0m0.224s
sys     0m0.303s
[root@2 ~]# time for i in `seq 1 100`;do dig @1.1.1.1 www.alidns.com > /dev/null 2>&1; done

real    0m27.393s
user    0m0.239s
sys     0m0.292s

阿里公共DNS223.5.5.5 和 223.6.6.6​的问题

阿里公共DNS 223.5.5.5 和 223.6.6.6是阿里巴巴集团推出的DNS递归解析系统,目标是成为国内互联网基础设施的组成部分,面向互联网用户提供“快速”、“稳定”、“智能”的免费DNS递归解析服务

通过批量测试发现,223.5.5.5 和 223.6.6.6解析不常用域名超慢,达到2-6秒甚至超时解析。这个不知道阿里DNS是什么时候改的,同样对比腾讯119.29.29.29及114DNS 114.114.114.114 及google DNS 8.8.8.8没有这个问题。


批量测试100次,看看返回结果时间:

[root@2 ~]# time for i in `seq 1 100`;do dig @223.6.6.6 www.dnsdizhi.com +short > /dev/null 2>&1; done

real    0m51.319s
user    0m0.215s
sys     0m0.316s
[root@2 ~]# time for i in `seq 1 100`;do dig @223.6.6.6 www.dnsdizhi.com +short > /dev/null 2>&1; done

real    0m3.533s
user    0m0.194s
sys     0m0.346s
[root@2 ~]# time for i in `seq 1 100`;do dig @223.6.6.6 www.dnsdizhi.com +short > /dev/null 2>&1; done

real    0m1.161s
user    0m0.221s
sys     0m0.328s
[root@2 ~]# time for i in `seq 1 100`;do dig @223.6.6.6 www.dnsdizhi.com +short > /dev/null 2>&1; done

real    0m1.135s
user    0m0.210s
sys     0m0.308s


第一个100次,需要51秒,而后面都非常快。


我们详细看看前100次域名解析耗时情况:

第1-10次:

[root@2 ~]# time for i in `seq 1 10`;do time dig @223.6.6.6 www.dnsdizhi.com +short; done
119.28.12.243

real    0m1.134s
user    0m0.004s
sys     0m0.002s

; <<>> DiG 9.8.2rc1-RedHat-9.8.2-0.68.rc1.el6_10.1 <<>> @223.6.6.6 www.dnsdizhi.com +short
; (1 server found)
;; global options: +cmd
;; connection timed out; no servers could be reached

real    0m6.005s
user    0m0.002s
sys     0m0.003s
119.28.12.243

real    0m0.032s
user    0m0.003s
sys     0m0.003s
119.28.12.243

real    0m2.072s
user    0m0.003s
sys     0m0.002s

; <<>> DiG 9.8.2rc1-RedHat-9.8.2-0.68.rc1.el6_10.1 <<>> @223.6.6.6 www.dnsdizhi.com +short
; (1 server found)
;; global options: +cmd
;; connection timed out; no servers could be reached

real    0m6.005s
user    0m0.001s
sys     0m0.004s

; <<>> DiG 9.8.2rc1-RedHat-9.8.2-0.68.rc1.el6_10.1 <<>> @223.6.6.6 www.dnsdizhi.com +short
; (1 server found)
;; global options: +cmd
;; connection timed out; no servers could be reached

real    0m6.006s
user    0m0.003s
sys     0m0.003s
119.28.12.243

real    0m0.009s
user    0m0.001s
sys     0m0.004s
119.28.12.243

real    0m0.037s
user    0m0.002s
sys     0m0.003s
119.28.12.243

real    0m2.032s
user    0m0.002s
sys     0m0.001s
119.28.12.243

real    0m0.012s
user    0m0.002s
sys     0m0.003s

real    0m23.347s
user    0m0.023s
sys     0m0.029s

第11-20次

[root@2 ~]# time for i in `seq 1 10`;do time dig @223.6.6.6 www.dnsdizhi.com +short; done
119.28.12.243

real    0m0.009s
user    0m0.003s
sys     0m0.003s
119.28.12.243

real    0m4.031s
user    0m0.003s
sys     0m0.002s
119.28.12.243

real    0m4.032s
user    0m0.002s
sys     0m0.003s
119.28.12.243

real    0m0.013s
user    0m0.004s
sys     0m0.002s

; <<>> DiG 9.8.2rc1-RedHat-9.8.2-0.68.rc1.el6_10.1 <<>> @223.6.6.6 www.dnsdizhi.com +short
; (1 server found)
;; global options: +cmd
;; connection timed out; no servers could be reached

real    0m6.005s
user    0m0.003s
sys     0m0.002s
119.28.12.243

real    0m0.032s
user    0m0.004s
sys     0m0.002s
119.28.12.243

real    0m0.011s
user    0m0.000s
sys     0m0.005s

; <<>> DiG 9.8.2rc1-RedHat-9.8.2-0.68.rc1.el6_10.1 <<>> @223.6.6.6 www.dnsdizhi.com +short
; (1 server found)
;; global options: +cmd
;; connection timed out; no servers could be reached

real    0m6.005s
user    0m0.002s
sys     0m0.003s
119.28.12.243

real    0m0.012s
user    0m0.004s
sys     0m0.002s
119.28.12.243

real    0m4.045s
user    0m0.000s
sys     0m0.005s

real    0m24.198s
user    0m0.026s
sys     0m0.029s

第21-30次

[root@2 ~]# time for i in `seq 1 10`;do time dig @223.6.6.6 www.dnsdizhi.com +short; done

; <<>> DiG 9.8.2rc1-RedHat-9.8.2-0.68.rc1.el6_10.1 <<>> @223.6.6.6 www.dnsdizhi.com +short
; (1 server found)
;; global options: +cmd
;; connection timed out; no servers could be reached

real    0m6.006s
user    0m0.002s
sys     0m0.003s
119.28.12.243

real    0m0.009s
user    0m0.003s
sys     0m0.003s
119.28.12.243

real    0m0.023s
user    0m0.003s
sys     0m0.002s
119.28.12.243

real    0m0.014s
user    0m0.004s
sys     0m0.001s
119.28.12.243

real    0m0.016s
user    0m0.002s
sys     0m0.002s
119.28.12.243

real    0m4.039s
user    0m0.002s
sys     0m0.003s

; <<>> DiG 9.8.2rc1-RedHat-9.8.2-0.68.rc1.el6_10.1 <<>> @223.6.6.6 www.dnsdizhi.com +short
; (1 server found)
;; global options: +cmd
;; connection timed out; no servers could be reached

real    0m6.006s
user    0m0.002s
sys     0m0.004s
119.28.12.243

real    0m0.027s
user    0m0.003s
sys     0m0.002s

; <<>> DiG 9.8.2rc1-RedHat-9.8.2-0.68.rc1.el6_10.1 <<>> @223.6.6.6 www.dnsdizhi.com +short
; (1 server found)
;; global options: +cmd
;; connection timed out; no servers could be reached

real    0m6.006s
user    0m0.003s
sys     0m0.003s
119.28.12.243

real    0m0.010s
user    0m0.002s
sys     0m0.003s

real    0m22.156s
user    0m0.027s
sys     0m0.026s

第31-40次

[root@2 ~]# time for i in `seq 1 10`;do time dig @223.6.6.6 www.dnsdizhi.com +short; done
119.28.12.243

real    0m0.012s
user    0m0.001s
sys     0m0.004s
119.28.12.243

real    0m4.076s
user    0m0.003s
sys     0m0.003s
119.28.12.243

real    0m2.026s
user    0m0.003s
sys     0m0.002s
119.28.12.243

real    0m0.025s
user    0m0.005s
sys     0m0.001s
119.28.12.243

real    0m0.033s
user    0m0.002s
sys     0m0.002s
119.28.12.243

real    0m0.026s
user    0m0.002s
sys     0m0.003s
119.28.12.243

real    0m2.026s
user    0m0.003s
sys     0m0.003s
119.28.12.243

real    0m0.026s
user    0m0.002s
sys     0m0.003s
119.28.12.243

real    0m0.010s
user    0m0.001s
sys     0m0.005s
119.28.12.243

real    0m0.028s
user    0m0.002s
sys     0m0.003s

real    0m8.291s
user    0m0.025s
sys     0m0.029s

第41-50次

[root@2 ~]# time for i in `seq 1 10`;do time dig @223.6.6.6 www.dnsdizhi.com +short; done
119.28.12.243

real    0m0.009s
user    0m0.003s
sys     0m0.002s
119.28.12.243

real    0m0.011s
user    0m0.001s
sys     0m0.005s
119.28.12.243

real    0m0.010s
user    0m0.001s
sys     0m0.003s
119.28.12.243

real    0m0.009s
user    0m0.001s
sys     0m0.003s
119.28.12.243

real    0m0.012s
user    0m0.002s
sys     0m0.003s
119.28.12.243

real    0m0.012s
user    0m0.001s
sys     0m0.003s

; <<>> DiG 9.8.2rc1-RedHat-9.8.2-0.68.rc1.el6_10.1 <<>> @223.6.6.6 www.dnsdizhi.com +short
; (1 server found)
;; global options: +cmd
;; connection timed out; no servers could be reached

real    0m6.004s
user    0m0.000s
sys     0m0.004s
119.28.12.243

real    0m0.008s
user    0m0.004s
sys     0m0.002s
119.28.12.243

real    0m0.015s
user    0m0.002s
sys     0m0.002s
119.28.12.243

real    0m0.017s
user    0m0.001s
sys     0m0.004s

real    0m6.109s
user    0m0.017s
sys     0m0.032s

第51-60次

[root@2 ~]# time for i in `seq 1 10`;do time dig @223.6.6.6 www.dnsdizhi.com +short; done
119.28.12.243

real    0m0.017s
user    0m0.001s
sys     0m0.005s
119.28.12.243

real    0m0.020s
user    0m0.002s
sys     0m0.003s
119.28.12.243

real    0m0.013s
user    0m0.003s
sys     0m0.002s
119.28.12.243

real    0m0.013s
user    0m0.000s
sys     0m0.006s
119.28.12.243

real    0m0.011s
user    0m0.004s
sys     0m0.001s
119.28.12.243

real    0m0.014s
user    0m0.003s
sys     0m0.002s

; <<>> DiG 9.8.2rc1-RedHat-9.8.2-0.68.rc1.el6_10.1 <<>> @223.6.6.6 www.dnsdizhi.com +short
; (1 server found)
;; global options: +cmd
;; connection timed out; no servers could be reached

real    0m6.005s
user    0m0.001s
sys     0m0.004s
119.28.12.243

real    0m0.019s
user    0m0.004s
sys     0m0.001s
119.28.12.243

real    0m0.024s
user    0m0.003s
sys     0m0.003s
119.28.12.243

real    0m0.017s
user    0m0.001s
sys     0m0.003s

real    0m6.155s
user    0m0.022s
sys     0m0.031s

第61-70次

# time for i in `seq 1 10`;do time dig @223.6.6.6 www.dnsdizhi.com +short; done
119.28.12.243

real    0m0.013s
user    0m0.003s
sys     0m0.003s
119.28.12.243

real    0m0.010s
user    0m0.003s
sys     0m0.002s
119.28.12.243

real    0m0.010s
user    0m0.001s
sys     0m0.004s
119.28.12.243

real    0m0.009s
user    0m0.000s
sys     0m0.004s
119.28.12.243

real    0m0.013s
user    0m0.002s
sys     0m0.003s
119.28.12.243

real    0m0.010s
user    0m0.002s
sys     0m0.003s

; <<>> DiG 9.8.2rc1-RedHat-9.8.2-0.68.rc1.el6_10.1 <<>> @223.6.6.6 www.dnsdizhi.com +short
; (1 server found)
;; global options: +cmd
;; connection timed out; no servers could be reached

real    0m6.005s
user    0m0.000s
sys     0m0.005s
119.28.12.243

real    0m2.047s
user    0m0.003s
sys     0m0.003s
119.28.12.243

real    0m0.009s
user    0m0.003s
sys     0m0.002s
119.28.12.243

real    0m0.013s
user    0m0.002s
sys     0m0.002s

real    0m8.140s
user    0m0.020s
sys     0m0.031s

第71-80次

# time for i in `seq 1 10`;do time dig @223.6.6.6 www.dnsdizhi.com +short; done
119.28.12.243

real    0m0.010s
user    0m0.002s
sys     0m0.003s
119.28.12.243

real    0m0.012s
user    0m0.001s
sys     0m0.003s
119.28.12.243

real    0m0.013s
user    0m0.002s
sys     0m0.004s
119.28.12.243

real    0m0.009s
user    0m0.001s
sys     0m0.003s
119.28.12.243

real    0m0.014s
user    0m0.001s
sys     0m0.003s
119.28.12.243

real    0m0.045s
user    0m0.004s
sys     0m0.002s
119.28.12.243

real    0m0.012s
user    0m0.001s
sys     0m0.003s
119.28.12.243

real    0m0.013s
user    0m0.001s
sys     0m0.004s
119.28.12.243

real    0m0.010s
user    0m0.000s
sys     0m0.005s
119.28.12.243

real    0m0.011s
user    0m0.002s
sys     0m0.003s

real    0m0.151s
user    0m0.017s
sys     0m0.033s

第81-90次

# time for i in `seq 1 10`;do time dig @223.6.6.6 www.dnsdizhi.com +short; done
119.28.12.243

real    0m0.009s
user    0m0.001s
sys     0m0.004s
119.28.12.243

real    0m0.029s
user    0m0.001s
sys     0m0.005s
119.28.12.243

real    0m0.011s
user    0m0.004s
sys     0m0.001s
119.28.12.243

real    0m0.009s
user    0m0.002s
sys     0m0.002s
119.28.12.243

real    0m0.013s
user    0m0.001s
sys     0m0.006s
119.28.12.243

real    0m0.010s
user    0m0.002s
sys     0m0.003s
119.28.12.243

real    0m0.012s
user    0m0.002s
sys     0m0.003s
119.28.12.243

real    0m0.015s
user    0m0.002s
sys     0m0.003s
119.28.12.243

real    0m0.009s
user    0m0.003s
sys     0m0.002s
119.28.12.243

real    0m0.012s
user    0m0.003s
sys     0m0.002s

real    0m0.131s
user    0m0.023s
sys     0m0.031s

第91-100次


# time for i in `seq 1 10`;do time dig @223.6.6.6 www.dnsdizhi.com +short; done
119.28.12.243

real    0m2.072s
user    0m0.000s
sys     0m0.005s
119.28.12.243

real    0m0.031s
user    0m0.002s
sys     0m0.003s
119.28.12.243

real    0m0.064s
user    0m0.004s
sys     0m0.001s
119.28.12.243

real    0m0.070s
user    0m0.004s
sys     0m0.001s
119.28.12.243

real    0m0.069s
user    0m0.003s
sys     0m0.002s
119.28.12.243

real    0m0.050s
user    0m0.002s
sys     0m0.002s
119.28.12.243

real    0m0.052s
user    0m0.004s
sys     0m0.002s
119.28.12.243

real    0m0.046s
user    0m0.001s
sys     0m0.003s
119.28.12.243

real    0m0.055s
user    0m0.002s
sys     0m0.003s
119.28.12.243

real    0m0.087s
user    0m0.002s
sys     0m0.004s

real    0m2.597s
user    0m0.024s
sys     0m0.027s

swoole最新的发行版安装

和任何开源项目一样, Swoole总是在最新的发行版提供最可靠的稳定性和最强的功能, 请尽量保证你使用的是最新版本

1. 直接使用Swoole官方的二进制包 (初学者 + 开发环境)

访问我们官网的下载页面

编译需求

  • Linux, OS X 系统 或 CygWin, WSL
  • PHP 7.0.0 或以上版本 (版本越高性能越好)
  • GCC 4.8 及以上

2. 使用PHP官方的PECL工具安装 (初学者)

pecl install swoole

3. 从源码编译安装 (推荐)

非内核开发研究之用途, 请下载发布版本的源码编译

cd swoole-src && \
phpize && \
./configure && \
make && sudo make install

启用扩展

编译安装到系统成功后, 需要在php.ini中加入一行extension=swoole.so来启用Swoole扩展

额外编译参数

使用例子: ./configure --enable-openssl --enable-sockets

  • --enable-openssl 或 --with-openssl-dir=DIR
  • --enable-sockets
  • --enable-http2
  • --enable-mysqlnd (需要 mysqlnd, 只是为了支持mysql->escape方法)

升级

⚠️ 如果你要从源码升级, 别忘记在源码目录执行 make clean

  1. pecl upgrade swoole
  2. git pull && cd swoole-src && make clean && make && sudo make install
  3. 如果你改变了PHP版本, 请重新执行 phpize clean && phpize后重新编译

Http性能压测工具wrk

用过了很多压测工具,却一直没找到中意的那款。最近试了wrk感觉不错,命令及结果很类似ab,写下这份使用指南给自己备忘用,如果能帮到你,那也很好。

安装

wrk支持大多数类UNIX系统,不支持windows。需要操作系统支持LuaJIT和OpenSSL,不过不用担心,大多数类Unix系统都支持。安装wrk非常简单,只要从github上下载wrk源码,在项目路径下执行make命令即可。

git clone https://github.com/wg/wrk make

make之后,会在项目路径下生成可执行文件wrk,随后就可以用其进行HTTP压测了。可以把这个可执行文件拷贝到某个已在path中的路径,比如/usr/local/bin,这样就可以在任何路径直接使用wrk了。

默认情况下wrk会使用自带的LuaJIT和OpenSSL,如果你想使用系统已安装的版本,可以使用WITH_LUAJIT和WITH_OPENSSL这两个选项来指定它们的路径。比如:

make WITH_LUAJIT=/usr WITH_OPENSSL=/usr

基本使用

  1. 命令行敲下wrk,可以看到使用帮助
Usage: wrk <options> <url>                            
  Options:                                            
    -c, --connections <N>  Connections to keep open  -d, --duration    <T>  Duration of test  -t, --threads     <N>  Number of threads to use  -s, --script      <S>  Load Lua script file  -H, --header      <H>  Add header to request  --latency          Print latency statistics  --timeout     <T>  Socket/request timeout  -v, --version          Print version details  Numeric arguments may include a SI unit (1k, 1M, 1G) Time arguments may include a time unit (2s, 2m, 2h)

简单翻成中文:

使用方法: wrk <选项> <被测HTTP服务的URL> Options:                                            
    -c, --connections <N> 跟服务器建立并保持的TCP连接数量  
    -d, --duration <T> 压测时间           
    -t, --threads <N> 使用多少个线程进行压测   
                                                      
    -s, --script <S> 指定Lua脚本路径       
    -H, --header <H> 为每一个HTTP请求添加HTTP头      
        --latency          在压测结束后,打印延迟统计信息   
        --timeout <T> 超时时间     
    -v, --version          打印正在使用的wrk的详细版本信息 <N>代表数字参数,支持国际单位 (1k, 1M, 1G) <T>代表时间参数,支持时间单位 (2s, 2m, 2h)
  1. 看下版本
wrk -v 输出: wrk 4.0.2 [epoll] Copyright (C) 2012 Will Glozer

看到是4.0.2版本的wrk,使用了epoll。这意味着我们可以用少量的线程来跟被测服务创建大量连接,进行压测。

  1. 做一次简单压测,分析下结果
wrk -t8 -c200 -d30s --latency "http://www.bing.com" 输出:
Running 30s test @ http://www.bing.com 8 threads and 200 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency 46.67ms 215.38ms 1.67s 95.59% Req/Sec 7.91k 1.15k 10.26k 70.77% Latency Distribution 50%    2.93ms 75%    3.78ms 90%    4.73ms 99%    1.35s  1790465 requests in 30.01s, 684.08MB read
Requests/sec: 59658.29 Transfer/sec: 22.79MB

以上使用8个线程200个连接,对bing首页进行了30秒的压测,并要求在压测结果中输出响应延迟信息。以下对压测结果进行简单注释:

Running 30s test @ http://www.bing.com (压测时间30s) 8 threads and 200 connections (共8个测试线程,200个连接)
  Thread Stats   Avg      Stdev     Max   +/- Stdev
              (平均值) (标准差)(最大值)(正负一个标准差所占比例)
    Latency 46.67ms 215.38ms 1.67s 95.59% (延迟)
    Req/Sec 7.91k 1.15k 10.26k 70.77% (处理中的请求数)
  Latency Distribution (延迟分布) 50%    2.93ms 75%    3.78ms 90%    4.73ms 99%    1.35s (99分位的延迟) 1790465 requests in 30.01s, 684.08MB read (30.01秒内共处理完成了1790465个请求,读取了684.08MB数据)
Requests/sec: 59658.29 (平均每秒处理完成59658.29个请求)
Transfer/sec: 22.79MB (平均每秒读取数据22.79MB)

可以看到,wrk使用方便,结果清晰。并且因为非阻塞IO的使用,可以在普通的测试机上创建出大量的连接,从而达到较好的压测效果。

使用Lua脚本个性化wrk压测

以上两节安装并简单使用了wrk,但这种简单的压测可能不能满足我们的需求。比如我们可能需要使用POST METHOD跟服务器交互;可能需要为每一次请求使用不同的参数,以更好的模拟服务的实际使用场景等。wrk支持用户使用–script指定Lua脚本,来定制压测过程,满足个性化需求。

  1. 介绍wrk对Lua脚本的支持

wrk支持在三个阶段对压测进行个性化,分别是启动阶段、运行阶段和结束阶段。每个测试线程,都拥有独立的Lua运行环境。

启动阶段
function setup(thread)

在脚本文件中实现setup方法,wrk就会在测试线程已经初始化但还没有启动的时候调用该方法。wrk会为每一个测试线程调用一次setup方法,并传入代表测试线程的对象thread作为参数。setup方法中可操作该thread对象,获取信息、存储信息、甚至关闭该线程。

thread.addr             - get or set the thread's server address thread:get(name)        - get the value of a global in the thread's env thread:set(name, value) - set the value of a global in the thread's env thread:stop()           - stop the thread
运行阶段
function init(args) function delay() function request() function response(status, headers, body)

init由测试线程调用,只会在进入运行阶段时,调用一次。支持从启动wrk的命令中,获取命令行参数;

delay在每次发送request之前调用,如果需要delay,那么delay相应时间;

request用来生成请求;每一次请求都会调用该方法,所以注意不要在该方法中做耗时的操作;

reponse在每次收到一个响应时调用;为提升性能,如果没有定义该方法,那么wrk不会解析headers和body;

结束阶段
function done(summary, latency, requests)

该方法在整个测试过程中只会调用一次,可从参数给定的对象中,获取压测结果,生成定制化的测试报告。

自定义脚本中可访问的变量和方法

变量:wrk

 wrk = {
    scheme  = "http",
    host    = "localhost",
    port    = nil,
    method  = "GET",
    path    = "/",
    headers = {},
    body    = nil,
    thread  = <userdata>,
  }

一个table类型的变量wrk,是全局变量,修改该table,会影响所有请求。

方法:wrk.fomat wrk.lookup wrk.connect

 function wrk.format(method, path, headers, body) wrk.format returns a HTTP request string containing the passed parameters
    merged with values from the wrk table.
    根据参数和全局变量wrk,生成一个HTTP rquest stringfunction wrk.lookup(host, service) wrk.lookup returns a table containing all known addresses for the host and service pair. This corresponds to the POSIX getaddrinfo() function.
    给定hostserviceport/well known service name),返回所有可用的服务器地址信息。 function wrk.connect(addr) wrk.connect returns true if the address can be connected to, otherwise
    it returns false. The address must be one returned from wrk.lookup().
    测试与给定的服务器地址信息是否可以成功创建连接
  1. 示例
使用POST METHOD
wrk.method = "POST" wrk.body   = "foo=bar&baz=quux" wrk.headers["Content-Type"] = "application/x-www-form-urlencoded"

通过修改全局变量wrk,使得所有请求都使用POST方法,并指定了body和Content-Type头。

为每次request更换一个参数
request = function() uid = math.random(1, 10000000) path = "/test?uid=" .. uid return wrk.format(nil, path) end

通过在request方法中随机生成1~10000000之间的uid,使得请求中的uid参数随机。

每次请求之前延迟10ms
function delay() return 10 end
每个线程要先进行认证,认证之后获取token以进行压测
token = nil path = "/authenticate" request = function() return wrk.format("GET", path) end response = function(status, headers, body) if not token and status == 200 then token = headers["X-Token"] path = "/resource" wrk.headers["X-Token"] = token end end

在没有token的情况下,先访问/authenticate认证。认证成功后,读取token并替换path为/resource。

压测支持HTTP pipeline的服务
init = function(args) local r = {}
   r[1] = wrk.format(nil, "/?foo")
   r[2] = wrk.format(nil, "/?bar")
   r[3] = wrk.format(nil, "/?baz")

   req = table.concat(r) end request = function() return req end

通过在init方法中将三个HTTP request请求拼接在一起,实现每次发送三个请求,以使用HTTP pipeline。

https://www.cnblogs.com/xinzhao/p/6233009.html

nginx+php-fpm,使用Unix Socket还是tcp方式连接?

将Nginx与FastCGI的通信方式由TCP改为Unix Socket。TCP在高并发访问下比Unix Socket稳定,但Unix Socket速度要比TCP快”,看来这是真的存在。两者各有优缺点啊

1.worker_processes 越大越好(一定数量后性能增加不明显)


2.worker_cpu_affinity 所有cpu平分worker_processes 要比每个worker_processes 都跨cpu分配性能要好;不考虑php的执行,测试结果worker_processes数量是cpu核数的2倍性能最优

3.unix domain socket(共享内存的方式)要比tcp网络端口配置性能要好
不考虑backlog,请求速度有量级的飞跃,但错误率超过50%
加上backlog,性能有10%左右提升

4.调整nginx、php-fpm和内核的backlog(积压),connect() to unix:/tmp/php-fpm.socket failed (11: Resource temporarily unavailable) while connecting to upstream错误的返回会减少
nginx:
配置文件的server块
listen 80 default backlog=1024;

php-fpm:
配置文件的
listen.backlog = 2048

kernel参数:
/etc/sysctl.conf,不能低于上面的配置
net.ipv4.tcp_max_syn_backlog = 4096
net.core.netdev_max_backlog = 4096

5.增加单台服务器上的php-fpm的master实例,会增加fpm的处理能力,也能减少报错返回的几率
多实例启动方法,使用多个配置文件:
/usr/local/php/sbin/php-fpm -y /usr/local/php/etc/php-fpm.conf &
/usr/local/php/sbin/php-fpm -y /usr/local/php/etc/php-fpm1.conf &

nginx的fastcgi配置
    upstream phpbackend {
#      server   127.0.0.1:9000 weight=100 max_fails=10 fail_timeout=30;
#      server   127.0.0.1:9001 weight=100 max_fails=10 fail_timeout=30;
#      server   127.0.0.1:9002 weight=100 max_fails=10 fail_timeout=30;
#      server   127.0.0.1:9003 weight=100 max_fails=10 fail_timeout=30;
      server   unix:/var/www/php-fpm.sock weight=100 max_fails=10 fail_timeout=30;
      server   unix:/var/www/php-fpm1.sock weight=100 max_fails=10 fail_timeout=30;
      server   unix:/var/www/php-fpm2.sock weight=100 max_fails=10 fail_timeout=30;
      server   unix:/var/www/php-fpm3.sock weight=100 max_fails=10 fail_timeout=30;
#      server   unix:/var/www/php-fpm4.sock weight=100 max_fails=10 fail_timeout=30;
#      server   unix:/var/www/php-fpm5.sock weight=100 max_fails=10 fail_timeout=30;
#      server   unix:/var/www/php-fpm6.sock weight=100 max_fails=10 fail_timeout=30;
#      server   unix:/var/www/php-fpm7.sock weight=100 max_fails=10 fail_timeout=30;
    }

        location ~ \.php* {
            fastcgi_pass   phpbackend;
#           fastcgi_pass   unix:/var/www/php-fpm.sock;
            fastcgi_index index.php;
       ……….
       }

6.测试环境和结果

内存2G
swap2G
cpu 2核 Intel(R) Xeon(R) CPU E5405  @ 2.00GHz
采用ab远程访问测试,测试程序为php的字符串处理程序


1)在开4个php-fpm实例,nginx 8个worker_processes 每个cpu4个worker_processes ,backlog为1024,php的backlog为2048,内核backlog为4096,采用unix domain socket连接的情况下,其他保持参数不变

性能和错误率较为平衡,可接受,超过4个fpm实例,性能开始下降,错误率并没有明显下降
结论是fpm实例数,worker_processes数和cpu保持倍数关系,性能较高
影响性能和报错的参数为
php-fpm实例,nginx worker_processes数量,fpm的max_request,php的backlog,unix domain socket


10W请求,500并发无报错,1000并发报错率为0.9%

500并发:
Time taken for tests:   25 seconds avg.
Complete requests:      100000
Failed requests:        0
Write errors:           0
Requests per second:    4000 [#/sec] (mean) avg.
Time per request:       122.313 [ms] (mean)
Time per request:       0.245 [ms] (mean, across all concurrent requests)
Transfer rate:          800 [Kbytes/sec] received avg.

1000并发:
Time taken for tests:   25 seconds avg.
Complete requests:      100000
Failed requests:        524
   (Connect: 0, Length: 524, Exceptions: 0)
Write errors:           0
Non-2xx responses:      524
Requests per second:    3903.25 [#/sec] (mean)
Time per request:       256.197 [ms] (mean)
Time per request:       0.256 [ms] (mean, across all concurrent requests)
Transfer rate:          772.37 [Kbytes/sec] received

2)在其他参数不变,unix domain socket换为tcp网络端口连接,结果如下

500并发:
Concurrency Level:      500
Time taken for tests:   26.934431 seconds
Complete requests:      100000
Failed requests:        0
Write errors:           0
Requests per second:    3712.72 [#/sec] (mean)
Time per request:       134.672 [ms] (mean)
Time per request:       0.269 [ms] (mean, across all concurrent requests)
Transfer rate:          732.37 [Kbytes/sec] received

1000并发:
Concurrency Level:      1000
Time taken for tests:   28.385349 seconds
Complete requests:      100000
Failed requests:        0
Write errors:           0
Requests per second:    3522.94 [#/sec] (mean)
Time per request:       283.853 [ms] (mean)
Time per request:       0.284 [ms] (mean, across all concurrent requests)
Transfer rate:          694.94 [Kbytes/sec] received

与1)比较,有大约10%的性能下降

7. 5.16调整fpm的max_request参数为1000,并发1000报错返回降到200个以下,
Transfer rate在800左右