本次服务端搬平台的一些体会。
以前的服务端是win32平台,STLport-5.1.4,boost-1.34.1,asio-0.3.8,apr的内存管理,消息池用的是MSMQ。
构架是loginserver,accountdb,gate,gamedb,gameserver,数据流向是:帐号密码->loginserver->accountdb->loginserver->client->选区->gate->gamedb->gate->client->选人->gate->gameserver
先说说现在的问题,win32平台就不说了^_^,也不谈stlport boost的效率问题,msmq也中规中矩,主要是apr的问题,使用的是这样的形式来做的内存管理
1
struct
cUser
2 {
3 apr_pool_t * pool;
4
5 char name[ 25 ];
6 ushort level;
7
8 };
9
10 // 申请
11 apr_pool_t * pool = 0 ;
12 apr_pool_create(_mainpool, & pool);
13 cUser * user = (cUser * )apr_pcalloc(pool, sizeof (cUser));
14 user -> pool = pool;
15 strcpy_s(user -> name, " test " );
16 user -> level = 0 ;
17
18 // 释放
19 if (user)
20 {
21 if (user -> pool)
22 apr_pool_destory(user -> pool);
23 }
2 {
3 apr_pool_t * pool;
4
5 char name[ 25 ];
6 ushort level;
7
8 };
9
10 // 申请
11 apr_pool_t * pool = 0 ;
12 apr_pool_create(_mainpool, & pool);
13 cUser * user = (cUser * )apr_pcalloc(pool, sizeof (cUser));
14 user -> pool = pool;
15 strcpy_s(user -> name, " test " );
16 user -> level = 0 ;
17
18 // 释放
19 if (user)
20 {
21 if (user -> pool)
22 apr_pool_destory(user -> pool);
23 }
服务端运行过程中很偶尔会出现user->pool为空,因为释放是程序结束时统一释放,所以没有理由怀疑释放错误,只能是内存越界,比如
1
apr_pool_t
*
pool
=
0
;
2 apr_pool_create(mainpool, & pool);
3
4 cUser * user = (cUser * )apr_pcalloc(pool, sizeof (cUser) * 20 );
5
6 for ( int i = 0 ; i < 20 ; i ++ )
7 user[i].pool = pool;
8
9 // 这只是个示例,当然不会有人这么做
10 // 假设cUser最后一个变量是 char temp[100];
11 struct cUser
12 {
13 apr_pool_t * pool;
14
15 char name[ 25 ];
16 ushort level;
17 char temp[ 100 ];
18 };
19 memcpy(user[ 0 ].temp, " test " , 104 );
20 // 这个时候user[1]的pool就是空的了。
2 apr_pool_create(mainpool, & pool);
3
4 cUser * user = (cUser * )apr_pcalloc(pool, sizeof (cUser) * 20 );
5
6 for ( int i = 0 ; i < 20 ; i ++ )
7 user[i].pool = pool;
8
9 // 这只是个示例,当然不会有人这么做
10 // 假设cUser最后一个变量是 char temp[100];
11 struct cUser
12 {
13 apr_pool_t * pool;
14
15 char name[ 25 ];
16 ushort level;
17 char temp[ 100 ];
18 };
19 memcpy(user[ 0 ].temp, " test " , 104 );
20 // 这个时候user[1]的pool就是空的了。
因为构架是我做的,具体逻辑不是我写的,在几十万行代码里一点一点跟哪里出错实在太渺茫,而且有点怀疑apr内部是否有bug,因为看错误的内存,明显整个user都是被apr_pool_destroy掉的。so。。这次不用apr了,那么大个库使用一个apr_pool是有点杀鸡牛刀的感觉。
这次简简单单定义
void
*
mem_alloc(size_t size);
void * mem_realloc( void * p, size_t size);
void mem_free( void * p);
// 实现
void * mem_alloc(size_t size)
{
void * p = 0 ;
p = malloc(size);
#ifdef _DEBUG
if (p)
memset(p, 0 , size);
#endif
return p;
}
void * mem_realloc( void * p, size_t size)
{
void * p = 0 ;
p = realloc(p, size);
return p;
}
void mem_free( void * p)
{
if (p)
{
free(p);
p = 0 ;
}
}
void * mem_realloc( void * p, size_t size);
void mem_free( void * p);
// 实现
void * mem_alloc(size_t size)
{
void * p = 0 ;
p = malloc(size);
#ifdef _DEBUG
if (p)
memset(p, 0 , size);
#endif
return p;
}
void * mem_realloc( void * p, size_t size)
{
void * p = 0 ;
p = realloc(p, size);
return p;
}
void mem_free( void * p)
{
if (p)
{
free(p);
p = 0 ;
}
}
当然后面打算带上gc,暂时直接申请内存方便valgrind挑错。
构架的问题就大了,一开始的设计是单loginserver多gate,单gate对单gameserver,后来发现一个gameserver带30几张地图,跑5000+npc简直就是自残,于是改,改单gate带多gameserver,问题来了,我们的构架是gamedb只和gate联系,一旦跨地图组队,user信息就要从一个gameserver带到gate再发给另一个gameserver,以前只考虑了由gate保存user信息,gameserver只是一份copy,更新数据方便,但是现在gate的负担超级重。
还有数据库问题,用的oracle,oci直接操作,accountdb没问题,gamedb是来了请求就去数据库拿或者写,没有做user的缓存,而且是整个user结构体带来带去,通信量特别大。结果是经常报告statement操作的游标过多,提高oracle的64个游标数量只是暂时解决方案。经常选了服就卡住,拿不到人物信息。
最主要就是msmq轮询取消息process的时候没有用阻塞模式(或者没有阻塞模式?)
1
if
(
0
==
MSMQGetMessage())
2 {
3 Sleep( 1 );
4 }
5 else
6 {
7 Process_Packet();
8 }
2 {
3 Sleep( 1 );
4 }
5 else
6 {
7 Process_Packet();
8 }
问题出在这个sleep(1)上了,不sleep,4个msmq线程,npc的process被抢的什么都干不成,sleep的话cpu就死活利用不上去。懒得找msmq的阻塞模式了。
还有就是设计上的问题了,比如
1
struct
User_Save_Info
2 {
3 char name[ 25 ]; // 没问题,12个中文字的名字。
4 int gender; // 性别,大哥,你有42亿种性别么?
5 int facestyle; // 脸型,同上
6 int hairstyle; // 发型,同上
7 // 后面类似的不说了。
8 };
2 {
3 char name[ 25 ]; // 没问题,12个中文字的名字。
4 int gender; // 性别,大哥,你有42亿种性别么?
5 int facestyle; // 脸型,同上
6 int hairstyle; // 发型,同上
7 // 后面类似的不说了。
8 };
我就说策划大哥们,我为了省包头的2字节绞尽脑汁,你们可好。。。无语了。。。
Item_Info_Save是存装备的,我们的装备有随机属性,但是他们居然把装备的通用属性都由服务器来发,最郁闷的是设计npc死亡掉落物品数量达到50件。。。就是一个npc死亡,我需要发8(小队人数)*50(装备个数)*sizeof(Item_Info_Save)(这个sizeof至少100字节)。。。
ok问题暂时说到这里,下一贴说重构后的改动。