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终于落地。
相关文章
- fedora 9 小集 - 01 05, 2009
- 多线程调试 - 12 17, 2008
- fedora 9 试用 - 12 05, 2008
typedef struct StateMsg {
uint32_t msgType;
uint64_t msgID;
} attribute((aligned(sizeof(uint64_t))));
这样就可以了吧
这个是编译器帮助把消息对齐为64位,那编译器能保证用于对齐的那部分内存初值为0吗?
你说的对