转载

lua-resty-redis 返回空值的问题记录

背景

我们的服务本来使用一组redis,以一致性哈希的方式来使用,现在打算替换为云平台的redis集群服务,因此需要设计一个平滑过渡的方案。解决方案并不难,两种方式可以使用不同的key,对于一种key使用ring_redis,另一种使用redis集群,这样只需要在redis库的接口内部进行key的解析,就无需对其他代码做过多改动了。

实现并不难,但在测试时,遇到个很诡异的问题:从redis中取一个不存在的key时,返回的值(正常情况是json格式的字符串)在不存在的情况下,会导致 nginx 500 错误,通过日志中的 trace 看到,是返回的字符串无法被 cjson 解析导致,返回的字符串是 userdata:NULL 。这个返回的字符串引起我的好奇心, userdata 是什么鬼?

什么是 userdata

userdata 是Lua中C API的一个基本类型,可以把任意的C数据存储在lua变量中,除了赋值和相等的判断外,没有其他的lua预定义的操作。 userdata 常用来表示由C应用或者库创建的新类型。

仔细看了 lua-resty-redis 的代码,才发现空值返回的是 ngx.null 这个变量。在 nginx-api-for-lua 中, ngx.null 的含义如下:

The ngx.null constant is a NULL light userdata usually used to represent nil values in Lua tables etc and is similar to the lua-cjson library's cjson.null constant. This constant was first introduced in the v0.5.0rc5 release.

问题解决

其中解决问题的方法很简单,还是RTFM!看了文档和示例,知道了 lua-resty-redis 的正确使用方法。

local ret, err = redis:get('foo')
if not ret then
    ngx.log('err: xxxx')
    return
end

if ret == ngx.null then
    ngx.log('err: not found')
    return
end

-- process the value

这个库的返回值,在出错的情况下,会有 err 的值,表示出错信息;但要注意的是,使用 get 命令时,需要判断一下是否为 ngx.lua ,否则后续处理就可能会出现问题。而我遇到的问题,就是再判断没有出错的情况下,直接使用 cjson 解析,导致nginx 500错误。

总结

最近总是充当救火队员,在几经多手的代码上,修修补补,填坑挖坑,很多时候发现出错的问题都是一些很小的问题,甚至有些读一下文档就可以避免,但还是会被想当然地使用错。另外,缺乏规范,一人一库一风格,改起来也着实费劲。算下来自己也快有两年的 ngx-lua 经验,但规范还是要多看看春哥的代码,多看多学习~

原文  http://www.hackcv.com/index.php/archives/106/
正文到此结束
Loading...