当开发时间被压缩后

  记得有一部纪录片《人类消失后的世界》说的是当人类突然从地球消失后,过多少时间后会发生什么事,有兴趣的可以在网上找到视频。而在软件研发过程中压缩时间也会有很趣的事情发生,主要从技术角度来分析下。

  前端:可能没办法适配非自己浏览器大小的尺寸,输入框的字数限制可能就没有了,校验也只剩必填。一些被设计为公用的枚举,样式,出现了差异,特殊化。页面整体风格和以前系统不一致。表单多列的可能就成了单列了。弹出/遮罩这些效果可能被其他组件遮盖掉。

  后端:数据合法性校验可能没了,不注重设计模式,复用,耦合度高。控制器层多了业务逻辑,服务层被架空。数据库表设计可能会没有索引,甚至注释也没了。组合查询效率慢,批量操作变成循环实现,并发控制百分之百会被忽略。修改版本没有记录,日志乱输出或者没有日志,导致后期调试困难。接口文档更新不及时。

  测试:之前整常的功能没有回归测试,没有压力测试。

  最终这一切又要以bug形式花时间来修正。

魔界之地黑岩角

  黑岩角位于深圳南澳镇最南端,当地人叫西尾,意思是西冲尾,一般人很少会去这里,大部分都是在西冲海滩玩。

  计划来此也是有许久了,一来是这里号称深圳“魔界”之地,其独特的岩石,表面上看呈灰黑色,常年的海风腐蚀成如刀刃般锋利,很有层次感,也使得这里更具险峻,稍不留意可能伤到皮肤,这不脚上就被岩石划伤了,还好准备了创可贴。

  早早在附近定好了民宿,和夜叔两人驱车来这里,由于两个人都不熟悉登山路线,车到酒店稍做休整后便出发先行踩点,以准备早上拍摄黑岩角日出,然而车到南西路尽头却发现是军事区,出于谨慎考虑,便没再前行。于是采取B方案,包快艇前去。

  驱车进入西冲一号沙滩,和快艇租赁的人聊了几句,开始都说到不了,在他们看来黑岩角是位于牛奶排或者更远的地方,因为那边根本没办法让船靠岸。后来给他们看了网上的样片后,才明白原来就是在西尾,很多拍婚纱的也是租他们的快艇过去的。最后以200块的价格送我们两过去,实际上行驶时间也就5分钟不到。

  上去后发现已经有不少摄影爱好者在上面了,这里可走动的面积也不多。询问得知他们都是山上爬下来的,抬头一看天啦,海拔大概也就100米样子,坡度几乎接近垂直于地面,没有任何扶手,下面还是坚硬的岩石,想想就觉得可怕了。不过看到陆续有人爬下来,何不挑战下。顺利爬到山顶观景平台,居然就是之前的军事区,和上面的人聊天得知,其实这一段是废弃了的。走出停车观景平台可以发现是两条路,一条是继续上山的军事区,而且也有自动门拦着的,而下山的路就是回到了南西路。

  就当是交了200的学费。后来想想,其实不必这么拼,200还是很划得来的,可惜人家最早也要6点半才出海,我们要在5点之前赶到,乌漆麻黑的爬这个坡更危险了,还带着这么重的器材。

  其实之前在网上也做了很多功课,却没人能说清楚究竟怎么去,这里我放上一张GPS线路图,供大伙参考。红圈是停车观景平台,车可以一直开到这上面,也可以露营。然后有石板路走到一个圆形的岗亭,之后就只能走泥地了,非常陡峭,下雨就不要尝试了,安全第一。

黑岩角GPS路径

  黑岩角只能看到日出,太阳从山后面升起,并不是海平面,并且天亮的很快,这次准备的还不够充分。本次拍摄的一些照片:https://snapast.com/albums/steve/A1EDibze1nFPDMheBKM6Gh

一次DDOS攻击记录

  就在昨天儿童节的时候,大概9点半左右收到微信公众号的报警信息,发现是服务器没有响应,5分钟内6次请求没有及时返回。当时并没有过多在意,因为之前也有过1~2次失败,都是是偶然因素。过了几分钟又收到dnspod的邮件报警,内容是snapast.com主站连接超时,这才意识到可能服务器宕机了。

  立刻手动访问一次,果然是打不开了,ssh也连接不上,下意识认为可能是服务器被重启了,因为之前托管在linkcloud的时候,隔个把月总会挂掉一下,但迁移到阿里云后一直很稳定,不太会出问题。

  登录到阿里云后台,在实例监控看到CPU一直满负荷运行,入网流量达到22M/s(云盾基础防护中显示有接近30M/s,忘了PPS多少来着),出网也已经塞满2M带宽。

实例监控

  通过阿里的终端登录到主机上,发现CPU是被4个nginx进程占满,后端几个tomcat负载并不高,说明并不是一般的大规模http请求(cc攻击)。而且nginx access log也是正常,但error log有很多xxx worker_connections are not enough,说明确实连接数较高,超过设定值。通过netstat统计居然有1.6w左右的连接数,远高于平时的300左右。

root@snapast:~# netstat -an | wc -l
16089

  到这里基本能判断极有可能是SYN Flood,想到云盾有一定抵抗DDOS的能力,试着开启流量清洗看看,原来人家的默认触发条件是流量100M/s,PPS是1w,我这点攻击还没办法触发呢,于是手动设置了一个最低条件达到10M/s就开始清洗,然而事实证明清洗毫无用处,依旧连接超时。但有个好处是开始清理后可以抓包。

  下载cap到本地用Wireshark打开一看,好家伙,果然是SYN握手攻击,大量的不同IP(美国为主)往443端口发SYN请求,极少数有回应RST,我猜应该是上层路由回的。云盾的抓包并不是你主机网卡包,而是在接入口的设备上。这下明了了,对于这种TCP层的攻击也没啥好办法抵御的,考虑到目前仅有相册用了https,所以先停掉nginx监听443端口,将机器负载降了下来,但也没办法彻底解决。有意思的是当时阿里云解析也出了故障没办法修改域名解析,屋漏偏逢连夜雨。

抓包

  就这么瞎折腾了2个小时,攻击才停止,一切也都恢复正常。今天来看,在微信接口调用统计中失败次数最为“壮观”的一天。

  现在想想其实也有一些办法可以减小宕机损失:比如将受攻击的域名临时解析到别处。再如将多个业务分离开来,用不同的域名,不同的IP接入,iptables将多次密集连接请求的IP drop掉。

Flat-UI 正确打开方式

  Flat-UI 是一款基于Bootstrap扁平风格的UI工具包,个人觉得风格比较美观,简洁,控件齐全,加之扁平化趋势,故用在了花图影铺项目中。有免费版和Pro版($39)可供选择,Pro版多了PSD原件,也用不到,选择免费就可以。

  众所周知,前端的项目一直以来都是拷贝HTML,CSS,JS到工程下直接引用就完事了,花图影铺之前就是这么做的,但这种做法已经非常过时了,自己做了修改后将无法再与官方的新版合并,而且有些细微的调整涉及到很多个地方要修改。对于Bootstrap这种巨复杂的设计,要定制化就几乎是不可能的事了。为了解决这些问题,前端开始有了新的玩法,从开发到测试再到构建都需要配套跟上。而Flat-UI 就是采用Grunt来进行自动化构建,用Bower来管理JS依赖,用Less来与编译CSS,等等等等。简单说下是如何构建Flat-UI的。

  Git clone下来的Flat-UI 包含了以下一些重要东西:

bower.json

这个是bower要用到的依赖声明文件,可以看到里面依赖了jQuery,bower会自动下载指定版本的jQuery到bower_components目录之下,以备后用。全局安装bower:npm install -g bower,新项目也可以用bower init来生成。

package.json

工程说明文件,包括工程名,作者,版本,Grunt依赖包等一些信息。如果一个新的项目,可以用grunt init打开一个向导一步一步填写。

Gruntfile.js

这个是Grunt执行脚本,会从上面的文件中读取值,里面定义了一些处理事件,比如清理之前构建,测试,压缩CSS,JS,生成文档,复制等等,甚至可以起一个静态服务器来调试。无比强大,类似于Maven pom文件。

  以上文件在Flat-UI工程目录中基本上不用修改,只需要在当前目录下执行bower install 下载依赖js包,grunt install 下载grunt工具,再执行grunt dist 就能在dist/目录下获得最新的可发布版本了,将该目录文件复制到web工程中引用就好了。

  关于less目录就包含了Flat-UI 所有CSS配置地方,主要修改的就是这里了,比如改变导航背景颜色等等。其中按模块归类的非常好,一眼就能看出该修改哪里,variables.less 定义了所用到的颜色,全局样式,排版,小图标,表格等等。修改起来非常容易,尤其还有一些联动的取色,通过一个基准色,计算出偏亮或者偏暗值,而不需要一个一个去查色板。修改完后只需要grunt dist 就能生成好CSS。

  Flat-UI 不仅是一个优秀的UI工具包,同时也是一个学习前后端分离构建的好例子,当然这只是针对我这以后端为主的开发者而言。

  参考:https://github.com/designmodo/Flat-UI

最优化使用阿里OSS云存储

  上一篇文章讲到了为何要迁移到阿里OSS,经过几天时间的实际验证,发现还是踩了不少的坑,这里记录下,供参考。

  首先有几个先决条件如下:

  1. 全站所有请求必须HTTPS
  2. 全站仅允许出现自有二级域名
  3. 上行和下行流量均不经过ECS服务器

  (代码洁癖 8)

  阿里OSS我们可以简单的认为分两个部分:

一是存储有关的,提供了两个访问域名:一个是公网,一个内网

<bucket>.oss-cn-shenzhen.aliyuncs.com (A域名)
<bucket>.oss-cn-shenzhen-internal.aliyuncs.com (B域名)

二是为图像处理(缩图,转码)有关的,也提供了一个访问域名:

<bucket>.img-cn-shenzhen.aliyuncs.com (C域名)

我们在这个图像处理的功能上面绑定了一个自有的二级域名:

image.snapast.com (D域名)

默认分配并指向了下面的CDN加速节点域名:

image.snapast.com.w.kunlunca.com (E域名)

  暂且称为A~E域名,注意其中细微差别。其中A和B域名本身是支持HTTPS的,但C不行,在绑定了D之后,可以上传SSL证书开启。A域名也可以绑定自有域名,但不支持HTTPS。图像处理设置了禁止原图访问,也就是C,D域名仅允许通过“样式”访问到缩略图。但A,B不受限制,本来就不同的系统。

于是第一个方案是这样的:

用户上传:HTTPS POST A域名
用户访问:HTTPS GET D域名

  初看没啥问题,除了引入一个第三方域名,不符合预定规范,但也运行良好,但有个很严重的问题,会泄漏原图,将D域名的路径拼接到A上面就能拿到原图。故pass掉,和客服聊了后给了个鸡贼的方案:

方案二:

用户上传:HTTPS POST upload.snapast.com -> proxy_pass -> B域名
用户访问:HTTPS GET D域名

  在nginx上将用户上行的POST请求转发到B域名,这样可以在nginx层面拦截原图访问,并可以支持自有域名HTTPS。虽然又点不符合规范了,虽然ECS下行带宽还是蛮大的,proxy_pass也是内网地址,似乎也无大碍。

方案三:
将bucket设置为私有,这样POST不变,GET需要增加signature,想想就复杂,搞的URL又长又丑,没再尝试。

  后来想想,能不能直接POST到D域名试试,居然成功了。Object 管理中证实了文件是传成功的,但感觉怪怪的,原来CDN还能upload。官方文档似乎也没有说这样用合不合理,暂且先如此把。