谈恋爱经

(一)爱你的,你爱的
如果要我去跟刚上大学的自己说的话,我可能会建议她不要谈恋爱,因为大学离家很远,谈了都成不了。
但我知道不可能,当时可想谈恋爱了。所以建议如下:
1.不要和离家很远的人谈恋爱。我一直觉得自己非常包容,但是在前男友家里大早上吃白米饭的时候,我是难以下咽的。因为我们这里早餐品种齐全,我20多年没吃过早餐吃米饭。他妈妈还叫我吃不下去放点开水。而且结婚的时候你才会意识到,本地人在这个城市的社会关系,会让刚出校门的你不至于感觉无所依靠,甚至有时候能成为你的助力。不过我也不建议你纯粹看条件,条件好的很多人很骄傲的,内心看不起对象。性价比不高。
2.别找不积极向上的人。当学生的时候会觉得不努力每天吊儿郎当的人很好玩,但是毕业了大概率是烂泥扶不上墙。为了避免遇到这种人,从一开始就别找,省得人家说我没变,是你变了。
这个我要讲得细致一点。
不要找那种特别会在朋友圈晒健身啊学习啊之类的男的,我遇到过一个,这么说吧,别人这么努力的健身,拍照修图,不是为了你一个女人的。
很多看起来普通的男生,其实有的很努力,要细致地了解。最好常常去图书馆,观察哪些人从大一到大四的目标几乎都一致,别找那种大一想考研,大二又想考公务员,大三又说要考教师,大四投简历的人,当然,如果都成功了可以找。
3.别找恋爱很多的人,我大学差点找了个高中就谈了8个的男生。有一说一,确实不错,约我会买好奶茶,讲话也好听。就是我拒绝了之后跟班里所有女生(共5个)表白了,有点尴尬。
4.别找精虫上脑的人。说你不跟我睡就是不爱我,我们分手吧。那就分,爱不爱的还要从这看,照他这么说性工作者简直普度众生了。这种人大概率以后会不尊重你的看法。
5.别因为寂寞谈恋爱。太难了,我随便写写,你随便看看,小姑娘想找人陪,根本不会冷静下来想想我是不是真的爱他。
6.别跟人品不好的人谈恋爱。到时候他在外面得罪人,别人会认为你也是一丘之貉。
7.遇到合适对象的方法就是:努力做好自己,并且开朗大方。
想找个努力的,你就也要努力,同时不要指望别人主动来找你,而是你去主动跟别人打招呼。相信我,直男的智商不会觉得是你不矜持。一般好的男生真的不会太主动,但我们人类都只会喜欢自己了解的人(看脸除外),所以努力让自己被别人所了解,有问题主动询问,对方帮助了再请个客,吃个饭,大大方方的,如果他对你有意思,一来二去就成了。而且别心急,你也要在普通交往中观察他是个什么样的人。
而且一定要坚持自我,我宁愿你显得自私一点。不要为了男朋友委屈自己,该给的关心、支持给到位,坦荡真诚待人,但不要为了男朋友损伤自己的利益。而且一个低自尊的人是注定被看不起的。坚持你的原则,做对自己好的事,如果有人因为这个离开你,那绝对不是你的良人。这点男女都一样。现在骗子太多了,不得不防。
如果可以的话,别高攀,别勉强,找个爱你,你爱,并且互相尊重的人。我知道这有点难,不过我们只需要一个这样的人啊。
(二)合适的三单
以前呢,大家恋爱都喜欢讲三观。
我想说,不妨也看看三单:账单菜单行程单
账单说明了两个人的消费观念,当然我不是推崇物质主义的恋爱,但是消费观念不一致的人是很难走到一起的。
花多花少是分人,但花在哪里是看心的,其实爱情里,尤其是女孩子,大家不也就是想要那种被放在心上的感觉吗?
菜单不只是在讲吃饭,其实更多的是两个人的生活方式,是看两个人能否和谐的生活。
一个人擅长做什么是他的本事,但一个人愿意为你做什么才是他的心意。他想到今天是你的例假特意给你带了红糖水,叮嘱今天不吃酸辣,记得你爱吃什么讨厌什么,哪天提起有家店很久没去过等等,细节之处可以透露生活。
如果说菜单是柴米油盐酱醋茶的生活,那行程单应该就是诗和远方了。
之前看过一篇文章,大概就是讲两个人合不合适出去旅游一次就知道了。因为只有在陌生环境和未知的世界里,一个人才会表现出本能的真实反应,也更能看出两个人的合适与否。
我见过很多人出去旅行一趟甚至中途就分手,旅途争吵时,他把你一个人扔下你转身就走是否是真的在乎你?两个人遇到困难时他是在冷静的想办法还是彼此埋怨?熟悉环境下的反应是可以控制的,但陌生环境下的本能可以暴露出很多问题。
如果说恋爱不要选哪些人,我建议你不要选三单不同的人。
(三)远离大叔
大叔!!!大叔!!!大叔!!!
重要的事情说三遍。
姑娘们,醒一醒,不要被电视上的那些帅气多金,动不动就壁咚的男人们给骗了啊
你以为你遇到的大叔会是韩商言啊
你以为你遇到的大叔会是温柔,体贴,愿意为你,从一个万花丛中过,片叶不沾身的老狐狸从此从了良?
醒醒吧,姑娘们。
我说的大叔是指三十岁以上,你以为的事业有成,温柔,体贴会照顾人的男人们
大学生,尤其是第一次谈恋爱,大叔这种危险的生物会满足你的虚荣心和所谓的安全感
在你看来,他成熟有魅力舍得给你花钱。在他看来,两三百的口红和出去吃顿大餐,送几次小礼物就能把你拿下!
都是久经沙场的老狐狸,骗的你团团转,你还要给他数钱呢
到时候,骗钱都是小事,要是真被骗了色,他拍拍屁股走了人,你失去清白不说,万一怀孕什么的,后顾之忧都是你的。吃亏的永远是女孩子!
所以啊,在大学里,什么样的男孩子没有啊。帅气的,闷骚的,高的,矮的,阳光正直有点直男的,稳重偶尔孩子气的,学霸的,学渣的,学霸装学渣的,学渣装学霸的,什么样的没有啊,总有一款适合你。
最起码,这些男孩子不会害你。当然,我不排除有那种和吕子乔一样,一心就为了泡妞的人存在,但是,相比较与社会来说,大学里的人真的是大多数都是很不错的啊
所以啊,姑娘们,擦亮你的眼睛,要是狐狸们真的想把尾巴藏起来,你觉得你会是他的对手?
大学生,还没出社会,以为校园里的人就是所有人了
以为体会过学生会的黑暗,有过不对等的奖学金评比,就是见过不公平的世界了
我告诉你,你还差远了
等你去社会上摔打几年,有了一定阅历,有了一定的认知水平,你就会明白原来的你有多么地可笑。
所以,少看点电视剧,少看点霸道总裁,多睁眼看看这个世界。
(四)远离暴躁的人
最好不要选那些容易情绪失控,性格偏激的人。
不论男孩子女孩子,离家上大学都容易产生焦虑和孤独感,也有一些同学是为了结伴学习,于是开始考虑发展亲密关系。
如果你正在接触的异性朋友在早期交往过程中出现这些问题,你就要谨慎考虑是否要及时止损。这些问题包括:
1.一句话就惹得他暴跳如雷,难以交流,或者对方的语言中透露着霸权主义。
比如你因为异性朋友随意翻看你的微信聊天、邮箱内容并且随意查看、回复和删除而不满,于是提出郑重交涉要求对方尊重你的隐私权。对方立刻反驳:你是不是有见不得人的事情?你是不是瞒着我有其他计划?你为什么没经过我同意就发出这些消息?谁允许你联系这个人的?
不要以为这种朋友很奇葩,在大学校园里很常见,他们往往打着:情侣之间没有隐私,我是为你考虑,你考虑不周全等等名号干涉你绑架你的社交圈。
2.控制欲非常强,不容你提出不同观点。
对方做事情我行我素,看电影只选自己喜欢的,吃饭只点自己爱吃的,安排学习计划完全按照自己所需,并且所有安排要求你必须一致,不考虑你的实际情况和所需。当你提出异议的时候,对方就说:我以为你会喜欢的,你怎么会不喜欢我安排的呢?我把你当做我的另一半,你要跟上我的节奏和安排,我做什么你就跟着走。计划都是我现成做好的,你还有什么不满意的?这些都属于人格绑架,强迫你变成另一个她/他。
3.常常通过否定你的价值观来灌输他/她的观念。
你可能喜欢和基友们偶尔打个游戏放松放松联络一下感情,结果被质问“不干正事”“游手好闲”“以后绝对不能让我看见你玩游戏”。当你喜欢某种风格的衣服,喜欢收拾一下摄影留念,就被指责“卖弄风骚”“不务正业”“轻薄”。不同的教育背景和家庭理念可能会产生不同的观念,允许每个人表达自己的想法。但是将自己的观念横加在别人身上并且让他/她产生耻辱感和否定自己,这是完全不能接受的。
4.容易情绪化、偏激,难以控制自己的脾气。
不随自己心意就发脾气,摔打,暴走,甚至拳打脚踢或者语言胁迫对方,因为一点琐事就爆发自己的负面情绪,并且将对方当做自己的出气筒,这是错误和失智的表现,这不是真性情,不是可爱或娇憨。
而且过于情绪化或者偏激的人也往往表现出暴力倾向,包括肢体暴力、语言暴力、精神暴力和性暴力。
5.否定自己做错事,拒绝道歉,回避指责。
做错事就要反思错误的来源,反思自己的行为,并且要及时改正及时道歉。但是以“我的出发点是好的,我只是做的不好,我不会为自己的行为道歉”为幌子为自己辩护,这是错误的。面对对方的批评和指责,完全忽视或者回避,这会埋下祸患,下次仍然继续发生同样的矛盾。
6.不尊重你的人格。
你是一个独立自强的人,对生活充满热情和期待,有自己的规划和安排,但是对方不断给你洗脑:你以后就跟着我混,我俩一起干。你那么要强干什么,以后还不是靠我?没有人喜欢那么聪明的的女生/男生!
在大学不仅是寻求知识,更要寻求自己的价值观。如果你有找对象的计划,最好找一个价值观相符的,人品端正的伴侣,而不是找一个烫手山芋。
后记:
什么样的不能找呢?
1.你走心,它走肾的。
2.喜欢你,但不止喜欢你一个的,爱你,又爱她她他(脚踏n条船)
3.把你对它的容忍,直接无视成你就这么善良
4.甜言蜜语一大堆,结果做到没几样
5.和你做了所有男女朋友该做的事,但就是不和你确定关系
6.一切责任推向对方(男或女),自己丑事做尽,还想给自己立个贞节牌坊
7.家中有妻室,家外有二奶。
8.对你若即若离,用时亲近,没价值时便一脚踢开
9.妈宝男
10.中央空调,对所有女的都暖洋洋,泡一个是一个
11.不主动不拒绝不负责
12.渣男锡纸烫,渣女大波浪(这条调节气氛勿当真)

原文链接:https://art.china.com/news/hot/13003932/20200805/38604407_1.html

All TAP-Windows adapters on this system are currently in use

想要通过openVPN链接远程VPN服务,需要本地虚拟网卡的支持
(TAP-Windows Adapter V9)

正常情况下,出现上面的错误,是要连多个台vpn服务器的时候,每多一台,就需要多一个虚拟网卡,而系统只有一个(TAP-Windows Adapter V9)虚拟网卡。自己新建一个虚拟网卡就可以解决问题了。

但是实际情况是,通过设备管理器新建的(TAP-Windows Adapter V9)可能不能用,别慌,看看能不能找到下面的文件

C:\Program Files\TAP-Windows\bin\addtap.bat

右击以管理员身份运行,会自动加上一个可用的(TAP-Windows Adapter V9)虚拟网卡,再次连接,发现连接成功。

curl 为什么比 file_get_content 快

一、背景

大家做项目的时候,不免会看到前辈的代码。博主最近看到前辈有的时候请求外部接口用的是file_get_contents,有的用的是curl。稍微了解这两部分的同学都知道,curl在性能上和速度上是优于file_get_contents的,那么为什么呢,从哪里体现出来的差距呢?
二、file_get_contents和curl

1、file_get_contents概述

file_get_contents() 函数把整个文件读入一个字符串中。
手册:http://www.w3school.com.cn/php/func_filesystem_file_get_contents.asp

这里可以看出来,file_get_contents函数的最优选择是读取文件的内容。要求对方的服务器php.ini必须开启:allow_url_fopen

2、curl的概述

CURL是一个非常强大的开源库,支持很多协议,包括HTTP、FTP、TELNET等,我们使用它来发送HTTP请求。它给我 们带来的好处是可以通过灵活的选项设置不同的HTTP协议参数,并且支持HTTPS。CURL可以根据URL前缀是“HTTP” 还是“HTTPS”自动选择是否加密发送内容。需要php.ini开启curl扩展

参考文章:http://www.cnblogs.com/manongxiaobing/p/4698990.html

从定义上来说,curl作为一个开源库,拥有众多的语法也支持众多的协议,这点能看出来curl相比于file_get_contents() 是能做更多的事情的
三、为什么curl比file_get_contents好

博主百度了网上的众多说法,总共分为下面几个方面:

1、file_get_contents() 更容易造成服务器挂掉

关于造成服务器挂掉,这部分主要涉及两个方面:

(1)直接使用file_get_contents,未设置超时处理造成nginx报错:502 Bad Gateway

这部分大家可以参考博客:http://www.cnblogs.com/aipiaoborensheng/p/5000096.html

设置超时时间即可。当然,如果是选用curl的话,设置超时时间会更加的方便,明显,一般不会因为超时而造成服务器垮掉。

(2)用file_get_contents请求效率很低,页面经常卡顿很久

这部分在网上也有个解释,说file_get_contents每次请求远程URL中的数据都会重新做DNS查询,并不对DNS信息进行缓存。而curl则可以通过设置参数的方式来缓存DNS,从而达到快速访问的目的

curl设置DNS缓存:


CURLOPT_DNS_USE_GLOBAL_CACHE 启用时会启用一个全局的DNS缓存,此项为线程安全的,并且默认启用。
CURLOPT_DNS_CACHE_TIMEOUT 设置在内存中保存DNS信息的时间,默认为120秒。


参考链接:https://www.cnblogs.com/jking10/p/6595981.html

(3)curl能做到file_get_contents做不到的事情

这部分是博主之前解决一个需求的时候发现的。当我需要把网络图片转换为二进制的图片流的时候,curl能实现,而file_get_contens就不行。

参考我之前的文章:https://blog.csdn.net/LJFPHP/article/details/81357839

2、file_get_contents速度很慢

关于速度慢的原因,一部分是DNS缓存,这确实是file_get_contents的瓶颈,另一方面就是关于header头的原因。大家都知道,file_get_contents的请求是不带头的,这样它接收完所有数据后,没有主动断开和服务器的http连接。

解决方案:


$opts = array(
‘http’=>array(
‘method’ => ‘POST’,
‘header’ => ‘Content-type:application/x-www-form-urlencoded’,
‘content’ => $postdata,
‘timeout’ => 60 * 10 // 超时时间(单位:s)
‘Connection’=>”close”
)
);
$context = stream_context_create($opts);
file_get_contents($filename, false, $context);


我们通过设置句柄的方式,定义超时时间和header头,这样就能最大化的提升file_get_contents的速度

3、file_get_contents请求HTTP时,使用的是http_fopen_wrapper,不会keeplive。而curl却可以。这样在多次请求多个链接时,curl效率会好一些。

这部分博主查询了下keeplive的相关知识,发现自己对于http请求方面还不是很熟悉。关于keeplive也是一个很大模块,博主这里就也不废话了,给大家推荐几篇不错的博客,有兴趣的可以看看:


(1)(apache)http的keeplive

https://blog.csdn.net/jackyrongvip/article/details/9217931
http://www.cnblogs.com/hixiaowei/p/9261358.html

(2)tcp的keepAlive

http://www.cnblogs.com/xiaoleiel/p/8308514.html


四、关于服务器是否支持file_get_contents的判断方法

众所周知的,file_get_contents是需要请求的服务商开启allow_url_fopen,但是很多服务商为了安全考虑都会关掉这个功能。而curl是要求php必须开启curl扩展。不过相对来说,很少有服务商不开启curl的,所以curl的运用场合会更多一些。

这里我们可以使用php自带的:function_exists方法来判断服务商是否定义的有此方法。
文档:http://php.net/manual/zh/function.function-exists.php
代码:


if(function_exists(‘file_get_contents’)) {
$file_contents = file_get_contents($url);
} else {
//这里可以执行curl方案
}


通过对比我们也能发现两个函数的优劣势。如果是读取文件或者只是去拉取数据,那么file_get_contents的效率比较高 也比较简单。如果是要进行远程连接或者高频次的访问,那么还是老老实实用curl吧。
————————————————
版权声明:本文为CSDN博主「铁柱同学」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/LJFPHP/article/details/83822628

css flex弹性布局详解

  flex( flexible box:弹性布局盒模型),是2009年w3c提出的一种可以简洁、快速弹性布局的属性。

主要思想是给予容器控制内部元素高度和宽度的能力。目前已得到以下浏览器支持:

  其中在webkit内核的浏览器中使用时,必须加上-webkit-前缀

采用Flex布局的元素,称为Flex容器(flex container),简称”容器”。

它的所有子元素自动成为容器成员,称为Flex项目(flex item),简称”项目”。

下图为flex的相关概念的示意图

 

  使用flex布局的容器(flex container),它内部的元素自动成为flex项目(flex item)。

容器拥有两根隐形的轴,水平的主轴(main axis),和竖直的交叉轴。

主轴开始的位置,即主轴与右边框的交点,称为main start;主轴结束的位置称为main end;

交叉轴开始的位置称为cross start;交叉轴结束的位置称为cross end。

item按主轴或交叉轴排列,item在主轴方向上占据的宽度称为main size,在交叉轴方向上占据的宽度称为cross size。

此外,需注意使用flex容器内元素,即flex item的float,clear、vertical-align属性将失效。

 

二、容器的属性

  以下6个属性设置在容器上。

  • flex-direction
  • flex-wrap
  • flex-flow
  • justify-content
  • align-items
  • align-content

2.1 flex-direction属性

  flex-direction属性决定主轴的方向(即项目的排列方向)。

  

  flex-direction: row | row-reverse | column | column-reverse;

 

 

  • row(默认值):主轴为水平方向,起点在左端。
  • row-reverse:主轴为水平方向,起点在右端。
  • column:主轴为垂直方向,起点在上沿。
  • column-reverse:主轴为垂直方向,起点在下沿。

 

2.2 flex-wrap属性

  默认情况下,项目都排在一条线(又称”轴线”)上。flex-wrap属性定义,如果一条轴线排不下,如何换行。

 

  flex-wrap: nowrap | wrap | wrap-reverse ; 

 

  • nowrap(默认值):不换行。
  • wrap:换行,第一行在上方。
  • wrap-reverse:换行,第一行在下方。

(1)nowrap(默认):不换行。

(2)wrap:换行,第一行在上方。

(3)wrap-reverse:换行,第一行在下方。

2.3 flex-flow

  flex-flow属性是flex-direction属性和flex-wrap属性的简写形式,默认值为row nowrap。

  flex-flow: <flex-direction> || <flex-wrap>;

2.4 justify-content属性

  justify-content属性定义了项目在主轴上的对齐方式。

它可能取5个值,具体对齐方式与轴的方向有关。下面假设主轴为从左到右。

 

    justify-content: flex-start | flex-end | center | space-between | space-around;

 

  • flex-start(默认值):左对齐
  • flex-end:右对齐
  • center: 居中
  • space-between:两端对齐,项目之间的间隔都相等。
  • space-around:每个项目两侧的间隔相等。所以,项目之间的间隔比项目与边框的间隔大一倍。

 

2.5 align-items属性

  align-items属性定义项目在交叉轴上如何对齐。

它可能取5个值。具体的对齐方式与交叉轴的方向有关,下面假设交叉轴从上到下。

 

   align-items: flex-start | flex-end | center | baseline | stretch;

 

  • flex-start:交叉轴的起点对齐。
  • flex-end:交叉轴的终点对齐。
  • center:交叉轴的中点对齐。
  • baseline: 项目的第一行文字的基线对齐。
  • stretch(默认值):如果项目未设置高度或设为auto,将占满整个容器的高度。

 

2.6 align-content属性

  align-content属性定义了多根轴线的对齐方式。如果项目只有一根轴线,该属性不起作用。

 

  align-content: flex-start | flex-end | center | space-between | space-around | stretch;

 

  • flex-start:与交叉轴的起点对齐。
  • flex-end:与交叉轴的终点对齐。
  • center:与交叉轴的中点对齐。
  • space-between:与交叉轴两端对齐,轴线之间的间隔平均分布。
  • space-around:每根轴线两侧的间隔都相等。所以,轴线之间的间隔比轴线与边框的间隔大一倍。
  • stretch(默认值):轴线占满整个交叉轴。

 

三、项目的属性

  以下6个属性设置在项目上。

  • order
  • flex-grow
  • flex-shrink
  • flex-basis
  • flex
  • align-self

3.1 order属性

  order属性定义项目的排列顺序。数值越小,排列越靠前,默认为0。

  order: <integer>;

3.2 flex-grow属性

  flex-grow属性定义项目的放大比例,默认为0,即如果存在剩余空间,也不放大。

如果所有项目的flex-grow属性都为1,则它们将等分剩余空间(如果有的话)。

如果一个项目的flex-grow属性为2,其他项目都为1,则前者占据的剩余空间将比其他项多一倍。

  flex-grow: <number>; /* default 0 */

 

3.3 flex-shrink属性

  flex-shrink属性定义了项目的缩小比例,默认为1,即如果空间不足,该项目将缩小。

如果所有项目的flex-shrink属性都为1,当空间不足时,都将等比例缩小。

如果一个项目的flex-shrink属性为0,其他项目都为1,则空间不足时,前者不缩小。

负值对该属性无效。

flex-shrink: <number>; /* default 1 */

 

3.4 flex-basis属性

  flex-basis属性定义了在分配多余空间之前,项目占据的主轴空间(main size)。

浏览器根据这个属性,计算主轴是否有多余空间。它的默认值为auto,即项目的本来大小。

它可以设为跟width或height属性一样的值(比如350px),则项目将占据固定空间。

  flex-basis: <length> | auto; /* default auto */

 

3.5 flex属性

  flex属性是flex-grow, flex-shrink 和 flex-basis的简写,默认值为0 1 auto。后两个属性可选。

该属性有两个快捷值:auto (1 1 auto) 和 none (0 0 auto)。

建议优先使用这个属性,而不是单独写三个分离的属性,因为浏览器会推算相关值。

  flex: none | [ <'flex-grow'> <'flex-shrink'> || <'flex-basis'> ]

 

3.6 align-self属性

  align-self属性允许单个项目有与其他项目不一样的对齐方式,可覆盖align-items属性。

默认值为auto,表示继承父元素的align-items属性,如果没有父元素,则等同于stretch。


   align-self: auto | flex-start | flex-end | center | baseline | stretch;

  • flex-start:交叉轴的起点对齐。
  • flex-end:交叉轴的终点对齐。
  • center:交叉轴的中点对齐。
  • baseline: 项目的第一行文字的基线对齐。
  • stretch(默认值):如果项目未设置高度或设为auto,将占满整个容器的高度。

文章来源:https://www.cnblogs.com/xiaobaiv/p/9020335.html

你不会还在用这8个错误的SQL写法吧?

1、LIMIT 语句

分页查询是最常用的场景之一,但也通常也是最容易出问题的地方。比如对于下面简单的语句,一般 DBA 想到的办法是在 type, name, create_time 字段上加组合索引。这样条件排序都能有效的利用到索引,性能迅速提升。
SELECT * 
FROM   operation 
WHERE  type = 'SQLStats' 
       AND name = 'SlowLog' 
ORDER  BY create_time 
LIMIT  1000, 10;
好吧,可能90%以上的 DBA 解决该问题就到此为止。但当 LIMIT 子句变成 “LIMIT 1000000,10” 时,程序员仍然会抱怨:我只取10条记录为什么还是慢?
要知道数据库也并不知道第1000000条记录从什么地方开始,即使有索引也需要从头计算一次。出现这种性能问题,多数情形下是程序员偷懒了。
在前端数据浏览翻页,或者大数据分批导出等场景下,是可以将上一页的最大值当成参数作为查询条件的。SQL 重新设计如下:
SELECT   * 
FROM     operation 
WHERE    type = 'SQLStats' 
AND      name = 'SlowLog' 
AND      create_time > '2017-03-16 14:00:00' 
ORDER BY create_time limit 10;
在新设计下查询时间基本固定,不会随着数据量的增长而发生变化。

2、隐式转换

SQL语句中查询变量和字段定义类型不匹配是另一个常见的错误。比如下面的语句:
mysql> explain extended SELECT * 
     > FROM   my_balance b 
     > WHERE  b.bpn = 14000000123 
     >       AND b.isverified IS NULL ;
mysql> show warnings;
| Warning | 1739 | Cannot use ref access on index 'bpn' due to type or collation conversion on field 'bpn'
其中字段 bpn 的定义为 varchar(20),MySQL 的策略是将字符串转换为数字之后再比较。函数作用于表字段,索引失效。
上述情况可能是应用程序框架自动填入的参数,而不是程序员的原意。现在应用框架很多很繁杂,使用方便的同时也小心它可能给自己挖坑。

3、关联更新、删除

虽然 MySQL5.6 引入了物化特性,但需要特别注意它目前仅仅针对查询语句的优化。对于更新或删除需要手工重写成 JOIN。
比如下面 UPDATE 语句,MySQL 实际执行的是循环/嵌套子查询(DEPENDENT SUBQUERY),其执行时间可想而知。
UPDATE operation o 
SET    status = 'applying' 
WHERE  o.id IN (SELECT id 
                FROM   (SELECT o.id, 
                               o.status 
                        FROM   operation o 
                        WHERE  o.group = 123 
                               AND o.status NOT IN ( 'done' ) 
                        ORDER  BY o.parent, 
                                  o.id 
                        LIMIT  1) t);
执行计划:
+----+--------------------+-------+-------+---------------+---------+---------+-------+------+-----------------------------------------------------+
| id | select_type        | table | type  | possible_keys | key     | key_len | ref   | rows | Extra                                               |
+----+--------------------+-------+-------+---------------+---------+---------+-------+------+-----------------------------------------------------+
| 1  | PRIMARY            | o     | index |               | PRIMARY | 8       |       | 24   | Using where; Using temporary                        |
| 2  | DEPENDENT SUBQUERY |       |       |               |         |         |       |      | Impossible WHERE noticed after reading const tables |
| 3  | DERIVED            | o     | ref   | idx_2,idx_5   | idx_5   | 8       | const | 1    | Using where; Using filesort                         |
+----+--------------------+-------+-------+---------------+---------+---------+-------+------+-----------------------------------------------------+
重写为 JOIN 之后,子查询的选择模式从 DEPENDENT SUBQUERY 变成 DERIVED,执行速度大大加快,从7秒降低到2毫秒。
UPDATE operation o 
       JOIN  (SELECT o.id, 
                            o.status 
                     FROM   operation o 
                     WHERE  o.group = 123 
                            AND o.status NOT IN ( 'done' ) 
                     ORDER  BY o.parent, 
                               o.id 
                     LIMIT  1) t
         ON o.id = t.id 
SET    status = 'applying' 
执行计划简化为:
+----+-------------+-------+------+---------------+-------+---------+-------+------+-----------------------------------------------------+
| id | select_type | table | type | possible_keys | key   | key_len | ref   | rows | Extra                                               |
+----+-------------+-------+------+---------------+-------+---------+-------+------+-----------------------------------------------------+
| 1  | PRIMARY     |       |      |               |       |         |       |      | Impossible WHERE noticed after reading const tables |
| 2  | DERIVED     | o     | ref  | idx_2,idx_5   | idx_5 | 8       | const | 1    | Using where; Using filesort                         |
+----+-------------+-------+------+---------------+-------+---------+-------+------+-----------------------------------------------------+

4、混合排序

MySQL 不能利用索引进行混合排序。但在某些场景,还是有机会使用特殊方法提升性能的。
SELECT * 
FROM   my_order o 
       INNER JOIN my_appraise a ON a.orderid = o.id 
ORDER  BY a.is_reply ASC, 
          a.appraise_time DESC 
LIMIT  0, 20 
执行计划显示为全表扫描:
+----+-------------+-------+--------+-------------+---------+---------+---------------+---------+-+
| id | select_type | table | type   | possible_keys     | key     | key_len | ref      | rows    | Extra    
+----+-------------+-------+--------+-------------+---------+---------+---------------+---------+-+
|  1 | SIMPLE      | a     | ALL    | idx_orderid | NULL    | NULL    | NULL    | 1967647 | Using filesort |
|  1 | SIMPLE      | o     | eq_ref | PRIMARY     | PRIMARY | 122     | a.orderid |       1 | NULL           |
+----+-------------+-------+--------+---------+---------+---------+-----------------+---------+-+
由于 is_reply 只有0和1两种状态,我们按照下面的方法重写后,执行时间从1.58秒降低到2毫秒。
SELECT * 
FROM   ((SELECT *
         FROM   my_order o 
                INNER JOIN my_appraise a 
                        ON a.orderid = o.id 
                           AND is_reply = 0 
         ORDER  BY appraise_time DESC 
         LIMIT  0, 20) 
        UNION ALL 
        (SELECT *
         FROM   my_order o 
                INNER JOIN my_appraise a 
                        ON a.orderid = o.id 
                           AND is_reply = 1 
         ORDER  BY appraise_time DESC 
         LIMIT  0, 20)) t 
ORDER  BY  is_reply ASC, 
          appraisetime DESC 
LIMIT  20;

5、EXISTS语句

MySQL 对待 EXISTS 子句时,仍然采用嵌套子查询的执行方式。如下面的 SQL 语句:
SELECT *
FROM   my_neighbor n 
       LEFT JOIN my_neighbor_apply sra 
              ON n.id = sra.neighbor_id 
                 AND sra.user_id = 'xxx' 
WHERE  n.topic_status < 4 
       AND EXISTS(SELECT 1 
                  FROM   message_info m 
                  WHERE  n.id = m.neighbor_id 
                         AND m.inuser = 'xxx') 
       AND n.topic_type <> 5 
执行计划为:
+----+--------------------+-------+------+-----+------------------------------------------+---------+-------+---------+ -----+
| id | select_type        | table | type | possible_keys     | key   | key_len | ref   | rows    | Extra   |
+----+--------------------+-------+------+ -----+------------------------------------------+---------+-------+---------+ -----+
|  1 | PRIMARY            | n     | ALL  |  | NULL     | NULL    | NULL  | 1086041 | Using where                   |
|  1 | PRIMARY            | sra   | ref  |  | idx_user_id | 123     | const |       1 | Using where          |
|  2 | DEPENDENT SUBQUERY | m     | ref  |  | idx_message_info   | 122     | const |       1 | Using index condition; Using where |
+----+--------------------+-------+------+ -----+------------------------------------------+---------+-------+---------+ -----+
去掉 exists 更改为 join,能够避免嵌套子查询,将执行时间从1.93秒降低为1毫秒。
SELECT *
FROM   my_neighbor n 
       INNER JOIN message_info m 
               ON n.id = m.neighbor_id 
                  AND m.inuser = 'xxx' 
       LEFT JOIN my_neighbor_apply sra 
              ON n.id = sra.neighbor_id 
                 AND sra.user_id = 'xxx' 
WHERE  n.topic_status < 4 
       AND n.topic_type <> 5 
新的执行计划:
+----+-------------+-------+--------+ -----+------------------------------------------+---------+ -----+------+ -----+
| id | select_type | table | type   | possible_keys     | key       | key_len | ref   | rows | Extra                 |
+----+-------------+-------+--------+ -----+------------------------------------------+---------+ -----+------+ -----+
|  1 | SIMPLE      | m     | ref    | | idx_message_info   | 122     | const    |    1 | Using index condition |
|  1 | SIMPLE      | n     | eq_ref | | PRIMARY   | 122     | ighbor_id |    1 | Using where      |
|  1 | SIMPLE      | sra   | ref    | | idx_user_id | 123     | const     |    1 | Using where           |
+----+-------------+-------+--------+ -----+------------------------------------------+---------+ -----+------+ -----+

6、条件下推

外部查询条件不能够下推到复杂的视图或子查询的情况有:
  • 聚合子查询;
  • 含有 LIMIT 的子查询;
  • UNION 或 UNION ALL 子查询;
  • 输出字段中的子查询;
如下面的语句,从执行计划可以看出其条件作用于聚合子查询之后:
SELECT * 
FROM   (SELECT target, 
               Count(*) 
        FROM   operation 
        GROUP  BY target) t 
WHERE  target = 'rm-xxxx' 
+----+-------------+------------+-------+---------------+-------------+---------+-------+------+-------------+
| id | select_type | table      | type  | possible_keys | key         | key_len | ref   | rows | Extra       |
+----+-------------+------------+-------+---------------+-------------+---------+-------+------+-------------+
|  1 | PRIMARY     | <derived2> | ref   | <auto_key0>   | <auto_key0> | 514     | const |    2 | Using where |
|  2 | DERIVED     | operation  | index | idx_4         | idx_4       | 519     | NULL  |   20 | Using index |
+----+-------------+------------+-------+---------------+-------------+---------+-------+------+-------------+
确定从语义上查询条件可以直接下推后,重写如下:
SELECT target, 
       Count(*) 
FROM   operation 
WHERE  target = 'rm-xxxx' 
GROUP  BY target
执行计划变为:
+----+-------------+-----------+------+---------------+-------+---------+-------+------+--------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-----------+------+---------------+-------+---------+-------+------+--------------------+
| 1 | SIMPLE | operation | ref | idx_4 | idx_4 | 514 | const | 1 | Using where; Using index |
+----+-------------+-----------+------+---------------+-------+---------+-------+------+--------------------+

7、提前缩小范围

先上初始 SQL 语句:
SELECT * 
FROM   my_order o 
       LEFT JOIN my_userinfo u 
              ON o.uid = u.uid
       LEFT JOIN my_productinfo p 
              ON o.pid = p.pid 
WHERE  ( o.display = 0 ) 
       AND ( o.ostaus = 1 ) 
ORDER  BY o.selltime DESC 
LIMIT  0, 15 
该SQL语句原意是:先做一系列的左连接,然后排序取前15条记录。从执行计划也可以看出,最后一步估算排序记录数为90万,时间消耗为12秒。
+----+-------------+-------+--------+---------------+---------+---------+-----------------+--------+----------------------------------------------------+
| id | select_type | table | type   | possible_keys | key     | key_len | ref             | rows   | Extra                                              |
+----+-------------+-------+--------+---------------+---------+---------+-----------------+--------+----------------------------------------------------+
|  1 | SIMPLE      | o     | ALL    | NULL          | NULL    | NULL    | NULL            | 909119 | Using where; Using temporary; Using filesort       |
|  1 | SIMPLE      | u     | eq_ref | PRIMARY       | PRIMARY | 4       | o.uid |      1 | NULL                                               |
|  1 | SIMPLE      | p     | ALL    | PRIMARY       | NULL    | NULL    | NULL            |      6 | Using where; Using join buffer (Block Nested Loop) |
+----+-------------+-------+--------+---------------+---------+---------+-----------------+--------+----------------------------------------------------+
由于最后 WHERE 条件以及排序均针对最左主表,因此可以先对 my_order 排序提前缩小数据量再做左连接。SQL 重写后如下,执行时间缩小为1毫秒左右。
SELECT * 
FROM (
SELECT * 
FROM   my_order o 
WHERE  ( o.display = 0 ) 
       AND ( o.ostaus = 1 ) 
ORDER  BY o.selltime DESC 
LIMIT  0, 15
) o 
     LEFT JOIN my_userinfo u 
              ON o.uid = u.uid 
     LEFT JOIN my_productinfo p 
              ON o.pid = p.pid 
ORDER BY  o.selltime DESC
limit 0, 15
再检查执行计划:子查询物化后(select_type=DERIVED)参与 JOIN。虽然估算行扫描仍然为90万,但是利用了索引以及 LIMIT 子句后,实际执行时间变得很小。
+----+-------------+------------+--------+---------------+---------+---------+-------+--------+----------------------------------------------------+
| id | select_type | table      | type   | possible_keys | key     | key_len | ref   | rows   | Extra                                              |
+----+-------------+------------+--------+---------------+---------+---------+-------+--------+----------------------------------------------------+
|  1 | PRIMARY     | <derived2> | ALL    | NULL          | NULL    | NULL    | NULL  |     15 | Using temporary; Using filesort                    |
|  1 | PRIMARY     | u          | eq_ref | PRIMARY       | PRIMARY | 4       | o.uid |      1 | NULL                                               |
|  1 | PRIMARY     | p          | ALL    | PRIMARY       | NULL    | NULL    | NULL  |      6 | Using where; Using join buffer (Block Nested Loop) |
|  2 | DERIVED     | o          | index  | NULL          | idx_1   | 5       | NULL  | 909112 | Using where                                        |
+----+-------------+------------+--------+---------------+---------+---------+-------+--------+----------------------------------------------------+

8、中间结果集下推

再来看下面这个已经初步优化过的例子(左连接中的主表优先作用查询条件):
SELECT    a.*, 
          c.allocated 
FROM      ( 
              SELECT   resourceid 
              FROM     my_distribute d 
              WHERE    isdelete = 0 
              AND      cusmanagercode = '1234567' 
              ORDER BY salecode limit 20) a 
LEFT JOIN 
          ( 
              SELECT   resourcesid, sum(ifnull(allocation, 0) * 12345) allocated 
              FROM     my_resources 
              GROUP BY resourcesid) c 
ON        a.resourceid = c.resourcesid
那么该语句还存在其它问题吗?不难看出子查询 c 是全表聚合查询,在表数量特别大的情况下会导致整个语句的性能下降。
其实对于子查询 c,左连接最后结果集只关心能和主表 resourceid 能匹配的数据。因此我们可以重写语句如下,执行时间从原来的2秒下降到2毫秒。
SELECT  a.*, 
        c.allocated 
FROM    ( 
            SELECT   resourceid 
            FROM     my_distribute d 
            WHERE    isdelete = 0 
            AND      cusmanagercode = '1234567' 
            ORDER BY salecode limit 20) a 
LEFT JOIN 
        ( 
            SELECT   resourcesid, sum(ifnull(allocation, 0) * 12345) allocated 
            FROM     my_resources r, 
            ( 
                SELECT   resourceid 
                FROM     my_distribute d 
                WHERE    isdelete = 0 
                AND      cusmanagercode = '1234567' 
                ORDER BY salecode limit 20) a 
WHERE    r.resourcesid = a.resourcesid 
GROUP BY resourcesid) c 
ON        a.resourceid = c.resourcesid
但是子查询 a 在我们的SQL语句中出现了多次。这种写法不仅存在额外的开销,还使得整个语句显的繁杂。使用 WITH 语句再次重写:
WITH a AS 
( 
    SELECT   resourceid 
    FROM     my_distribute d 
    WHERE    isdelete = 0 
    AND      cusmanagercode = '1234567' 
    ORDER BY salecode limit 20)
SELECT    a.*, 
          c.allocated 
FROM      a 
LEFT JOIN 
          ( 
              SELECT   resourcesid, sum(ifnull(allocation, 0) * 12345) allocated 
              FROM     my_resources r, a 
              WHERE    r.resourcesid = a.resourcesid 
              GROUP BY resourcesid) c 
ON        a.resourceid = c.resourcesid

总结

数据库编译器产生执行计划,决定着SQL的实际执行方式。但是编译器只是尽力服务,所有数据库的编译器都不是尽善尽美的。
上述提到的多数场景,在其它数据库中也存在性能问题。了解数据库编译器的特性,才能避规其短处,写出高性能的SQL语句。
程序员在设计数据模型以及编写SQL语句时,要把算法的思想或意识带进来。
编写复杂SQL语句要养成使用 WITH 语句的习惯。简洁且思路清晰的SQL语句也能减小数据库的负

原文链接:https://juejin.im/post/5d84c348f265da03951a2eb4

Linux性能监控之vmstat和dstat

本文链接:https://blog.csdn.net/smooth00/article/details/78623728
说来惭愧,做了这么久的性能测试,居然对linux的vmstat这个命令还不熟悉,对很多指标的具体意义都有点模糊不清,今天花了点时间好好学习、整理一下这个命令的相关资料。因为这个命令确实比较重要,而且频繁用到。顺便再介绍一下另一个更强大的工具dstat。

vmstat是Virtual Meomory Statistics(虚拟内存统计)的缩写,可对操作系统的虚拟内存、进程、IO读写、CPU活动等进行监视。它是对系统的整体情况进行统计,不足之处是无法对某个进程进行深入分析。

命令语法:
vmstat [-a] [-n] [-S unit] [delay [ count]]
vmstat [-s] [-n] [-S unit]
vmstat [-m] [-n] [delay [ count]]
vmstat [-d] [-n] [delay [ count]]
vmstat [-p disk partition] [-n] [delay [ count]]
vmstat [-f]
vmstat [-V]

命令参数:

不同版本Linux的cp命令参数有可能不同。不过默认应该都是[ delay [ count ] ] ,delay是间隔,count显示多少次信息。可以和上面的某些参数结合使用。

参数

英文描述

描叙

delay

刷新时间间隔。如果不指定,只显示一条结果。

count

刷新次数。如果不指定刷新次数,但指定了刷新时间间隔,这时刷新次数为无穷。

-a

The -a switch displays active/inactive memory, given a 2.5.41 kernel or better.

开启显示active/inactive memory。

-f

The -f switch displays the number of forks since boot. This includes the fork, vfork, and clone system calls, and is equivalent to the total number of tasks created. Each process is represented by one or more tasks, depending on thread usage. This display does not repeat.

显示此系统启动以来的forks的总数,包括fork、vfork和clone system calls

-m

The -m displays slabinfo

显示slabinfo信息

-n

The -n switch causes the header to be displayed only once rather than periodically.

只显示头信息,不周期性显示.也就是说开启这个参数,只显示头部信息一次。

-s

The -s switch displays a table of various event counters and memory statistics. This display does not repeat.

显示各种事件计数器表和内存统计信息,这显示不重复。

-d

The -d reports disk statistics (2.5.70 or above required)

显示磁盘统计数据(内核要求2.5.70 或以上)

-w

The -w enlarges field width for big memory sizes

可以扩大字段长度,当内存较大时,默认长度不够完全展示内存。

-p

The -p followed by some partition name for detailed statistics (2.5.70 or above required)

显示磁盘分区数据(disk partition statistics )

-S

The -S followed by k or K or m or M switches outputs between 1000, 1024, 1000000, or 1048576 bytes

参数S控制输出性能指标的单位,k(1000) K(1024) 或 M(1048576) 默认单位为K(1024 bytes)

-V

The -V switch results in displaying version information.

查看vmstat命令的版本

我们常用的示例是(每隔3秒刷新一次):

vmstat -n 3

vmstat -a 3

vmstat -w 3

输出字段的意义:

这块是我一直也记不住的地方,所以特别整理了下面一张表,部分参考网上的说明,部分根据自己的理解进行补充。

输出列

输出列说明

输出列详细说明

Procs

r

The number of processes waiting for run time

等待运行的进程数。如果等待运行的进程数越多,意味着CPU非常繁忙。另外,如果该参数长期大于和等于逻辑cpu个数,则CPU资源可能存在较大的瓶颈。

b

The number of processes in uninterruptible sleep

处在非中断睡眠状态的进程数。意味着进程被阻塞。主要是指被资源阻塞的进程对列数(比如IO资源、页面调度等),当这个值较大时,需要根据应用程序来进行分析,比如数据库产品,中间件应用等。

Memory

swpd

the amount of virtual memory used

已使用的虚拟内存大小。如果虚拟内存使用较多,可能系统的物理内存比较吃紧,需要采取合适的方式来减少物理内存的使用。swapd不为0,并不意味物理内存吃紧,如果swapd没变化,si、so的值长期为0,这也是没有问题的

free

the amount of idle memory

空闲的物理内存的大小,free很小并不代表内存不足,这是linux的优越性,大量的buffers和cache也属于可用内存的一部分。

buff

the amount of memory used as buffers

用来做buffer(缓存,主要用于块设备缓存)的内存数,

单位:KB

cache

the amount of memory used as cache

用来做cache(缓存,主要用于缓存文件)的内存,

单位:KB

inact

the amount of inactive memory.
(要用vmstat -a)

inactive memory的总量(长时间未访问过的页面放进inactive list,该值大表明在必要时可以回收的页面很多)

active

the amount of active memory.
(要用vmstat -a)

active memroy的总量(刚访问过的页面放进active list,无法马上回收,只能通过与文件或交换区进行页交换)

Swap

si

Amount of memory swapped in from disk (/s)

从磁盘交换到内存的交换页数量,单位:KB/秒。

so

Amount of memory swapped to disk (/s)

从内存交换到磁盘的交换页数量,单位:KB/秒

内存够用的时候,这2个值都是0,如果这2个值长期大于0时,系统性能会受到影响,磁盘IO和CPU资源都会被消耗。当看到空闲内存(free)很少的或接近于0时,就认为内存不够用了,这个是不正确的。不能光看这一点,还要结合si和so,如果free很少,但是si和so也很少(大多时候是0),那么不用担心,系统性能这时不会受到影响的。

当内存的需求大于RAM的数量,服务器启动了虚拟内存机制,通过虚拟内存,可以将RAM段移到SWAP DISK的特殊磁盘段上,这样会 出现虚拟内存的页导出和页导入现象,页导出并不能说明RAM瓶颈,虚拟内存系统经常会对内存段进行页导出,但页导入操作就表明了服务器需要更多的内存了, 页导入需要从SWAP DISK上将内存段复制回RAM,导致服务器速度变慢。

IO

bi

Blocks received from a block device (blocks/s)

每秒从块设备接收到的块数,单位:块/秒 也就是读块设备。

bo

Blocks sent to a block device (blocks/s)

每秒发送到块设备的块数,单位:块/秒 也就是写块设备。

System

in

The number of interrupts per second, including the clock

每秒的中断数,包括时钟中断。与cs一般同步增长。in和cs两值越大,会看到由内核消耗的CPU时间(sy)也会越大。

cs

The number of context switches per second

每秒的环境(上下文)切换次数。比如我们调用系统函数,就要进行上下文切换,而过多的上下文切换会浪费较多的cpu资源,这个数值应该越小越好,如果太大了,要考虑调低线程或者进程的数目,例如apache和nginx这种web服务进程。

CPU These are percentages of total CPU time.

us

Time spent running non-kernel code.(user time, including nice time)

用户CPU时间(非内核进程占用时间)(单位为百分比)。 us的值比较高时,说明用户进程消耗的CPU时间多。

sy

Time spent running kernel code. (system time)

系统使用的CPU时间(单位为百分比)。sy的值高时,说明系统内核消耗的CPU资源多,这并不是良性表现,我们应该检查原因。

id

Time spent idle. Prior to Linux 2.5.41, this includes IO-wait time.

空闲的CPU的时间(百分比),在Linux 2.5.41之前,这部分包含IO等待时间。

wa

Time spent waiting for IO. Prior to Linux 2.5.41, shown as zero.

等待IO的CPU时间,在Linux 2.5.41之前,这个值为0 .这个指标意味着CPU在等待硬盘读写操作的时间,用百分比表示。wait越大则机器io性能就越差。说明IO等待比较严重,这可能由于磁盘大量作随机访问造成,也有可能磁盘出现瓶颈(块操作)。

st

Time stolen from a virtual machine

针对虚拟技术,如果st不为0,说明本来分配给本机的CPU时间被其他虚拟机偷走了。

Vmstat是对系统的整体情况进行统计,不足之处是无法对某个进程进行深入分析,所以我们再引入另一个工具dstat。dstat是一个可以取代vmstat、iostat、netstat和ifstat这些命令的多功能产品。dstat克服了这些命令的局限并增加了一些功能和监控项,也变得更灵活了。dstat可以很方便监控系统运行状况并用于基准测试和排除故障。

特性:

结合了vmstat,iostat,ifstat,netstat以及更多的信息
实时显示统计情况
在分析和排障时可以通过启用监控项并排序
模块化设计
使用python编写的,更方便扩展现有的工作任务
容易扩展和添加你的计数器(请为此做出贡献)
包含的许多扩展插件充分说明了增加新的监控项目是很方便的
可以分组统计块设备/网络设备,并给出总数
可以显示每台设备的当前状态
极准确的时间精度,即便是系统负荷较高也不会延迟显示
显示准确地单位和和限制转换误差范围
用不同的颜色显示不同的单位
显示中间结果延时小于1秒
支持输出CSV格式报表,并能导入到Gnumeric和Excel以生成图形

安装方法:
Ubuntu/Mint和Debin系统:
# sudo apt-get install dstat
RHEL/Centos和Fedora系统:
# yum install dstat
ArchLinux系统:
# pacman -S dstat

使用方法:
dstat的基本用法就是输入dstat命令,输出如下:

这是默认输出显示的信息:
CPU状态:CPU的使用率。这项报告更有趣的部分是显示了用户,系统和空闲部分,这更好地分析了CPU当前的使用状况。如果你看到”wait”一栏中,CPU的状态是一个高使用率值,那说明系统存在一些其它问题。当CPU的状态处在”waits”时,那是因为它正在等待I/O设备(例如内存,磁盘或者网络)的响应而且还没有收到。

磁盘统计:磁盘的读写操作,这一栏显示磁盘的读、写总数。

网络统计:网络设备发送和接受的数据,这一栏显示的网络收、发数据总数。

分页统计:系统的分页活动。分页指的是一种内存管理技术用于查找系统场景,一个较大的分页表明系统正在使用大量的交换空间,或者说内存非常分散,大多数情况下你都希望看到page in(换入)和page out(换出)的值是0 0。

系统统计:这一项显示的是中断(int)和上下文切换(csw)。这项统计仅在有比较基线时才有意义。这一栏中较高的统计值通常表示大量的进程造成拥塞,需要对CPU进行关注。你的服务器一般情况下都会运行运行一些程序,所以这项总是显示一些数值。

默认情况下,dstat每秒都会刷新数据。如果想退出dstat,你可以按”CTRL-C”键。

需要注意的是报告的第一行,通常这里所有的统计都不显示数值的。这是由于dstat会通过上一次的报告来给出一个总结,所以第一次运行时是没有平均值和总值的相关数据。

但是dstat可以通过传递2个参数运行来控制报告间隔和报告数量。例如,如果你想要dstat输出默认监控、报表输出的时间间隔为3秒钟,并且报表中输出10个结果,你可以运行如下命令:

dstat 3 10

在dstat命令中有很多参数可选,你可以通过man dstat命令查看,大多数常用的参数有这些:

-l :显示负载统计量
-m :显示内存使用率(包括used,buffer,cache,free值)
-r :显示I/O统计
-s :显示交换分区使用情况
-t :将当前时间显示在第一行
–fs :显示文件系统统计数据(包括文件总数量和inodes值)
–nocolor :不显示颜色(有时候有用)
–socket :显示网络统计数据
–tcp :显示常用的TCP统计
–udp :显示监听的UDP接口及其当前用量的一些动态数据

当然不止这些用法,dstat附带了一些插件很大程度地扩展了它的功能。你可以通过查看/usr/share/dstat目录来查看它们的一些使用方法,常用的有这些:

-–disk-util :显示某一时间磁盘的忙碌状况
-–freespace :显示当前磁盘空间使用率
-–proc-count :显示正在运行的程序数量
-–top-bio :指出块I/O最大的进程
-–top-cpu :图形化显示CPU占用最大的进程
-–top-io :显示正常I/O最大的进程
-–top-mem :显示占用最多内存的进程

举一个我常用的例子,显示哪些进程在占用IO、内存、CPU:

#dstat -l -m -r -c --top-io --top-mem --top-cpu

如何输出一个csv文件
想输出一个csv格式的文件用于以后,可以通过下面的命令:

# dstat –output /tmp/sampleoutput.csv -cdn
————————————————
原文链接:https://blog.csdn.net/smooth00/article/details/78623728

压测记录

项目上线前要做压测,好激动,这是站主第一次正式的做上线前的压测。

根据以往经验,单php执行的话,速度不会慢,压测前,想着应该能清请松松压过去的。

实际上了测试环境后,压测才发现,与想想的十万八千里,只能去做优化,然而,再次查看一遍代码流程,基本所有操作都是业务的最小单元了,没找到太值得修改优化的点。简单的改动下,再次压测,效果不怎么理想。

怎么办?一个现实的问题。将架构组的同学拉进来帮忙,然后自己将每一个代码小单元前后加上时间(microtime(true)),输出到日志,压测完将日志拿,然后写代码分析日志,最后发现两个大的时间消耗点在两个外部接口的请求上。

ok,找到问题点下面就好说了。框架组的意思,是压测时间的增长是一个逐渐积累的过程。但是开发组的人对整个流程认识较浅。没有很明白框架组童鞋给出的意思。本着非我族类,其心必异的想法(是你们的接口,拖慢了io,那你们优化去把),把压力推到了提供接口的开发人员那边。

但是接口提供方的接口压测结果却是很理想的。也没什么可优化的点了。没办法,公司相关技术人员一起讨论。先是要把问题想明白了,到底是不是接口问题。通过运维对整个流程的介绍,最后发现,问题出在nginx 和 php 的交互上,nginx 把大量的请求发送到php,php处理不过来,造成了排队。

最后,通过加缓存当方式解决了问题。

总结:
1.php-fpm 是进程,每一次求情,对与php来说,是开启一个线程(单线程),单个php线程的处理时间,决定php-fpm进程的效率(当php-fpm设定最大开启2个,nginx同一时间转来请求是100个,假设每个线程需要执行500毫秒,则认定php每秒可处理4个请求,其他请求要么排队,要么因超时被抛弃,被抛弃的就是我们常见的502)。php-fpm进程数可以调多,多了会对服务器cpu和内存产生压力(多核cpu协同调度的流程暂时还不是太清楚,先跳过)。

2.php链接redis,可开启长链接($redis->pconnect()),链接句柄保存在php-fpm中,开启长连接后,close()方法可以认为没作用了,想要消除句柄,可以用unset();mysql 同样可以开启长链接。长链接,普通链接,单例 三者的区别:长连接是放在php-fpm中的,正常情况下,生命周期和php-fpm的生命周期是一样的。普通链接随线程的结束而释放。单例的意义在于整个线程中仅进行一句柄请求。

3.php fgets():函数。是上当前系统(应该是内从中吧)中读取数据,如果如果读取的资源是来自于网络,则会先等待网络资源传输完毕后,再进行读取。一下信息并不全面,也不一定正确,单作为phper这么理解应该没问题。

fsockopen()    // 三次握手建立网络链接
fwrite()       // 将求情信息发送到输出缓冲区,由系统处理后发送数据包
fgets()        // 等待对方网络数据包到达缓冲区,然后从缓冲区读取数据

4.我们整个架构中存在 kong服务 , 对他了解还不够深刻,也没明显看到他的存在作用(当前的了解是dns将域名解析到kong,kong负责“域名转发?”)。但是知道当php-fpm进程开大后,他就会成为新的瓶颈。。汗!!!

5.注意点:当项目上线后,随着数据库数据量的增加,数据查询应该会成为新的瓶颈点,到时可考虑使用静态化,添加cdn等方式解决,解决方法很多,具体怎么解决待定,反正由巨人在顶着天^_^!

推荐两个好用的压测工具:
ab 和 webbench :

 

ab
安装ab

yum -y install httpd-tools

按照20并发,进行 100 次的请求

ab -n 100 -c 20 http://192.168.0.2/
-c 20 即:每次并发20个
-n 100 即:共发送100个请求

返回结果参考

Concurrency Level:      100                    // 并发等级 100并发
Time taken for tests:   9.366 seconds          // 总请求时长
Complete requests:      1000                   // 总请求次数
Requests per second:    106.77 [#/sec] (mean)  // 吞吐量

 

webbench
安装webbench

wget http://home.tiscali.cz/cz210552/distfiles/webbench-1.5.tar.gz
tar zxvf webbench-1.5.tar.gz
cd webbench-1.5
make && make install

按照20并发,进行10秒钟请求

webbench -c 20 -t 10 http://192.168.0.2/
-c 20 即:每次并发20个
-t 10 即:请求时长为10秒

返回结果参考

Speed=44616 pages/min, 287068 bytes/sec.      // 分析:每秒钟响应请求数:Speed=44616 pages/min,每秒钟传输数据量287068 bytes/sec
Requests: 7436 susceed, 0 failed.             // 请求成功 7436 次 ,请求失败 0  次

vue sortable 火狐拖拽搜索问题

使用vue 列表的拖动排序功能,谷歌拖拽没问题,但是在火狐测试时候,拖拽时候能成功,但是在火狐中却会打开了一个新的tab并搜索。

使用vue 列表的拖动排序功能,谷歌拖拽没问题,但是在火狐测试时候,拖拽时候能成功,但是在火狐中却会打开了一个新的tab并搜索。搜索后发现了好的解决办法。参考传送
添加以下代码就可以了:

<script>
document.body.ondrop = function (e) {
e.preventDefault();
e.stopPropagation();
}
</script>

Centos7上安装docker

先学安装,再学使用

Docker从1.13版本之后采用时间线的方式作为版本号,分为社区版CE和企业版EE。

社区版是免费提供给个人开发者和小型团体使用的,企业版会提供额外的收费服务,比如经过官方测试认证过的基础设施、容器、插件等。

社区版按照stable和edge两种方式发布,每个季度更新stable版本,如17.06,17.09;每个月份更新edge版本,如17.09,17.10。

 一、安装docker

1、Docker 要求 CentOS 系统的内核版本高于 3.10 ,查看本页面的前提条件来验证你的CentOS 版本是否支持 Docker 。

通过 uname -r 命令查看你当前的内核版本

 $ uname -r

2、使用 root 权限登录 Centos。确保 yum 包更新到最新。

$ sudo yum update

3、卸载旧版本(如果安装过旧版本的话)

$ sudo yum remove docker  docker-common docker-selinux docker-engine

4、安装需要的软件包, yum-util 提供yum-config-manager功能,另外两个是devicemapper驱动依赖的

$ sudo yum install -y yum-utils device-mapper-persistent-data lvm2

5、设置yum源

$ sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo

6、可以查看所有仓库中所有docker版本,并选择特定版本安装

$ yum list docker-ce --showduplicates | sort -r

7、安装docker

$ sudo yum install docker-ce  #由于repo中默认只开启stable仓库,故这里安装的是最新稳定版17.12.0
$ sudo yum install <FQPN>  # 例如:sudo yum install docker-ce-17.12.0.ce

8、启动并加入开机启动

$ sudo systemctl start docker
$ sudo systemctl enable docker

9、验证安装是否成功(有client和service两部分表示docker安装启动都成功了)

$ docker version

 

 二、问题

1、因为之前已经安装过旧版本的docker,在安装的时候报错如下:

复制代码
Transaction check error:
  file /usr/bin/docker from install of docker-ce-17.12.0.ce-1.el7.centos.x86_64 conflicts with file from package docker-common-2:1.12.6-68.gitec8512b.el7.centos.x86_64
  file /usr/bin/docker-containerd from install of docker-ce-17.12.0.ce-1.el7.centos.x86_64 conflicts with file from package docker-common-2:1.12.6-68.gitec8512b.el7.centos.x86_64
  file /usr/bin/docker-containerd-shim from install of docker-ce-17.12.0.ce-1.el7.centos.x86_64 conflicts with file from package docker-common-2:1.12.6-68.gitec8512b.el7.centos.x86_64
  file /usr/bin/dockerd from install of docker-ce-17.12.0.ce-1.el7.centos.x86_64 conflicts with file from package docker-common-2:1.12.6-68.gitec8512b.el7.centos.x86_64
复制代码

2、卸载旧版本的包

$ sudo yum erase docker-common-2:1.12.6-68.gitec8512b.el7.centos.x86_64

3、再次安装docker

$ sudo yum install docker-ce

原文地址:https://www.cnblogs.com/yufeng218/p/8370670.html