Padding也要小心

为了在32位机器和64位机器之间传递状态消息,我们给消息格式做了padding:

struct StateMsg
{
uint32_t msgType;
uint32_t padding;
uint64_t msgID;
};

这样,不管是在32位机器上还是64位机器上,消息的大小都是16个字节。开始一切正常,直到后来我们发现有问题:程序里会比较本条状态消息与上一条有什么不同,如果不一样,要清空路由表;如果一样,就说明状态没有变化,于是不做任何操作。而错误出现在我们的消息比较用的是memcmp:

memcmp(oldMsg, newMsg, sizeof(struct StateMsg));

这下连padding也加入比较了,但是padding我们却没有对它赋初值!结果,每条消息都和上一条不同,路由表于是被频繁的清空....
padding本身是用来对齐的,对业务没有任何意义,所以赋值的时候容易忘掉它。教训啊。



====== 2010.12.1 ======

fix这个bug以后,在生产上我们上线了一部分机器,但是发现流量不均匀的问题依旧。照理说路由表被清空的已经不怎么频繁了,怎么还会流量不匀呢?

和架构师一起查这个问题又查了两周,才发现:原来我们的路由表是分段的,每个段都有单独的RoundRobin计数器,一旦路由表清空,这所有段的RoundRobin计数器都置0。线上的服务器很多,我们估算有50台,对应路由表中有400个段!一旦清空,假如来了400个消息,正好均匀分布到400个段上(这有可能发生),于是,这400个消息都从头开始RoundRboin。所以,一次清空路由表的影响,被这个分段机制给恶化了。

分段还是要的,解决方案不变,还是把所有的服务器上的软件都升到fix bug的最新版本。只要“路由表频繁清空”这个根源解掉,后继的问题就都会消失。

找了个周一的下午,和PE一起升级,最后看到流量慢慢恢复均匀了。长达半年的bug终于落地。


相关文章

分类

3 Comments

woso said:

typedef struct StateMsg {
uint32_t msgType;
uint64_t msgID;
} attribute((aligned(sizeof(uint64_t))));
这样就可以了吧

DongHao Author Profile Page said:

这个是编译器帮助把消息对齐为64位,那编译器能保证用于对齐的那部分内存初值为0吗?

woso said:

你说的对

留言:

关于文章

This page contains a single entry by DongHao published on 07 1, 2010 11:26 AM.

公用电话 was the previous entry in this blog.

旧事一则 is the next entry in this blog.

Find recent content on the main index or look in the 存档 to find all content.