V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
The Go Programming Language
http://golang.org/
Go Playground
Go Projects
Revel Web Framework
Aidenboss
V2EX  ›  Go 编程语言

搞了好久的,终于为 SDB 增加了 lua 脚本

  •  1
     
  •   Aidenboss · 2022-10-28 01:45:14 +08:00 · 1338 次点击
    这是一个创建于 551 天前的主题,其中的信息可能已经有所发展或是发生改变。

    SDB 背后的思考 ———— lua 脚本支持


    lua 脚本是酷炫的,Redis 、Nginx 等开源项目都可以内嵌 lua 实现业务逻辑。所以 SDB 也打算支撑 lua 脚本。还好找到了优秀的开源项目:gopher-lua

    初始化

    L := lua.NewState()
    defer L.Close()
    

    方法注册

    将 SDB 的方法注册到 lua 脚本中,以 LCount 为例子:

    L.SetGlobal("LCount", L.NewFunction(func(L *lua.LState) int {
    	userKey := L.CheckString(1)
    	luaLogger.Printf("[LCount] userKey: %s", userKey)
    
    	res, err := luaService.list.Count(batch, []byte(userKey))
    	if err != nil {
    		L.RaiseError("%s", err)
    	}
    	L.Push(lua.LNumber(res))
    	return 1
    }))
    

    如何保证事务操作?

    lua 脚本是灵活的,在上面我们可以写很多的业务逻辑,如果我们在 lua 中用了:LLPush 、LRPush 如何能保证多个方法是操作是事务的呢?也比较简单,我们只需要创建一个 batch 对象,执行完我们的 lua 脚本后进行 commit 。保证执行每一次脚本是事务的。

    加锁逻辑?

    这其实是最容易被忽略的一点。对比 Redis 来说,由于是单线程的,所以 lua 脚本是不需要考虑锁的。

    但是 SDB 不同,SDB 首先是支持多线程的,那么对 userKey 的写操作会进行加锁。lua 脚本在某种程度上破坏了对单个 userKey 的加锁策略。

    首先 lua 脚本得让用户传入会操作的 userKey 列表,然后对每个 userKey 进行加锁。只有获取了所有锁,lua 脚本才能开始运行。

    但这是不够的,可能会出现死锁问题。如当一个 lua 脚本操作 a 、b 两个 userKey ,另一个 lua 脚本操作 b 、d 两个 userKey 。假设 d 和 a 的锁是同一把。就会出现死锁的问题。

    防止死锁的解决方法也很简单,只需要保证先对 lua 脚本的 userKey 按某种顺序依次获取锁既可。

    ClarkAbe
        1
    ClarkAbe  
       2022-10-28 09:00:38 +08:00 via Android
    这个库的 State 本身就不支持真正的并发,哪怕 Clone State 也是一样....在多个时间片段同时读写就会触发恐慌.....需要自己 fork 把里面一堆 map 全部改了才行......
    Aidenboss
        2
    Aidenboss  
    OP
       2022-10-28 09:17:51 +08:00
    @ClarkAbe 如果每个 lua 请求都是新的 State 呢
    lesismal
        3
    lesismal  
       2022-11-04 16:52:05 +08:00
    gopher-lua 的性能比较差,而且不管是 c 版还是 go 版的 lua 都不支持并发,多个 lua state 对性能提升意义也不大。另外,如果 lua 写复杂了 gopher-lua 的语法解析还可能出错、运行不正确。

    > 如果每个 lua 请求都是新的 State 呢

    @Aidenboss 这个成本就更高了,这会让你的程序慢太多了,只适合请求量低的系统。
    Aidenboss
        4
    Aidenboss  
    OP
       2022-11-05 01:55:56 +08:00
    @lesismal 嗯嗯,那看起来是:gopher-lua 不是并发安全的,但多个 state 是没问题的。至于性能,没有考虑的,如果要考虑限制下 lua 脚本的并发数量就好了。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   1851 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 26ms · UTC 00:48 · PVG 08:48 · LAX 17:48 · JFK 20:48
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.