varnish负载均衡的实现分析

本文深入剖析了Varnish缓存系统中的负载均衡机制,重点介绍了wrk_thread线程的功能及其实现过程,展示了Varnish如何高效处理HTTP请求并通过工作线程池分配任务。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Varnish负载均衡的分析

 

最近分析了varnis-2.0.4的一部分代码,主要侧重于其在负载均衡部分的实现。通过阅读一些参考文献,以及自己的一些见解我分析,将代码分析文档整理于此。

首先将varnish整体工作流程在此进行介绍。

1.        Varnish 的总体结构

 

Varnish 主要有两个进程:管理进程和 cache 子进程。

1)       管理进程主要就是对于varnish的整个工作状态进行的调整和设置。编译运行之后,它将建立一个守护进程varnishd。Varnishd不断folk()出cache子进程来处理HTTP请求。它的实现部分在源代码中bin/varnishd/目录中,主要文件有varnishd.c 、mgt.h、mgt_chld.c、mgt_param.cmgt_cli.h、mgt_pool.c 、mgt_vcc.c、mgt_cli.h、mgt_cli.c。

 

2)       下面谈谈cache子进程。

Cache子进程包含了实现命令行加载、请求处理、缓存以及负载均衡的所有线程。分别为:命令行接受处理线程(CLI_Run) ,放牧线程(wrk_herder_thread),放牧超时线程(wrk_herdtimer_thread),请求接受线程(vca_acct),数据接受线程(vca_main),很多工作线程(wrk_thread),HTTP对象超时线程(exp_timer),后台服务器连接探测线程(vbp_wrk_poll_backend)。

主要涉及到的文件有:cache_lck.c 、cache_panic.c、cache_cli.c、cache_fetch.c、cache_center.c、cache_vcl.c、cache_http.c、cache_session.c、cache_backend_cfg.c、cache_backend_pool.c、cache_backend.h、cache_pool.c、cache_expire.c、cache_hash.c、cache_accptor.c

Cache 子进程处理所有具体工作,各个线程的任务包括:

命令行接受处理线程(CLI_Run):接受从管理进程通过管道传过来的命令,做出相应决定。其中初始时由管理进程默认产生,三个命令(vcl.load、vcl.use、start)来启动后台服务器连接探测线程和两个接受线程。

放牧线程(wrk_herder_thread):用于产生工作线程池。线程不足时会增加线程池。

放牧超时检查线程(wrk_herdtimer_thread):清理一些工作超时的工作线程。

请求接受线程(vca_acct):接受 HTTP 初次请求,并叫醒某个工作线程,处理请求。

数据接受线程(vca_main):在发送数据以后,继续可能的再次请求,并把请求交给工作线程。

工作线程(wrk_thread):不断处理请求,进入状态机。如果缓存没有命中,还需要从后台服务取过数据,存入缓存并回复。然后把该连接通过管道转给数据接受线程并睡去。

HTTP对象超时检查线程(exp_timer):检查二叉堆中 HTTP 超时对象,删除之。

后台服务器连接探测线程(vbp_wrk_poll_backend):针对不同的后台服务器组进行轮询,检查存活与否。

各线程的工作流程大致如图一所示

图一:cache子进程各个线程流程图

 

2.        负载均衡实现的分析

 

就目前分析来看,Cache子进程的代码实现部分主要由cache_main.c这个文件为主要脉络的。Cache_main.c中将cache子进程的各个线程一一初始化。

 

目前我所关注的重点在于wrk_thread部分,它是实现varnish负载均衡的主要内容。

 

1)        wrk_thread的作用:不断处理请求,进入状态机。如果缓存没有命中,还需要从后台服务取过数据,存入缓存并回复。然后把该连接通过管道转给数据接受线程并sleep。

2)        wrk_thread的工作流程:

图二:cache子进程中,wrk_thread线程工作流程

3)       Wrk_thread的代码实现分析:wrk_thread线程在cache_main.c文件中初始化(代码:WRK_Init() ,cache_main.c,line121),具体实现在cache_pool.c文件中出现。

Cache_pool.c文件中主要函数有:

static void

wrk_addpools(const unsigned pools):增添work线程池

static void *

wrk_herder_thread(void *priv) :放牧进程,用于产生工作线程池。线程不足时会增加线程;

static void *

wrk_herdtimer_thread(void*priv):放牧超时检查线程,清理一些工作超时的工作线程。

static void

wrk_breed_flock(structwq *qp):在需要并且空间允许的情况下,产生新的线程

static void

wrk_decimate_flock(structwq *qp, double t_idle, struct varnish_stats *vs):检查空闲或者已经执行完的线程,从线程池中清除。

static void *

wrk_thread(void*priv):实际的工作线程,实现主要功能。

针对此函数,进行具体分析:

//摘自cache_pool.c//


//////////////////////////////////////////////////////////////////


static void *

wrk_thread(void *priv)

{

       struct worker *w, ww;

       struct wq *qp;

       unsigned char wlog[params->shm_workspace];

       struct SHA256Context sha256;

 

       THR_SetName("cache-worker");

       w = &ww;

       CAST_OBJ_NOTNULL(qp, priv, WQ_MAGIC);

       memset(w, 0, sizeof *w);

       w->magic = WORKER_MAGIC;

       w->lastused = NAN;

       w->wlb = w->wlp = wlog;

       w->wle = wlog + sizeof wlog;

       w->sha256ctx = &sha256;

       AZ(pthread_cond_init(&w->cond, NULL));

 

       VSL(SLT_WorkThread, 0, "%p start", w);

 

       Lck_Lock(&qp->mtx);

       qp->nthr++;

       while (1) {

              CHECK_OBJ_NOTNULL(w, WORKER_MAGIC);

 

              /* Process overflow requests, if any */

              w->wrq = VTAILQ_FIRST(&qp->overflow);

              if (w->wrq != NULL) {

                     VTAILQ_REMOVE(&qp->overflow, w->wrq, list);

                     qp->nqueue--;

              } else {

                     if (isnan(w->lastused))

                            w->lastused = TIM_real();

                     VTAILQ_INSERT_HEAD(&qp->idle, w, list);

                     Lck_CondWait(&w->cond, &qp->mtx);

              }

              if (w->wrq == NULL)

                     break;

              Lck_Unlock(&qp->mtx);

              AN(w->wrq);

              AN(w->wrq->func);

              w->lastused = NAN;

              w->wrq->func(w, w->wrq->priv);

              AZ(w->wfd);

              assert(w->wlp == w->wlb);

              w->wrq = NULL;

              Lck_Lock(&qp->mtx);

       }

       qp->nthr--;

       Lck_Unlock(&qp->mtx);

 

       VSL(SLT_WorkThread, 0, "%p end", w);

       if (w->vcl != NULL)

              VCL_Rel(&w->vcl);

       AZ(pthread_cond_destroy(&w->cond));

       if (w->srcaddr != NULL)

              free(w->srcaddr);

       if (w->nobjhead != NULL) {

              Lck_Delete(&w->nobjhead->mtx);

              FREE_OBJ(w->nobjhead);

       }

       if (w-> NULL)

              STV_free(w->nobj->objstore);

       return (NULL);

}

 

 

3.         参考文献

[1]      http://varnish-cache.org/  

[2]      http://varnish-cache.org/wiki/VarnishInternals

[3]      http://yaoweibin2008.blog.163.com/blog/static/11031392008102163141550/

[4]      http://yaoweibin.cn/maindoc/Varnish_cache.pdf

[5]      《Varnish应用技术指南V2.1》,Freeke 整理于2008-12-15

 

以上为目前分析varnish所得,发布在此欢迎探讨,以后会持续更新。

http://blog.chinaunix.net/uid-22969935-id-80586.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值