写一部导演¶
Varnish已经提供了一组通用的控制器,从Varnish 4开始,它被捆绑在内置的 VMOD导向器-Varnish导向器模块 。编写导向器归根结底是使用适当的数据结构和API编写VMOD。如果没有一个内置组件满足您的需求,您不仅可以编写自己的控制器,而且从Varnish 4.1开始,您甚至可以编写自己的后端。
后端可以分为以下几类:
静态:在VCL中声明的本机后端
动态:由VMOD创建的本机后端
定制:由VMOD创建和完全管理的后端
后端与控制器¶
后端和定向器的直观分类是前者的端点和后者的负载均衡器,但实际实现要稍微微妙一些。VMOD可以接受后端参数并在VCL中返回后端(请参见 VCL和C数据类型 ),但底层的C类型是 struct director
也就是 VCL_BACKEND
泰德福。在引擎盖下,导演是一个通用的概念,后端是一种导演。
在这一点上,两者之间的界限有点模糊,让我们来看看一些代码::
// VRT interface from vrt.h
struct vdi_methods {
unsigned magic;
#define VDI_METHODS_MAGIC 0x4ec0c4bb
const char *type;
vdi_http1pipe_f *http1pipe;
vdi_healthy_f *healthy;
vdi_resolve_f *resolve;
vdi_gethdrs_f *gethdrs;
vdi_getip_f *getip;
vdi_finish_f *finish;
vdi_event_f *event;
vdi_release_f *release;
vdi_destroy_f *destroy;
vdi_panic_f *panic;
vdi_list_f *list;
};
struct director {
unsigned magic;
#define DIRECTOR_MAGIC 0x3336351d
void *priv;
char *vcl_name;
struct vcldir *vdir;
struct lock *mtx;
};
一名董事可以概括为:
作为一种特殊的
type
具有一组对该特定类型的所有实例都相同的操作某些特定于实例的属性,如
vcl_name
和type
-特定的私有数据
两者之间的区别是 load balancing 导演和一名 backend 导演主要是他们要执行的职能。
实施导向器的基本步骤包括:
实施所需的功能
填写一份
struct vdi_methods
使用您的控制器类型和函数指针的名称存在一种
healthy
回调表示控制器具有某种动态确定其健康状态的方法。在构造函数或其他初始化例程中,分配和初始化特定于控制器的配置状态(也称为私有数据)并调用
VRT_AddDirector()
你的struct vdi_methods
、指向您所在州的指针和您的Director实例名称的打印格式实现返回的方法或函数
VCL_BACKEND
在析构函数或其他终结器中,调用
VRT_DelDirector()
实施
destroy
回调以摧毁实际的董事私有状态。它将在对导演的所有引用都消失时被调用,在此之前,私有状态必须保持不变vdi_methods
可调用的函数(但它们可能返回错误)。
虽然VMOD可以实现返回导向器的功能, 对象和方法 通常是更自然的表示,其中vmod对象实例是或引用导向器私有数据。
负载平衡控制器¶
如中所示 VMOD导向器-Varnish导向器模块 ,您可以编写将共享相同角色的后端分组的董事,并根据策略选择他们。如果您需要的不只是内置的策略(循环、散列等),即使它们可以堆叠在一起,您也可以编写自己的策略。
在这种情况下,您只需实现 resolve
为导演发挥作用。导演们一直在走访,直到找到一位叶导演。一位叶导演没有 resolve
函数,用于实际发出后端请求,就像您在VCL中声明的后端一样。
load balancing 董事们使用 VRT_Assign_Backend()
引用其他董事的意见。他们 must 实施 release
回调,它必须释放对其他控制器的所有引用,并确保在返回后不获取任何引用。
静态导向器¶
与下面介绍的动态后端不同,保证具有VCL生存期(即,它们在VCL变冷之前不会被销毁)的控制器可以调用 VRT_StaticDirector()
以避免引用计数开销。
动态后端¶
如果您想在TCP或UDS上使用HTTP/1,但由于某种原因VCL不适合,那么您可以重新使用整个后端工具。例如,它允许您按需添加和删除后端,而无需重新加载您的VCL。然后,您可以利用您的供应系统。
请考虑以下代码片段:
backend default {
.host = "localhost";
}
VCL编译器将此声明转换为 struct vrt_backend
。加载VCL时,Varnish调用 VRT_new_backend
(或者更确切地说 VRT_new_backend_clustered
为了提高VSM效率),以便创建导向器。Varnish没有为实际的后端公开它的数据结构,只有控制器抽象和动态后端是像静态后端一样构建的,一个 struct 一次来一次。你可以去掉那些 struct vrt_backend
一旦你有了 struct director
。
(动态)后端不能超过其VCL的寿命,因为原生后端 owned 由VCLS提供。尽管动态后端的寿命不能超过其VCL,但可以使用以下命令随时删除它 VRT_delete_backend
。一旦丢弃,VCL会删除剩余的后端,您不需要打理它。
引用计数用于确保不再引用的后端被销毁。
最后,Varnish将负责以下方面的事件传播 all 原生后端,但动态后端只能在VCL处于热状态时创建。如果您的后端是由独立线程创建的(基本上在VCL作用域之外),则必须订阅VCL事件并监视VCL状态(请参见 事件函数 )。如果你试图在冷的VCL上创建一个后端,Varnish将会死机 VRT_new_backend
会回来的 NULL
如果VCL正在冷却。此外,我们亦鼓励您遵守 VCL温度 总体而言。
健康探测仪¶
在VCL程序中,可以查询控制器的运行状况(请参见 Bool Healthy(后端BE) )。如果一个董事实现了 healthy
功能,否则它总是被认为是健康的。
除非您正在制作动态后端,否则您需要自己照顾健康探头。为 load balancing 董事,健康通常意味着至少有一个健康的底层后端或董事。
对于动态后端,只需将 probe
字段中的 struct vrt_backend
。一旦创建了控制器,也不再需要探测定义。然后,Varnish将负责运行状况探测器并禁用冷VCL上的功能(请参见 事件函数 )。
无需初始化您自己的探测器定义,您可以获得一个 VCL_PROBE
直接从VCL构建(请参见 VCL和C数据类型 )。
自定义后端¶
如果您想实现自定义后端,请看一看Varnish如何实现本机后端。它是规范的实现,尽管它提供其他服务,如连接池或统计,但它本质上是一个控制器,它的状态是 struct backend
。Varnish本地后端目前通过TCP或UDS使用HTTP/1,因此,如果您希望Varnish执行其他操作,例如通过UDP连接或使用不同的协议,则需要创建自己的自定义后端。
如果您想利用VCL中的探测器声明,因为它们只是规范,所以具有可重用的优势,您可以。但是,您需要从头开始实现整个探测基础设施。
您还可以考虑使您的自定义后端与VCL状态兼容(请参见 事件函数 )。
如果您正在实现 gethdrs 方法(即,您的后端能够生成后端响应以在 vcl_backend_response ),您将希望记录响应代码、协议和它将创建的各种标头,以便于调试。对于这一点,您可以查看 VSL* 中列出的函数族 cache/cache.h 。
数据结构注意事项¶
在创建自定义后端时,您可能希望提供本机后端的语义。在这种情况下,您可以使用宏,而不是在数据结构之间重复冗余字段 VRT_BACKEND_FIELDS
和 VRT_BACKEND_PROBE_FIELDS
一下子把它们都宣布出来。这是Varnish用来在 struct vrt_backend
以及它的内部数据结构。
可以使用宏自动执行复制 VRT_BACKEND_HANDLE
和 VRT_BACKEND_PROBE_HANDLE
。您可以了解如何在Varnish代码库中使用它们。