Record

机会是留给有准备的人

cpu使用率低但load高

起因

这个其实是去年已经解决的问题,去年系统会经常出现异常,访问不了之类的
工作日运维在的时候,运维每次都很快的解决,但问其原因,却说使用了运维大法“重启系统”,
由于一时没去解决,特别是到周末出现这个问题,就要崩溃啊。运维找不到人,自己有在外。
所以还是痛下决心研究一番是什么原因。

分析

其实用top就发现问题了。cpu使用率低,load高,然后用此关键词查找一番,发现阿里云已经有排查方案了,
依照此方案,发现是du 看磁盘空间的时候,出现了D进程。出现大量D进程,其实就是定时跑监控脚本时出现这个

解决办法

  1. 停的监控脚本
  2. 重启系统

sql优化

起因

公司慢日志里满是这sql耗时

分析

从图一看,使用explain 分析一下,主要原因是Using temporary; Using filesort,用到临时表,然后又来个排序。就非常耗时
试了多种写法,最后发现改了第二个join 为子查询后,速度很快,explain一下,发现Using temporary; Using filesort没了。

修改一,发现三个表join,然后order by 必然会出现Using temporary; Using filesort,
然后就减少表join,使用子查询。

修改二,仍然发现order by 主表字段时必然出现Using temporary; Using filesort,
改order by join的表就未出现(原因待解),只出现Using filesort

修改三,给hits表count字段添加索引
原因是:order by字段能够使用index的有序性,所以没有使用filesort

问题又来了,由于是ruby代码写的,无从下手。
这就是为什么一直不喜欢不写sql的程序员。

linux磁盘空间未释放?


最近发现测试环境的服务器磁盘满了,于是,找到一些无用的大文件将其删除后,释放20G,但是过了几天,发现磁盘空间又爆了,但是du -sh 看了一下,发现磁盘并未大增,这是什么原因呢?百撕不得骑姐啊。
在想是否一些job模块太久没重启,是否删除的日志文件依然被进程占用,内存没释放呢?于是restart模块,磁盘瞬间清爽了。啊啊啊啊啊啊哈哈哈哈

OpenResty+GraphicsMagick为图片添加水印与缩略图

之前公司项目一直是用java+GraphicsMagick生成缩略图,开发起来非常繁琐。效率也不高。
后面就使用了这个方法,效果还行

nginx代码

location ~ .*\.(jpg|jpeg|png)$ {
        root   /data/image;
        set $image_root /data/image;
        set $file "$image_root$uri";
        if (!-f $file)
        {
            content_by_lua_file lua/image.lua;
        }
        proxy_next_upstream http_502 http_504 error timeout invalid_header;
        proxy_cache_valid  200 304 12h;
        proxy_cache_key $uri$is_args$args;
        index  index.html index.htm;
        expires 7d;
    }

lua代码

local function writefile(filename, info)
    local wfile=io.open(filename, "w")
    assert(wfile)
    wfile:write(info)
    wfile:close()
end

local function is_dir(sPath)
    if type(sPath) ~= "string" then return false end

    local response = os.execute( "cd " .. sPath )
    if response == 0 then
        return true
    end
    return false
end

local file_exists = function(name)
    local f=io.open(name,"r")
   if f~=nil then io.close(f) return true else return false end
end

local area = nil 
local originalFile = ngx.var.file;
local index = string.find(ngx.var.uri, "([0-9]+)X([0-9]+)");
local indexw=string.find(ngx.var.uri, "watermark");
if index then
    area = string.sub(ngx.var.uri, index);
    index = string.find(area, "([.])");
    area = string.sub(area, 0, index-1);
        local index = string.find(originalFile, "([0-9]+)X([0-9]+)");
    originalFile = string.sub(originalFile, 0, index-2)
    originalFile = originalFile..'.jpg'

elseif indexw then
    local index = string.find(originalFile, "watermark");
    originalFile = string.sub(originalFile, 0, index-2)
    originalFile = originalFile..'.jpg'
end

-- 判断是否有原图片
if not file_exists(originalFile) then 
    writefile(originalFile, data)
end

local image_sizes = { "200X200","300X300", "400X400","800X800"};
function table.contains(table, element)
  for _, value in pairs(table) do
        if value == element then
            return true
        end
  end
  return false
end

if area and  table.contains(image_sizes, area) then

    local command = "gm convert ".. originalFile.." -thumbnail "..area.."! "..ngx.var.file;
   os.execute(command);
elseif indexw then
  local command ="gm composite -gravity southeast     /data/image/logo.png"..originalFile.." "..ngx.var.file;
      os.execute(command);
end;

if file_exists(ngx.var.file) then
      ngx.exec(ngx.var.uri)
else
      ngx.exit(404)
end

blog重新上线

2015年底服务器挂了,数据备份没同步到线下,导致2015年的数据丢失了,
最近玩了一下go语言,并将好久没弄过的blog,用beego框架替换了django,
让blog重新上线,但是时间关系,还没完全重构完成,只是将主要功能实现了。
beego写起来还是挺简洁的,容易上手,比django学习成本低。

ios开发代码优化

最近发现写ios一些类里的代码越来越长,恶心的要死,为项目短平快的上线,没怎么使用设计思维,实在是失误啊。 这二天对代码做了一些优化,发现ios使用的继承,块,代理,都大大的提高了可读性,代码也大大的减少。赞一个

一张图看懂ios drawRect

enter image description here

#import "CGArrow.h"

@implementation CGArrow

- (void)drawRect:(CGRect)rect {

  // 绘制
  CGContextRef con = UIGraphicsGetCurrentContext();

  //线的颜色
  CGContextSetStrokeColorWithColor(con,[[UIColor grayColor]CGColor]);

  //三角形箭头
  //左起点
  CGContextMoveToPoint(con, 0, 25);

  //中间点
  CGContextAddLineToPoint(con, 25, 0);

  //右终点
  CGContextAddLineToPoint(con, 50, 25);

  //竖线 起点
 CGContextMoveToPoint(con, 25, 0);

 //竖线终点
 CGContextAddLineToPoint(con, 25, 50);

 //连接所有点
 CGContextStrokePath(con);

}

@end

开发ios项目简单总结

经过一个多月的努力,今天华强北商城特卖app终于提交到苹果官网审核。
这段时间比较忙。现在对这个项目做个简单总结吧

一.初学object-c

以前搞java的刚开始以为object-c比较难学,但只要你看懂那些符号是什么意思,学起来就快了

二.需要认真了解ios常用控件使用

主要用到UIView,UIImageView ,UITableView,UILabel,UIScrollVie等 比较难的是动画交互

三.第三方库的使用

使用cocoaPods,管理库还是比较方便,也是经过多方打听,才使用这个 但是pod install 速度慢的要死,原因是被墙,另外使用淘宝的gem sources也 是很慢,最后找到山东理工大学的才好点

四.xcode使用

xcode的优点:安装方便,编译成功的话,启动也快
xcode的缺点:
1.快捷键不够 intellij idea智能,写起代码不是很顺
2.编译是麻烦事,编译不通过时,想砸电脑的心都有,在合并代码时容易出错,
最郁闷的是有次不小心动了一个库中点类,马上按command+z还原了,xcode这到好,直接编译不过,在网上找了很多方式,要删除一些文件才行。 等等一系列让你预想不到的问题 3.git与xcode结合的不是很好,每次更新代码都怕,特别是有冲突的时候,xcode可能会直接闪退。

五.git

1.git下载源码是非常方便的,感觉还是不如svn方便,也许还不熟git的使用吧
到现实还不到怎么能不能与历史文件对比还原

六.测试

1.样式排版细节处理是比较花时间的
2.程序崩溃,会闪退,主要是网络获取数据异常时要校验数据,不然可悲剧了
还有快速连击button,程序未能快速响应,可能出现多个事件触发导致系统崩溃
3.流畅体验问题,也是因请求网络会耗时间。一开始就请求网络数据,会感觉程序死了不动,过了一会才跳转到下个页面,最后的做法是先跳转再请求网络渲染数据,这样视觉上看起来流畅很多

七.提交审核

要准备一堆的资料,文案,图片等等,图片要png的,同事把jpg的改了后缀为png,但苹果在苹果那提交不了审核,还有就是图片命名规范。

swift有感

今天在了解swift时,发现有趣的是可以直接将object-c转换成swift语言。
比如:

CLGeocoder *geocoder=[[CLGeocoder alloc] init];

swift直接就可以

let geocoder:CLGeocoder = CLGeocoder()

难怪那些牛人在swift刚出生下来,就写出了Flappy Bird ,2048等。

但在将object-c转换成swift时,闭包就必须要了解了,下面代码必须要能看的懂才行
用闭包排序:

var a=["d","a","b","v"]

func backwords(f:String,s:String) -> Bool {
  return f < s
}

sort(a,backwords)

利用appleScript切换网络位置

缘起:

每次从家里到公司,在mac上都要切换一下网络,切换过程比较繁琐,
于是动手写了个切换网络位置到applescript。

apple script 1

因使用的是dialog,只支持3个button,所以你只有二个网络位置时使用此脚本方便

tell application "System Events"
tell network preferences
    get the name of every location

    set allLocations to the name of every location
end tell
end tell

set allLocations to allLocations & {"cancel"}

display dialog "请选择当前的网络位置" buttons allLocations default button 3

set the button_pressed to the button returned of the result

if the button_pressed is not "cancel" then
tell application "System Events"
    tell network preferences
        do shell script "scselect '" & button_pressed & "'"

    end tell
end tell
else
beep

end if

apple script 2

因dialog只支持3个,所以写出下面支持多个网络位置的切换

tell application "System Events"
tell network preferences
    get the name of every location

    set allLocations to the name of every location
end tell
end tell

set chosen_network to choose from list allLocations

if the chosen_network is false then

else
tell application "System Events"
    tell network preferences
        do shell script "scselect '" & chosen_network & "'"
    end tell
end tell
end if

使用方式

1.保存代码格式是脚本,可以用命令启动:osascript scriptname(不推荐) 不推荐是因为,需要在命令行运行,打开命令行需要时间,
其实命令行你可以直接输入scselect home就可以切换了

2.保存代码格式为应用程序,直接双击运行,或结合alfred使用(推荐此方式)

注意

网络位置命名要英文,不然会有乱码异常

mac openresty配置安装

目的

最近公司里的前端和后端模块在本地调试启动时都用80端口。
二个一起启动调试是会冲突的,于是用nginx做个反向代理以解决端口冲突。

mac nginx安装使用


1. 到 openrestry 下载
2.安装Install Homebrew,如已安装怎无需安装,安装时直接在终端输入下面命令

ruby -e "$(curl -fsSL https://raw.github.com/Homebrew/homebrew/go/install)"

3.安装pcre,会安装到/usr/local目录里

brew install pcre

4.解压安装

tar xzvf ngx_openresty-VERSION.tar.gz

cd ngx_openresty-VERSION/

./configure --with-luajit --with-cc-opt="-I/usr/local/Cellar/pcre/8.35/include" --with-ld-opt="-L/usr/local/Cellar/pcre/8.35/lib" --prefix=/usr/local/webserver

make

make install

5.设置环境变量

PATH=/usr/local/webserver/nginx/sbin:$PATH
export PATH

6.启动与使用

 启动
/usr/local/webserver/nginx/sbin/nginx

快速退出
/usr/local/webserver/nginx/sbin/nginx -s stop

优雅退出
/usr/local/webserver/nginx/sbin/nginx -s quit

更换配置,启动新的工作进程,优雅的关闭以往的工作进程
/usr/local/webserver/nginx/sbin/nginx -s reload

重新打开日志文件
/usr/local/webserver/nginx/sbin/nginx -s reopen

微信支付开发问题

最近开发微信支付有个问题一至困扰着我很久,就是在微信iPhone端能使用支付,微信andoid端手机不可以
参数排序,加密,js调试都弄了好几遍都不能。微信andoid端就是提示不能支付,system:access_denied
由于忙于项目一直未能好好想想怎么解决。今天偶然去看看链接,发现微信android跳到支付页的链接与微信iPhone端链接不一样
iphone端可以正常跳到支付页,android端貌似跳转正常,但是,关键的是链接没有变,坑爹啊。就是这问题。
微信支付是会判断支付链接目录的。andoid端的链接不变,就导致system:access_denied。

极度鄙视微信支付团队。发了n封邮件也不回。打电话也不接。

团队的建立

无论开会,还是聊天老大一再强调团队的文化:

服务意识,崇尚行动,负责到底。


一开始并没觉得这句话的有多大力量,估计很多人都只是记得这话,但实际行动起来并不会有多上人记得
但看到老大一步步主动推动事情都能顺利的完成。可谓功力深厚啊
譬如他提到他是如何推动羽毛球俱乐部的建立的。
其实一开始公司本来就给员工提供去打羽毛球的资金,但是没人牵头,很快就没人去打了
而研发部愿意去打羽毛球的还是很多的。于是他为了推动俱乐部的成立,先找2个人带头组织开始
先在研发部号召参加,这是要交会费的,免费大家就可能随便起来,约好的就可能不去了,
交了会费大家才会比较珍惜。其他部们想参加还要贵点(哈哈),就这样越来越多人参加了。
俱乐部由此成立。

玩游戏有感

最近看到2048的游戏很火,看老婆,看同事都在玩,而且玩的不亦乐乎。于是自己就体验了一把。
游戏看似简单,但刚开始一般最多玩到1024,很难玩到2048,但经同事说有规律可循,不要往上移动就可。
但是玩了几次才发现,不只是不要往上移动,还要最大的数字保持在一个角落,数字尽可能从大到小排列。
然后就是随机应变。发现这规律过,就基本能轻松玩过2048,甚至更高的数字。
生活工作也应多考虑多寻规律以免做许多吃力的事情。

组织开发抢购活动

最近负责组织开发抢购活动,刚听到都有些小紧张啊,因之前公司搞的大型秒杀抢购都是遇到某系统挂了,但是看过老大搞的秒杀抢购的代码,心中还是有点数的,只是没实战过。这次终于有机会了。然后开始...

活动专题

需求是运营给的,抢购活动核心就是要使用预约码,就是预先领取一个号码,等抢购那天凭此码来抢,没预约码的就哪凉快哪呆着哈。

UED设计活动专题页,设计花了一天就把设计搞弄出了。

前端与php负责切图,拉数据,领取预约码等,代码与调试各花了一天。

后端预约码领取数量,预约码查询,手机验证等都是用java处理。这代码都是以前写好的,我就测试了一下,还能用就给他们了。

终于在21号晚上上线。在公司待到9点,没发现啥事,就高高兴兴回家了,
突然在回家路上运营来电,就知道有事发生,
果然回家一看,老用户可以正常领取,新用户就领半天都不行,一猜是手机未绑定问题,
之前是看着前端同学测试的。到线上就没了,郁闷之极,第二天一早就陪他们改bug,却发现还有其他问题
1.答题错误就永远错误,是关闭弹窗校验问题。
2.用户完善手机号时又多请求一次,会提示此号码已被使用。
最后在上午终于改完,一切ok。只是关闭弹窗要刷新页面,因时间问题就没让他们改了。不影响领取。
其实看他们调试发现有以下几个问题:
1.由于是模版发布,前端同学有时候直接在编辑页改代码,代码没保存到就会丢失了
2.由于有缓存原因php同学与前端同学保存代码不一至,还好二人坐一起,可以商量弄 ,坐远了,改了就不知道谁覆盖了谁的代码了
3.看他们在用alert调试代码,要添alert代码,保存发布很费时间,而且不精准定位问题,其实firefox,chrome的debug功能还是比较强大的。

防高并发

应对高并发请求,首选nginx,能抗住每秒2万请求,嘿嘿,没写过nginx,
老大让我自己想办法,代码之前老大有写过的。我就照着他的代码,写了一个。
其实都简单,核心是有个计数器的东东。超过多少人就重定向到系统繁忙页了。
如果全都放进来,java是抗不住的。预计抢购当天有1万人。
在开发过程中又发现问题:
1. 请求java取活动时间时,在nginx有缓存,导致活动时间有延时现象。
2.活动专题页与抢购页的倒计时不同步,因为活动专题是php的,抢购页是java的 各自取时间不一样,最后统一取nginx服务器时间。

开始抢购

在26号上午12点08分大家开始抢购,此时流量直线上升,打开页面有些缓慢。
后台显示一单单的抢购成功幸运者,并付款成功。好吧可以开开心心的吃午饭了。
吃饭中微博却像突然一盆冷水泼来。搞的吃不下饭,网友在微博上大骂怎么预约码错误。
后来找了一个下午原因,从代码,缓存数据取出,日志分析都未找到真正正确的原因。
郁闷中度过一个下午。。。
遇到这事只能以后防范:
1.永远不要让用户知道哪错了。让他知道其实是系统太忙了就好或还在排队中。可以减少公关压力
2. 加多一些日志记录

end

log4j MDC 工作原理

缘起

前几天接到一个任务,要分析日志,看是谁在线上乱操作。非常郁闷的是在关键请求url操作功能上没有记录到userId。 虽然在InitMDCFilter时有记录userId。但是InitMDCFilter 加载顺序稍后于PageFilter,所以userId没有输出。 经老大提醒,本应在InitMDCFilter 里remove掉的,改在PageFilter 先取到userId,然后remove,伪代码如下 InitMDCFilter :

  try {
        MDC.put("userId", userId);

        chain.doFilter(request, response);

    } finally {

    }

PageFilter :

 try {
        chain.doFilter(request, response);

    } finally {
        log.info(requestUrl+MDC.get("userId"));
        MDC.remove("userId");
    }

一开始不明白神马原理,经看了MDC的源码就明白了

原理

1.先在log4j.xml的ConversionPattern配置 %X{userId},PatternParser会去解析
2.当请求过来时先经过PageFilter(因用户未登录也必须输出请求url,而如果InitMDCFilter先的话,用户未通过登录校验就不执行PageFilter,最后请求url数据都会没有)
3.再经过InitMDCFilter,先验证用户是否登录,登录后取出userId,通过 MDC存储userId,MDC会将数据放入ThreadLocalMap存储
4.由于运行时InitMDCFilter 与PageFilter 是同一个Thread的,所以他们可以共享ThreadLocalMap数据,所以PageFilter 可以在finally里取出userId
5.log4j通过MDCPatternConverter又从MDC里取出数据并打印日志
6.最后在finally里remove数据

PathMatchingResourcePatternResolver 找配置文件

在使用PathMatchingResourcePatternResolver 查找指定配置文件时遇到一个问题,就是有些目录下不会去找。

原因跟启动时 -classpath 有关,classpath没有加载要扫描的目录,如果使用maven,就是pom没有依赖到相关的项目

 ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();

    try {
        Resource[] metaInfResources = resourcePatternResolver
                .getResources("classpath*:**/*.xml");
        for(Resource r : metaInfResources){
            System.out.println("URL:"+r.getDescription());
        }
    } catch (IOException e) {
        e.printStackTrace();
    }

GenerateAllSetter

介绍

GenerateAllSetter 是我在intellij idea开发的一个生成调用Set方法的插件,
在开发时有时候会遇到初始化domain时需要调用很多Set方法,
需要人工一个一个操作,非常的麻烦,所以开发了这个插件,提高效率。

插件安装

1.直接下载GenerateAllSetter.jar放到本地磁盘,也可下载源码自己打包
2.然后在intellij idea 插件安装,选install plugin from disk 安装重启即可使用

插件使用

在new domain时,需要初始化调用所有Set方法时,只需要将光标移动到类上,
然后按快捷键( Ctrl+Shit+G )或(alt+insert -input all set>,就会自动生成代码

插件开发 参见intellij idea development

HTTP Trace插件

HTTP Trace插件是google chrome 的插件,用于追踪页面上都有哪些http请求, 所以请求,http header,cookies等

使用场景:
1.监测页面上的所有http请求或参数 在看维品会的微信支付,一直看不清楚维品会的链接跳转,用此插件就可以跟踪到所有链接

2.查看http header
今天遇到联合登录过来先请求java是,然后再跳转到php交互时,产生的session不一至问题,
用http trace追踪也很容易发现