Record

机会是留给有准备的人

简单版的goroutine pool


package main

import (
    "sync"
    "fmt"
    "time"
)

func main(){
    goPool()
    noPool()
}

type f func()

func worker(){
    fmt.Println("hello pool")
}

//简单版的goroutine pool,核心是启动goroutine,没有及时结束,用channel阻塞
func goPool(){

    start :=time.Now()

    var wg sync.WaitGroup

    //定义一个函数类型的channel
    task := make(chan f , 100)

    for i := 0; i < 10; i++ {
        wg.Add(1)
        go func() {
            defer wg.Done()
            //从channel循环取出函数
            for f := range task {
               f()  //运行函数
            }

        }()
    }

    //循环的将需要允许的函数写入channel
    for i:=0;i<100;i++  {
        task <- worker
    }

    close(task)
    wg.Wait()
    end :=time.Now()
    fmt.Println(end.Sub(start))

}

func noPool(){

    start :=time.Now()
    var wg sync.WaitGroup

    for i:=0;i<1000000;i++  {
        wg.Add(1)
        go func(){
            defer wg.Done()
            worker()

        }()
    }

    wg.Wait()
    end :=time.Now()
    fmt.Println(end.Sub(start))
}



执行完所有的goroutine方式

在使用goroutine时,如果未有程序阻塞主程序,在主程序执行很快的时候,往往goroutine里的程序未执行完,主程序就退出了,导致程序提早结束。所以下面二个方式可以让goroutine先执行完,主程序再退出。
第一种方式使用WaitGroup
第二种方式使用channel
如下代码:

    package main
    
    import (
        "fmt"
        "time"
        "sync"
    )
    
    func testFunc(quit chan int,i int)error{
        fmt.Println("hello world",i)
        <-quit  //写出管道
        return nil
    }
    
    func testFunc2(wg *sync.WaitGroup,i int)error{
        fmt.Println("hello world",i)
        wg.Done()
        return nil
    }
    
    func main(){
    
        //第一种方式使用WaitGroup
        //WaitGroup的用途:它能够一直等到所有的goroutine执行完成,并且阻塞主线程的执行,直到所有的goroutine执行完成。
        //sync.WaitGroup只有3个方法,Add(),Done(),Wait()。
        //其中Done()是Add(-1)的别名。简单的来说,使用Add()添加计数,Done()减掉一个计数,计数不为0, 阻塞Wait()的运行。
    
        start2 :=   time.Now()
        runTimes2 := 1000
        var wg2 sync.WaitGroup
        for i:=0;i<runTimes2 ;i++  {
            wg2.Add(1)
            go testFunc2(&wg2,i)
        }
        wg2.Wait()
    
        end2 :=time.Now()
        fmt.Println(end2.Sub(start2))
    
    
        //第二种方式使用channel
        //利用channel的写入写出阻塞,执行完释放
        start := time.Now()
        runTimes := 1000
        quit :=make(chan int)
        //执行完释放
        for i:=0;i<runTimes ;i++  {
            go testFunc(quit,i)
        }
    
        //循环写入channel
        for i := 0; i < runTimes; i++ {
            quit <- 0
        }
        end:=time.Now()
        fmt.Println(end.Sub(start))
    
    }

在线SQL转Go结构体

起因:

最近用beego写了一些代码,但是每次建表后,就需要写一些繁琐结构体,增删改查方法,按照在之前开发java的经验,这些如果规范的好,完全是可以自动生成的。

结果:

好吧,为了提高点效率,开始动手写了个“在线SQL转Go结构体”。

未来会增加增删改查方法,controller,路由等

点击链接: 在线SQL转Go结构体

受到Memcache UDP 反射放大攻击与解决

起因:

今天收到大量阿里云的短信,邮件,报cpu使用率超过80%,时不时正常,时不时恢复。

排查分析:

1.上服务器用top命令查看,发现有时候卡死top显示不出来,有时候占有率却很低,算是看不出名堂

2.看阿里云安全警告显示:进程异常行为-Linux异常文件下载,想看具体原因要升级企业版,又看了企业版好几千块呢,尼玛,老板肯定不批了。

3.接着看到上千条ECS服务器管理重要通知:“由于被检测到对外攻击,已阻断该服务器对其它服务器端口(UDP:ALL)的访问”
上网一查都说redis未设置密码,而我的服务器是有密码的

4.看了一下云监控,果然显示出网网卡都是跑满的,不卡才怪。

5.在服务器装了个iftop,一看出入网流量不大啊,看ip都是内网IP,哦,原来iftop默认看的是eth0的流量

6.继续使用iftop -i eth1,果然出网数据大

7.继续用p命令查看端口,端口是没看到,但是显示的是memcache

8.发给牛逼的运维一看,立马给我看了一篇文章“Memcache UDP 反射放大攻击 II: 最近的数据分析”

9.立马关了memcahce试试看,果然就不发包了。

解决办法:

1.设置阿里云禁止外网出入数据的端口
2.修改默认端口
3.升级memcahce

快速排序之golang实现

    func main()  {
    
        arr := []int{16 ,1, 20, 17, 19, 13, 4, 5, 10, 8}
           //arr的下标0  ,1 , 2,  3,  4,  5,  6, 7, 8, 9
        quickSort(arr,0,len(arr)-1)
        fmt.Println(arr)
    
    }
    
    //快速排序
    func quickSort(arr []int,start int,end int)  {
    
        if start > end {
            return
        }
    
        i ,j ,temp := start,end,arr[start]
    
    
        for i < j {
    
            //从右向左查找小于基准数的元素
            for i < j && arr[j] > temp {
                j--
            }
    
            //从左到右查找大于等于基准数的元素
            for i < j && arr[i] <= temp {
                i++
            }
    
            //交换
            if i< j {
                //fmt.Println("交换前 =",arr)
                arr[j],arr[i] =arr[i],arr[j]
                fmt.Println("从右边开始找下标第",j,"的元素(",arr[i],")与左边下标第",i,"的元素(",arr[j],")交换,结果:",arr)
            }
    
    
    
        }
    
    
        arr[start],arr[i] =arr[i],arr[start]
        fmt.Println("基准数",arr[i],"与",arr[start],"交换,结果",arr)
        fmt.Println("-----------华丽的分割线-------------")
    
        quickSort(arr,start,i-1) //递归继续排左边数据
        quickSort(arr,i+1,end) //递归继续排右边数据
    
    }

插入排序之golang实现

    func main() {
    
        arr := []int{19, 7, 2, 9, 4, 12, 43, 32, 14}
        insertSort(arr)
    
    }
    
    //插入排序
    func insertSort(arr []int) {
    
        //从第2个元素开始取数据,因为第一个不用排
        for i := 1; i < len(arr); i++ {
    
            temp := arr[i] //取出当前位置i的元素,其中i-1已经排好序
    
            j := 0
            //temp与前面已排好的元素逐一比较,如果比她大就往后移位,再继续比较,直到比temp小的元素前停下
            for j = i; j > 0 && temp < arr[j-1]; j-- {
                arr[j] = arr[j-1]
                fmt.Println(j)
            }
    
            arr[j] = temp //合适位置插入
    
            fmt.Println("i =", i, arr)
    
        }
    
    }

冒泡排序之golang实现

    
    func main()  {
    
        var arr = []int{5,10, 6, 9, 3, 7, 1, 4, 2, 8}
    
        leftBubbleSort(arr)
    
        //rightBubbleSort(arr)
    
    }
    
    //从左边开始排,先排好最小的数
    func leftBubbleSort(arr []int) {
        
        for i := 0; i < len(arr)-1; i++ {
    
            //加i 左边已排好的不需要再比较,减少循环次数
            for j := i + 1; j < len(arr); j++ {
    
                if arr[i] > arr[j] {
    
                    arr[i], arr[j] = arr[j], arr[i]
    
                }
                fmt.Println("i=", i, ", j=", j, arr)
                
            }
    
        }
    }
    
    //从右边开始排,先排好最大的数 
    func rightBubbleSort(arr []int) {
        
        for i:=0;i<len(arr);i++ {
    
            //减i 右边已排好的不需要再比较,减少循环次数
            for j:=0;j<len(arr)-i-1;j++ {
                if arr[j] > arr[j+1] {
                    arr[j], arr[j+1] = arr[j+1], arr[j]
                }
                fmt.Println("i=",i,", j=",j, arr)
                
            }
        }
        
    }

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封邮件也不回。打电话也不接。