后台开发,上线总是一件令人心惊胆战的事儿。就像《大规模网站技术架构》中描述的:

发布日,整个技术部门甚至运营部门就如临大敌,电话声此起彼伏,工程师步履匆匆,连空气中的温度都仿佛升高了几度。即便如此,发布过程还是常常出错,发布日工程师加班到凌晨是常有的事。而且容易忙中出错,因发布引发的故障也居高不下。

工作至今,也遇到不少次上线挂掉的经历,这些经历可都是弥足珍贵啊,也如《大规模网站技术构建》所说:

大型网站的技术本质都很简单,没有很花哨的东西,掌握起来也不难。大型网站的架构师最有价值的地方不在于他们掌握了多少技术,而在于他们经历过多少故障。每一次故障都会给公司带来难以估计的利益损失,所以培养一个网站架构师的成本不单要看付了他多少薪水,给了他多少股票,还要看为他引起的故障买了多少次单。

所以在此记录这些经历,希望你我都不要重蹈覆辙。

SQL中,删除记录是delete而不是drop

不要笑,我刚刚开始工作的时候,上来一句drop ...就把一个非常重要的库给整个删了👼。。。

还好是开发机上,还算是恢复了。总是drop是非常危险的一个操作,需要小心。

SQL不要跨库!

2015年12月29日

虽然一般开发环境中所有的数据库都是在一个数据库中的。但是线上可就不是了。而且默认也是不存在‘把多个机子的mysql模拟一个mysql’的功能的。所以虽然线下你可以跨库,但是上线了可是要跪的。。。

这个在业内是非常低级的错误,虽然我在学习过程中重来没听说过相关的知识点,但是在我犯错的一个月后,我在《大规模网站技术构建》中分布式存储看到了相关的说法。。。。

PHP中,重构函数,添加函数参数个数,注意要加上默认参数

2016年01月27日

事情是这样的,一个老函数,我觉得参数不够用了,需要额外的参数,于是我就添加了一个参数,并且用phpstrom把所有调用处都修改了。

但是,测试三天后上线,挂了。

错误提示是有一个调用没有传我新加的参数。我擦,明明所有调用我都修改了为何还有没传的地方?查代码一看,在我的代码提测期间,有人有写了新的这个函数的调用,因为我的代码还没上线,所以他的代码中,函数并没有改变,他那么写是没有错的。但是当我的代码也上线后,就跪了。。。

这里面其实包含了git流程的一个问题。但是我目前还没想明白,在自己提测期间有人上线应该怎么破,破法应该是测试在上线前要把这次的测试用例全过一遍吧。但是也不一定能覆盖到期间别人提交的代码。

对于重构而言,尤其是这种语法层面上的重构,静态语言就不会有这个问题,因为在编译期间就会提示出错。这也是为什么大型项目喜欢使用静态类型的语言吧。这也是我喜欢的原因。

推荐阅读:

因为第一代动态语言做错了一些事。

  1. 动态语言开发效率高是相对的(这个做项目的深有体会,不需要展开说了,另外就是动态语言的一些效率被静态语言通过强大的辅助工具,ide给弥补甚至超越了);
  2. 静态语言也融入了部分动态特性(比如:很多情况下,类型是可以推导的,不需要手动去写。再比如:动态语言甚至web app的开发迭代周期快的优点也正在被静态语言借鉴)。
  3. 编译时类型检查的重要性,尤其是项目比较大的时候。机器可以帮你做很多,就可以少些很多相关测试代码,随着项目规模的增长,这个优势愈发明显。
    静态类型+类型推导可以让编译器工作的舒服,人写起来也高兴。随着不断发展,类型推导系统做到一定程度,第一代动态语言完全扔掉类型注释所带来那些优势几乎全无,倒是弊端一大堆。
    现在一些动态语言都着手开始添加类型注释(如php,python,perl等等)就说明了这个问题。
    不过它们依然没有静态类型语言的某些优势,所以就像native app和web app之争一样,我觉得最终的趋势又是互相取长补短,趋于融合。

xml转array的一个问题

2016年02月29日

<areaInfo>北京市</areaInfo>
会转为:
"areaInfo" => 北京市

<areaInfo></areaInfo>或<areaInfo/>
则会转为
"areaInfo" => array()

注意哦,不是空字符串哦!!!!

拼接SQL时,需要注意反斜杠

2016年03月14日

案例:请求芝麻信用接口的返回结果(json格式)保存到数据库后,再取出的时候就不是一个合法json了?!

无意看了芝麻信用的文档,发现其返回结果好坑啊。。。

1
2
3
4
5
6
7
8
9
10
11
{
"content": {
"xx": "T",
"xx": [
{
"xx": "001",
"yyy": "{\"id\":{\"field\":\"id\", \"name\":\" 编号\",\"value\":\"aabbcc\"}, \"current_overdue_status\":{\"field\":\" current_over_due_status\",\"name\":\"状态\", \"value\":\" test\"}}"
}
]
}
}

这里的yyy字段,起内容竟然是“json字符串”。在json中竟然保存了一个json字符串。。。最后追查到,是因为sql语句的问题,导致了json字符串中本来应该保留的反斜杠在存入数据库的时候没了。。

看一个例子:

insert table_name (a) valuse ('a\"b')

插入后,a的值是?

先看看PHP中,对于单引号双引号的区别是:

  • 单引号不会对字符串进行转义
  • 双引号对字符串进行转义

感觉不少语言也是这个规则的。但是MySQL中不是!!

MySQL中不论单引号双引号都会对字符串中的转义字符进行转义,他们的区别只有一个:单引号字符串中可以出现双引号,双引号字符串中可以出现单引号。看例子:

1
2
3
4
5
6
7
8
9
select 'a\'b'; -- a'b
select 'a\"b'; -- a"b
select "a\'b"; -- a'b
select "a\"b"; -- a"b
select 'a\\b'; -- a\b
select "a\\b"; -- a\b
-- select "a\\"b"; -- error
select "a\\\"b"; -- a\"b
select 'a\nb'; -- a换行b

所以如果你就是要保留字符串的反斜杠的话,你需要在拼接SQL前对字符串进行转义。方法有两个:

  • 使用addslashes($r);函数添加反斜杠
  • 使用$hex_value = bin2hex( $r );$r = “unhex(‘$hex_value’)”;把字符串以16进制的方式拼接到sql中

除以零错误

2016年04月13日

今天,我又来更新这篇文章啦😊

这次上线是更新了一个价格计算的算法。上线后,线上报了一个500错误:

bcdiv(): Division by zero

肇事的代码是

$percent = bcdiv($cur,$all,2);

本来是用来计算价格还可以降低百分之多少。在这次更新前,这个价格是不能出现为0的状态的,所以除法安然无恙。但是这次更新,价格可能是0了,所以就出现了除零错误。修改倒是很简单:

if($all == 0){
    $percent = 0;
}else{
    $percent = bcdiv($cur,$all,2);
}

这个案例我觉得很经典。当你在写出一个除法,其除数是一个变量的时候,你就要小心,他可能为0么?他可能为0么?他可能为0么?他现在不可能为0,以后可能为0么?以后可能为0么?以后可能为0么?以后可能为0。

新老算法时间点,务必记得考虑好这一点

2016年04月14日

依然是昨天上线的那个新算法系统。在老算法中固定的一个系数,在新算法中变为根据不同用户而不同的5档系数了。这么做是为了测试用户对于不同系数的敏感程度。

今天发现了一个问题。一个订单,第一次使用到这个系数的时候,系统未上线,使用老的。而订单的生命周期中,会有多次计算,导致之后的计算使用了新的系数。导致订单的表现有些异常。

这是一个经典的问题。如果你在做一个新算法,那么你要考虑,新算法是覆盖老算法还是分流老算法呢?无论是覆盖还是分流,都一定要考虑新老交接处的边界情况,这种边界情况是用老算法还是使用新算法??这些都是需要考虑的。