育儿网邮寄地址插件

编    写:袁    亮
时    间:2015-01-20
说    明:育儿网邮寄地址插件使用说明

一、问题
1、收货的邮寄地址需要用户填写省市区
2、省市区等信息会变,需要统一管理
3、需要实现联动效果,不需要各个项目都做这一套

二、使用范例
1、代码(参考demo.html文件)
<form name="recvaddress_form">
<select name="province" onchange="ciarea.selcity(this.value,0);" style="width:80px;"></select> 省
<select name="city" style="width:120px;" onchange="ciarea.selarea(this.value,0);"></select> 市
<select name="area" style="width:120px;"></select> 区
</form>
<script type="text/javascript" src="http://shiyong.ci123.com/district/common.js"></script>
<script type="text/javascript">
window.onload = function(){
//ci_province=11;ci_city=1100;ci_area=41306; //编辑的时候,需要默中省市区的时候设置
ciarea.selprovince(ci_province,ci_city,ci_area);
}
</script>
2、需要注意的地方
2.1 form的name必须设置为recvaddress_form,js中有用到
2.2 三个select的name的名称是确定的这三个
2.3 两个onchange事件不能少
2.4 引用common.js
2.5 页面加载的时候,触发数据加载
2.6 编辑地址的时候,需要有默认选中的时候,则设置相应的三个js变量即可

三、参考页面
1、http://shiyong.ci123.com/user/address.php
2、http://user.ci123.com/account/EditUserInfo/detail

http协议的简单总结

编    写:袁    亮
时    间:2014-6-26
说    明:http协议的简单总结

一、基本流程
1、在浏览器输入网址
2、浏览器根据网址,封装http请求头数据包
3、数据包根据地址查找到相应服务器
4、服务器根据头信息进行相应处理并返回返回头信息以及body内容
5、浏览器接收到返回数据,展示body部分内容,并根据头消息进行相应设置,比如cookie等
6、浏览器根据内容进行相应的排版现实,并且运行其中的js交互脚本
7、一次完整的交互完成

二、查找服务器过程
1、根据域名查找本地hosts文件,看是否有对应ip
2、发送到代理,代理去请求数据
3、如果没有,则发送请求到公网dns查询该域名对应的服务器地址
4、cdn加速访问
5、前端代理转发
6、http服务器接收请求,并交给php解析运行
7、服务器将返回的数据再传输回用户的浏览器

三、http常用状态码
200:正常返回
301:永久跳转
302:临时重定向
304:资源未修改,直接使用本地缓存
403:权限不够
404:找不到文件
500:服务器错误,一般是程序语法错误等
502:代理服务器未能接受到正确响应
504:响应超时

crontab书写的一些注意事项

编	写:袁	亮
时	间:2014-03-13
说	明:crontab书写的一些注意事项

一、使用说明:
crontab 是指定时linux服务器,自动的定时去执行一个脚本
一般用于定时去进行一些数据统计,缓存更新,消息提醒等等

二、使用流程:
1、脚本编写,并执行测试(/opt/ci123/php/bin/php *.php),看功能是否正常
	a、定时脚本最好不要在浏览器中执行,因为定时脚本一般执行时间较长,如果在浏览器下执行,有死循环或者太耗时间的语句,中途停止不了,很容易因为这个把数据库等弄挂,项目不能正常访问。而在linux下直接执行,如果卡或异常,可以直接ctrl+c中止。
	b、引入外部文件最好以全路径包含:通过define("FROOT",(dirname(__FILE__)))获取当前文件路径,再通过FROOT来拼接(易于迁移,防止多重include导致相对路径计算错误等)
	c、不允许浏览器访问,防止爬虫等异常访问,加在脚本的前面
		[code]
		if(isset($_SERVER['HTTP_HOST'])){//定时脚本不允许浏览器访问
 		       die();
		}
		[/code]
	d、必须有输出,包括:脚本开始时间、结束时间,各模块的结束时间,方便后期排查

2、加入crontab
	a、crontab -e 进行crontab文件编辑,-e参数不可少,否则会导致将crontab内容清楚,切记
	b、添加一条记录,例如:
		第一行	以#开头的是注释,谁写的,什么时间,做什么用的
		第二行,前5个,分别代表分、时、日、月、周(具体数字代表固定时间;1-5,代表区间;1,4,7代表指定几个时间;*/5代表每5个单位时间执行一次;*代表任意时间;);
			source /etc/profile.d/ice-3.2.1.sh;这个是有ice扩展的时候才加;
			后面是调试时候的执行代码;
			>>/tmp/bbs_static_hour_log 是指将输出以追加的方式记录到/tmp/bbs_static_hour_log这个文件中,命名需规范
			2>&1; 代表不管是正常输出,还是错误提示都记录到日志,照抄即可

		[code]
		#袁亮-2013-12-03,统计bbs每天24小时发帖、回帖等数据
		37 2 * * * ( source /etc/profile.d/ice-3.2.1.sh; /opt/ci123/php/bin/php 		/opt/ci123/www/html/bbs/sadmin/cront/makeStatic.php >>/tmp/bbs_static_hour_log  2>&1;)
		[/code]
	
	

php数组的相关知识

编    写:袁    亮
时    间:2015-01-20
说    明:php数组的相关知识

一、相关概念
1、把有限个变量用同一个名字标识,然后使用不同的名称标识,标识称为下标。本身是一个集合
2、php数组有三种
索引数组 - 带有数字索引的数组
关联数组 - 带有指定键的数组
多维数组 - 包含一个或多个数组的数组

二、常用功能
1、数组创建
$data = array(//索引数组
'user_id'    => 1535917,
'username'    => 'yuanliang847',
'nickname'    => '暗夜御林',
);

$data = array('yuanliang','暗夜御林');//如果数组很小,不需要跟上面似的,写成多行;索引数组

$data['username'] = 'yuanliang847';

$data[] = '暗夜御林';//索引数组,下标值自动加1

第一种方式key后面使用Tab键缩进保持代码对齐,不要打一堆空格,值的前面是一个空格
最后一个值的“,”可以省略,但建议不要省,方便其他人加一个下标的时候,忘了补从而出错
多维数组只是把其中的值value变成一个数组即可
2、循环遍历
foreach($data as $k=>$v){
echo $v."<hr />";
}
php数组使用最多的方式,没有之一
for循环只能对索引数组循环,而foreach可以对任意数组进行循环遍历
$k 是相应的数组下标,$v是对应的值
3、数组计算
$num = count($data);
多维数组也只记第一维的个数

三、数组打印调试
1、var_dump()
var_dump($data);
die();

这是php调试中最常使用的调试打印方法,任意类型的变量都可以打印
2、echo
echo $data['username'];
程序嵌套部分,都是使用的echo把php变量输出成对应的html
3、var_export()
var_export($data);
与var_dump类似,但是这个打印出来的内容,复制出来,可以直接复制给php变量使用,有些时候非常有用
$d = var_export($data,1);//把转化的数据变成字符串,经常会用来生成php文件

四、其他比较有用的功能
1、排序
sort ksort
排序的不同方式,有一堆sort结尾的函数,需要的时候,具体看函数列表
2、数组去重
array_unique
先将值作为字符串排序,然后对每个值只保留第一个遇到的键名,接着忽略所有后面的键名
一般只对一维数组排,多维数组排没有任何意义
3、多个数组合并
array_merge
如果键名有重复,该键的键值为最后一个键名对应的值(后面的覆盖前面的)。如果数组是数字索引的,则键名会以连续方式重新索引
4、查看给定的值在数组中是否存在
in_array($str,$arr)
一般我们只用在索引数组里
5、随机获取一个或者多个元素
array_rand
6、把数组中的值赋给一些变量
$data = array(1535917,'yuanliang847','暗夜御林');
list($user_id,$username,$nickname) = $data;
省去了多次赋值
7、与字符串的互相转换
字符串转索引数组:
explode(separator,string,limit)
数组转字符串:(不要使用join别名,高版本会报错,ps:没记错的话是5.3之后)
implode(separator,array)

翻墙的相关知识

编    写:袁    亮
时    间:2015-06-25
说    明:翻墙的相关知识

一、为什么需要翻墙?
1、天朝有个东西叫GFW(中国长城防火墙),会将一些不希望网民看到的东西封禁,导致我们上不了一些网站
DNS解析:DNS解析服务器不受国内控制,采用的域名劫持的办法使得我们上不了相应域名,也封锁了海外相当多的DNS服务器
连接阶段:请求与被封禁名单匹配,重置连接
URL关键词:在路由器上,对链接的关键词进行匹配,封禁
页面扫描:对国际出口,扫描页面内容,发现关键词,则在一定时间段内,不能连接到该网站,骨干网省级接入处也有
ps:国内网站基本上会通过行政干预,整改或者关闭,主要针对的是国外不能控制的网站
2、查找技术资料、问题的时候,百度经常搞不定
3、很多较新的技术,国内没有相关资料,需要翻墙

二、如何实现翻墙
1、加host
只适用于访问固定某个网站,比如给google加相应的host,像下载adt等的时候就会这么干
大部分时候无效,因为那些固定ip经常被封,
了解即可,正常翻墙不会这么干
2、代理
正常上网的话,需要路由器,dns解析等等,这个时候,防火墙会进行各种干扰导致上不了
使用代理,其实就是找到一个可以不经过防火墙的服务器(国外,国内肯定被墙),去帮你访问这些网站,并把这些网站的返回数据返回给我们,因为代理服务器没有被封,所以我们可以正常的连接到这台服务器上,而这台服务器又可以正常的上那些网站,所以通过它,我们就可以愉快的上各种网站了
代理不对请求内容进行加密,知识通过代理服务器进行了请求转发
这个一般都是在浏览器中设置相应的代理,只有设置了相应代理的浏览器才能翻墙
3、拨vpn
VPN:虚拟专用网络,架设一台VPN服务器,客户端上网的时候,通过加密的方式将数据传输到VPN服务器上,VPN服务器进行解密
从而进行通信,一般是用来作为企业内网使用
通过VPN上网的话,是在操作系统层面修改了连接方式,不管是什么浏览器,QQ还是其他客户端,都是走的VPN
连接vpn之后,本机将作为vpn网络的内网进行相应访问,vpn服务器作为统一的对外出入口
只要vpn服务器本身没有被墙,则访问任何网站都是可以的
vps:虚拟专用服务器,虚拟机

三、常用翻墙软件
1、免费,自动搜索代理服务器
自由门:经常需要更换代理,要求不高用用还可以
无界:一般,不大稳定,跟自由门差不多
webfreer浏览器:没用过
2、免费,固定代理
goagent:需要先翻墙才能申请google账号,也会时不时的被封
3、免费VPN
百度搜索,需要经常更换
http://qqbox.org/vpn/freevpn 这边有很多推荐的,可以自己试下
4、付款VPN
Shadowsocks:在用,99一年,还不错
红杏:没用过

php与apache的各种报错情况整理

编    写:盛星衡
时    间:2014-09-24
功    能:对php与apache的各种报错情况整理

php运行的报错,错误日志涉及下面几个参数的设置:
display_errors//on:页面显示错误提示,off页面屏蔽错误提示
log_errors,//on记录错误日志,off不记录错误日志
error_reporting,//设定报错级别

开发环境下一般把display_errors设置为on,error_reporting设置为8191,也就是E_ALL,宽松点可以设置为7,也可以写成error_reporting(E_ERROR | E_WARNING | E_PARSE);
一般开发模式会开warning提示,可以帮助开发人员找到一些边界处理的失误;

线上项目设置为display_errors设置为off,error_reporting设置为5,log_errors设置为on,并且apache设置log文件地址。

常见问题:
1、开发模式下设置了开启报错,但是就是没有错误提示?
这种问题一般是因为php.ini中把错误提示关闭了,程序中虽然开启了错误提示,但是语法错误,程序中设置不起效,导致没有错误提示。

2、php配置文件中把报错关闭了,没有权限对php配置文件进行修改,然后写了很长一段代码,语法错误,怎么看到错误提示?
这种情况在线上项目的调试会遇到,可以另写一个php文件,在文件中把报错开启,然后include语法错误的文件,就可以看到错误提示了。
常见的应用就是在apache上做rewrite,项目下的所有访问都统一到一个入口文件中,报错在入口文件当中配置,开启,关闭报错都比较方便。
在inc/gloal.php进行配置,然后引用,在文件本身语法错误的情况下,配置失效。

3、线上项目明明设置为把错误记录到日志中,php配置文件中设置了关闭页面报错,为什么还是把错误提示显示在页面上了?
在设置记录日志的情况下,apache配置中没有设置log文件或者没有权限操作log文件时,错误日志会直接显示在页面上。

4、如果php.ini中设置了不显示warning报错,apache重启之后,还是没用,可能是因为apache中设置了phpvalue error_reporting导致
参考文档:
http://php.net/manual/zh/errorfunc.configuration.php
http://www.jb51.net/article/31499.htm
http://www.w3school.com.cn/php/func_error_reporting.asp

ajax的简单使用和常见问题


编	写:袁	亮
时	间:2015-01-16
说	明:ajax的简单使用和常见问题

一、介绍
	1、异步js和xml
	2、在不刷新整个网页的情况下,异步的请求服务器改变部分页面数据

二、简单使用范例
	1、一般我们直接使用jquery封装好的方法直接调用,原生的实现,可以参考w3c教程
	2、范例
		function addPost(f){
			var title = f.title.value;
			var uid = 1535917;

			if(title.length<2){
				alert('标题最少2个字');
				f.title.focus();
				return false;
			}

			//$.get("sub/post_add_sub.php?rid="+Math.random(),{title:title,user_id:uid},function(data){
			$.post("sub/post_add_sub.php?rid="+Math.random(),{title:title,user_id:uid},function(data,state){
				console.log("b");
				if(data == '1'){
					//成功后的处理,显示
				}else{//失败后的提示处理等
					alert(data);
				}
			});

			console.log("a");
			return false;//不能少
		}

	3、简单说明
		1、get和post方法使用方法一样
		2、第一个参数代表的是你访问的网址是什么,后面加了一个参数rid,是因为浏览器会对js的请求进行缓存
			我们使用ajax的请求,不希望被缓存,所以加了一个随机数
		2、第二个参数{title:title,user_id:uid}
			title是传给post_add_sub.php页面的参数名,第二个title是js的变量,传递值
			user_id:uid同理
		3、第三个参数,这是一个回调函数
			data是post_add_sub.php的返回值,string类型的(类似于post请求到那边,页面输出的源代码)
			state:表示的是这次请求的状态,是否成功等,简化使用的时候我们没有判断该参数
			function(data,state){

			}
		4、设置了两个console.log,一半来说a会比b先写进去
			ajax请求是一个异步的,发出这个请求,不管有没有成功,继续执行下面的代码,console.log("a");
			异步的请求执行完之后,才会执行到回调函数中console.log("b");
			因此一般的网络请求,都会是a先触发,后触发的b

三、适用场景
	1、异步提交数据
		填写了一个表单,写了一堆东西,结果提交过去之后,因为某些错误,返回重写,导致之前的努力全部白费
		这个时候非常需要异步提交,增强用户体验
	2、局部刷新页面数据
		页面只有一小部分数据需要刷新,有改动的情况
		比如说:投完票,我需要实时的查看现在的票数
		比如说,删除了一行数据
		或者一个很大的页面,其中一小块的数据需要进行分页等等
	3、性能
		一个页面如果有非常多的数据量,如果一次全部取出来,加载的话,会非常卡,而且有很多无效的查询和请求
		这个时候,可以有个简单的优化办法,按需加载
		比如页面滚动的时候,加载相应数据、图片等

四、缺点
	1、实现会比之前的稍微复杂些
	2、后加载的内容对搜索引擎不友好,搜索引擎抓取不到
		也有办法解决,就是会很麻烦
	3、复制链接给其他用户或者自己收藏的时候,下次打开发现跟预期的不一样
		可以通过锚点解决这个问题,可以百度看下相关资料

五、调试方法
	1、可以通过firebug,或者chrome的F12查看相应的network状态
		http请求的具体知识,请查看相应文档
	2、先使用get请求的方法访问,调试
		在新窗口中打开该请求,刷新页面调试即可,与正常网页一样
	3、使用抓包工具Fiddler2抓取请求包分析

六、常见问题
	1、编码
		只认utf-8编码,sub那边的返回数据必须设置编码格式
	2、跨域
		js不允许post跨域,浏览器同源安全策略
		get跨域,跨域通过jsonp方法解决(jquery的getJson方法)
		也可以采用本域中转页面,然后发起一个服务端到服务端的请求,从而绕过跨域限制
	3、缓存
		ajax请求,正常情况下是会被浏览器缓存中的,所以请加随机数防止


Mysql使用过程中的一些规范


编	写:袁	亮
时	间:2014-10-30
说	明:Mysql使用过程中的一些规范,tech4内部试行版

一.说明
	1.1 不管是新入职的实习生,还是工作多年的老油条,都需要遵守
	1.2 里面有些可能不是那么合理,如果觉得有疑问,可以随时找我沟通讨论
	1.3 所有的规定都是基于某些原因考虑的,只是这边没有说的太仔细
	1.4 过早优化、过渡优化都是一种错误,不要在一个小项目里,过渡的使用各种优化

二.数据库设置选择
	2.1 统一字符集:utf8
		2.1.1 校对规则:utf8_general_ci
		2.1.2 建库和建表的时候必须选,建表的时候选是因为有些老库没有设置该字符集
		2.1.3 乱码:SET NAMES UTF8 (这个是因为有很多老坑,否则这个是应该去掉,很影响性能),程序也要设置utf8
		2.1.4 如果不想在程序段处理emoj等表情,可以使用UTF8MB4字符集做兼容(5.5.3版本以后)
	2.2 mysql版本最好是5.1 或者5.5以后的版本
		2.2.1 我们新的都已经是5之后了,只有几个非常老的项目,还是4.几的版本
	2.3 引擎的选择
		2.3.1 大大小小10几种引擎,但我们常用的就Myisam和InnoDB
		2.3.2 mysql 5以后的版本,默认引擎用InnoDB
		2.3.3 InnoDB的效率,根据我看网上各家的评测结果,应该是全面占优了,之前一直理解是Myisam读性能强于InnoDB
		2.3.4 我们的老项目,基本上都是Myisam,新项目尽量使用InnoDB
	2.4 程序连接数据库的账号权限
		2.4.1 指定ip连接(内网或者指定ip)
		2.4.2 主库给增、删、改、查权限
		2.4.3 从库只需要查的权限即可,禁止给全部权限

三.字段介绍选择
	3.1 常用字段:
		3.1.1 tinyint:0-255,枚举类型,性别等等,均以tinyint来
		3.1.2 int:一般的整型均用该类型,int不要设置长度,设不设置,实际存储都一样
		3.1.3 decimal:存储确定精度的浮点数时,不要用float和double,M是所有数字的个数,D是小数点后面的个数
		3.1.4 char:定长字符串,性能较高,存储md5后的值之类的非常适合
		3.1.5 varchar:变长字符串,非常常用,设置适合长度的(过长不会影响使用空间,但会影响内存使用)
		3.1.6 date:存储日期,生日之类的
		3.1.7 datetime:具体时间,精确到秒,不推荐timestamp,查看太麻烦了,性能还可以
		3.1.8 text:文本类型,最好分单独的表
		3.1.9 longtext:长文本,存储富文本编辑器中的内容,单独分表存储
	3.1 常用类型:
		3.2.1 主键:id		int		不要设置长度
		3.2.2 用户id:user_id		int		
		3.2.3 用户名:username	varchar(30)	根据用户名规则长度
		3.2.4 昵称:nickname 		varchar(30)	根据注册规则定
		3.2.5 Ip地址:ip		varchar(15)
		3.2.6 记录时间:dated		datetime	
		3.2.7 修改时间:update_dated	datetime	
		3.2.8 生日:birthday		date	
		3.2.9 手机号:mobile		char(11)	如果要兼容国内外的和座机,可以用varchar
		3.2.10 链接地址:url		varchar(255)
		3.2.11 标题:title		varchar(255)
		3.2.12 图片地址:pic		varchar(255)
		3.2.13 描述:describe		varchar(255)
		3.2.14 内容:content		text		分到单独的表中
		3.2.15 状态:state		tinyint		每个值对应什么含义,在数据字典里标明
		3.2.16 类型:types		tinyint		同状态	
		3.2.17 是否显示:is_show	tinyint		0:不线上,1:显示,不要反过来	
	3.1 字段设计的几点禁忌
		3.3.1 每张表,必须加两个字段,一个id,自增长主键,一个dated,这条记录的生成时间,不管你有没有用到,必须加
		3.3.2 不要使用枚举类型或者set,使用tinyint来代替,否则数据量上去之后,想改就是个悲剧
		3.3.3 所有字段必须是not null,并且默认值不要给null
		3.3.4 text或者longtext的拆分到单独的表中存储,不要跟主逻辑表混一起
		3.3.5 图片等不允许用blob等存储图片内容,只存图片地址
		3.3.6 密码不允许明文存储,MD5(密码+定义的字符串密钥)
		3.3.7 单张表,字段数不要超过15个,超过的话,考虑拆分成多张表,例如:
			主表:posts:id,user_id,title,....,dated
			附属表,不常用字段 post_details:id,post_id,describe,...,dated
			大文本内容: post_contents:id,post_id,content,dated
			通过post_id来做关联,将最常用的字段放到主表里,不怎么用的字段放到detail表,长文本content单独一张表

四.命名规则
	4.1 库、表、字段、索引名等:只允许小写字母、_ 、数字组成,命名不要超过20个字符
	4.2 索引命名:idx_字段名_字段名 (太长的时候,对字段名采用简写)
	4.3 避免保留字命名
	4.4 表名最后加s,看表名,字段名,需要知道这张表是干什么的,不要起一些奇奇怪怪的名字
	4.5 同一个功能模块,采用统一前缀,比如特卖购物中,订单会有多个表:
		trade_totals:
		trade_alis:
		trade_details:
		trade_express:
		不要是下面这种命名
		total_trades:
		ali_trades:
		express:
		所有订单模块涉及的表,它的表前缀必然都是trade_
	4.6 数据字典维护,以及表注释维护
	4.7 常用表名

五.数据库规模控制
	5.1 除非是一些不重要的库,否则一个库最好是一个数据库实例(同一台服务器同一个端口)
	5.2 单个数据库,表的个数不超过300,总体大小,最好在100G以内
	5.3 数据表规模:
		5.3.1 log表等,只根据索引查询的,可以大点,超过4G,也不会有什么大的性能影响
		5.3.2 核心表,比如博客的文章表等,会有很多复杂查询等,最好不要超过1G,否则性能下降会非常严重(垂直分表)
		5.3.3 单张表,字段数不超过15个(log表等,不超过30个)
		5.3.4 学会预估表的大小,预估5年时间的数据量,可以在本地插入1000条左右的正常记录,看表的大小,然后预估
	5.4 表结构设计的时候,降低数据库规模
		5.4.1 只在数据库在可预期的时间里,可能会超大的时候才优化
		5.4.2 一个字段,如果只有表中的少量记录有值,拆分到一个新的表里,空间占用将会减少很多,比如tags
		5.4.3 log表等,可以定时备份清零

六.禁止以下写法,性能考虑
	6.1 【重要】order by rand 
	6.2 【重要】子查询
	6.3 【重要】联表查询
	6.4 【重要】不带limit的sql(除了insert)
	6.5 【重要】like '%username%' 这种前缀%的查询
	6.6 or的改写(尽量不要用or,实在没办法的时候,采用以下方法优化):
		6.6.1 同一字段的不同条件,请采用in来优化,in的个数不要超过200个,否则性能下降很严重
		6.6.2 不同字段上的条件,使用union all,不要用union(union会去重,严重影响性能)
	6.7 不要出现select *,在一些大表中,这个会浪费各种字段(内存、带宽、cpu等等),会导致一堆问题
	6.8 不要在sql中,使用mysql的内置函数,比如md5等等(绝对不能在索引列上使用)
	6.9 避免not , != , <> , !< 、!> 、NOT EXISTS 、NOT IN 、NOT LIKE 等语法
	6.10 少写大sql,或者让人看起来不易懂的sql
	6.11 不要用存储过程、触发器等,mysql做的并不好
	6.12 分页考虑大页码时候的优化(redis的有序集合非常擅长做这个)
	6.13 group by的时候,可以采用order by null 来去除排序(group by 本身会进行排序)

七.索引
	7.1 自增长id主键必须有
	7.2 字符串上建索引定长,不要全部索引(一般前8或者前10即可)
	7.3 不允许在索引列上,用mysql做运算(其他字段除非实在没办法,否则也不允许)
	7.4 不要使用外键(高并发,锁竞争会死的很惨,而且调bug很不方便,程序约束)
	7.5 explain必须要经常用,看懂基本的
	7.6 字段上越分散,索引效果越好(比如性别上单独建索引,性能提升基本没有,甚至出现性能下降)
	7.7 联合索引只能使用最左前缀
	7.8 覆盖索引速度最快
	7.9 不要出现重复索引(比如user_id上加了个索引,又在user_id上建个唯一索引)

八.sql规范
	8.1 sql语句采用小写
	8.2 字段名、表名必须加``包含起来,因为你不知道什么时候就会碰到mysql关键字
	8.3 容易导致条件不明显的加()区分先后顺序,谁要考验我逻辑运算先后顺序,我就会去考验他加班的耐性...
	8.4 尽量使用等值条件
	8.5 不要对字段使用函数,比如where abs(`num`)>3这种的
	8.6 union all代替union
	8.7 数据库配置统一
	8.8 A项目需要使用B项目中的数据库,不要直接连,采用B项目的接口形式
	8.9 insert的时候,必须指明插入哪些字段,否则改下表结构,就废了
	8.10 select的时候,取字段名数据,不要以数字下标,理由同insert

九.其他操作
	9.1 导入大批量数据
		9.1.1 使用load data比insert快20倍
		9.1.2 先不要索引,导入完之后,再建立索引会很快很多
		9.1.3 如果只用insert的话,一次insert多条,不要每次insert一条
		9.1.4 大批量的话,尽量不要在高峰期间执行
	9.2 insert select 可能导致复制异常
	9.3 较大项目的时候,读写分离
	9.4 不允许程序端对mysql加锁
	9.5 平时上phpmyadmin的话,上从库的,不要在主库在做操作
	9.6 对于不清楚性能的sql,在前面讲explain先看下查询计划,没问题之后再执行,要是不清楚的话,可以找其他人问下再确定是否执行
	9.7 执行大规模统计等的时候,严禁在浏览器中访问统计脚本
		9.7.1 见过最极端的是一个apache进程跑了差不多20000秒,6个小时
		9.7.2 浏览器里,执行的时候,卡住,很多人直接关浏览器,导致进程一直堵塞
		9.7.3 浏览器上如果有百度插件,你访问了一个连接,百度马上就会去爬下这个链接,也可能会死的很惨
		9.7.4 在服务器上,直接php static.php这样来执行,发现卡住,ctrl+c可以终止进程
		9.7.5 该统计脚本执行完之后,删除或者在最上面die掉,不允许一直留着
	9.8 搜索
		9.8.1 精确搜索,通过索引等解决
		9.8.2 非模糊前缀的,可以同上,通过索引解决
		9.8.3 模糊搜索,通过sphinx来建立索引,不要直接用mysql的
	9.9 定时脚本,禁止通过http访问
		if(isset($_SERVER['HTTP_HOST'])){
			die();
		}
	9.10 log表过大,备份,清空
		9.10.1 导出原表结构,并记录下来
		9.10.2 对原表进行rename
		9.10.3 根据原表结构,进行建表

附录:
1.不同类型数据比较
	字符列与数值型
	数值列与字符串
2.数值溢出,导致转换失败,从而不能使用索引,性能大降
	$sql = "update `users` set `name`='hello' where id='2147483648' limit 1";
	因为id是有符合整型,最大值是2147483647,而sql中的值超过上限,转换失败,update的时候,因为没有转成整型,索引使用失败,全表扫描
	没有超过上限的话,加不加单引号,效率基本一致
3.emoji 表情符,MYSQL版本不支持的话,需要预先转换再存入数据库中,否则会被截断,可以参考文档
	mysql内容截断原因.wps
	手机聊天表情
4.php中的mysql_query
	mysl_query执行之后,其实跟数据库打交道的事情就已经解决了,后面mysql_fetch_rows等的时候,只是把内存中的数据读出来
	所以不要抱着侥幸心理,我只是query了一下,没取出来,所以对数据库没影响


	

日志分析能力

编    写:袁    亮
时    间:2014-01-16
说    明:后端开发人员需要会的apache日志简单分析能力

一、说明
1、作为一个开发人员,查看分析日志的能力是必须掌握的,出现问题,第一个反应就是看日志
2、学会一些简单的命令行,对开发能力的提升帮助非常大

二、apache日志记录项说明
1、例子,这是我们服务器常见的日志记录格式,一行代表一个请求,以空格作为分割符
192.168.0.253 101.39.76.182, 124.193.166.140, 222.186.129.150 - - [16/Jan/2015:14:21:16 +0800] "GET /flashsale/specialsale-taobao-119.html HTTP/1.0" 200 2410 31020 "http://shop.ci123.com/flashsale/specialsale-taobao-119.html" "Mozilla/5.0 (Linux; U; Android 4.2.2; zh-cn; GT-I9152 Build/JDQ39) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30  WebView (com.ci123.pregnancy; 4.8; 38)"

2、具体说明:
2.1 前端代理ip:
192.168.0.253
apache服务最后一个交互的ip,一般是我们的nginx前端
详细可以参考文档:ip传递过程
2.2 x-forward-ip
101.39.76.182, 124.193.166.140, 222.186.129.150
这是从客户端带前端代理,总共经过的ip记录
第一个一般就是客户端的真实ip
2.3 apache进程启动时间
16/Jan/2015:14:21:16
2.4 请求方式
"GET
一般只有get和post两种请求
2.5 请求路径
/flashsale/specialsale-taobao-119.html
http请求头里的请求地址path
2.6 http协议版本号
HTTP/1.0"
2.7 返回状态码
200
http响应状态码,可以查看百度百科,也可以参考文档http常见状态码
2.8 apache返回数据大小
2410
单位字节,表名这是请求返回的内容大小
2.9 apache响应时间
31020
单位微秒,这是apache的响应时间,在性能分析的时候第一个要关注的就是这个
2.10 请求referer
"http://shop.ci123.com/flashsale/specialsale-taobao-119.html"
从哪个页面过来的
2.11 用户的user-agent
"Mozilla/5.0 (Linux; U; Android 4.2.2; zh-cn; GT-I9152 Build/JDQ39) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30  WebView (com.ci123.pregnancy; 4.8; 38)"

3、日志文件位置
3.1 我们的apache日志一般在/opt/ci123/apache/logs下
3.2 命名一般是***.ci123.com-access.****
3.3 查不到的话,请根据apache配置自行查找

三、apache日志分析常用命令
1、查看日志文件
less shop.ci123.com-access.0116
切忌不要使用vim,日志文件一般都很大,vim打开会很惨
可以使用shift+g跳到最后
2、实时监控日志文件变化
tail -f shop.ci123.com-access.0116
3、查看最新1000个请求
tail -n 1000 shop.ci123.com-access.0116|less
4、搜索指定记录(时间、指定链接、特定ip、状态码等)
grep ' 500 ' shop.ci123.com-access.0116|less
查看500报错请求
5、awk命令
awk '{print $2}' baobao.ci123.com-access.0725 |less
打印每一行的第二列数据
每行默认是以空格做为分割符分割为多列,也可以使用-F参数指定分割符

四、常用命令组合
1、查看某个连接的所有访问记录
grep '/sadmin/' shop.ci123.com-access.0120|less
查看所有带/sadmin/的请求

2、查看错误访问记录
grep 'HTTP/1.0" 500' shop.ci123.com-access.0120|less
grep 'HTTP/1.0" 404' shop.ci123.com-access.0120|less
查看对应的错误状态码的请求

3、查看某个ip的访问记录
grep '111.13.47.163' shop.ci123.com-access.0120|less
grep '111.13.47.163' shop.ci123.com-access.0120|wc -l
前面是这个ip对应的所有访问记录
后面是这个ip的访问次数

4、查看某个页面有多少个独立ip访问
grep '/sadmin/' shop.ci123.com-access.0120|awk '{print $2}'|sort|uniq -c|wc -l

5、查看某个页面每个ip的访问次数,并根据访问次数排序
grep '/sadmin/' shop.ci123.com-access.0120|awk '{print $2}'|sort|uniq -c|sort -nr|less

6、查看某段时间或者某个链接最慢的查询
grep '/sadmin/' shop.ci123.com-access.0120|awk -F '+0800' '{print $2}'|sort -k6 -nr|less

7、统计某个时间段或者链接的平均访问时间
awk -F '+0800]' '{print $2}' shop.ci123.com-access.0120 |awk '{sum +=$6;num+=1}END{print sum/num/1000}'|less
根据+0800]分割每一行的数据,并输出第二列
对每一行的第6列累加,并记录行数num
输出第六列的和除以行数,计算平均响应时间,除以1000是把微秒转成毫秒方便查看

8、分析日志,最主要的是根据需求将以上这些命令组合
能过滤数据的命令先执行,把影响范围先缩进,再去统计、分析、排序,做所有其他分析的时候也遵循的是这个规则
如果发现自己执行的命令卡住了,使用ctrl+c中止进程
其他的日志分析原理基本上一致

Mmemcached的使用文档

编    写:袁    亮
时    间:2015-01-15
说    明:Mmemcached的使用文档

一、使用场景
1、在系统中,会有大量的比较耗时的重复计算,这会导致系统性能的急剧下降,为了解决该问题,我们希望将这些计算结果存下来,使得在一定时间内,直接获取结果就好。

2、例如:
一个首页,每天50W次访问,在首页上,有一个地方显示的是最近24小时内,回复数最多的10个用户,正常的取的话,我们需要取24小时内的所有回复,然后根据user_id进行groupby,并统计每个user_id对应的回复数,再根据回复数倒序,取前面10个,这会非常耗时间;
我们可以将计算出来的结果存储下来,在一定时间内(比如5分钟)内,直接返回这10个用户,那么这一块的系统性能提升接近:50W/24/(60/5)=1736倍(计算次数减少)

3、缓存技术在it的各个角落都能看到,是最基础的概念之一,不管是硬件、软件、互联网,都离不开它,是所有优化里第一个要接触的

二、常规使用方法
include_once("/opt/ci123/www/html/ci123libs/data/classes/hash/memcache/memcache.php"); //很多服务器上有

$key = "index_user_list";
$data = M::Get($key);
if($data !== false){ //没有设置值的时候,返回是false,flase本身设置到memcache里会变成空字符串
$data = '';//原有获取数据的逻辑
M::Set($key,$data,600);//将数据写入到Memcache中,并缓存600秒
}

三、缓存的两种基本形式
1、不精确,定时缓存
直接将结果,缓存到一定时间周期,过期则重新计算获取
优点:实现简单、效率高
缺点:源数据如果在缓存有效期内有更改,可能出现数据取出来是错误的
适用场景:对数据精确性要求不高
常见情况:浏览器静态缓存、nginx缓存、cdn缓存、dns缓存等等
Memcache缓存绝大多数都是这么使用

2、预先生成,精确缓存
当源数据有更改的时候,同时更改缓存中的数据
优点:数据精准
缺点:实现复杂,有些情况下甚至不可实现(与缓存本身违背,比如浏览器缓存)
适用场景:系统高度可控,并且对精度要求很高的情况
场景情况:mysql内部查询缓存、短链计算统计等
Memcache如果要使用这种的话,有一个比较简单的办法,在第一种做法的前提下,更新、删除等操作的时候,将相应的缓存删除,这样也能实现数据精确,而且实现简单。(不适用更新非常频繁的情况,否则缓存也白加了)

四、Memcached简单介绍
1、分布式的系统
2、纯内存缓存系统
3、key value结构的hashmap

五、避免出现的情况
1、存大key
场景:
比如我要缓存用户数据,有两种办法,一种是每一个用户一个key,里面对应的用户信息,uinfo_{$uid}
还有一种,我把所有用户信息写到一个key里,这样我只要一个key,节省了内存空间,uinfos
问题:
不要出现一个key里,存很大的数据,缓存粒度控制
但第二种其实是一个非常糟糕的设计,假设我有10W个用户,每个用户信息1Kb,那么这个key就将有100Mb
因此我每个页面取一次缓存,将会导致需要每次从memcache里取100M的数据,10个并发,内网千兆带宽就崩掉了

2、不要缓存执行次数很少的
场景:
有个统计,每天统计一下前一天的数据信息,大概要执行1分钟,太慢了,我要优化它,所以把他扔缓存里
问题:
这种就是一个非常典型的失败例子,缓存的数据后面压根不会用到,所有缓存能起效的前提,都必须是这个请求会是重复多次执行的

3、缓存可能不到时间就会失效(LRU替换算法,不要做精准的统计计算等操作)
场景:
记录页面的访问次数(精确的),因为mysql写太频繁导致锁严重,因此我把计数放在memcache里,很快,读取这些数据的时候我也通过memcache读取,一切都很美好。
问题:
某天你会突然发现,这统计数据不对啊,为什么昨天这个页面明明已经有5000多次了,今天怎么变300多了?而且缓存也没有过期啊,什么情况?
因为Memcahe会有内部的删除数据算法,在空间不够的情况下,会删除某些不常用的数据
解决办法:
持久层还是放在MYSQL里去实现,但可以把写合并,比如累加次数达到一定值的时候重新写回mysql,注意不要是定值重写,这会导致数据上涨的非常有规律,看起来很奇怪。
$num = M::Get("post_view_{$post_id}");
if($num > rand(10,30)){//平均20次更新写回mysql
//写回Mysql
//将memcache中的数字清空
}

4、Memcache不做持久化,服务重启,数据会全部丢失,启动的时候可能会导致数据库压力狂涨
如果项目很大的情况下,可能会出现挂掉之后数据库马上报警,又挂了
这个时候可以少量放开部分用户访问,然后慢慢加量,一般情况下不用管,直接硬抗几分钟就好了

5、命名 同一个系统里,不要出现两个同名的,会导致数据变的莫名其妙,统一管理
命名最好语意清晰,不会和别人写的导致重复
同一个Memcache的key管理,可以统一在一个文件里定义使用,防止因为key名重复导致逻辑出错

六、可视化 管理系统
MemAdmin
基于php和jquery开发,简单易用
http://192.168.0.249/memadmin/
admin fuyuan1906

七、Memcache本身的一些限制
1、最大过期时间30天(设置永久也无效)
2、最大键长128字节(不要取太长的,这个是会占内存空间的)
3、单个key的最大数据1M(一般不缓太大的数据,memcache的访问频率很高,如果单个key很大,带宽会非常高)
4、连接操作等无需验证,因此必须放在防火墙后面,只允许内网访问