邮箱:oxwangfeng@qq.com
分类: 云计算
2016-01-15 19:35:37
目录
object乱码
描述
问题跟踪
主页乱码180s超时
描述
问题跟踪
Ats设置cache头部资源不可信
乱码出现active timeout原因
问题解决方案
主页乱码包括两个现象,一个是出现object乱码,一个是超过active timeout后连接才关闭,两者是同时出现的;下面分别介绍这两个问题。
object乱码
描述
客户端从ATS请求object,未命中需回源,源站object进行gzip压缩传输,ats缓存对象响应客户端;然后,源站object资源清空;客户端再次请求ats拉取object,未命中回源,这次object为空,更新缓存;这时,客户端再次请求ats拉取object,出现乱码。
问题跟踪
乱码的没有经过openWriteMain,也就是没有将数据data写入cache;
跟踪vc->f.rewrite_resident_alt=true:
初始化情况下od->move_resident_alt =1.只有当304状态下才设置为0。但是在更新doc为空(total_len=0)情况下,又重新设置od->move_resident_alt
= 1.所以这儿需要修改的是在content length=0的情况下,将od->move_resident_alt
= 0;
CacheVC::updateVector(int /* event ATS_UNUSED */, Event
*/* e ATS_UNUSED */)
{
//正常情况下
if (update_key == od->single_doc_key && (total_len || !vec))
od->move_resident_alt = 0;
//当是乱码的时候od->move_resident_alt=1
if (od->move_resident_alt && first_buf._ptr() && !od->has_multiple_writers()) {
if (small_doc && have_res_alt && (fragment || (f.update && !total_len))) {
f.rewrite_resident_alt = 1;
}
}
}
2.将以前cache的data copy到新的cache buffer:
将原来cache的内容copy到buffer中,由于以前cache的data是gzip压缩的,而这次header是非gzip压缩,所以导致了乱码;
Proxy/http/CacheWrite.cc
static int
agg_copy(char *p, CacheVC *vc)//VolHeaderFooter
{
…
#ifdef HTTP_CACHE
if (vc->f.rewrite_resident_alt)
iobufferblock_memcpy(doc->data(), vc->write_len, res_alt_blk, 0);
else
#endif
iobufferblock_memcpy(doc->data(), vc->write_len, vc->blocks, vc->offset);
…
}
主页乱码180s超时
描述
上一个问题描述出现后,这时空object已经缓存,再次访问对象状态是cHs f命中。虽然object乱码立即返回,但是ats后台这次object访问连接没有释放,即HttpClientSession没有释放。就会发生180s超时后,连接关闭。超时时间配置文件可配置。
问题跟踪
Ats设置cache头部资源不可信
导致s->hdr_info.trust_response_cl 设置为false,即设置头部信息不可信:
当http访问命中缓存后,发现头部content-length的大小和cache object的size大小不一样的时候,设置s->hdr_info.trust_response_cl = false;
s->cache_info.object_read->object_size_get()和base->get_content_length() 两者大小不一样;
void
HttpTransact::handle_content_length_header(State* s, HTTPHdr* header, HTTPHdr* base)
{
DebugTxn("http_trans", "Content Length header and cache object size mismatch." "Disabling keep-alive");
s->hdr_info.trust_response_cl = false;
}
导致receive_chunked_response设置为true:
当cache的头部信息为不可信的时候, receive_chunked_response = true;当设置为不可信后,如果头部包含content-length,则删除;
void
HttpTransact::handle_response_keep_alive_headers(State* s, HTTPVersion ver, HTTPHdr* heads)
{
…
If(…. || s->hdr_info.trust_response_cl == false)) || …)
{
s->client_info.receive_chunked_response = true;
}
…
//make sure no content length header is send when transfer encoding is chunked
if ( s->client_info.receive_chunked_response ) {
s->hdr_info.trust_response_cl = false;
// And delete the header if it's already been added...
heads->field_delete(MIME_FIELD_CONTENT_LENGTH, MIME_LEN_CONTENT_LENGTH);
}
….
}
导致HttpTunnelProducer.chunking_action= TCA_CHUNK_CONTENT:
由于receive_chunked_response设置为true,导致HttpTunnelProducer.chunking_action= TCA_CHUNK_CONTENT
HttpSM::setup_cache_read_transfer()
{
…
if ( t_state.client_info.receive_chunked_response ) {
tunnel.set_producer_chunking_action(p,client_response_hdr_bytes,TCA_CHUNK_CONTENT);
tunnel.set_producer_chunking_size(p, t_state.txn_conf->http_chunking_size);
}
…
}
乱码出现active timeout原因
由于action为TCA_CHUNK_CONTENT,触发了p->do_chunking = true,进而设置c_write = INT64_MAX;然后在do_io_write中将往client net io写的字节数设置为INT64_MAX;在发送给client的过程中, 由于producer产生的object大小和消费者认为的大小不一致,所以event设置为VC_EVENT_WRITE_READY;所以一直处于ready状态,直到active timeout,连接关闭;
设置vio.nbytes= INT64_MAX:
Proxy/http/HttpTunnel.cc
HttpTunnel::producer_run(HttpTunnelProducer * p)
由于触发了如下代码:
if (action == TCA_CHUNK_CONTENT)
p->do_chunking = true;
… p855
if (p->do_chunking == true) {
c_write = INT64_MAX;
}
然后调用
c->vc->do_io_write(this, c_write, c->buffer_reader);
调用iocache/cache/Cache.cc:
VIO *
CacheVC::do_io_write(Continuation *c, int64_t nbytes, IOBufferReader *abuf, bool owner)
{
//此处将vio的nbytes即往client net io写的字节数设置为INT64_MAX
vio.nbytes = nbytes;
}
设置event 为VC_EVENT_WRITE_READY:
….
然后调用UnixNetVConnection.cc:
void
write_to_net_io(NetHandler *nh, UnixNetVConnection *vc, EThread *thread)
{
….
/*
ntodo=9223372036854775807,towrite=448..
*/
// signal write ready to allow user to fill the buffer
if (towrite != ntodo && buf.writer()->write_avail()) {
//由于producer产生的object大小和消费者认为的大小不一致,所以event设置为VC_EVENT_WRITE_READY
if (write_signal_and_update(VC_EVENT_WRITE_READY, vc) != EVENT_CONT) {
return;
}
….
//这个函数就是往fd里面发送数据了;
int64_t r = vc->load_buffer_and_write(towrite, wattempted, total_wrote, buf, needs);
…
}
导致active timeout
当状态为VC_EVENT_WRITE_READY时,启动消费者,启动write vio;也就是一直等待生产者往buffer里面填充数据;当等待超过active timeout的时候,就会触发VC_EVENT_INACTIVITY_TIMEOUT事件;
VC_EVENT_WRITE_READY:
case VC_EVENT_WRITE_READY:
this->consumer_reenable(c);
break;
case VC_EVENT_WRITE_READY:
server_entry->write_vio->reenable();
break;
断开连接:
当event为VC_EVENT_INACTIVITY_TIME
方案:网页出现乱码的根本原因是doc header中的content length和doc body中的实际长度不一致导致的,解决这个问题的关键是让doc header中的content length和doc body一致。
解决方法:
1. 当从二级cache接受到的header的content length=0,设置一个标志位flag=true;
2. 当写cache的时候,if flag = true,则doc 的data部分可以设置为null(即不往doc的data部分写数据);