OpenResty 中的 Redis 使用技巧

前言

  Redis 是非常流行的 NoSQL 数据库之一,因其高效、稳定、开源、数据结构丰富,深受业内钦赖。很幸运,OpenResty 也内置了对 Redis 的支持。
  在使用 OpenResty 的过程中,Redis 一直是主力存储方式之一。虽然 OpenResty 内置了 Redis 驱动,但在实际项目中,对其进行进一步的封装,能更方便的使用和管理。
  在这个过程中,遇到了很多需要注意的点,也积累了一些技巧和经验,在此总结一下。

技巧

单例模式

  单例模式是对数据连接或数据查询工具类的常用处理模式。保持数据连接的单例好处很多,最重要的一点是确保了同一连接的复用,不会被重复打开浪费资源,也方便了连接的管理和状态维护。

阅读更多

妥善的处理重试请求

前言

  手机游戏项目中,由于用户在很多时间使用的是移动网络,和服务器连接不稳定在所难免。客户端发送给服务端的请求没接收到应答,也是经常碰到的情况。
  同样是没有接收到应答,是因为服务端未接收到请求,还是发送应答给客户端失败,客户端很难区分。对客户端来说,这两种情况几乎没有什么分别。
  这会带来一个问题:客户端在无法接收到应答的时候,是否发送重试请求?
  如果是因为服务端没收到请求造成的无应答,那么发送重试请求并没有什么问题。但如果是因为服务端发送应答给客户端失败造成的无应答,那么发送重试请求,会让服务端重复处理已处理过的请求。
  如果只是强化、升级这种请求,重复处理请求也许问题也不是太大。但如果是购买、消费这种请求,重复消费恐怕会引起玩家的重度不适,收到很多吐槽和投诉。

阅读更多

需要“局部变量化”全局函数么?

前言

  在很多的 Lua 语言相关的著作中都强调,在代码头部将代码里使用到的全局函数或者全局库局部变量化,将大大提升代码的执行效率。
  举个栗子,Roberto Ierusalimschy《Lua Programming Gems》 的第二章 Lua Performance Tips 提到:

 除了一些明显的地方外,另有几处也可使用局部变量,可以助你挤出更多的性能。比如,如果在很长的循环里调用函数,可以先将这个函数赋值给一个局部变量。这个代码:

1
2
3
for i = 1, 1000000 do
local x = math.sin(i)
end

比如下代码慢 30%:

1
2
3
4
local sin = math.sin
for i = 1, 1000000 do
local x = sin(i)
end
阅读更多

巧设 Openresty 包含路径

路径的难题

  我在之前的一篇文章中提到,关于 OpenResty 中的文件包含路径,是个值得注意的问题。
  OpenResty 仅会将它自己的 lualib 目录加入 package.pathpackage.cpath,我们的项目目录需要自己处理。
  最初我曾经试过将 项目目录加入到 package.pathpackage.cpath 中,确实达到了目的。
  但在 nginx 上配置了第二个 server 并将它的目录也加入包含路径之后,由于 lua_code_cache 的存在,不同 server 间的相同相对路径的文件的缓存会互相冲突,导致 require 可能不能加载正确的文件。  

巧妙的方案

  其实解决方案来自 PHP 中 autoload 的启发,我使用了一些 nginx 配置和一个单独的函数用来加载项目中的文件。

阅读更多

关于 OpenResty 的两三事

基础原理

  Nginx 采用的是 master-worker 模型,一个 master 进程管理多个 worker 进程,基本的事件处理都是放在 woker 中,master 负责一些全局初始化,以及对 worker 的管理。
  每个 woker 使用一个 LuaVM,当请求被分配到 woker 时,将在这个 LuaVM 里创建一个 coroutine。协程之间数据隔离,每个协程具有独立的全局变量 _G

阅读更多