作者存档: 朱坤乾 - 第5页

减少mongod占用的内存

日志服使用的mongod,发现其中一台上占用内存比较多:

google之,发现如果开启journal时,会导致内存占用过多,同时也会有journal文件占用硬盘空间。

因为我们的日志并不是关键数据,允许故障时丢失。所以首先要关闭mongod的journal。

如果在启动时,可以指定: –nojournal 来关闭。

另外,如果内存占用过多,可以定时调用以下命令来释放缓存:

use admin;

db.runCommand({closeAllDatabases:1})

assetbundle打包

终于开始处理每个项目都会遇到的assetbundle的问题了。

研究了一下,还是使用传统的手动代码打包方式,好处是可以更细粒度的掌控好资源分包。

而且打包时,有些资源必须提取为公共包。

举例:

1、两个UI,打两个assetbundle包,如果将依赖全打进去,则会发现,unityengine.ui.dll两个包都被打进去了。遇到这种情况,我们就可以将重复资源提取出来,打为一个公共包。

如果打为公共包,则如何组织包的结构是一个大问题。

现在初步的想法是,最大限度的避免重复的资源,如果资源分的太细,导致某个assetbundle依赖过多时,则使用多线程将文件读入内存(避免读取过慢导致耗时过长),单线程内存中加载。

备用方案,最细粒度打包资源,在玩家手机上合并资源为一个拥有所有依赖的整包,这样也可以同时避免了加载依赖导致的耗时。只是会在玩家第一次打开游戏时,会有一个合并包的过程。

unity中的SceneCamera

在设置场景相机时,发现使用GameObject.Find(“SceneCamera”)获得了一个对象,很奇怪的是场景中并没有这个对象。

测试一下, 发现应该是SceneView中的camera,竟然连各种文档上都找不到对应的描述,应该是unity自己保留的对象,连用FindByType都无法查询到这个对象,却通过名字可以直接获取到。

 

考虑引入udp

udp传输在手机网络环境下,比tcp可以获得更小的延迟。

以后游戏考虑引入udp。

推荐两个:

KCP同 UDT/ENET的性能比较

https://github.com/cloudwu/rudp

关于网络同步的一篇文章: http://www.skywind.me/blog/archives/1343#more-1343

另外还确定一件事情。

如果要获得最好的用户体验,客户端必须实现不会因为等待某个消息返回而处于停顿状态。

这里要求开发时要支持消息非顺序到达。

非顺序到达可以,可以先放入一个消息队列中,然后等待丢失的消息到达。但似乎逻辑处理起来,还是需要按消息顺序处理对开发人员更方便。

1、网络层消息可以非顺序到达。

2、业务逻辑按顺序处理消息。

为skynet添加lua-cjson库

skynet早期版本有lua-cjson库,后来使用sproto取代了cjson,也直接将代码移除,但游戏中还是有json的需求。

lua5.3开始支持整形,但cjson并没有适配lua5.3, 如果直接编译使用会造成将json串中的数字转为浮点数。

所幸云风为cjson出一个补丁:https://github.com/mpx/lua-cjson/pull/22

当然如果感觉麻烦,还可以直接使用云风维护的一个分支:https://github.com/cloudwu/lua-cjson

 

为skynet添加syslog库

上个项目使用的syslog,发现效果很不错,也希望在skynet中添加syslog模块,顺便也搜索一下使用c为lua编写独立模块。

参考了一下skynet原有crypt模块的代码和lua文档,写的lua-syslog.c如下:

#include <syslog.h>

#include <lua.h>
#include <lauxlib.h>

static int
lsyslog(lua_State *L) {
        size_t sz = 0;
        const char * text = (const char *)luaL_checklstring(L,1, &sz);
        syslog (LOG_INFO, text);
        return 0;
}

int
luaopen_syslog(lua_State *L) {
        luaL_checkversion(L);
        luaL_Reg l[] = {
                { "log", lsyslog },
                { NULL, NULL}
        };
        luaL_newlib(L,l);
        return 1;
}

代码量并不大,非常合适我这种已经N年不写C代码的人。

使用make编译出syslog.so模块,放出的Makefile只供参考,因为和项目目录存放关联密切,并不是直接COPY就可以使用。

PLATS = linux macosx
.PHONY : $(PLATS) all clean skynet

CC ?= gcc
PLAT ?= linux

linux : PLAT = linux
macosx : PLAT = macosx

GSHARED = -fPIC --shared
CFLAGS = -g -O2 -Wall -I$(GLUA_INC)
macosx : GSHARED := -fPIC -dynamiclib -Wl,-undefined,dynamic_lookup

linux macosx :
        $(MAKE) all PLAT=$@ GSHARED="$(GSHARED)"
GLUA_INC ?= skynet/3rd/lua

GLUA_CLIB = cjson syslog
GLUA_CLIB_PATH ?= skynet/luaclib

all : skynet \
  $(foreach v, $(GLUA_CLIB), $(GLUA_CLIB_PATH)/$(v).so)

$(GLUA_CLIB_PATH)/cjson.so : | $(GLUA_CLIB_PATH)
        cd 3rd/lua-cjson && $(MAKE) LUA_INCLUDE_DIR=../../$(GLUA_INC) CC=$(CC) CJSON_LDFLAGS="$(GSHARED)" && cd ../.. && cp 3rd/lua-cjson/cjson.so $@

$(GLUA_CLIB_PATH)/syslog.so : 3rd/lua-syslog/lua-syslog.c | $(GLUA_CLIB_PATH)
        $(CC) $(CFLAGS) $(GSHARED) $^ -o $@
skynet :
        cd skynet && $(MAKE) CC=$(CC) $(PLAT)

clean :
        cd 3rd/lua-cjson && $(MAKE) clean
        cd skynet && $(MAKE) CC=$(CC) clean

测试代码:

package.cpath = "luaclib/?.so;"
                                .. "../luaclib/?.so;"
                                .. "../../luaclib/?.so;"
                                .. "../../../luaclib/?.so;"
                                .. "../../skynet/luaclib/?.so"

local log = require "syslog"

log.log("moon1 hello")
log.log("")
log.log("helloworld")

关于如何打开syslog及查看syslog,就不在这里多累述了,相信了解syslog的朋友已经对此很熟悉了。

如果使用mac os:

使用以下命令停止syslog
launchctl unload /System/Library/LaunchDaemons/com.apple.syslogd.plist 

使用以下命令启动syslog
launchctl unload /System/Library/LaunchDaemons/com.apple.syslogd.plist

接收log的服务上的配置,仅供参考。

$EscapeControlCharactersOnReceive off

$template TraditionalFormat1,"%msg:R,ERE,1,DFLT:[0-9a-zA-Z]+ (.*$)--end%\n"
        if re_match($syslogtag,'^game[0-9_a-zA-Z]+\\[[0-9]+\\]') then {
                $ActionFileDefaultTemplate TraditionalFormat1
                $template DynFile1,"/opt/logs/skynet-log/%syslogtag:R,ERE,1,DFLT:([0-9a-zA-Z]*).*--end%/%timegenerated:1:10:date-rfc3339%/%syslogtag:R,ERE,1,DFLT:([0-9a-zA-Z]*).*--end%-%msg:R,ERE,1,DFLT:([0-9a-zA-Z]+)--end%_%timegenerated:1:10:date-rfc3339%.log"
                *.* -?DynFile1
                stop
        }

后记:

最初想法是直接向本系统的syslog发送消息,然后使用syslog用udp转发至日志服。

进行压力测试时,发现在macos上syslogd有 -mps_limit 限制,默认是500/s, 用户进程默认是36000/小时。超出的消息直接丢弃掉了。

Mar 30 11:01:20 localhost game1[45275]: game moon1 2016-03-30 11:01:20 DEBUG hello world 36039 1459306880.61
Mar 30 11:01:20 localhost game1[45275]: game moon1 2016-03-30 11:01:20 DEBUG hello world 36040 1459306880.61
Mar 30 11:01:20 localhost game1[45275]: *** LOG MESSAGE QUOTA EXCEEDED - SOME MESSAGES FROM THIS PROCESS HAVE BEEN DISCARDED ***
Mar 30 11:01:21 localhost game1[45275]: game moon1 2016-03-30 11:01:21 DEBUG hello world 56029 1459306880.99
Mar 30 11:01:21 localhost game1[45275]: game moon1 2016-03-30 11:01:21 DEBUG hello world 56030 1459306880.99

转至linux上测试,也有相同的限制,想想也是合理:

Mar 30 11:18:13 iZu1fh2yq8yZ game1: game moon1 2016-03-30 11:18:13 DEBUG hello world 999 1459307893.8
Mar 30 11:18:13 iZu1fh2yq8yZ game1: game moon1 2016-03-30 11:18:13 DEBUG hello world 1000 1459307893.8
Mar 30 11:18:13 iZu1fh2yq8yZ game1: game moon1 2016-03-30 11:18:13 DEBUG hello world 1001 1459307893.8
Mar 30 11:18:43 iZu1fh2yq8yZ journal: Suppressed 320255 messages from /user.slice/user-0.slice
Mar 30 11:18:43 iZu1fh2yq8yZ game1: game moon1 2016-03-30 11:18:43 DEBUG hello world 321257 1459307923.32
Mar 30 11:18:43 iZu1fh2yq8yZ game1: game moon1 2016-03-30 11:18:43 DEBUG hello world 321258 1459307923.32

再测试一下直接使用udp发送至远程日志服务器:

1、查看了一下syslog中并没有提供函数可以直接udp远程进行发送,文档也说的很明白,如果要远程发送需要自己使用tcp或udp发送。

2、查看了一下syslog的udp协议,也很简单,正好skynet中支持udp,连c库都省的写了, http://tools.ietf.org/html/rfc5424

function test3()
	local c = socket.udp(function(str, from)
		print("client recv", str, socket.udp_address(from))
	end)
	socket.udp_connect(c, "10.230.10.102", 514)
	for i=1,20 do
		socket.write(c, "<190>1 2003-10-11T22:14:15.003Z HOSTNAME skynet 11 MESSAGTEID A " .. i)	-- write to the address by udp_connect binding
	end
end

rsyslog中的系统属性列表:http://www.rsyslog.com/doc/v8-stable/configuration/properties.html

使用udp连续发送100万日志,发送砂时18秒左右。7万/s 日志,可以接受。但发现UDP有丢失包的现象。

内网也会丢包~~,为了确认使用:tcpdump udp port 514 > 1.log 将收到数据包记录下来,然后进行对比,发现,确实在网络一层丢失包。继续测试tcp ~~~

继续改为tcp测试一下。

tcp文献索引:http://tools.ietf.org/html/rfc3164

发送和udp有一点不同,需要在消息结尾附带 \r\n表示一条消息的结束。

测试发现,竟然达到了10万/s 日志的性能,-.-!! 而且没有丢包。

一个抓取手机上gles渲染代码的工具

adreno profiler

高通出品,只能用在高通CPU的安卓手机上,非常棒。

IOS上可以使用 frame capture.

如果遇到问题:

Found a device, but no Adreno Profiler-enabled app.

用以下方式解决:

1、执行
adb shell setprop debug.egl.profiler 1
2、退出profiler,重新启动。

一般情况下,上面的问题都会解决,可以看到设置,虽然文档上写说profiler2.x, 会自动设置,不需要我们手动再执行一下。
我只想说,文档有时也不全对。

jenkens设置允许启动的进程不被kill掉

https://wiki.jenkins-ci.org/display/JENKINS/ProcessTreeKiller

java -Dhudson.util.ProcessTree.disable=<span class="code-keyword">true</span> -jar jenkins.war

linux下查看及修改客户端连接的端口号

[root@xyxm-iosgame-001 ~]# cat /proc/sys/net/ipv4/ip_local_port_range 
1024    65535

查看客户端分配的端口。因为游戏开发通常也需要绑定端口号,所有需要我们游戏绑定的端口号和socket连接分配的端口号不能冲突。

这里可以修改这个分配的范围:

#修改端户端允许分配的端口号范围
echo 32668 65535 > /proc/sys/net/ipv4/ip_local_port_range

unixbenchmark

游戏在越南服上,其中一个虚拟机上,一直说是玩家玩起来非常卡。

查了两天时间,终于确认那台虚拟机就是非常卡。

从网上找了一个benchmark工具,测试一下,明天把测试结果结果贴出来。

unixbench-5.1.2.tar

注意:

1、yum -y  install perl-Time-HiRes

2、如果没有图形界面,需要修改Makefile,将其中的 GRAPHIC_TESTS 注释掉。

 

以后最好新开服时,直接用这个脚本测试一下机器性能。避免入坑。

昨天晚上跑的结果,出问题的那台机器得分只有其它机器的30%左右。

 

 


Warning: Use of undefined constant XML - assumed 'XML' (this will throw an Error in a future version of PHP) in /opt/wordpress/wp-content/plugins/wp-syntaxhighlighter/wp-syntaxhighlighter.php on line 1048