找到 lua 死循环代码

最近遇到 lua 死循环的情况,就研究下如何找到死循环所在的代码,方便定位和解决问题。

首先,要找到出问题的协程(lua_State)。lua vm 实现时,每个协程都有自己独立的堆栈(stack),以及函数栈(CallInfo)。

所以,要先找到死循环的协程,再从这个协程函数栈找到代码。

怎么找到这个协程?

有两种办法:
方法1、 在死循环会执行到的 opcode ,加代码取得当前协程;
方法2、 遍历所有 gc 数据对象,找到当前正在执行的协程。

继续阅读找到 lua 死循环代码

lua5.3 垃圾回收分析

前注

最近我一直在看lua gc,阶段性做一下总结。网上很多文章没讲明白,我也当弥补下这个问题。文章以我看的lua 5.3.6做分析。

lua 垃圾回收发展历程

5.0 及以前使用的是双色标记清除法,gc 过程会停止主程序执行,直到 gc 完成;
5.1 实现了增量式 gc,采用三色标记法,gc 过程分多步,与主程序交替执行;
5.2 实现了分代 gc,实际效果不理想;
5.3 移除了分代 gc;
5.4 重新实现了分代 gc

两种标记清除算法

标记清除算法,就是遍历所有对象,将还在使用的对象打上标记,遍历完成后,没有标记的对象就是垃圾对象,要清理掉。

所以,系统至少需要记录两个数据集合,一个是所有的对象集合,一个是还在使用的对象集合。在 lua 中,还在使用的对象集合包括了全局变量、 栈中对象、处于激活状态的协程等。
继续阅读lua5.3 垃圾回收分析

lua table怎么检查数据变了

为了缓解数据库压力,数据会缓存在lua table,满足频繁读写需求,再定时检查,发现数据变了则落地。

问题来了,lua table怎么检查数据变了?

table检查数据变了

答案很简单,使用 metatable,这里贴一个简单的例子。

-- db数据
db = {openid="openid_123", token="token_123"}

-- 缓存
cache = {}

setmetatable(cache, {
	__index = function(t, k)
		return db[k]
	end,
	__newindex = function(t, k, v)
		if k ~= "__dirty" then
			db.__dirty = true
		end
		db[k] = v
	end,
	__pairs = function(t, k)
		return next, db, k
	end,
})


for k, v in pairs(cache) do
	print(k, v)
end

cache.__dirty = nil
print("cache.__dirty", cache.__dirty)

cache.token = "token_456"
print("cache.__dirty", cache.__dirty)


执行结果如下:

> dofile("test.lua")
token   token_123
openid  openid_123
cache.__dirty      nil
cache.__dirty      true

问题到这里就结束了。

接下来,我们再提出一个问题,lua table如何检查子项为table的数据变了?
继续阅读lua table怎么检查数据变了

Google Protobuf协议分析

protobuf 是google开源的一个序列化框架,类似xml,json,最大的特点是基于二进制,比传统的XML表示同样一段内容要短小得多。还可以定义一些可选字段,用于服务端与客户端通信。前面几篇文章说了protobuf的用法,看到网上也没有分析protobuf协议的文章,就利用一些时间写了 protobuf 的协议分析。

protobuf协议核心思想
基于128bits的数值存储方式(Base 128 Varints)
数据表示方式:每块数据由接连的若干个字节表示(小的数据用1个字节就可以表示),每个字节最高位标识本块数据是否结束(1:未结束,0:结束),低7位表示数据内容。(可以看出数据封包后体积至少增大14.2%)

数字1的表示方法为:0000 0001,这个容易理解
数字300的表示方法为:1010 1100 0000 0010
继续阅读Google Protobuf协议分析

Erlang集群IP及端口管理

erlang集群是依靠epmd维护的,epmd是erlang集群节点间端口映射的守护进程,负责维护集群内的节点连接,提供节点名称到IP地址及端口的解析服务。

epmd 自定义端口号

epmd端口配置
默认情况下,epmd绑定在4369端口。但是,端口固定的话,容易遭受攻击,可能导致新节点的认证失败而无法启动,或无法加入集群。或者要在一台机器上部署不同的erlang集群,希望不会互相干扰。
epmd -daemon -port 5000
如果想用调试模式启动 epmd,使用 epmd -d -port 5000

另外,epmd通常伴随着erlang节点启动时自动启动,无须手动处理,所以,这里也可以通过修改erl启动参数以达到自动调整epmd端口。
erl -name hello@127.0.0.1 -epmd “epmd -port 5000 -daemon” 
继续阅读Erlang集群IP及端口管理