[master] ab34ea9f2 update and (hopefully) improve the directors dev guide

Nils Goroll nils.goroll at uplex.de
Wed Sep 12 17:44:09 UTC 2018


commit ab34ea9f24235952596fce211f9a9b05a9ddd77d
Author: Nils Goroll <nils.goroll at uplex.de>
Date:   Wed Sep 12 19:41:25 2018 +0200

    update and (hopefully) improve the directors dev guide
    
    Much more could be said, but I hope this helps understand the
    overall concepts a bit better.
    
    I've also taken the freedom to reword "cluster" in the director
    concept to "load balancer" because at least in my experience, the
    former is used more for some form of tighter binding between nodes,
    while the latter is a common term for what directors usually do.

diff --git a/doc/sphinx/reference/directors.rst b/doc/sphinx/reference/directors.rst
index 10e41d6ae..b359133ae 100644
--- a/doc/sphinx/reference/directors.rst
+++ b/doc/sphinx/reference/directors.rst
@@ -21,45 +21,78 @@ Backends vs Directors
 =====================
 
 The intuitive classification for backend and director is an endpoint for the
-former and a cluster for the latter, but the actual implementation is a bit
+former and a loadbalancer for the latter, but the actual implementation is a bit
 more subtle. VMODs can accept backend arguments and return backends in VCL (see
-:ref:`ref-vmod-vcl-c-types`), but the underlying C type is ``struct director``.
+:ref:`ref-vmod-vcl-c-types`), but the underlying C type is ``struct director``
+aka the ``VCL_BACKEND`` typedef.
 Under the hood director is a generic concept, and a backend is a kind of
 director.
 
 The line between the two is somewhat blurry at this point, let's look at some
 code instead::
 
+    // 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_destroy_f                   *destroy;
+        vdi_panic_f                     *panic;
+        vdi_list_f                      *list;
+    };
+
     struct director {
-            unsigned                magic;
-    #define DIRECTOR_MAGIC          0x3336351d
-            const char              *name;
-            char                    *vcl_name;
-            vdi_http1pipe_f         *http1pipe;
-            vdi_healthy_f           *healthy;
-            vdi_resolve_f           *resolve;
-            vdi_gethdrs_f           *gethdrs;
-            vdi_getbody_f           *getbody;
-            vdi_getip_f             *getip;
-            vdi_finish_f            *finish;
-            vdi_panic_f             *panic;
-            void                    *priv;
-            const void              *priv2;
+        unsigned                        magic;
+    #define DIRECTOR_MAGIC              0x3336351d
+        unsigned                        sick;
+        void                            *priv;
+        char                            *vcl_name;
+        struct vcldir                   *vdir;
     };
 
 A director can be summed up as:
 
-- a name (used for panics)
-- a VCL name
-- a set of operations
-- the associated state
+- being of a specific ``type`` with a set of operations which is
+  identical for all instances of that particular type
+- some instance specific attributes such as a ``vcl_name``, health
+  state and ``type``\ -specific private data
+
+The difference between a *load balancing* director and a *backend*
+director is mainly the functions they will implement.
+
+The fundamental steps towards a director implementation are:
+
+- implement the required functions
+- fill a ``struct vdi_methods`` with the name of your director type
+  and your function pointers
+- in your constructor or other initialization routine, allocate and
+  initialize your director-specific configuration state (aka private
+  data) and call ``VRT_AddDirector()`` with your ``struct
+  vdi_methods``, the pointer to your state and a printf format for the
+  name of your director instance
+- implement methods or functions returning ``VCL_BACKEND``
+- in your destructor or other finalizer, call ``VRT_DelDirector()``
 
-The difference between a *cluster* director and a *backend* director is mainly
-The functions they will implement.
+For forwards compatibility, it is strongly recommended for the last
+step not to destroy the actual director private state, but rather
+implement and declare in ``struct vdi_methods`` a ``destroy``
+callback.
 
+While vmods can implement functions returning directors,
+:ref:`ref-vmod-vcl-c-objects` are usually a more natural
+representation with vmod object instances being or referring to the
+director private data.
 
-Cluster Directors
-=================
+Load Balancing Directors
+========================
 
 As in :ref:`vmod_directors(3)`, you can write directors that will group
 backends sharing the same role, and pick them according to a strategy. If you
@@ -75,9 +108,10 @@ request, just like the backends you declare in VCL.
 Dynamic Backends
 ================
 
-If you want to speak HTTP/1 over TCP, but for some reason VCL does not fit the
-bill, you can instead reuse the whole backend facility. It allows you for
-instance to add and remove backends on-demand without the need to reload your
+If you want to speak HTTP/1 over TCP or UDS, but for some reason VCL
+does not fit the bill, you can instead reuse the whole backend
+facility. It allows you for instance to add and remove backends
+on-demand without the need to reload your
 VCL. You can then leverage your provisioning system.
 
 Consider the following snippet::
@@ -86,25 +120,24 @@ Consider the following snippet::
         .host = "localhost";
     }
 
-The VCL compiler turns this declaration into a ``struct vrt_backend``. When the
-VCL is loaded, Varnish calls ``VRT_new_backend`` in order to create the
-director. Varnish doesn't expose its data structure for actual backends, only
-the director abstraction and dynamic backends are built just like static
-backends, one *struct* at a time. You can get rid of the ``struct vrt_backend``
-as soon as you have the ``struct director``.
-
-A (dynamic) backend can't exceed its VCL's lifespan, because native backends
-are *owned* by VCLs. Though a dynamic backend can't outlive its VCL, it can be
-deleted any time with ``VRT_delete_backend``. The VCL will delete the remaining
-backends once discarded, you don't need to take care of it.
-
-.. XXX Consider using an object (see :ref:`ref-vmod-objects`) to manipulate dynamic
-
-Consider using an object to manipulate dynamic
-backends. They are tied to the VCL life cycle and make a handy data structure
-to keep track of backends and objects have a VCL name you can reuse for the
-director. It is also true for *cluster* directors that may reference native
-backends.
+The VCL compiler turns this declaration into a ``struct
+vrt_backend``. When the VCL is loaded, Varnish calls
+``VRT_new_backend`` (or rather ``VRT_new_backend_clustered`` for VSM
+efficiency) in order to create the director. Varnish doesn't expose
+its data structure for actual backends, only the director abstraction
+and dynamic backends are built just like static backends, one *struct*
+at a time. You can get rid of the ``struct vrt_backend`` as soon as
+you have the ``struct director``.
+
+A (dynamic) backend can't exceed its VCL's lifespan, because native
+backends are *owned* by VCLs. Though a dynamic backend can't outlive
+its VCL, it can be deleted any time with ``VRT_delete_backend``. The
+VCL will delete the remaining backends once discarded, you don't need
+to take care of it.
+
+.. XXX this does not quite work yet because the deleted backend could
+   be referenced, but at least that's where we want to get to. See
+   also https://github.com/varnishcache/varnish-cache/pull/2725
 
 Finally, Varnish will take care of event propagation for *all* native backends,
 but dynamic backends can only be created when the VCL is warm. If your backends
@@ -116,7 +149,7 @@ is cooling. You are also encouraged to comply with the
 :ref:`ref_vcl_temperature` in general.
 
 
-.. _ref-writing-a-director-cluster:
+.. _ref-writing-a-director-loadbalancer:
 
 Health Probes
 =============
@@ -125,9 +158,10 @@ It is possible in a VCL program to query the health of a director (see
 :ref:`func_healthy`). A director can report its health if it implements the
 ``healthy`` function, it is otherwise always considered healthy.
 
-Unless you are making a dynamic backend, you need to take care of the health
-probes yourselves. For *cluster* directors, being healthy typically means
-having at least one healthy underlying backend or director.
+Unless you are making a dynamic backend, you need to take care of the
+health probes yourselves. For *load balancing* directors, being
+healthy typically means having at least one healthy underlying backend
+or director.
 
 For dynamic backends, it is just a matter of assigning the ``probe`` field in
 the ``struct vrt_backend``. Once the director is created, the probe definition
@@ -138,19 +172,18 @@ probe and disable the feature on a cold VCL (see
 Instead of initializing your own probe definition, you can get a ``VCL_PROBE``
 directly built from VCL (see :ref:`ref-vmod-vcl-c-types`).
 
-What's the difference ?
-
 
 Custom Backends
 ===============
 
 If you want to implement a custom backend, have a look at how Varnish
-implements native backends. It is the canonical implementation, and though it
-provides other services like connection pooling or statistics, it is
-essentially a director which state is a ``struct backend``. Varnish native
-backends currently speak HTTP/1 over TCP, and as such, you need to make your
-own custom backend if you want Varnish to do otherwise such as connect over
-UDP or UNIX-domain sockets or speak a different protocol.
+implements native backends. It is the canonical implementation, and
+though it provides other services like connection pooling or
+statistics, it is essentially a director which state is a ``struct
+backend``. Varnish native backends currently speak HTTP/1 over TCP or
+UDS, and as such, you need to make your own custom backend if you want
+Varnish to do otherwise such as connect over UDP or speak a different
+protocol.
 
 If you want to leverage probes declarations in VCL, which have the advantage of
 being reusable since they are only specifications, you can. However, you need


More information about the varnish-commit mailing list