使用 Graylog 之前试过很多方案,包括流行的 ELK,也用过 fluentd 搭配各种存储,influxdb, mongodb 等等。但这些方案在日志量大了之后出现性能瓶颈都没有提供解决方案。而 Graylog 作为整合方案,使用 elasticsearch 存储,mongodb 缓存,带流量控制 (throttling),简单易用的查询界面,方便的管理界面,易于扩展。转移到 Graylog 省心了不少。在使用过程中积累了些经验,准备陆续分享出来。

第一篇是关于如何安装 Graylog。

最近把 Graylog 升级到集群。因为使用了 syslog UDP 作为输入,所以需要做个 UDP 的负载均衡。因为机器在阿里云,所以首先是创建了个阿里云内网的 UDP 负载均衡,但是发现负载不平均,而且也没办法关闭检测连接的心跳包。而常见的 HTTP 负载均衡工具 HAProxy 不支持 UDP。最后发现 Nginx 是可以实现 UDP 负载均衡的。

Redis 比较常见的是作为读缓存。读取数据的时候检查 Redis 是否存在,存在的话缓存命中,不需要访问后端存储。没命中的话从后端存储中获得,并同时存入 Redis。写数据的时候直接写入后端存储,清除 Redis 中对应的缓存或者更新成新的值。这种模型可以安全的随时删除缓存中的内容而不会造成数据丢失,因为最新的数据一定是写入到后端存储里了。

但如果系统的瓶颈出现在了写入这块,上面的模型就没法解决了。稍加修改可以得到写缓存的模型:

  • 读的时候检查 Redis,如果 Redis 存在直接使用 Redis 中的数据,否则从后端存储中读取。
  • 写的时候只写入 Redis,通过消息队列通知后台任务把 Reids 中缓存的内容保存到后端存储中。
  • 后台任务监听消息队列,在把缓存内容保存成功之后从 Redis 中删除对应的内容。

任务队列可以使用 Redis 的 LIST 来实现,官方的 RPOPLPUSH – Redis 命令文档中已经很详细描述了如何实现一个可靠的消息队列。于是剩下的问题就是如何能保证安全的删除已经保存过的缓存?

最近在公司的一个 Cocos2D-X 项目中碰到一个问题,TTF 文本加描边后会变宽,而且很明显没有对齐,字和描边之间没齐,每个字的水平基准线也没有对齐。最后发现是排版的代码有问题,官方分支上已经修复,但是这个项目使用的是 quick 分支出来的社区版,所以手动把修改做了个补丁提交了个修复TTF 描边效果的 PR

在 Cocos2D-X 是 TTF 的排版是使用的开源库 FreeType 2,核心的实现基本都在 cocos/2d/CCFontFreeType.cpp 中的 FontFreeType::getGlyphBitmap。原理是通过 FreeType 为每个字生成位图,然后通过 FreeType 返回的排版信息放到合适的位置,而问题就出现加了描边之后,位置计算的不正确。

为了弄清楚原因,又去看了下相关的文档,了解了下 Cocos2D-X 具体是如何排版 TTF 的。

在上一次游戏测试中,因为用了新的机器,并且从 ansible 切换到了 salt stack,其中 nofile 相关的配置步骤漏掉了,结果所有进程的 nofile 限制是默认的 1024。结果就是当在线人数达到一定数据之后,出现大量 lua 找不到文件的错误,导致后来的玩家没法登录,已经在线的玩家也没法正常游戏。

开发服务端程序,nofile 是很重要的配置。它限制了一个进程最多能够打开的文件数量。对于高并发的服务,每个连接都会打开一些文件,尤其是使用像 Lua 这样的脚本语言,更是要打开大量的文件。

当前的限制可以使用 ulimit -a 查看。

要修改也比较简单,以 Ubuntu 为例,最简单的就是修改 /etc/security/limits.conf,在该文件中添加下面内容即可,不需要重启,新创建的进程会使用新的配置。

* hard nofile 1000000
* soft nofile 1000000

一图胜千言,通过截图加标注能够很直白的说明问题。不过有时候会碰到标注很多很复杂的情况,比如针对截图对 UI 或者游戏系统进行分析,这个时候结合思维导图就比较方便了。

OmniGraffle 是个图表绘制和图表绘制工具。通过结构化编辑,和自动图表风格,也可以作为思维导图工具。而使用锚点编辑的连接功能 ,可以在图片的对应位置上使用引导线来引出各个主题。

我写了不少 macOS 脚本来自动化我的工作。这个脚本可以是用的最多的。我用它来在各种 App 中,将当前选中的对象做为任务添加到 OmniFocus 中。通过捕获的链接可以在 OmniFocus 中直接打开相关的文档。

Vcpkg 是微软推出的用于在 Windows 上管理 C/C++ 库的工具。通过它能够方便的安装常用的 C/C++ 库,而且提供了 CMake 的集成。这使得使用 CMake 的项目在 Windows 下构建方便了很多,不需要自己手动去指定在 Windows 下如何找到依赖的库了。

不过实际使用中还是碰到一些问题。为了减少依赖,直接复制一个可执行程序就能在其它机器上运行,经常会需要静态链接依赖的库。而在 Windows 上使用 vcpkg 静态链接需要一些特殊的操作。

Concourse CI 是个很不错的开源持续集成工具,安装和上手都相当简单。如果没有在用 Gitlab 又想自己架设 CI 服务的话是个不错的选择。

Concouse CI 提供了 Docker 镜像,部署起来相当方便。不过可能会踩到一些坑。

公司主要用 skynet 和 cocos2d-x Lua 来开发游戏。两者都采用了嵌入 Lua 来开发。因为性能,要和原生代码交互等原因,需要在 Lua 和其它语言之间进行交互。最近做了挺多这样的工作,积累了一些心得,会陆续总结分享出来。

这一篇是 Lua C API 的简单介绍。