翻墙的相关知识

编    写:袁    亮
时    间: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、连接操作等无需验证,因此必须放在防火墙后面,只允许内网访问

调试排错能力

编    写:袁    亮
时    间:2015-01-20
说    明:php后端程序人员简单排错能力

一、说明
能力强不强是通过解决问题来体现的,不能解决问题的话,其他的都是白搭
ps:不要觉得错误莫名其妙,我这边明明是好的,用户那边有问题,就怀疑是电脑有问题啊,服务器有问题啊什么的,mysql有问题啊之类
99%的问题,都是程序上的问题,没能重新,只是你没重现出那个特殊的情况

二、常见错误类型
1、网站打不开,不能访问
2、能打开页面,但是页面显示不正常,比如白页,404等
3、操作失败,比如不能发帖,不能删帖等
4、逻辑错误,比如帖子的回复数不对,页面缓存一直错误
5、页面打开很慢,性能问题,超时,卡等
6、定时脚本执行结果不符合预期

三、网站不能访问
当有人反馈,网站打不开的时候,可以参考以下几个步骤来进行排查
ps:需要确定的是,直接访问不了,而不是访问的时候页面出错,访问出错请参考第四条
1、要到相应的链接及报错截图,自己打开电脑访问下,是否能正常
2、如果自己能正常访问,使用阿里测或者17测看下,是否正常
3、如果17测等不能正常访问,看下是否是自己加了host所以能正常访问
4、如果17测等有些不能正常访问,需要让对方ping下这个域名是到哪个ip
这个时候需要看该域名是否使用了CDN加速,如果使用了可能是CDN节点有问题
如果ping的ip和自己的电脑一样,那就需要看下对方访问出错的截图,是否是因为cookie头过长等原因导致不能访问
5、通过以上步骤,基本上都能搞定该类问题

四、页面能打开,但是显示不正常
该问题指的是,已经能正常由apache返回数据,但是返回的页面和正常页面不同
1、查看http返回头状态码(firebug或者chrome里,网络中都能很容易看到)
2、500
如果有显示报错,根据报错信息查看哪边出问题即可
如果直接白页,查看apache错误日志中的报错信息即可,或者复制一个临时文件出来,开启报错查看也可
3、404
是否是文件被删了
还是rewrite规则写的有问题,导致没有找到相应文件
也有可能是程序逻辑中判断,比如哪个资源没有了,所以显示的404,需要根据具体的代码逻辑来查找
4、502
一般来说,这是由nginx返回的,说明后端apache的响应时间过久
查看apache日志,找到超时的请求,看下执行了多久
在程序中的响应地方记录log,看是哪段代码超时了
一般来说,都是sql语句导致,查看对应数据库的慢查询sql即可快速找到,然后优化
5、200
页面如果显示错误信息等,根据错误提示调试代码即可
如果没有显示,可以查看apache错误日志
页面排版错误等,直接按F12查看调整或者查看源代码,一般来说html代码有问题,源代码里都会标红等,一眼就能看到
页面错误还有很大一种可能是静态文件缓存:CDN缓存,nginx缓存,浏览器缓存等等需要注意

重要:如果是正式项目中,页面有显示报错信息,务必将报错关闭,不允许在线上开启报错

五、操作失败
页面等能正常访问,但是进行相应操作的时候失败,比如发帖,删帖等
1、自己操作一遍,看下是否能成功
在操作测试的时候,请以真实的数据去测试,并及时删除,不要乱写什么test之类的进行测试
并且在测试完之后,马上将测试数据通过正常操作删除
2、如果自己能成功,其他人失败,看是否有失败的提示信息
比如权限不足,有违禁词等等,根据提示找到为什么失败
3、需要通过修改程序来debug的话,请务必保证在以下两种情况(线上项目)
3.1 项目有测试机
在测试机上进行调试,debug,改完之后,通过svn上线到线上版本
3.2 没有测试机,并且比较紧急的话
将相应的操作文件copy一份出来,然后输出调试,找到问题出在哪
改完之后,copy回去之前,先备份原文件,并diff比对下两个文件,保证没有改了多余的地方
copy覆盖回去之后,必须要进行全面测试,保证之前出问题的情况不会出现,以及正常操作的时候也没问题
不要出现原来的问题解决了,但是带来了新的问题
4、在3满足的情况下,参考以下的debug步骤
第一步就是开启报错,80%的问题,开启报错之后就能知道是什么问题了(或者看错误日志)
不要从头开始看代码,指望着看出来问题,这是不现实的,我很讨厌别人跟我在说,我在看
根据问题状况,定位到哪边出的问题,比如发帖之后,posts表没有插入数据,那就先找到插入posts表的代码在哪
找到这段代码的时候,可以通过var_dump,die看下这段代码是否执行到了,是否执行成功
如果执行不成功,sql的话,直接输出这条sql,放在phpmyadmin里执行看报错
如果没有执行到的话,向前找节点(if else判断等)),看是在哪一步判断导致没有运行到该出
在大段代码,设置debug节点的时候,不要很秀气的每次一行一行的设置,那会疯掉的
最简单的二分法,400行代码,出问题,先在200行左右var_dump,die一次,不行,就100行的地方,再不行,就50行的地方
5、注意事项
有些时候觉得有些bug莫名其妙,总是重现不了,需要考虑下,用户的情况跟你是不一样的
比如账号不同,比如cookie不同,比如当前电脑的时间不同,比如发了一些特殊符号等等都有可能导致用户出问题
之前还出现过一次因为bing爬虫爬取错误链接然后导致缓存出错的问题,这个问题在解决之前也是觉得莫名其妙

六、逻辑错误
比如帖子的回复数不对,用户的积分不对,用户付完钱,结果订单被取消等等
1、这种问题,一般来说都比较麻烦,首先需要知道的是有哪些地方涉及到该逻辑
2、猜测哪些操作可能导致该问题的出现,比如用户的积分多了,是不是该减积分的地方没减,加的时候加多了?
3、针对比较可能出问题的操作点,重新操作,看是否有问题

七、页面性能
该类问题比较大,只列几个粗略的方向
1、查看apache日志,找到最慢的那些请求和平均的请求时间,定位哪些访问有问题
2、找到对应请求,设置时间点,找到慢的程序块
3、具体分析,打印相应的块执行时间,找到问题点
4、查看mysql慢日志是一种比较快能定位到问题,一般来说web项目卡都是数据库层面出了问题

八、定时脚本执行未达到预期
1、确定定时脚本是否有执行
查看定时脚本执行log,是否有
如果没有,则查看下报错log,根据报错log调整
复制要执行的脚本,其他操作都不执行,只输出一个最简单的内容,修改定时脚本的执行时间,每分钟执行,看是否正常
2、脚本有执行,但是结果和预期不同
定时脚本编辑的时候,必须在各个关键节点输出日志
出问题之后,根据自己记录的log日志,查看哪一步跟预期不同
如果之前未记录,则根据问题表象,在相应节点输出相应的log,可以临时执行该定时脚本,查看是哪边出的问题

RPC接口的使用


编	写:袁	亮
时	间:2015-01-15
说	明:xmlrpc的工作原理和使用

一、为什么需要这个?
	1、学名叫远程过程调用,即调用远程其他项目的函数方法
	2、例如A项目,里面有用户的图片,在B项目里,我需要获取到这个用户的图片,最老的方法,就是直接连A项目的数据库,重新写一遍获取数据的逻辑。这会带来非常多的问题:
		2.1 同样的一个功能,我需要重复写非常多遍
		2.2 如果项目要迁移,我都不知道要改多少地方(比如数据库连接等等)
		2.3 如果之前的功能稍微做点改动,我得把每个涉及到的项目都得改一遍,然后测试,保证没问题
	3、为了解决上述问题,我们希望通过接口的方式去调用其他项目的相应功能,xmlrpc就是其中一种解决办法
		soap,或者直接通过http获取数据等,也都可以解决
	4、数据采用xml的形式进行传递,

二、工作原理
	1、一次服务器与服务器之间的http调用
	2、客户端根据相应的参数,构建相应的http请求头信息
	3、使用fsockopen发送数据请求,请求数据转为xmlrpc协议格式
	4、服务端接收到请求,查看是否有定义相应的函数
	5、服务端调用已注册的rpc方法,并输出xml格式的返回值
	6、客户端接收到相应的响应数据后,将xml重新解析会php变量
	7、rpc过程结束

三、使用范例
	1、服务端编写接口
		include_once("../inc/class_xmlrpc.php");

		function messAdd($m,$p){
		    $p = $p[0];
		    $ms = new MessClass;
		    return $ms->messAdd($p);
		}

		$xmlrpc_funcs = array(// 注册函数
    		'messAdd',
		);
		$xmlrpc_name = 'api/mess';
		$xmlrpc_server = new xmlrpc_server();
		foreach ($xmlrpc_funcs as $v) {
		        $xmlrpc_server->register_method($xmlrpc_name.'.'.$v, $v);
		}
		$xmlrpc_server->call_method();

		1.1 引入xmlrpc类
		1.2 正常写一个函数,第一个参数预留,封装的类里用到的,第二个参数是客户端传过来的参数
			$p[0] $p[1] 分别代表第一、第二个参数,依次类推
		1.3 将本地的方法注册,使其可以成为可以被rpc调用的方法
			需要一个命名空间,类似api/mess
			register_method中,函数名可以不一样,但我习惯会命名成一样的
		1.4 查看是否有语法错误
			访问下接口地址,是否正常的输出xml格式的数据

	2、客户端调用
		include_once("../inc/class_xmlrpc.php");

		$c = new xmlrpc_client("http://commentdev.ci123.com/mess/rpc/server.php","api/mess");
		$p = array(
		    'to_user_id'    => 1535917,
		    'temp_id'       => 134,
			'target_id' => 3217,
		    'platforms'     => '1,3',
		    'user_id'   => 2199,
		);
		$data = $c->call("messAdd",$p);
		var_dump($data);

		2.1 引用封装的类
		2.2 初始化rpc client类
			api/mess需要跟服务端那边取的名字保持一致
		2.3 调用相应的方法
		2.4 这边data只能接受到服务端return的返回值,使用var_dump,echo等输出是不行的
			因为那边输出的是函数的返回值,var_dump等并不是函数返回值
		2.5 如果是测试机,需要在对应的服务器上加host,在本地加host是没用的
			因为这是服务器跟服务器之间的通信(如果在本机上测试,hosts是同一份)

四、常见问题
	1、在服务器上调用一个测试服务器的rpc,出错
		需要在服务器上加host,因为服务器找不到测试机的域名
	2、如果rpc所在服务器加了http basic认证
		可以在client初始化的时候,把账号、密码传过去
	3、超时时间在客户端初始化的时候设置
	4、测试用例保留
		客户端调用范例文件保存,在最开始die掉