LuaRocks Tutorial

LuaRocks 是一个 Lua 的包管理工具,提供了一个命令行的方式来管理 Lua 包依赖。官网

安装 Lua 5.1.5

wget http://www.lua.org/ftp/lua-5.1.5.tar.gz
mkdir /usr/local/lua-5.1.5 && cd lua-5.1.5
# 配置 Makefile,指定安装目录,INSTALL_TOP = /usr/local/lua-5.1.5
# aix ansi bsd freebsd generic linux macosx mingw posix solaris 支持的平台
make macosx
make macosx install
ln -sf /usr/local/lua-5.1.5/bin/lua /usr/local/bin/lua

安装 LuaRocks

wget https://luarocks.org/releases/luarocks-2.4.1.tar.gz
tar zxpf luarocks-2.4.1.tar.gz && cd luarocks-2.4.1
mkdir /usr/local/luarocks-2.4.1
./configure --prefix=/usr/local/luarocks-2.4.1 --with-lua=/usr/local/lua-5.1.5
make build  && make install

使用 LuaRocks 安装包

luarocks install dkjson
require("dkjson") 然后就可以使用了

贡献 Rock 包

创建 .rockspec 文件,下面是我写的一个名为 nginx-lua-frequency 的 Lua 模块的案例。

package = "nginx-lua-frequency"
version = "0.1-1"
source = {
   url = "git://github.com/itsmikej/nginx-lua-frequency.git"
}
description = {
   summary = "A frequency module for Nginx written in Lua",
   homepage = "https://github.com/itsmikej/nginx-lua-frequency",
   maintainer = "Jiang Yang<jiangyang33@gmail.com>",
   license = "MIT"
}
dependencies = {
   "lua=5.1",
   "lua-resty-memcached=0.13-0"
}
build = {
   type = "builtin",
   modules = {
      ["frequency"] = "src/frequency.lua",
      ["frequency.adapter.memcached"] = "src/adapter/memcached.lua"
   }
}

保存文件名为 nginx-lua-frequency-0.1-1.rockspec,格式必须是"{package}-{version}.rockspec",最后上传即可:
luarocks upload nginx-lua-frequency-0.1-1.rockspec --api-key ********
执行完这个命令后,会在当前目录生成一个名为 nginx-lua-frequency-0.1-1.src.rock 的二进制文件,其实这个文件就是当前项目的一个压缩包,使用 luarocks install 安装时,其实就是用的这个压缩包。

BTW

nginx-lua-frequency 是一个基于 memcached 的通用频率限制模块,可同时做多个时间维度(秒,分,小时)的请求频率配置。Github链接

参考

https://github.com/luarocks/luarocks/wiki/Documentation
http://www.jianshu.com/p/196b5dad4e78
https://segmentfault.com/a/1190000003920034

Lua 中点号和冒号操作符的备忘

分两种情况来看

函数定义

冒号默认会隐式 接收 一个 self 参数,使用点号则需要显示传入 self

函数调用

冒号默认会隐式 传入 一个 self 参数,点号只是普通调用

案例

local _M = { _VERSION = "0.0.1" }

function _M.new(self, o)
    o = o or {}
    setmetatable(o, {__index = self})
    return o
end

function _M:foo(arg1, arg2)
    ngx.say(self._VERSION)
    ngx.say(arg1)
    ngx.say(arg2)
    ngx.say("--------")
end

function _M:bar()
    self.foo("arg1", "arg2")
    self.foo(self, "arg1", "arg2")
    self:foo("arg1", "arg2")
end

local ins = _M:new() -- 默认带入了 self 参数

ins.foo("arg1", "arg2")
-- 因为 foo 函数会默认接收 self, arg1 传给了 self,所以第一个参数会输出 nil
-- nil
-- arg2
-- nil

ins.foo(ins, "arg1", "arg2") -- 这样就 OK 了
-- 0.0.1
-- arg1
-- arg2

ins:foo("arg1", "arg2") -- 输出符合预期
-- 0.0.1
-- arg1
-- arg2

ins:bar() -- 同样的输出

Golang 中的类型转换

基础类型转换

如下图

类型转换

string与其他类型转换

Golang中string类型和其他基础类型的转换主要通过 strconv 这个包来处理

package main

import (
    "fmt"
    "strconv"
)

func main() {
    // string to int
    fmt.Println(strconv.Atoi("1")) //  ParseInt("1", 10, 0)
    // int to string
    fmt.Println(strconv.Itoa(1))

    // parse系函数: 将string转成其他类别
    // string to bool
    fmt.Println(strconv.ParseBool("true"))
    // string to float64
    fmt.Println(strconv.ParseFloat("3.1415", 64))
    // string to int64
    fmt.Println(strconv.ParseInt("-42", 10, 64))
    // The parse functions return the widest type (float64, int64, and uint64),
    // but if the size argument specifies a narrower width
    // the result can be converted to that narrower type without data loss
    // 第二个参数指定进制 第三个参数指定bit范围
    v64 := "354634382672430"
    if s, err := strconv.ParseInt(v64, 10, 32); err == nil {
        fmt.Printf("%T, %v\n", s, s)
    } else {
        // 超限,这里会报错,bitSize改成64则正常
        // strconv.ParseInt: parsing "354634382672430": value out of range
        fmt.Println(err)
    }
    // string to uint64
    fmt.Println(strconv.ParseUint("42", 10, 64))

    // format系函数: 将其他类别转成string
    fmt.Println(strconv.FormatBool(true))                 // true
    fmt.Println(strconv.FormatFloat(3.1415, 'E', -1, 64)) // 3.1415E+00
    fmt.Println(strconv.FormatInt(-42, 16))               // -2a
    fmt.Println(strconv.FormatUint(42, 16))               // 2a

    // append系函数: 跟format一样,只不过是将结果追加到一个slice上
}

参考

https://golang.org/pkg/strconv

有用的 shell&vim 命令

shell 相关

工作中,总会碰到一些『乍一看处理起来巨麻烦』的问题,特别是一些文本处理类的,但事实上只要能合理巧妙的运用 shell 命令,就能迅速的得到想要的答案,省时又省力。本文将记录下这些有用的 shell 命令,并持续更新。PS: 这里给出的方案不一定是最佳,如果有更好的方案,请留言指出:)

文本处理类

假设请求日志格式为:10.18.122.28 - - [01/Apr/2017:08:15:55 +0000] "GET /sug?channel=type_map&word=%E5%8C%97%E4%BA%AC HTTP/1.1" 200 1508 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36" "-" -0.023

1. 怀疑有坏人在刷请求,如何快速定位到对应的一批 ip。

➜ tail -f access.log | awk '{print $1}' > t.txt
先将 ip 信息先收集到单独的文件中,可减少计算量
➜ cat t.txt | sort | uniq -c | sort -nr | head -10
将结果排序|去重并记录条数|倒序|取前十条。

2. web服务器负载异常,想确认是否是 qps 过高导致。

➜ tail -f access.log | grep "\"GET " | awk '{print $4}' | uniq -c
找到请求时间戳|计算次数,也可以查到某个接口的 qps,grep 到那个接口就行。不过这样会有一个小问题,如果日志中的时间不是增量,就会有重复的情况,但基本能得到一个粗略的结果。

网络系统类

1. 查看系统最占用资源的进程

ps aux | head -1;ps aux | grep -v PID | sort -rn -k +3 | head # CPU
ps aux | head -1;ps aux | grep -v PID | sort -rn -k +4 | head # 内存
其实就是将进程的按某列倒序排序而已,友情提示:ps 查看的是进程启动以来的平均CPU利用率,并不反应实时的。

查找类

1. 提取文件名&目录名

# 1. 使用 ${}
➜  ~  var=/Users/itsmikej/zsh_ext.sh.tar.gz
➜  ~  echo ${var%%.*}
/Users/itsmikej/zsh_ext
➜  ~  echo ${var%/*}
/Users/itsmikej
➜  ~  echo ${var#*.}
sh.tar.gz
➜  ~  echo ${var##*.}
gz
➜  ~  echo ${var##*/}
zsh_ext.sh.tar.gz
# 2. 使用 basename 和 dirname
➜  ~  echo $(dirname $var)
/Users/itsmikej
➜  ~  echo $(basename $var)
zsh_ext.sh.tar.gz

关于 ${}
#:表示从左边算起第一个
%:表示从右边算起第一个
##:表示从左边算起最后一个
%%:表示从右边算起最后一个
换句话来说,#总是表示左边算起,%总是表示右边算起。
:表示要删除的内容
via:http://blog.csdn.net/ljianhui/article/details/43128465

常用数据结构&语法

......

vim 相关

普通模式

  • * 查找当前目标单词(:set hls 高亮),选中之后可以执行 cw n 批量修改。
  • b (begin)移动到单词的开头
  • e (end)移动到单词的最后
  • x 删除当前字符
  • d{motion} 删除,dd行,dl字符,daw(delete a word)单词,dap段落。(dw, db, de, dw)
  • f{char} 跳转
  • c{motion} 修改, cw 删除当前选中单词,并切换到插入模式
  • y{motion} 复制
  • g 切换大小写,g~反转,gU转大写,gu转小写
  • < > 缩进

可视模式

  • v 进入面向字符的可视模式
  • V 进入面向行的可视模式
  • ctrl+v 进入面向列块的可视模式
  • gv 重选上次的高亮选区
  • o 返回起始的选中位置

选中内容之后,就能做一些有用的操作了,比如

多行缩进:Vj 选中行,然后 >. 缩进
列操作:ctrl+v 3j 选中列, c|I|d 操作,esc 所有选中项执行该修改

......

做了一点微小的工作

还记得很久之前,给 Blog 做过一次优化,从 Wordpress 迁移到 Typecho,同时上了 HTTPS,然后为了加快页面加载速度,给全站的静态资源加上了七牛的 CDN。不过由于服务器在境外,用的又是 DigitalOcean 最低配的 VPS,访问速度还是很慢。

现在又有提升性能的机会啦,PHP7 在去年年底的时候正式发布,本来想第一时间升级,不过想了想刚发布的版本大大小小都会有 Bug,还是不做小白鼠了,还是等等吧,结果一拖就是一年。。好吧,是我懒。

今天折腾了快一个下午的时间,不光是升级了 PHP,还做了其他的升级和优化。

  • 升级了 VPS 套餐
  • 重新部署了startssl 家的 HTTPS 证书(毕竟免费..)
  • 升级 Nginx 到1.10.2
  • 升级 PHP 到 7.0.13

为了达到 PHP7 的最佳性能,可参考鸟哥的博客 http://www.laruence.com/2015/12/04/3086.html。HTTPS也可以做很多配置优化可参考 http://op.baidu.com/2015/04/https-s01a03。比较幸运,升级基本上比较顺利,Typecho 对 PHP7 完全兼容,唯一需要修改的是将配置中数据库的适配器改为 PDO 即可,因为 PHP7 已经不支持最原始的 MySQL 扩展了。

最终升级完成之后,还是很有效果的。虽然没有做测试,但从肉眼看,等待时间明显减少了:)

-- 2017-3-31 Update

  • 由于 StartCom 遭到了 Google 的 惩罚,导致证书不被 chrome 信任,于是使用 Let’s Encrypt 证书做了替换,并自动更新有效期,参考 acme-tiny
  • 将 VPS 由 NewYork 机房搬到了 SanFrancisco 机房,减少了路由节点跳数,不得不给 digitalocean 点个赞,全程自动化的操作简直太方便

-- 2017-05-12 Update

升级了 Openssl, 重新编译了 Nginx, 并做了如下优化:

  • 添加了对 HTTP2 的支持
  • 优化了 ssl ciphers 配置,修复已知的漏洞
  • 添加了 HSTS 特性,可减少一次 RTT
  • 添加了 fastopen 特性
  • 参考 mozilla 的推荐配置