admin管理员组

文章数量:1646247

数据结构和算法:
	物理结构和逻辑结构
		1.逻辑结构(集合结构,线性结构,树形结构,图形结构)
		2.物理结构一般是讲内存,顺序存储结构,链式存储结构
	浅谈算法中,高斯算法从1加到100,循环的话是100次,高斯的方法只需要一次
		1.推导大O阶:O(1) O(n) O(n^2) O(logn)
			1.常数1取代时间所有加法常数
			2.只保留最高项
			3.去除项相乘的常数,去掉系数
		2.O(1)<O(logn)<O(n)<O(nlogn)<O(n^2)<O(n^3)<O(2^n)<O(n!)时间复杂度从小到大
		3.一般是指的最坏运行时间
	线性表:
		线性表顺序存储结构的三个属性:
			1.存储空间的起始位置:数组data,他的存储位置就是存储空间的存储位置
			2.最大存储容量:数组长度MAXSIZE
			3.当前长度:length
			获取元素:L.data[i-1] , 时间复杂度是O(1)

			插入元素:  时间复 杂度都是O(n)
			1.如果插入位置不合理,抛出异常
			2.线性表长度大于等于数组长度,抛出异常或动态增加容量
			3.从最后一个元素开始向前遍历到第i位置,分别向后移动一个位置 L->data[k+1]=L->data[k]
			4.将元素填入位置i处 L->data[i-1]=e
			5.表长加1

			删除元素: 时间复杂度都是O(n)
			1.如果删除位置不合理,抛出异常
			2.取出删除元素 L.data[i-1] 
			3.从删除位置开始遍历到最后一个位置,向前移动一个位置 L->data[k-1]=L->data[k]
			4.表长减一
		单链表结构和顺序存储结构的优缺点:
			1.存储分配方式=>顺序存储是用一段连续的存储单元依次存储线性表的数据元素;单链表采用链式存储结构,用一组任意存储单元存放
			2.时间性能=>查找 顺序结构是O(1) 单链表是O(n) ;插入和删除 顺序存储是O(n) 单链表是O(1)
			3.空间性能=>顺序存储是预分配存储空间 ; 单链表不需要预分配,元素个数不受限制

		1.将单链表中终端结点的指针端由空指针改为指向头结点,单循环链表,循环链表和单链表的主要差异就在于循环的判断条件上
		原来是判断p->next是否为空,现在则是p->next不等于头结点,则循环未结束
		2.指向终端结点的尾指针代表该循环链表
		3.两条循环链表合并成一个循环链表
		p=rearA->next;保存A表的头结点
		rearA->next=rearB->next->next;将本是B表的第一个结点赋值给rearA->next
		rearB->next=p; 将原A表的头结点赋值给rearB->next free(p)

		1.双向链表就是在单链表的每个结点中,再设置一个指向其前驱结点的指针域
		2.双向链表的插入操作,将s插入到p和p->next之间 , 先搞定s的前驱和后继 , 再搞定后结点的前驱 ,最后搞定前结点的后继
		s->prior=p ;把p赋值给s的前驱
		s->next=p->next ;把p->next赋值给s的后继
		p->next->prior=s ;把s赋值给p->next的前驱
		p->next =s ;     把s赋值给p的后继
		3.删除结点p
		p->prior->next=p->next ;把p->next赋值给p->prior的后继
		p->next->prior=p->prior ;把p->prior赋值给p->next的前驱

		反转链表:
			1.常见方法分为迭代和递归,迭代是从头到尾,递归是从尾到头
			2.设置两个指针,old和new,每一项添加在new的后面,新链表头指针指向新的链表头
			3.old->next不能直接指向new,而是应该设置一个临时指针tmp,指向old->next指向的地址空间,保存原链表数据,然后old->next指向new,new往前移动到old处new=old,最后old=tmp取回数据
			while(old!=null){
				tmp=old->next
				old->next=new
				new=old
				old=tmp
			}

	队列:
		1.队列是先进先出的线性表,FIFO,允许插入的一端叫队尾,允许删除的一端队头
		2.队列的抽象数据类型
		InitQueue(*Q):初始化操作 QueueLength(Q):返回队列的长度
		DestroyQueue(*Q):销毁队列 ClearQueue(*Q):清空队列 QueueEmpty(Q):判断队列是否为空
		GetHead(Q,*e):用e返回队列的队头元素
		EnQueue(*Q,e):插入e到队列的队尾元素
		DeQueue(*Q,*e):删除队列的队头元素
		3.引入两个指针front指向队头元素,rear指向队尾元素的下一个位置,队列顺序存储的不足,出队列时每个元素都移动,如果不移动会有假溢出问题
		4.循环队列,把队列头尾相接的顺序存储结构,解决假溢出问题
	哈希表查找:
		1.顺序表查找:挨个比较
			for(i=1;i<=n;i++){a[i]==key return}
			顺序表查找的优化:
				解决每次都要对i是否小于n作比较,设置一个哨兵,如果查找失败,一定会在结尾a[0]处等于key,此时返回0;免去了每次都判断是否越界
				a[0]=key;i=n;while(a[i]!=key){i--}
		2.有序表查找:二分法查找
			1.折半查找:取中间记录的查找方法,又称为二分查找.前提是线性表中的记录必须是有序的,取中间记录作为比较对象,若关键字相等则查找成功,若小于则在左半区查找,若大于则在右半区查找
				left mid right
				while(left<right){
					mid=(left+right)/2
					if(key<a[mid]){right=mid-1}
					else if(key>a[mid]){left=mid+1}
					else{return mid}
				}return 0
		3.散列表查找:存储的时候使用散列函数计算出地址,直接通过存储位置查找
			1.定向查找的存储技术,通过关键字和哈希函数得到一个位置
			2.不适合查找关键字相同,不适合查找范围的,对于一对一的查找最好
	排序算法:
		非线性比较类:
			交换排序
				冒泡:平均O(n^2),最坏O(n^2) 最好O(n) 空间O(1) 稳定
				快速:平均O(nlogn),最坏O(n^2),平均O(nlogn),空间O(nlogn) 不稳定
			插入排序
				插入:平均O(n^2),最坏O(n^2) 最好O(n) 空间O(1) 稳定
				希尔:平均O(n^1.3),最坏O(n^2),最好O(n),空间O(1) 不稳定
			选择排序
				选择:平均O(n^2),最坏O(n^2),最好O(n^2),空间O(1) 不稳定
				堆  :平均O(nlogn),最坏O(nlogn),平均O(nlogn),空间O(1) 不稳定
			归并排序
				二路归并:平均O(nlogn),最坏O(nlogn),平均O(nlogn),空间O(1) 稳定
				多路归并
		线性非比较类:
			计数:平均O(n+k),最坏O(n+k),最好O(n+k),空间O(n+k) 稳定
			桶:平均O(n+k),最坏O(n^2),最好O(n),空间O(n+k) 稳定
			基数:平均O(n*k),最坏O(n*k),最好O(n*k),空间O(n+k) 稳定
		稳定:原来a在b前面,a=b,排序后a任然在b前面  冒泡,插入,归并,计数,桶,基数
		不稳定:a=b,排序前a在b前面,排序后可能在后面,快速,希尔,选择,堆
		冒泡排序:
			1.比较相邻元素,从第一个开始较大的逐渐往后移动,后面是所有已经排好序的了
			2.for{for{}},arr[j]>arr[j+1]
			for($x=0;$x<count($arr)-1;$x++){
	            for($y=0;$y<count($arr)-$x-1;$y++){
	                if($arr[$y]>$arr[$y+1]){
	                    $temp=$arr[$y];
	                    $arr[$y]=$arr[$y+1];
	                    $arr[$y+1]=$temp;
	                }
	            }
	        }
		选择:
			1.两层循环,假定第一层循环的i元素是最小值,
			2.内层循环找出比i还小的元素,交换下他们
			3.数组分成前后两个部分,前部分是排序的,后部分是无序的
			4.两层循环,先假定当前循环的第一个索引为最小值,内部循环找比该索引还小的值,找到交换
			function selectSort(&$arr){
			        $len=count($arr);
			        for($i=0;$i<$len;$i++){
			                $minIndex=$i;//假定当前i是最小值
			                for($j=$i+1;$j<$len;$j++){
			                        if($arr[$j]<$arr[$minIndex]){
			                                $minIndex=$j;
			                                break;
			                        }   
			                }   
			                $t=$arr[$i];
			                $arr[$i]=$arr[$minIndex];
			                $arr[$minIndex]=$t;
			        }   
			        return $arr;
			}
		插入排序:
			定义数组长度变量$len,使用count()函数,参数:数组
			for循环数组,条件:从第二个开始,遍历数组,循环内
         	定义临时变量$temp,赋值当前元素
         	for循环数组,条件:遍历当前元素前面的所有元素
         	判断当前元素与它前面的元素的大小,利用临时变量,转换变量
         	function insert_sort($arr){
			    $len=count($arr);
			    for($i=1;$i<$len;$i++){
			        $temp=$arr[$i];
			        for($j=$i-1;$j>=0;$j--){
			            if($temp<$arr[$j]){
			                $arr[$j+1]=$arr[$j];
			                $arr[$j]=$temp;
			            }else{
			                break;
			            }
			        }
			    }
			    return $arr;
			}
		快速排序:
			1.基于二分的思想
			2.第一个作为基准数,左右各一个指针,同时扫描,右边先走,找到比基准数小的停下
			左边再走,找到比基准数大的停下,左右交换
			3.当左右相遇的时候,把当前的和基准数调换,递归调用
			4.快速排序的最差时间复杂度和冒泡排序是一样的都是O(N2),它的平均时间复杂度为O(NlogN)
			quickSort &arr,left,right
				if left>right return
				temp=arr[left]
				i=left
				j=right
				while i=temp && i SYN MSS=1460(最大数据包是1460字节) [seq=0  序列号是0]  ===> 服务器
				客户端 <=== SYN,ACK [seq=0,ack=1  序列号是0,确认号是1] MSS=1424(服务器最大数据包是1424字节) WS=7(window) win=3737600(服务器最多缓存3737600字节)<=== 服务器
				客户端 ===> ACK [seq=1,ack=1 序列号是1,确认号是1] win=66816(客户端最多缓存是66816字节) ===> 服务器
			2.面向字节流,比如 发送文件,文件二进制=>TCP发送缓存=>TCP接收缓存=>应用程序,这也是发送和接收窗口技术
			3.TCP协议使用滑动窗口技术实现可靠传输
				1.停止等待协议效率不高,连续发送确认是窗口技术
				2.以字节为单位的滑动窗口技术,连续发送,接收窗口收到后确认,往右滑动发送窗口,接收窗口也要往右滑动
				3.如果中间有顺序的包丢了,接收窗口发送确认号的时候,会发丢之前的ack号,选择重发的包序号,选择确认
				4.超时重传,tcp每发送一个报文段,就设置一次计时器,重传时间到但还没收到确认,就重传这一报文段,这个时间是加权平均的往返时间
			4.TCP流量控制是解决的通信两端处理数据能力不一致的问题,TCP协议如何实现流量控制
				1.接收方数据处理不完了,就调整了接收窗口的大小
				2.通过窗口大小来控制流量
			TCP的传输连接管理:
				1.连接建立=>数据传输=>连接释放
				2.主动发起连接的是客户端,被动接受连接的是服务器
				3.  客户端 ==> SYN是1同步 ,ACK确认标志是0,seq序号是x  ==> 服务器
					客户端  <==  SYN是1同步 ,ACK确认标志是1,seq序号是y,ack确认号是x+1 <==服务器
					客户端  ==>  ACK确认标志是1,seq序号是x+1,ack确认号是y+1 ==>服务器
				4.为什么需要第三次握手再次确认,因为服务器需要确认客户端收到我的回复
				5.状态转移
					1.客户端发送完变成 SYN-SENT , 服务端接收到后变成SYN-RECEIVED,客户端接收到确认变成 ESTABLISHED,服务端收到确认变成 ESTABLISHED   
					2.当客户端访问不存在的IP时,可以看到客户端变成SYN-SENT状态,接收不到服务端的确认回复
					3.SYN攻击,可以伪造来源ip,因此可以看到服务端变成SYN-RECEIVED状态,接收不到客户端的确认回复
				6.四次挥手
				客户端(主动关闭)  ==> FIN标志是1,seq序号是u ==>服务器
				客户端  <== ACK确认标志是1,seq序号是v,ack确认号是u+1 <== 服务器
				客户端  <== FIN标志是1,ACK确认标志是1,seq序号是w,ack确认号是u+1 <== 服务器
				客户端  ==> ACK确认标志是1,seq序号是u+1,ack确认号是w+1 ==>服务器
				7.状态转移
				主动关闭的一方是time_wait的状态
				被动关闭的一方是close_wait的状态
 		UDP(用户报文协议) 一个数据包就能完成数据通信,不需要建立会话,不分段,不用流量控制,不可靠传输
 		SSL:位于传输层和应用层之间,专门实现在传输之前加密,在接收端给应用层之前解密;使用非对称加密技术

HTTP:
	客户端浏览器解析HTML内容
		客户端浏览器首先解析状态行,查看表明请求是否成功的状态代码。然后解析每一个响应头,响应头告知以下为若干字节的HTML文档和文档的字符集。客户端浏览器读取响应数据HTML,根据HTML的语法对其进行格式化,并在浏览器窗口中显示。
		例如:在浏览器地址栏键入URL,按下回车之后会经历以下流程:
		1、浏览器向 DNS 服务器请求解析该 URL 中的域名所对应的 IP 地址;
		2、解析出 IP 地址后,根据该 IP 地址和默认端口 80,和服务器建立TCP连接;
		3、浏览器发出读取文件(URL 中域名后面部分对应的文件)的HTTP 请求,该请求报文作为 TCP 三次握手的第三个报文的数据发送给服务器;
		4、服务器对浏览器请求作出响应,并把对应的 html 文本发送给浏览器;
		5、释放 TCP连接;
		6、浏览器将该 html 文本并显示内容; 
	HTTP连接管理:
		1.HTTP如何使用TCP连接的
		2.TCP连接的时延,瓶颈,存在的障碍
		3.HTTP的优化,并行连接,keep-alive,管道连接
		4.HTTP就是HTTP over TCP over IP,HTTPS是HTTP和TCP之间插入放入TLS或者SSL
		5.保持TCP连接的正确运行,四个值<源ip地址,源端口,目的ip,目的端口
		6.HTTP时间线,请求=>DNS查询=>响应=>请求=>服务器处理=>响应=>关闭
		7.TCP性能点:TCP连接建立握手(花费50%时间);
			TCP延迟确认算法(占第二);
			TIME_WAIT时延和端口耗尽(记录最近所关闭连接的IP地址和端口号,2MSL通常2分钟)
			TCP慢启动拥塞控制;数据聚集的Nagle算法;

	HTTP首部(head头信息)
		1.通用首部:Date
			通用缓存首部(Cache-Control)
		2.请求首部:Accept
			条件请求首部(if-),安全请求首部(Authorization)
		3.响应首部:Server
		4.实体首部(用于主体部分的首部):content-type:
		5.扩展首部:非标准的,自己定义的
	HTTP状态码:
		100-199 信息性状态码
	    	100 continue 请继续
		    101 switching protocols 切换协议,返回upgraded头
		200-299 成功状态码
		    200 ok
		    201 created  创建资源
		    202 accepted 请求已经接收到,不保证完成
		    203 non-authoritative information 非权威信息,不是来自于源端服务器
		    204 no content 没有内容
		    205 reset content 重置内容,主要是对浏览器html元素
		    206 partial content 执行了部分内容
		300-399 重定向状态码
		    300 multiple choices 多项选择,会返回一个选项列表
		    301 moved permanently 资源被移除,location中包含url
		    302 Found 与301类似,客户端应该使用location中的url临时定位
		    303 see other 允许post请求的响应重定向
		    304 not modified 资源没有修改,返回的时候不能有主体内容,还是本地的内容
		    305 use proxy  使用代理来请求资源
		    307 temporary redirect 临时重定向,与301类似
		    因为http1.0和http1.1的差别因此有交叉
		4xx系列和客户端有关:
		    400 bad request 错误请求
		    401 unauthorized 没权限
		    402 payment required 未使用
		    403 forbidden 禁止
		    404 not found
		    405 methord not allowed 请求url不支持的方法,应该返回allow首部告诉允许啥
		    406 not acceptable 客户端指定参数说明可以接受什么类型的文本
		    407 proxy authentication required 要求代理服务器认证权限
		    408 request timeout 请求超时
		    409 conflict 请求冲突
		    410 gone 类似404
		    411 length required 需要请求中包含content-length
		    412 precondition failed  先决条件失败
		    413 request entity too large 客户端发的内容太大
		    414 request uri too long 请求的url太长
		    415 unsuport media type 不支持的媒体类型
		    416 requested range not satisfiable 请求的范围不满足,无效
		    417 expectation failed 服务器无法满足请求
		    nginx自定义的状态码:
			495, https certificate error
			496, https no certificate
			497, http to https
			498, canceled
			499, client has closed connection是客户端等到超时主动关掉的
		500-599 服务器错误状态码
		    500 internal server error 内部错误
		    501 not implemented 没有实现,超出了服务器的范围
		    502 bad gateway 代理或者网关下一链路收到未响应
		    503 service unavailable 服务不可用
		    504 gateway timeout 类似408,超时来自代理
		    505 http version not supported http协议版本不支持
	主流的WEB服务:REST,SOAP,RPC
		1.REST是基于HTTP协议的一个补充,他的每一次请求都是一个HTTP请求,然后根据不同的method来处理不同的逻辑
		2.SOAP是W3C在跨网络信息传递和远程计算机函数调用方面的一个标准。但是SOAP非常复杂
		3.GO天生提供方便的RPC机制
		4.有连接的流式Socket(SOCK_STREAM)TCP 和无连接数据报式Socket(SOCK_DGRAM)UDP
		5.IPv4的地址位数为32位,也就是最多有2的32次方的网络设备可以联到Internet上,IPv6采用128位地址长度,几乎可以不受限制地提供地址
MySQL:
	mysql分层:
	1.client  ==>连接层 ==>服务层==>引擎层==>存储层 server
	3.连接层:
		提供与客户端连接的服务
	4.服务层:
		1.提供各种用户使用的接口(增删改查),sql解析
		2.提供SQL优化器(MySQL Query Optimizer),重写查询,决定表的读取顺序,选择合适的索引
			mysql的hint关键字有很多比如:SQL_NO_CACHE FORCE_INDEX SQL_BUFFER_RESULT
	5.引擎层:innoDB和MyISAM
		1.innoDB:事务优先(适合高并发修改操作;行锁)
		2.MyISAM:读性能优先
		3.show engines;查询支持哪些引擎
		4.查看当前默认的引擎 show variables like '%storage_engine%';default_storage_engine

	sql的解析过程比如:
	from ... on ... where ... group by  ... having ... select ... order by ... limit
	mysql join:笛卡尔积形式
		左连接:left join,左表全部,右表没有用null
		右连接:right join,右表全部,左表没有用null
		内连接:inner join,左右表中都有的
		左表独有:left join where b is null
		右表独有:right join where a is null
		全连接:union
	join原理:
		1.MySQL内部采用了一种叫做 nested loop join的算法。Nested Loop Join 实际上就是通过驱动表的结果集作为循环基础数据,然后一条一条的通过该结果集中的数据作为过滤条件到下一个表中查询数据,然后合并结果。
		2.如果还有第三个参与 Join,则再通过前两个表的 Join 结果集作为循环基础数据,再一次通过循环查询条件到第三个表中查询数据,如此往复,基本上MySQL采用的是最容易理解的算法来实现join。所以驱动表的选择非常重要,驱动表的数据小可以显著降低扫描的行数
		3.条件中尽量能够过滤一些行将驱动表变得小一点,用小表去驱动大表 
		4.explain中可以看到谁是驱动表
		5.有三种nested loop join方法,循环嵌套Simple Nested-Loop Join,索引嵌套Index Nested-Loop Join,Block Nested-Loop Join(多了个join buffer)
		6.索引嵌套,不再需要一条条记录进行比较,而可以通过索引来减少比较,从而加速查询。这也就是平时我们在做关联查询的时候必须要求关联字段有索引的一个主要原因

	innoDB引擎的四大特性:插入缓冲,二次写,自适应哈希索引,预读
	事务的四种隔离级别:读未提交(read uncommitted),读已提交(read committed),可重复读(repeatable read),串行(serializable)
	事务的ACID特性:
		原子性(atomicity):一个事务是一个不可分割的最小工作单位,事务中包括的诸操作要么都做,要么都不做。
		一致性(consistency):事务必须是使数据库从一个一致性状态变到另一个一致性状态。一致性与原子性是密切相关的。
		隔离性(isolation):一个事务的执行不能被其他事务干扰。即一个事务内部的操作及使用的数据对并发的其他事务是隔离的,并发执行的各个事务之间不能互相干扰。
		持久性(durability):持续性也称永久性(permanence),指一个事务一旦提交,它对数据库中数据的改变就应该是永久性的。接下来的其他操作或故障不应该对其有任何影响。
	MYSQL的锁机制:
		1.无论何时只要有多个查询在同一时刻修改数据,都会产生并发控制的问题
		2.讨论mysql在两个层面,服务器层和存储引擎层,如何并发控制读写
		3.举了个mbox邮箱文件的例子,说如果有多个进程同时对mbox文件写东西,那么在文件的末尾会,交叉混乱的添加,比如进程1写了几行,进程2也写了几行,互相交叉,数据就是错误的了.设计良好的mbox需要加锁,比如进程1锁住了文件,进程2必须等待进程1结束,锁释放才能去写.但是这样的话就不支持并发了,同一时刻只有一个进程可以写数据
		4.读取时可能也会有问题,比如一个进程正在读数据,另一个进程同时想去删数据,此时就是不安全的;共享锁叫读锁,排他锁叫写锁
		5.读锁是共享的,它不会阻塞其他读锁;写锁是排他的,它会阻塞其他读锁和写锁;读读不互斥,读写互斥,写写互斥
		6.mysql每时每刻都在发生锁定,当某用户在修改数据时,会阻塞其他用户读取该数据
		7.mysql中有两种锁粒度,锁住整张表和锁住表中一行
		表锁:当某用户修改数据时,会获取写锁,此时会锁住整张表,其他用户都不能读和写,myisam
		行锁:当某用户修改某几行数据,会获取写锁,此时只是锁住那几行,那几行其他用户不能读和写;其他行没有影响,但是管理锁会消耗资源,innodb
		8.使用命令来锁表
			unlock tables 解锁所有行
			lock tables 表名 read或者write
	MVCC 多版本并发控制实现的事务:
		1.没有一个统一的实现标准,实现了非阻塞的读操作,写操作也只锁定必要的行
		2.通过保存数据在某个时间点的快照实现的
		3.典型的有乐观并发控制和悲观并发控制
		4.innodb的mvcc是每次事务都有递增的版本号,通过在每行记录的后面添加两列隐藏字段,两列分别是是创建版本号和删除版本号,存储操作它事务的版本号
		5.在事务中增删改查就是对两列版本号字段进行操作

		insert 为新插入的每一行保存当前事务版本号到 行创建版本号字段
		update 插入一行新的保存当前事务创建版本号,修改原行数据的删除版本号为本次事务的版本号
		delete 修改行的删除版本号字段为本次事务的版本号
		select 查询 创建版本号字段 小于等于当前事务版本的数据    确保该记录是本次之前就存在的或本次事务新插的
			   查询 删除版本号字段 不存在或者大于当前版本的数据 确保该记录在本次事务之前没删除

		6.这样的设计就不需要加锁了,读和操作性能好,但是需要额外的存储空间
		7.mvcc只在REPEATABLE READ和READ COMMITED两个隔离下工作;READ UNCOMMITED总是读取最新数据;SERIALIZABLE对读取的行都加锁
	mysql 死锁:
		1.两个或多个事务在同一个资源上相互占用,并请求锁定对方占用的资源,导致恶性循环
		2.解决这种问题,检测到死锁的循环依赖,立即返回一个错误
		3.时间达到了锁等待超时限定,放弃锁请求
		4.将持有最少行级写锁的事务回滚
		5.如果是真正的数据冲突,这种是很难避免的,必须要提交或回滚其中一个事务
		ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
	Schema与数据类型优化
		A.选择优化的数据类型 1.数据类型的选择原则:* 更小的通常更好* 简单就好* 尽量避免NULL 2.应该尽量只在对小数进行精确计算时才使用DECIMAL,使用int类型通过程序控制单位效果更好
		3.使用VARCHAR合适的情况:字符串列的最大长度比平均长度大很多;列的更新很少,所以碎片不是问题;使用了像UTF-8这样复杂的字符集,每个字符都使用不同的字节数进行存储
		4.CHAR适合存储很短的字符串,或者所有值都接近同一个长度;不容易产生碎片,在存储空间上更有效率
		5.通常应该尽量使用TIMESTAMP,它比DATETIME空间效率更高
		6.MySQL schema设计中的陷阱 1.不好的设计:* 太多的列 * 太多的关联 * 全能的枚举 * 变相的枚举
	范式和反范式
		1.范式的优点:* 范式化的更新操作通常比反范式化要快* 当数据较好地范式化时,就只有很少或者没有重复数据,所以只需要修改更少的数据
		* 范式化的表通常更小,可以更好地放在内存里,所以执行操作会更快
		* 很少有多余的数据意味着检索列表数据时更少需要DISTINCT或者GROUP BY语句
		2.范式化设计的缺点是通常需要关联
		3.反范式的优点:避免关联,避免了随机I/O,能使用更有效的索引策略
	缓存表和汇总表
		1.有时提升性能最好的方法是同一张表中保存衍生的冗余数据,有时也需要创建一张完全独立的汇总表或缓存表
		2.物化视图,MySQL并不原生支持,Flexviews
		3.如果应用在表中保存计数器,则在更新计数器时可能踫到并发问题,创建一张独立的表存储计数器,可以帮助避免缓存失效
		4.解决独立表并发问题可以建多行,根据id随机更新,然后统计时sum()* 按天或小时可以单独建行,旧时间可定时任务合并到统一的一行
	加快ALTER TABLE操作的速度
		1.两种方式:* 一是在一台不提供服务的机器上执行ALTER TABLE操作,然后和提供服务的主库进行切换* 2.是通过“影子拷贝”,创建一张新表,然后通过重命名和删表操作交换两张表及里面的数据
		3..快速创建MyISAM索引,先禁用索引,导入数据,然后重新启用索引
	A.索引基础
		1.索引可以包含一个或多个列的值,如果索引包含多个列,那么列的顺序也十分重要,因为MySQL只能高效地使用索引的最左前缀列
		2.ORM工具能够产生符合逻辑的、合法的查询,除非只是生成非常基本的查询,否则它很难生成适合索引的查询
		3.在MySQL中,索引是在存储引擎层而不是服务器层实现的,所以,并没有统一的索引标准:不同存储引擎的索引的工作方式并不一样,也不是所有的存储引擎都支持所有类型的索引
		4.B-Tree意味着所有的值都是按顺序存储的,并且每一个叶子页到根的距离相同,能够加快访问数据的速度,从索引的根节点开始进行搜索,适用于全键值、键值范围或键前缀查找
		5.B-Tree索引的限制:
			* 如果不是按照索引的最左列开始查找,则无法使用索引
			* 不能跳过索引中的列
			* 如果查询中有某个列的范围查询,则其右边所有列都无法使用索引优化查找
		6.哈希索引(hash index)基于哈希表实现,只有精确匹配索引所有列的查询才有效,只有Memory引擎显式支持哈希索引
		7.哈希索引的限制:
			* 哈希索引只包含哈希值和行指针,而不存储字段值,所以不能使用索引中的值来避免读取行
			* 哈希索引数据并不是按照索引值顺序存储的,所以也就无法用于排序
			* 哈希索引也不支持部分索引列匹配查找,因为哈希索引始终是使用索引列的全部内容来计算哈希值的
			* 只支持等值比较查询,不支持任何范围查询
			* 访问哈希索引的数据非常快,除非有很多哈希冲突
			* 如果哈希冲突很多的话,一些索引维护操作的代价也会很高
		8.空间数据索引(R-Tree),MyISAM表支持空间索引,可以用作地理数据存储,开源数据库系统中对GIS的解决方案做得比较好的是PostgreSQL的PostGIS
		9.全文索引,适用于MATCH AGAINST操作,而不是普通的WHERE条件操作
	B.索引的优点
		1.三个优点:* 索引大大减少了服务器需要扫描的数据量* 索引可以帮助服务器避免排序和临时表* 索引可以将随机I/O变为顺序I/O
		2.索引三星系统:* 索引将相关的记录放到一起则获得一星* 如果索引中的数据顺序和查找中的排序一致则获得二星* 如果索引中的列包含了查询中需要的全部列则获得三星
	C.高性能的索引策略
		1.独立的列:如果查询中的列不是独立的,则MySQL不会使用索引。“独立的列”是指索引列不能是表达式的一部分,也不能是函数的参数
		2.前缀索引和索引选择性
			* 通常可以索引开始的部分字符,可以大大节约索引空间,但也会降低索引的选择性
			* 索引的选择性是指,不重复的索引值(也称为基数,cardinality)和数据表的记录总数(#T)的比值,范围从1/#T到1之间,选择性越高则查询效率越高,因为选择性高的索引可以让MySQL在查找时过滤掉更多的行
			* MySQL无法使用前缀索引做ORDERY BY和GROUP BY,也无法做覆盖扫描
		3.选择合适的索引列顺序
			* 正确的索引列顺序依赖于使用该索引的查询,并且同时需要考虑如何更好地满足排序和分组的需要
			* 在一个多列B-Tree索引中,索引列的顺序意味着索引首先按照最左列进行排序,其次是第二列
			* 将选择性最高的列放到索引最前列
		4.聚簇索引:并不是一种单独的索引类型,而是一种数据存储方式
			* 最好避免随机的(不连续且值的分布范围非常大)聚簇索引,特别是对于I/O密集型的应用
		5.覆盖索引:如果一个索引包含(或者说覆盖)所有需要查询的字段的值,就称为覆盖索引
			* 覆盖索引必须要存储索引列的值,
		6.如果EXPLAIN出来的type列的值为“index”,则说明MySQL使用了索引扫描来做排序
		7.压缩(前缀)索引,默认只压缩字符串,减少索引大小,对于CPU密集型应用,因为扫描需要随机查找,压缩索引在MyISAM上要慢好几倍
		8.重复索引是指在相同的列上按照相同的顺序创建的相同类型的索引,应该避免这样创建重复索引
		9.索引可以让查询锁定更少的行
	D.维护索引和表
		1.CHECK TABLE检查表是否损坏,ALTER TABLE innodb_tb1 ENGINE=INNODB;修复表
		2.records_in_range()通过向存储引擎传入两个边界值获取在这个范围大概有多少条记录,对于innodb不精确
		3.info()返回各种类型的数据,包括索引的基数
		4.可以使用SHOW INDEX FROM命令来查看索引的基数
		5.B-Tree索引可能会碎片化,这会降低查询的效率



	mysql中的索引类型(index/key):
		普通索引:默认的
		主键索引:自增字段一定是,唯一性约束;主键不一定自增
		唯一索引:提供唯一性约束,可以有多个唯一索引
		全文索引:不支持中文全文检索,一般用第三方,coreseek/xunsearch
		外键索引:只有InnoDB支持,效率不高不推荐,只使用外键思想保证数据一致性和完整性
	mysql索引:
		1.索引如果没有特别指明类型,一般是说b树索引,b树索引使用b树数据结构存储数据,实际上很多存储引擎使用的是b+树,每一个叶子节点都包含指向下一个叶子节点的指针,从而方便叶子节点的范围遍历
		2.底层的存储引擎也可能使用不同的存储结构,NDB集群存储引擎使用了T树,InnoDB使用的是B+树
		3.MyISAM使用前缀压缩技术使得索引更小,InnoDB按照原数据格式进行存储,MyISAM通过数据的物理位置引用被索引的行,InnoDB根据主键引用被索引的行
		4.b树意味着所有的值是按照顺序存储的,并且每一个叶子页到根的距离相同
		5.b树索引能够加快访问数据的速度,存储引擎不需要再进行全表扫描来获取需要的数据,取而代之的是从索引的根节点开始进行搜索,根节点的槽中存放了指向子节点的指针,存储引擎根据这些指针向下层查找.通过比较节点页的值和要查找的值可以找到合适的指针进入下层子节点.树的深度和表的大小直接相关
		6.叶子节点比较特别,他们的指针指向的是被索引的数据,而不是其他的节点页
		7.b树对索引列是顺序存储的,所以很适合查找范围数据.
		8.索引对多个值进行排序的依据是,定义索引时列的顺序,比如联合索引key(a,b,c),这三个列的顺序
		9.上面的联合索引对以下查询语句有效
			全值匹配 where a=x and b=x and c=x
			最左前缀 where a=x
			匹配列前缀 where a like x%
			匹配范围值 where a>x and a、in等。eq_ref或者ref_or_null。且查询需要访问表的整行数据,即不能直接通过二级索引的元组数据获得查询结果(索引覆盖)。      
			(6)index:遍历所有索引。type列是index,如果没有覆盖全部查询列,速度慢,只有当索引的列顺序和order by子句的顺序完全一致并且所有列的排序顺序都一样,才能使用索引来做排序    
			(7)all:遍历全表
		possible_keys:显示可能应用在这张表中的索引
		key: 实际使用的索引
		key_len:使用的索引的长度。在不损失精确性的情况下,长度越短越好
			mysql索引的长度计算:
			1.所有的索引字段,如果没有设置not null,则需要加一个字节。
			2.定长字段,int占4个字节、date占3个字节、char(n)占n个字符。
			3.变长字段,varchar(n),则有n个字符+两个字节。
			4.不同的字符集,一个字符占用的字节数不同。latin1编码的,一个字符占用1个字节,gbk编码的,一个字符占用2个字节,utf8编码的,一个字符占用3个字节。utf8mb4是一个字符占4个字节
			5.使用explain语句查询到的key_len字段,可以适用于上面的计算规则,可以看到查询是否使用到了联合索引
			6.mysql优化器会对条件中的 and的前后顺序根据多列索引顺序自动纠正过来
		rows:通过索引查询到的数据量,需要扫描的行数
		extra:
			(1) Using filesort:文件内排序,说明mysql使用了外部排序。      
			(2) Using temporary:使用了保存中间结构。(order by 、group by),使用了隐式临时表   
			(3) Using index:效率不错,表示使用了索引,使用到了覆盖索引。  
	mysqldump客户端逻辑备份程序,可以生成一组sql或csv,文本,xml
		1.如果不使用--single-transaction选项,mysqldump至少需要SELECT权限,SHOW VIEW,TRIGGER和LOCK TABLES权限
		2.对于大规模备份和还原,物理备份更合适,以原始格式复制数据文件,可以快速恢复
		3.表主要是InnoDB表考虑使用MySQL Enterprise Backup产品的mysqlbackup命令;主要MyISAM表,考虑使用mysqlhotcopy
		4.mysqldump默认是逐行检索,要启用内存缓冲,使用--skip-quick,此时如果是大表内存会可能有问题
	utf8mb4:
		1.可以获取更好的兼容性,可以存储emoji表情符,建议使用 utf8mb4 而非 utf8,事实上,最新版的phpmyadmin默认字符集就是utf8mb4。
		2.数据库表采用utf8mb4编码,其中varchar(255)的column进行了唯一键索引,而mysql默认情况下单个列的索引不能超过767位(不同版本可能存在差异) 
		3.utf8mb4编码,一个字最多可以占用4个字节,那255*4就会超出767的字符限制了
		4.解决索引长度不够问题[Err] 1071 - Specified key was too long; max key length is 767 bytes
		设置: innodb_large_prefix=1 改为on就是限制3072 innodb_file_format=Antelope 
	mysql分区:
		1.只有InnoDB和NDB存储引擎才能这样做
		2.通过检查SHOW PLUGINS语句的输出来确定您的MySQL服务器是否支持分区,| partition | ACTIVE | STORAGE ENGINE | NULL | GPL |
	mysql分库分表:
		1.如果只是为了分页,可以考虑这种分表,就是表的id是范围性的,且id是连续的,比如第一张表id是1到10万,第二张是10万到20万,这样分页应该没什么问题。
		2.其他的分表方式,建议用sphinx先建索引,然后查询分页
		3.减小数据库的负担,缩短查询时间。mysql中有一种机制是表锁定和行锁定,是为了保证数据的完整性。表锁定表示你们都不能对这张表进行操作,必须等我对表操作完才行。行锁定也一样,别的sql必须等我对这条数据操作完了,才能对这条数据进行操作
		4.不管是分表还是垂直分库都是为了解决 写负载的 而不是读负载。 分表以后只有一种查询方式会效率高,那就是根据分表键查。其他查询条件相反会慢于没分表前的正表查询。 所以 能不分尽量不要分表。大数据量的查询可以使用读写分离,旧数据归档
		5.SELECT * FROM table WHERE id >= (SELECT id FROM table LIMIT 1000000, 1) LIMIT 10;分页
		6.当只需要一条数据时,使用limit 1 
	优化实战:
		在进行查询导出登陆日志的项目中,根据联合索引的最左前缀原则,把中间空缺的字段type加上,type in (1,2,3,4),后面的time字段的范围查询也可以用到索引了
Redis:
	五种数据类型必记:
		字符串(string), 散列(hash), 列表(list), 集合(set), 有序集合(sorted set) 
	redis的设计与实现:
		1.假如有一个用户关系模块,要实现一个共同关注功能,计算出两个用户关注了哪些相同的用户,本质上是计算两个用户关注集合的交集,如果使用关系数据库,需要
		对两个数据表执行join操作,对合并的结果执行去重distinct操作,非常复杂
		2.Redis直接内置了集合数据类型,支持对集合执行交集/并集/差集等集合计算操作,交集操作可以直接用于共同关注功能,使用之后速度更快代码量更少,可读性大大提高
		3.越来越多的疑问:五种数据类型是由什么数据结构实现的?字符串数据类型既可以存储字符串,又可以存储整数浮点数,二进制位,在内部是怎么存储这些值的?
		有些命令只能对特定数据类型执行,是如何进行类型检查的?怎样存储各种不同类型的键值对?过期键是怎样实现自动删除的?发布与订阅/脚本/事务等特性是如何实现的?使用什么模型处理客户端的命令请求?一条命令从发送到返回需要经历的步骤?
		4.第一版发布的时候还不是很完善,作者一边注释源码一边写,只介绍了内部机制和单机特性,新版添加了关于二进制位操作/排序/复制/Sentinel和集群等主题的新章节
		5.数据结构与对象,单机数据库的实现,多机数据库的实现,独立功能的实现
		6.数据库里面的每个键值对都是由对象组成的:数据库键总是字符串对象;键的值可以是字符串对象/列表对象(list object)/哈希对象(hash object)/集合对象(set object)/有序集合对象(sorted set object),这五种中的其中一种
		7.第一部分和第二部分单机功能比较重要:第一部分,简单动态字符串,链表,字典,跳跃表,整数集合,压缩列表,对象
		8.Redis自己构建了一个SDS的类型用来保存所有的字符串对象,包括键值对的键,值中存储字符串对象的底层也是SDS

	redis的设计与实现-list的底层实现 链表
		1.链表提供了高效的节点重排能力,顺序性的节点访问方式,通过增删节点调整链表的长度,C语言不内置,Redis构建了自己的链表实现
		2.列表键的底层实现之一就是链表,当元素比较多,元素都是比较长的字符串,就会使用链表作为底层实现
		3.发布与订阅,慢查询,监视器等功能也用到了链表,redis本身使用链表保存多个客户端的状态信息
		4.每个链表节点使用adlist.h/listNode结构表示,通过prev和next指针组成双端链表;使用adlist.h/list结构操作更方便,提供了表头指针head,表尾指针tail,长度计数len,特定类型的函数等
		5.链表表头前置和表尾后置都是指向null,所以是无环链表,设置不同类型特定函数,可以用于保存不同类型的值

	Redis 哈希(Hash)
		Redis hash 是一个string类型的field和value的映射表,hash特别适合用于存储对象。
		Redis 中每个 hash 可以存储 232 - 1 键值对(40多亿)。
		hget hset
			1.hmset user:1000 username taoshihan birthyear 1991 verified 1  //设置hash中的多个域
			2.hget user:1000 username //hget是取回单个域
			3.hgetall user:1000  //hgetall取回所有域
			4.hmget user:1000 username birthyear //hmget取回多个域
	redis是单线程的为什么那么快:
		1.数据存于内存
		2.用了多路复用I/O
	内部数据结构:
		简单动态字符串SDS
		双端链表
			双端链表及其节点的性能特征如下:
			节点带有前驱和后继指针
			链表是双向的,所以对表头和表尾操作都是O(1)
			链表节点可以会被维护,LLEN复杂度为O(1)
		哈希表
			字典的底层实现为哈希表,每个字典含有2个哈希表,一般只是用0号哈希表,1号哈希表是在rehash过程中才使用的
			哈希表使用链地址法来解决碰撞问题
			rehash可以用于扩展或者收缩哈希表
			对哈希表的rehash是分多次、渐进式进行的
		跳跃表
	主从复制模式下,主挂了怎么办?redis提供了哨兵模式(高可用):
		1.通过哨兵节点进行自主监控主从节点以及其他哨兵节点,发现主节点故障时自主进行故障转移
		2.三个定时监控任务
			1 每隔10s,每个S节点(哨兵节点)会向主节点和从节点发送info命令获取最新的拓扑结构
			2 每隔2s,每个S节点会向某频道上发送该S节点对于主节点的判断以及当前Sl节点的信息,同时每个Sentinel节点也会订阅该频道,来了解其他S节点以及它们对主节点的判断(做客观下线依据)
			3 每隔1s,每个S节点会向主节点、从节点、其余S节点发送一条ping命令做一次心跳检测(心跳检测机制),来确认这些节点当前是否可达
		3.选举出某一哨兵节点作为领导者
		4.故障转移(选举新主节点流程)
PHP-FPM:
	cgi:一种协议,CGI/1.1 标准
	fastcgi:一种升级版协议,常驻型
	php-cgi:解释PHP脚本的程序,实现了fastcgi协议,进程管理较差
	php-fpm:是fastcgi进程的管理器,升级版php-cgi,升级了进程调度
	php-fpm控制子进程的个数:
		pm = dynamic #对于专用服务器,pm可以设置为static。
		#如何控制子进程,选项有static和dynamic。如果选择static,则由pm.max_children指定固定的子进程数。如果选择dynamic,则由下开参数决定:
		pm.max_children #,子进程最大数
		pm.start_servers #,启动时的进程
		pm.min_spare_servers #,保证空闲进程数最小值,如果空闲进程小于此值,则创建新的子进程
		pm.max_spare_servers #,保证空闲进程数最大值,如果空闲进程大于此值,此进行清理
	php-fpm开启慢查询日志:
		/etc/php/7.0/fpm/pool.d/www.conf 
		slowlog = /var/log/php-fpm-$pool.log.slow
		request_slowlog_timeout = 5
	配置php-fpm的php的错误日志:
		/usr/local/php7.1.10/etc/php-fpm.d/www.conf
		php_admin_value[error_log] = /var/log/php-fpm/fpm-php.www.log
		php_admin_flag[log_errors] = on
		php-fpm的默认错误日志,在这里配置/etc/php/7.0/fpm/php-fpm.conf error_log,只是fpm启动信息的日志,没有php的错误日志
	配置临时文件目录:
		env[TMP] = /data1/phptmp
		env[TMPDIR] = /data1/phptmp
		env[TEMP] = /data1/phptmp
	PHP-FPM的优点:
		1.先进的进程控制,优雅的停止启动
		2.能够使用不同的uid/gid/chroot/environment启动worker,使用不同的php.ini,监听不同的端口
		3.stdout stderr日志记录
		4.opcode cache破坏的情况下紧急重启
		5.加速上传支持
		6.slowlog慢日志记录脚本,可以记录PHP跟踪和远程进程的execute_data, ptrace或者类似工具读取和分析
		7.fastcgi_finish_request()刷新所有数据,当在做耗时操作的时候,比如视频转换和统计处理,在fastcgi_finish_request()之后,该脚本仍将占用FPM进程。因此,对于长时间运行的任务过度使用它可能会占用所有FPM线程,直到pm.max_children
		8.动态静态子进程产生
		9.基础的SPAI状态,基于php.ini的配置文件
NGINX:
	PATH_INFO的配置:
		1.PATH_INFO是一个CGI 1.1的标准,不要误解为nginx的功能
		2.PHP对该标准进行了支持,PHP中有两个pathinfo,环境变量$_SERVER['PATH_INFO'];pathinfo() 函数
		3.pathinfo() 函数以数组的形式返回文件路径的信息,先不管它
		4.nginx的配置项是对$_SERVER['PATH_INFO]值进行设置,如果不配置默认是没有的
		5.因为路径部分是这样的index.php/111,所以location ~ \.php {} 把php后面的$必须以php结尾去掉
		6.传递PATH_INFO参数:
		fastcgi_param  PATH_INFO $fastcgi_path_info; 此时
		 ["PHP_SELF"]=>string(3) "NFO"
		 ["PATH_INFO"]=>string(3) "NFO"
		7.
		fastcgi_split_path_info ^((?U).+.php)(/?.+)$;此时
		["PATH_INFO"]=>"/111"
		["PHP_SELF"]=>"/index.php/111"
		8.重写隐藏index.php,如果请求的是文件名才重写
		if (!-e $request_filename) {
			rewrite ^/(.*)$ /index.php/$1 last;
			break;
		}
		此时:
		 ["PATH_INFO"]=>"/111"
		 ["PHP_SELF"]=>"/index.php/111"
		REQUEST_URI是域名后面的url所有的部分,  ["REQUEST_URI"]=>string(24) "/test/server.php/ss?a=ss"

	nginx可以用信号控制:
		kill -s HUP 8587 将HUP信号发送到主进程,使用新配置启动新的工作进程,正常关闭旧工作进程,即打开日志文件和新的侦听套接字。
		kill -s USR2 8587 即时升级可执行文件
	location 
		location = /uri    =开头表示精确匹配,只有完全匹配上才能生效。
		location ^~ /uri   ^~ 开头对URL路径进行前缀匹配,并且在正则之前。
		location ~ pattern  ~开头表示区分大小写的正则匹配。
		location ~* pattern  ~*开头表示不区分大小写的正则匹配。
		location /uri     不带任何修饰符,也表示前缀匹配,但是在正则匹配之后。
		location /      通用匹配,任何未匹配到其它location的请求都会匹配到,相当于switch中的default。  

	Nginx 的特点:
		1.处理静态文件
		2.反向代理加速
		3.fastCGI,简单的负载均衡和容错
		4.模块化的结构
		5.分阶段资源分配技术,使得它的 CPU 与内存占用率非常低,保持 10,000 个没有活动的连接,它只占 2.5M 内存
		6.支持内核 Poll 模型,能经受高负载的考验,有报告表明能支持高达 50,000 个并发连接数
		7.采用 master-slave 模型,能够充分利用 SMP 的优势,且能够减少工作进程在磁盘 I/O 的阻塞延迟。当采用 select()/poll() 调用时,还可以限制每个进程的连接数
		8.强大的 Upstream 与 Filter 链,有点像 Unix 的管道
		9.采用了一些 os 提供的最新特性如对 sendfile (Linux2.2+),accept-filter (FreeBSD4.1+),TCP_DEFER_ACCEPT (Linux 2.4+)的支持

		Nginx 架构:
		1.默认采用多进程后台模式启动,可以手动配置成单进程前台模式用于调试,进程数一般和cpu内核数相同,太多进程会导致竞争cpu资源,带来不必要的上下文切换
		2.发送kill -HUP pid的信号给master进程,master进程会从新加载配置文件,启动新的worker进程,退出老的worker进程,也是-s reload所做的
		3.在master进程建立好需要listen的 socket,然后fork出子进程,子进程抢accept_mutex的互斥锁,抢到的子进程进行 accept处理
		4.每个子进程采用异步非阻塞事件处理, select/poll/epoll/kqueue的系统调用,设置超时时间,当事件没准备好时,放到 epoll 里面,事件准备好了,我们就去读写,当读写返回 EAGAIN(再试一次)时,我们将它再次加入到 epoll 里面,线程还是只有一个,在请求间进行不断的循环切换,这里的切换没有代价,只要内存够大就行
		5.apache那种简单的多线程,每个请求会独占一个工作线程,当并发数上到几千时,就同时有几千的线程在处理请求占用内存大,线程间上下文切换占用的cpu开销大
		6.事件处理通常包含,网络信号(异步非阻塞),信号,定时器(放在一颗维护定时器的红黑树里面)

		nginx的connection
		1.主进程监听端口创建socket,fork出子进程,子进程互斥锁竞争accept新的连接,三次握手建立连接以后,异步非阻塞读写事件处理,nginx或客户端主动关掉连接
		2.每个进程都有连接数的限制,ulimit -n,超过时创建socket会失败
		3.nginx能建立的最大连接数 worker_连接数*worker_进程数;作为反向代理时则为worker_连接数*worker_进程数 /2 ,nginx也要请求另外的处理服务占用一个连接
		4.利用accept_mutex锁来平衡每个worker进程的连接数

		nginx与keepalive
		1.http1.0和http1.1都支持长连接,默认1.0是关闭的,1.1是打开的
		2.http1.0需要指定Connection:keep-alive表示使用长连接,响应头中会包含content-length,客户端依据这个长度表示接收完成,否则会一直接收数据
		3.http1.1不需要指定connection,响应头中Transfer-encoding 为 chunked则会是流式传输,每块会包含当前块的长度;如果非chunked则要有content-length,否则会一直接收直到服务端主动断开
		4.keepalive_timeout 来配置超时时间,如果为0则会直接关闭,默认65秒

		nginx的请求处理:
			1.worker进程中有个函数,无限循环,不断处理收到的客户端请求,并进行处理
			2.系统提供的事件处理机制(select/epoll/kqueue)
			3.接收数据,初始化HTTP Request ,处理请求头请求体
			4.读取配置文件进行处理阶段,location rewrite filter等
			5.产生响应发送给客户端

			1.Epoll是poll的改进版,在高并发下能同时处理大量文件描述符,nginx使用了
			2.Poll是监控资源是否可用,轮询整个文件描述符集合,例如在多个socket连接建立后,可以知道哪些连接发了请求,与select比不会清空文件描述符
			3.Epoll只会查询被内核IO事件唤醒的集合,只有发生IO的socket会调用callback函数
			4.文件描述符,一切皆文件网络是文件键盘是文件,像写文件那样传输网络数据,通过/proc/的文件看到进程的资源使用情况
PHP:
	session id的生成原理:
		hash_func = md5 / sha1 #可由php.ini配置
		PHPSESSIONID = hash_func(客户端IP + 当前时间(秒)+ 当前时间(微妙)+ PHP自带的随机数生产器)
	获取UUID:
		apt-get install uuid uuid-dev
		pecl install uuid配置cli和fpm的ini文件,引入扩展
		php有这个扩展uuid:
		uuid_create()生成唯一id:时间戳、毫秒数、机器码、自增计数
	接口安全性:
		接口的安全性主要围绕Token、Timestamp和Sign三个机制展开设计,保证接口的数据不会被篡改和重复调用,下面具体来看:
		(1)Token授权机制:(Token是客户端访问服务端的凭证)--用户使用用户名密码登录后服务器给客户端返回一个Token(通常是UUID),并将Token-UserId以键值对的形式存放在缓存服务器中。服务端接收到请求后进行Token验证,如果Token不存在,说明请求无效。
		(2)时间戳超时机制:(签名机制保证了数据不会被篡改)用户每次请求都带上当前时间的时间戳timestamp,服务端接收到timestamp后跟当前时间进行比对,如果时间差大于一定时间(比如5分钟),则认为该请求失效。时间戳超时机制是防御DOS攻击的有效手段。
		(3)签名机制:将 Token 和 时间戳 加上其他请求参数再用MD5或SHA-1算法(可根据情况加点盐)加密,加密后的数据就是本次请求的签名sign,服务端接收到请求后以同样的算法得到签名,并跟当前的签名进行比对,如果不一样,说明参数被更改过,直接返回错误标识。
	array系列函数:
		1.in_array ( mixed $needle , array $haystack [, bool $strict = FALSE ] )
		第三个参数是true,就检测类型,否则不检测

		2.array_flip — 交换数组中的键和值,返回一个反转后的 array,例如 array 中的键名变成了值,而 array 中的值成了键名。
		$arr=array_flip($haystack); 
		if ( isset($arr[$needle]) ) 判断是否存在在数组中 

		3.array_map — 为数组的每个元素应用回调函数
		因为in_array不区分大小写,所以使用这个对数组的所有元素转成小写
		return in_array(strtolower($needle), array_map('strtolower', $haystack));
		
		4.分割成数组,使用逗号或空格(包含" ", \r, \t, \n, \f)分隔短语,因为在分割数组的时候,空格的数量不一定是几个,explode不能用
			$keywords = preg_split("/[\s,]+/", "hypertext language, programming");
		print_r($keywords);

		5.array_slice — 从数组中取出一段
			$input = array("a", "b", "c", "d", "e");
			$output = array_slice($input, 2);      // returns "c", "d", and "e"
			$output = array_slice($input, -2, 1);  // returns "d"
			$output = array_slice($input, 0, 3);   // returns "a", "b", and "c"
		6.array_merge 合并两个数组
			$logList=array_merge($logList, $lastMonthLogList);
		7.array_push — 将一个或多个单元压入数组的末尾(入栈)
			array_push($stack, "apple", "raspberry");
			$array[] = $var;相当于这样
			如果是数组,那就相当于二维数组了
	php魔术方法:
		__construct()[构造], __destruct()[析构], __call()[调用不存在的方法], __callStatic()[调用不存在的静态方法], 
		__get()[获取不存在属性的值], __set()[为不存在属性赋值调用],
		__isset()[isset不存在的属性], __unset()[unset不存在的属性], __sleep()[序列化对象的时候], __wakeup()[反序列化对象的时候], __toString(), __invoke(), __set_state(), __clone() 和 __debugInfo() 
	类的自动加载:
		1. spl_autoload_register() 函数可以注册任意数量的自动加载器,当使用尚未被定义的类(class)和接口(interface)时自动去加载。
		2.__autoload() 函数也能自动加载类和接口,在以后的版本中它可能被弃用
	动态设置php.ini中的include_path 配置选项:
		两种方式
		set_include_path($new_include_path)
		ini_set('include_path',$new_include_path);
		利用常量 PATH_SEPARATOR 可跨平台扩展 include path,可以把自己设置的path加在现有include_path的尾部
	OO设计的基本原则
		单一原则:一个类只做一件事
		开闭原则:对扩展开放,对修改关闭
		里式替换:子类必须能够替换所有父类的使用
		依赖倒置:设计依赖于抽象而不是实现
		最少知识:对象应当尽可能少的去了解其他对象
		接口隔离:接口倾向于小而多
		组合优先:优先使用类的组合而不是继承
		OOA面向对象分析 OOD面向对象设计 OOP面向对象编程
	单例:
		私有化构造方法
		通过静态方法创建并保持对象
		注意实例化方法需要线程安全
		private static $instance;private function __construct(){}
		public static function getInstance(){
			if(self::instance==null) self::instance=new self();
			return self::instance;
		}
		适用场景:类的对象全局唯一,节约频繁创建对象的资源开销,单例类必须是无状态的

	工厂模式:
		负责生成其他对象的类或方法,这就是工厂模式,下面是一个经常见到的用法
	    public function getSetting(){
	        if(!$this->setting){
	            $this->setting=new Setting();
	        }
	        return $this->setting;
	    }
	适配器模式:
		就是将一个类的接口方法转换成我希望用的另一个方法 , 下面是个常见的用处
	    public function set($key,$value){
        	return $this->mc->set($key,$value,MEMCACHE_COMPRESSED,3600);
    	}
	依赖注入与控制反转与call_user_func_array
		$conf=array(
			'name'=>'taoshihan',
			'age'=>10
			);
		$user=call_user_func_array(array('User', "createResource"), array($conf));


	PHP过滤XSS
	    $ra=Array('/([\x00-\x08,\x0b-\x0c,\x0e-\x19])/','/script/','/javascript/','/vbscript/','/expression/','/applet/','/meta/','/xml/','/blink/','/link/','/style/','/embed/','/object/','/frame/','/layer/','/title/','/bgsound/','/base/','/onload/','/onunload/','/onchange/','/onsubmit/','/onreset/','/onselect/','/onblur/','/onfocus/','/onabort/','/onkeydown/','/onkeypress/','/onkeyup/','/onclick/','/ondblclick/','/onmousedown/','/onmousemove/','/onmouseout/','/onmouseover/','/onmouseup/','/onunload/');
	    $value  = addslashes($str); //给单引号(')、双引号(")、反斜线(\)与NUL(NULL字符)加上反斜线转义
	    $value  = preg_replace($ra,'',$value);     //删除非打印字符,粗暴式过滤xss可疑字符串
	    $str = htmlentities(strip_tags($value)); //去除 HTML 和 PHP 标记并转换为HTML实体
	php异步执行一个脚本:
		echo exec("php /var/www/html/test/2.php >/dev/null 2>&1 &");
		>/dev/null 输出到空设备中  等同于 1>/dev/null
		1代表stdout标准输出
		2代表stderr标准错误 & 表示等同于的意思
		2>&1 2的输出重定向等同于1,都是到空设备中
	下载安装xunsearch,中文分词全文搜索
		wget http://www.xunsearch/download/xunsearch-full-latest.tar.bz2
		tar -xjf xunsearch-full-latest.tar.bz2
		cd xunsearch-full-1.4.13
		sh setup.sh
		/usr/bin/xunsearch
		/usr/bin/xunsearch/bin/xs-ctl.sh restart
		配置文件
		/usr/bin/xunsearch/sdk/php/app/sopans.ini 
		project.name = sopans
		project.default_charset = utf-8
		server.index = 8383
		server.search = 8384
		[id]
		type = id
		[title]
		type = title
		/usr/bin/xunsearch/sdk/php/util/Indexer.php --project=sopans --source=mysql://root:密码@localhost/pan --sql="select * from texts"
	stttotime处理时间:
		date("Y-m-d",strtotime('Monday'));
		date("Y-m-d",strtotime('Next Monday'));下周一
		date("Y-m-d",strtotime('Last Monday'));上周一
		$starttime=date('Y-m-d H:i:s',strtotime("-7 day")); 七天前
		$lastMonth=date("m",  strtotime("-1 month"));一月前
	正则表达式模式修正符:
		i 忽略大小写
		m 多行视作一行
		g 全局匹配
		s .圆点匹配换行符,默认不包括换行   这个相当有用
		x 空白字符除了被转义的或在字符类中的以外完全被忽略,在未转义的字符类之外的 # 以及下一个换行符之间的所有字符,包括两头,也都被忽略。
		e preg_replace() 在替换字符串中对逆向引用作正常的替换
		u 此修正符启用了一个 PCRE 中与 Perl 不兼容的额外功能。模式字符串被当成 UTF-8。
		U : 正则表达式的特点:就是比较”贪婪“  .* .+ 所有字符都符合这个条件
Linux
	
	多线程比多进程的优势:
		在Linux系统下,启动一个新的进程必须分配给它独立的地址空间,建立众多的数据表来维护它的代码段、堆栈段和数据段,这是一种”昂贵”的多任务工作方式。而运行于一个进程中的多个线程,它们彼此之间使用相同的地址空间,共享大部分数据,启动一个线程所花费的空间远远小于启动一个进程所花费的空间,而且,线程间彼此切换所需的时间也远远小于进程间切换所需要的时间
	linux按照时间顺序排序文件列表
		ll -t   -r是反转倒序,按时间顺序反转倒序
	指定nologin用户执行命令
		su -s /bin/bash -c "ls" www
	运行级别原理:
		目录下/etc/rc.d/init.d 有许多服务器脚本文件,称为service,命名规则为 S(两位数)服务名 K(两位数)服务名
		查看运行级别:runlevel 
		chkconfig nginx on,这个命令的原理是在/etc/rc.d/rc级别.d/下面增加了一个软连接
	centos查看当前系统的启动级别
		vim /etc/inittab  
			id:3:initdefault:
		/etc/rc.d/init.d

		service 系统服务脚本:
		目录/etc/init.d
		1.$0	当前脚本的文件名
		2.shell特殊变量$n	传递给脚本或函数的参数。n 是一个数字,表示第几个参数。例如,第一个参数是$1,第二个参数是$2
		3.case的分支判断
		case $1 in
		"xxx")
		        echo "xxx";
		        ;;
		esac

	容器化
		1.Linux 发展出了另一种虚拟化技术:Linux 容器(Linux Containers,缩写为 LXC)
		2.Linux 容器不是模拟一个完整的操作系统,而是对进程进行隔离
		3.Docker 属于 Linux 容器的一种封装,提供简单易用的容器使用接口
		4.Docker 是服务器----客户端架构。命令行运行docker命令的时候,需要本机有 Docker 服务
		curl -sSL https://get.docker/ | sh
		service docker start
		5.Docker 把应用程序及其依赖,打包在 image 文件里面
		6.容器实例,本身也是一个文件,称为容器文件
		docker image pull 名称 //拉取image文件
		docker image ls//列出所有image
		docker image rm [imageName] //删除 image 文件
		docker container run hello-world //运行image文件
		docker container start [containID]//运行已经存在的容器
		docker container kill [containID] //终止容器
		docker container ls --all  //列出所有容器,包括终止的
		docker container rm [containID]//删除容器

		hello-world:
		1.docker run hello-world
		2.没有这个image会自动拉取镜像,然后运行起来

		在ubuntu的docker中运行ubuntu
		1.docker container run -p 6666:80  -it dc86b7b90238  bash //端口映射外面的6666到内部的80
		2.docker container exec  -it 3ce8952ce68d  bash  //在运行的容器中执行命令,-i

		在ubuntu的docker中运行centos
		1.docker pull centos:6
		2.给运行的容器映射本地端口
			1)docker commit  6e54eac36507  centos_image1//提交运行中的容器为一个镜像
			2)docker run -d -it -p 6667:80 centos_image1 /bin/bash  //从新run新的镜像

		制作自己的 Docker 容器
		1. .dockerignore 忽略打包的文件
		2. Dockerfile 文件
		3. docker image build -t koa-demo .  //创建image文件
		4. docker container run -p 8000:3000 -it koa-demo /bin/bash //从image文件生成容器运行
		容器的 3000 端口映射到本机的 8000 端口,-it参数 容器的 Shell 映射到当前的 Shell
	DNS的通信过程:
		tcpdump -i eth0 -s 0 -n -l port 53 

		10:44:10.203166 IP 10.105.38.204.47751 > 10.236.158.114.53: 44627+ A? www.huiful. (32)
		我的IP地址10.105.38.204端口47751向DNS服务器的10.236.158.114端口53发送请求
		44627是我这个请求的标识,+代表启用递归查询,A?表示A类型的查询,32代表DNS查询报文长度

		3.DNS的响应
		10:44:10.203634 IP 10.236.158.114.53 > 10.105.38.204.47751: 44627 1/0/0 A 123.207.167.115 (48)
		44627和请求对应,1/0/0  1个应答资源 0个授权记录 0个额外信息记录 A记录IP地址 48是报文长度

		host -t A www.baidu的DNS查询过程:
		IP 10.105.38.204.39732 > 10.236.158.106.53: 11431+ A? www.baidu. (31)
		IP 10.236.158.106.53 > 10.105.38.204.39732: 11431 3/0/0 CNAME www.a.shifen., A 115.239.210.27, A 115.239.211.112 (90)
	统计在一台前端机上高峰时间TCP连接的情况,统计命令:
		netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'
		netstat -n可以查看网络连接情况
Golang

	Golang核心编程:

	区块链研发工程师(分布式账本技术,互联网数据库技术,特点是去中心化)
	Go服务器端/游戏软件工程师(现在主流是C C++,处理日志,数据打包,文件处理,美团后台流量支撑,处理大并发;游戏后台数据通道)
	Golang分布式/云计算软件工程师(盛大云,cdn,京东消息推送系统,分布式文件处理)

	Golang的应用领域:
	区块链应用
	后端服务器应用:主站后台流量(排序,推荐,搜索等),提供负载均衡,cache,容器,按条件分流;游戏服务器(通讯,逻辑,数据存储)
	云计算/云服务后台应用:cdn内容分发网络,cdn的调度系统,分发系统,监控系统,短域名服务;分布式文件系统;说明golang的计算能力很强

	高效而愉快的学习
	先整体框架,再细节
	工作中用到什么,快速学习的能力
	学习软件编程是在琢磨别人是怎么做,而不是我认为应该怎么做的过程
	把重点放在逻辑处理和编程思想上,而不是语法本身

	如何深入的学习一个新技术或者知识点
	1.项目开发过程中,需要解决某个问题
	2.先看看是否能用传统的技术解决,使用新技术
	3.研究原理和基本语法
	4.快速入门案例,简单,了解新技术的基本使用
	5.研究技术的细节,这个地方是最能体现程序员的能力,也是最废时间的

	Go语言的特点:
	1.从c语言继承了许多特性,数据类型,参数,指针等
	2.引入了包的概念,每一个文件归属一个包,不能单独存在
	3.引入了垃圾回收机制
	4.天然并发,goroutine,基于CPS并发模型
	5.支持管道通信机制
	6.支持函数返回多个值
	7.新的创新,比如切片slice,延时执行defer等

	开发工具:VSCode Sublime Text  Vim  Emacs

	windows搭建开发环境:
	1.下载安装就可以,
	https://studygolang/dl
	比如我的目录 D:\golang\    code目录(存放第三方类库) go目录(golang安装目录)  workspace目录(我自己的代码目录)
	2.三个环境变量
	PATH变量,执行go安装的目录D:\golang\go\bin;
	GOPATH变量,D:\golang\go\code
	GOROOT变量,D:\golang\go\workspace

	Golang执行流程分析
	1.编译后的文件会把资源打包进去,因此会变得很大,可以拷贝到没有Go运行环境的地方执行
	2.程序如果有错误,编译时,会在错误的那行进行提示
	3.Golang默认会给每行后面加分号
	4.同一个main包下只能有一个main函数,同一个目录下只能是同一个包

	Golang标准库
	1.Go标准库下的包和源文件 D:\golang\go\src
	2.文档http://docscn.studygolang/pkg/
	3.调用包的方式 import 包名   包名.函数名

  

转载于:https://wwwblogs/taoshihan/p/10758680.html

本文标签: 知识点日常