VMOD - Модули Varnish
Для всего, что вы можете сделать в VCL, есть вещи, которые вы не можете сделать. Например, поиск IP-адреса в файле базы данных. VCL предоставляет встроенный C-код, и там вы можете сделать все, но это не удобный или даже читабельный способ решения таких проблем.
Вот где вступают в игру VMOD: VMOD — это общая библиотека с некоторыми функциями C, которые можно вызывать из кода VCL.
Например:
import std;
sub vcl_deliver {
set resp.http.foo = std.toupper(req.url);
}
Модуль «std» — это модуль, который вы получаете с Varnish, он всегда будет там, и мы добавим в него функции «boutique», такие как функция «toupper», показанная выше. Полное содержимое модуля «std» документировано в vmod_std(3).
Эта часть руководства посвящена тому, как написать свой собственный VMOD, как работает языковой интерфейс между C и VCC, где можно найти сторонние VMOD и т. д. В этом объяснении будет использоваться VMOD «std» в качестве примера; иметь под рукой исходное дерево Varnish может быть хорошей идеей.
Директория VMOD
Директория VMOD содержит актуальную компиляцию поддерживаемых расширений, написанных для Varnish Cache:
Файл vmod.vcc
Интерфейс между вашим VMOD и компилятором VCL («VCC») и временем выполнения VCL («VRT») определен в файле vmod.vcc, который скрипт Python под названием «vmodtool.py» превращает в сложные C-структуры данных, выполняющие всю тяжелую работу.
Файл vmod.vcc для модулей std примерно такой:
$ABI strict $Module std 3 "Varnish Standard Module" $Event event_function $Function STRING toupper(STRANDS s) $Function STRING tolower(STRANDS s) $Function VOID set_ip_tos(INT)
Строка $ABI необязательна. Возможные значения — strict (по умолчанию) и vrt. Она позволяет указать, что VMOD интегрируется с благословленным vrt интерфейсом, предоставляемым varnishd, или углубиться в стек.
Как правило, если VMOD использует больше, чем VRT (Varnish RunTime), в этом случае его необходимо скомпилировать для конкретной версии Varnish, используйте strict. Если он соответствует VRT и его нужно перекомпилировать только при внесении изменений в API VRT, используйте vrt.
Строка $Module указывает имя модуля, раздел руководства, где будет находиться документация, и описание.
Строка $Event определяет необязательную функцию «Event», которая будет вызываться всякий раз, когда программа VCL, импортирующая этот VMOD, загружается или переходит в состояние «warm», «active», «cold» или «discarded». Подробнее об этом ниже.
Строки $Function определяют три функции в VMOD, вместе с типами аргументов, и именно там, вероятно, находится самая сложная часть написания VMOD, поэтому мы поговорим об этом подробно чуть позже.
Обратите внимание, что третья функция возвращает VOID, что делает ее «процедурой» в терминологии VCL, что означает, что она не может использоваться в выражениях, в правой части присваиваний и т. д. Вместо этого она может использоваться в качестве основного действия, чего не могут функции, возвращающие значение:
sub vcl_recv {
std.set_ip_tos(32);
}
Запуск vmodtool.py в файле vmod.vcc создает файлы «vcc_if.c» и «vcc_if.h», которые необходимо использовать для построения файла вашей общей библиотеки.
Забудьте о vcc_if.c везде, кроме вашего Makefile; вам никогда не придется беспокоиться о его содержимом, и вы определенно никогда не должны его изменять, это сразу аннулирует вашу гарантию.
Но vcc_if.h важен для вас; он содержит прототипы функций, которые вы хотите экспортировать в VCL.
Для модуля std скомпилированный файл vcc_if.h выглядит так:
VCL_STRING vmod_toupper(VRT_CTX, VCL_STRANDS); VCL_STRING vmod_tolower(VRT_CTX, VCL_STRANDS); VCL_VOID vmod_set_ip_tos(VRT_CTX, VCL_INT); vmod_event_f event_function;
Это ваши C-прототипы. Обратите внимание на префикс vmod_ в именах функций.
Имена аргументов и значения по умолчанию
Базовая синтаксическая конструкция объявления функций в vmod.vcc, представленная выше, делает все аргументы обязательными для вызовов из vcl — это подразумевает, что они должны передаваться в нужном порядке.
Именование аргументов, как в:
$Function BOOL match_acl(ACL acl, IP ip)
разрешает вызовы из VCL с именованными аргументами в любом порядке, например:
if (debug.match_acl(ip=client.ip, acl=local)) { # ...
Именованные аргументы также принимают значения по умолчанию, поэтому в этом примере из модуля debug:
$Function STRING argtest(STRING one, REAL two=2, STRING three="3",
STRING comma=",", INT four=4)
только аргумент one является обязательным, поэтому все следующие являются допустимыми вызовами из vcl:
debug.argtest("1", 2.1, "3a")
debug.argtest("1", two=2.2, three="3b")
debug.argtest("1", three="3c", two=2.3)
debug.argtest("1", 2.4, three="3d")
debug.argtest("1", 2.5)
debug.argtest("1", four=6);
Интерфейс C не изменяется при использовании именованных аргументов и значений по умолчанию, аргументы остаются позиционными, а значения по умолчанию выглядят ничем не отличающимся от явно указанных пользователем.
Note что значения по умолчанию должны быть заданы в родном синтаксисе C-типов, см. ниже. В качестве особого случая NULL должно быть задано как 0.
Дополнительные аргументы
В объявлении vmod.vcc также допускаются необязательные аргументы в квадратных скобках, например:
$Function VOID opt(PRIV_TASK priv, INT four = 4, [STRING opt])
При наличии любого необязательного аргумента прототип функции C выглядит совершенно по-другому:
- Только аргументы
VRT_CTXи указатель на объект (только для методов) остаются позиционными - Все остальные аргументы передаются в структуре как последний аргумент функции C.
Структура аргументов простая; авторы VMOD должны проверить сгенерированный vmodtool файл vcc_if.c для объявлений функций и структур:
-
для каждого необязательного аргумента используется член
valid_argumentдля сигнализации о наличии соответствующего необязательного аргумента.valid_Члены argstruct должны использоваться только как значения истинности, независимо от их фактического типа данных. - именованные аргументы передаются в членах структуры аргументов с тем же именем и типом данных.
- безымянные (позиционные) аргументы передаются как
argnсn, начинающимся с 1 и увеличивающимся с позицией аргумента.
Объекты и методы
Varnish также поддерживает простую модель объектов для vmod. Объекты и методы объявляются в файле vcc следующим образом:
$Object class(...) $Method .method(...)
Для объявленных классов объектов vmod экземпляры объектов затем можно создать в vcl_init { } с помощью оператора new:
sub vcl_init {
new foo = vmod.class(...);
}
и вызывать их методы в любом месте (в том числе в vcl_init {} после создания):
sub somewhere {
foo.method(...);
}
Ничто не мешает методу иметь такое же имя, как у конструктора, и смысл такого метода зависит от автора vmod:
$Object foo(...) $Method .bar(...) $Method .foo(...)
Экземпляры объектов представляются указателями на реализованные vmod C-структуры. Varnish предоставляет только место для хранения адресов экземпляров объектов и гарантирует, что правильный адрес объекта передается в функции C, реализующие методы.
- Область действия и жизненный цикл объектов — vcl
- Объекты могут быть созданы только в
vcl_init {}и имеют свои деструкторы, вызываемые varnish после завершенияvcl_fini {}.
Авторам vmod рекомендуется понять прототипы в сгенерированном vmodtool файле vcc_if.c:
- Для объявлений
$Objectдолжны быть реализованы конструктор и деструктор -
Конструктор имеет суффикс
__init, всегда имеет тип возвратаVOIDи имеет следующие аргументы перед параметрами, объявленными в vcc:-
VRT_CTXкак обычно - указатель-указатель для возвращения адреса созданного объекта
- строка, содержащая имя экземпляра объекта в vcl
-
- Деструктор имеет суффикс
__fini, всегда имеет тип возвратаVOIDи имеет один аргумент — указатель-указатель на адрес объекта. От деструктора ожидается очистка адреса объекта, хранящегося в этом указателе-указателе. -
- Методы получают указатель на объект в качестве аргумента после
-
VRT_CTX.
Поскольку varnish никак не участвует в управлении экземплярами объектов, кроме передачи их адресов, vmods должны реализовать все аспекты управления экземплярами, в частности, управление памятью. Поскольку жизненный цикл экземпляров объектов — это vcl, они обычно выделяются из кучи.
Ограничение области действия функций и методов
Блок $Restrict предлагает способ ограничения области действия предшествующей функции vmod или метода, чтобы их можно было вызывать только из ограниченных мест вызова vcl. Он должен появляться только после $Method или $Function и имеет следующий синтаксис:
$Restrict scope1 [scope2 ...]
Возможные значения области действия: backend, client, housekeeping, vcl_recv, vcl_pipe, vcl_pass, vcl_hash, vcl_purge, vcl_miss, vcl_hit,
vcl_deliver, vcl_synth, vcl_backend_fetch, vcl_backend_response, vcl_backend_error, vcl_init, vcl_fini
Устаревшие псевдонимы
Блок $Alias предлагает механизм переименования функции или метода объекта без удаления предыдущего имени. Это позволяет изменять имена для сохранения совместимости до тех пор, пока псевдоним не будет отменен.
Синтаксис для функции:
$Alias deprecated_function original_function [description]
Синтаксис для метода:
$Alias .deprecated_method object.original_method [description]
Блок $Alias может находиться в любом месте, это позволяет сгруппировать их в отдельном разделе «устаревшие» в их руководстве. Необязательное описание можно использовать для объяснения причины переименования функции.
Типы данных VCL и C
Типы данных VCL ориентированы на задачу, поэтому, например, у нас есть типы данных, такие как «DURATION» и «HEADER», но у них все есть какое-то представление на языке C. Вот их описание.
У всех типов, кроме типов PRIV, есть определения типов: VCL_INT, VCL_REAL и т. д.
Обратите внимание, что большинство типов, не являющихся собственными (указатели C), являются const, которые, если возвращаются функцией/методом vmod, считаются неизменяемыми. Другими словами, vmod must not не может изменить данные, которые были ранее возвращены.
При возвращении значений, не являющихся собственными, функция, производящая эти значения, отвечает за управление памятью. Либо путем освобождения структуры позже любым доступным способом, либо путем использования памяти, выделенной из рабочих пространств клиента или бэкэнда.
- ACL
-
Тип C:
const struct vrt_acl *Тип для именованных ACL, объявленных в VCL.
- BACKEND
-
Тип C:
const struct director *Тип для реализаций бэкенда и директора. См. Создание Директора.
- BLOB
-
Тип C:
const struct vmod_priv *Непрозрачный тип для передачи произвольных кусков памяти между функциями VMOD.
- BODY
-
Тип C:
const void *Тип, используемый только в левой части присваивания, который может принимать либо blob, либо выражение, которое может быть преобразовано в строку.
- BOOL
-
Тип C:
unsignedНоль означает ложь, все остальное означает истину.
- BYTES
-
Тип C:
doubleЕдиница: байты.
Место хранения, например, 1024 байта.
- DURATION
-
Тип C:
doubleЕдиница: секунды.
Промежуток времени, например, 25 секунд.
- ENUM
-
Синтаксис vcc: ENUM { val1, val2, … }
Пример vcc:
ENUM { one, two, three } number="one"Тип C:
const char *Позволяет значения из набора константных строк.
Noteуказывает, что тип C – это строка, а не C-перечисление.Перечисления будут передаваться как фиксированные указатели, поэтому вместо сравнения строк возможны также сравнения указателей с
VENUM(name). - HEADER
-
Тип C:
const struct gethdr_s *Это константы, сгенерированные компилятором VCL, ссылающиеся на определенный заголовок в определенном HTTP-объекте, например,
req.http.cookieилиberesp.http.last-modified. Передав ссылку на заголовок, код VMOD может как читать, так и записывать нужный заголовок.Если заголовок был передан как STRING, код VMOD видит только значение, но не его источник.
- HTTP
-
Тип C:
struct http *Ссылка на объект заголовка как
req.httpилиbereq.http. - INT
-
Тип C:
longЦелое число (long), как мы его знаем и любим.
- IP
-
Тип C:
const struct suckaddr *Это непрозрачный тип. См. файл
include/vsa.hдля поддержки примитивов этого типа. - PRIV_CALL
-
См. Указатели Приватного доступа ниже.
- PRIV_TASK
-
См. Указатели Приватного доступа ниже.
- PRIV_TOP
-
См. Указатели Приватного доступа ниже.
- PRIV_VCL
-
См. Указатели Приватного доступа ниже.
- PROBE
-
Тип C:
const struct vrt_backend_probe *Определение именованного автономного зонда бэкенда.
- REAL
-
Тип C:
doubleЗначение с плавающей точкой.
- REGEX
-
Тип C:
const struct vre *Это непрозрачный тип для регулярных выражений со сферой VCL. Тип REGEX предназначен только для литералов регулярных выражений, управляемых компилятором VCL. Для динамических регулярных выражений или сложных случаев обратитесь к API из файла
include/vre.h. - STRING
-
Тип C:
const char *Строка текста с завершающим нулем.
Может быть NULL для обозначения отсутствия строки, например, в:
mymod.foo(req.http.foobar);
Если заголовка “foobar” HTTP не было, функция vmod_foo() получила бы в качестве аргумента указатель NULL.
- STEVEDORE
-
Тип C:
const struct stevedore *Хранилище бэкенда.
- STRANDS
-
Тип C:
const struct strands *Strands – это список строк, которые передаются в структуре со следующими членами:
-
int n: количество строк -
const char **p: массив строк сnэлементами
VMOD не должен хранить ссылки на strands после выполнения функции или метода. См.
include/vrt.hдля получения подробностей. -
- TIME
-
Тип C:
doubleЕдиница: секунды с момента эпохи UNIX.
Абсолютное время, например, 1284401161.
- VCL_SUB
-
Тип C:
const struct vcl_sub *Непрозрачная обработка подпрограммы VCL.
Ссылки на подпрограммы могут передаваться в VMOD в качестве аргументов и вызываться позже через
VRT_call(). Сфера строго ограничена VCL: vmods должны гарантировать, чтоVCL_SUBникогда не вызываются из другого VCL.VRT_call()отклоняет VCL для рекурсивных вызовов и когдаVCL_SUBне может быть вызван из текущего контекста (например, вызов подпрограммы, обращающейся кreqсо стороны бэкенда).Для более чем одного вызова
VRT_call(), VMODы обязаны проверять, возвращает лиVRT_handled()ненулевое значение между вызовами: вызываемая подпрограмма может вернуть действие (любоеreturn(x)помимо простогоreturn) или может отклонить VCL, и в обоих случаях вызывающий VMOD обязан также вернуть результат, возможно, после проведения некоторых очистных операций. Обратите внимание, что отмена обработки черезVRT_handling()является ошибкой.VRT_check_call()может использоваться для проверки, будет ли вызовVRT_call()успешным, чтобы избежать потенциального отклонения VCL. Она возвращаетNULLеслиVRT_call()сделает вызов, или строку ошибки, почему нет. - VOID
-
Тип C:
voidМожет использоваться только для значения возврата, что делает функцию процедурой VCL.
Приватные указатели
Часто для функций библиотеки полезно поддерживать локальное состояние, это может быть что угодно, от предварительно скомпилированного регулярного выражения до открытых дескрипторов файлов и обширных структур данных.
Компилятор VCL поддерживает следующие приватные указатели:
-
PRIV_CALLПриватные указатели «на вызов» полезны для кэширования/хранения состояния, относящегося к конкретному вызову или его аргументам, например, скомпилированному регулярному выражению, специфичному для оператора regsub(), или просто для кэширования последнего результата какой-либо дорогостоящей операции. Эти приватные указатели существуют в течение загрузки VCL. -
PRIV_TASKПриватные указатели «на задачу» полезны для состояния, применимого к вызовам для определенного запроса или запроса бэкэнда. Например, это может быть результат парсинга cookie, специфичного для клиента. Обратите внимание, чтоPRIV_TASKконтексты отдельные для клиентской и бэкенд-сторон, поэтому использование вvcl_backend_*приведет к другому приватному указателю, чем тот, который используется на клиентской стороне. Эти приватные указатели существуют только в течение своей задачи. -
PRIV_TOPПриватные указатели «на главный запрос» существуют в течение одного запроса и всех его ESI-включений. Они определены только для клиентской стороны. При использовании из VCL-подпрограмм бэкэнда потенциально будет передан NULL-указатель, что может вызвать ошибку VCL. Эти приватные указатели существуют только в течение своего главного запроса. -
PRIV_VCLПриватные указатели «на vcl» полезны для такого глобального состояния, которое применимо ко всем вызовам в этом VCL, например, для флагов, определяющих, являются ли регулярные выражения регистронезависимыми в этом vmod или подобные. ОбъектPRIV_VCL— тот же объект, который передаётся в функцию события VMOD. Этот приватный указатель существует в течение загрузки VCL.PRIV_CALLvmod_privs завершаются передPRIV_VCL.
В коде vmod используется struct vmod_priv *, передаваемый в функции, где один из PRIV_* типов аргументов указан.
Эта структура содержит три члена:
struct vmod_priv {
void *priv;
long len;
const struct vmod_priv_methods *methods;
};
Элементы .priv и .len могут использоваться кодом vmod по своему усмотрению.
.methods может быть необязательным указателем на структуру обратных вызовов:
typedef void vmod_priv_fini_f(VRT_CTX, void *);
struct vmod_priv_methods {
unsigned magic;
const char *type;
vmod_priv_fini_f *fini;
};
.magic должен быть инициализирован VMOD_PRIV_METHODS_MAGIC. .type должен быть описательным именем для отладки.
.fini будет вызван для не-NULL .priv struct
vmod_priv при завершении области действия этого .priv указателя в качестве второго аргумента помимо VRT_CTX.
Общий случай, когда структура данных приватной памяти выделяется с помощью malloc(3), выглядит так:
static void
myfree(VRT_CTX, void *p)
{
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
free (p);
}
static const struct vmod_priv_methods mymethods[1] = {{
.magic = VMOD_PRIV_METHODS_MAGIC,
.type = "mystate",
.fini = myfree
}};
// ....
if (priv->priv == NULL) {
priv->priv = calloc(1, sizeof(struct myfoo));
AN(priv->priv);
priv->methods = mymethods;
mystate = priv->priv;
mystate->foo = 21;
...
} else {
mystate = priv->priv;
}
if (foo > 25) {
...
}
Управление памятью приватных указателей
Общий подход malloc(3) / free(3), описанный выше, работает для всех приватных указателей. Он самый простой и менее подвержен ошибкам (поскольку выделенная память должна быть освобождена через обратный вызов fini), но сопряжён с вызовом выделения памяти в куче.
Структуры данных, константы для каждого vmod, могут быть назначены любому типу приватного указателя, но, очевидно, free(3) не следует использовать для них.
Динамические данные, хранящиеся в PRIV_TASK и PRIV_TOP указателях, также могут поступать из области работы:
-
Для
PRIV_TASK, любое выделение изctx->wsработает, например:if (priv->priv == NULL) { priv->priv = WS_Alloc(ctx->ws, sizeof(struct myfoo)); if (priv->priv == NULL) { VRT_fail(ctx, "WS_Alloc failed"); return (...); } priv->methods = mymethods; mystate = priv->priv; mystate->foo = 21; ... -
Для
PRIV_TOP, прежде всего, следует помнить, что он должен использоваться только из клиентского контекста, поэтому код vmod должен выдавать ошибку дляctx->req == NULL.Для динамических данных должна использоваться область работы главного запроса, что немного усложняет ситуацию:
if (priv->priv == NULL) { struct ws *ws; CHECK_OBJ_NOTNULL(ctx->req, REQ_MAGIC); CHECK_OBJ_NOTNULL(ctx->req->top, REQTOP_MAGIC); CHECK_OBJ_NOTNULL(ctx->req->top->topreq, REQ_MAGIC); ws = ctx->req->top->topreq->ws; priv->priv = WS_Alloc(ws, sizeof(struct myfoo)); // ... same as above for PRIV_TASK
Обратите внимание, что выделения в области работы не требуют освобождения, их срок жизни соответствует задаче.
Приватные указатели и объекты
PRIV_TASK и PRIV_TOP аргументы к методам не относятся к экземпляру объекта, а к vmod, как и для обычных функций vmod. Таким образом, vmod, требующие состояния «на задачу» / «на главный запрос» для экземпляров объектов, должны реализовывать другие способы связывания хранилища с экземплярами объектов.
Вот для чего предназначены VRT_priv_task() / VRT_priv_task_get() и VRT_priv_top() / VRT_priv_top_get():
Функции, не являющиеся get, либо возвращают существующий PRIV_TASK / PRIV_TOP для данного аргумента void *, либо создают его. Они возвращают NULL в случае ошибки выделения.
Функции _get() не создают PRIV_*, а возвращают либо существующий, либо NULL.
Согласно соглашению, приватные указатели для экземпляров объектов создаются по адресу объекта, как в этом примере для PRIV_TASK:
VCL_VOID
myvmod_obj_method(VRT_CTX, struct myvmod_obj *o)
{
struct vmod_priv *p;
p = VRT_priv_task(ctx, o);
// ... see above
Случай PRIV_TOP выглядит идентично, за исключением вызова VRT_priv_top(ctx, o) вместо VRT_priv_task(ctx, o), но помните, что функции VRT_priv_top*() должны вызываться только из клиентского контекста (если ctx->req != NULL).
Функции событий
VMOD может иметь функцию «события», которая вызывается при загрузке или удалении VCL, импортирующего VMOD. Это соответствует событиям VCL_EVENT_LOAD и VCL_EVENT_DISCARD соответственно. Кроме того, эта функция будет вызвана при изменении температуры VCL на холодную или тёплую, соответствующую событиям VCL_EVENT_COLD и VCL_EVENT_WARM.
Первый аргумент функции события — контекст VRT.
Второй аргумент — специфичный для данного VCL vmod_priv, и при необходимости, к его «функции освобождения» может быть прикреплена функция «fini» VMOD, специфичная для VCL.
Третий аргумент — событие.
Если VMOD имеет глобальное состояние, которое включает все открытые сокеты или файлы, всю память, выделенную для глобальных или приватных переменных в коде C, и т.д., VMOD несет ответственность за отслеживание того, сколько VCL было загружено или удалено, и освобождение этого глобального состояния, когда счёт достигнет нуля.
Разработчикам VMOD настоятельно рекомендуется высвободить все ресурсы, относящиеся к конкретному VCL, когда VCL генерирует событие VCL_EVENT_COLD. У вас будет возможность повторно получить доступ к ресурсам, прежде чем VCL снова станет активным, и вы получите уведомление в первую очередь с событием VCL_EVENT_WARM . Если пользователь не решит, что определенный VCL должен всегда быть тёплым, неактивный VMOD в конечном итоге станет холодным и должен управлять ресурсами соответственно.
Функция события должна возвращать ноль при успехе. Невозможно отклонить инициализацию только с событиями VCL_EVENT_LOAD или VCL_EVENT_WARM . В случае такой ошибки событие VCL_EVENT_COLD или VCL_EVENT_DISCARD будет отправлено VMOD, которые успешно выполнили задачу, чтобы вернуть их в холодное состояние. VMOD, который потерпел неудачу, не получит это событие и поэтому не должен оставаться полуинициализированным в случае ошибки.
Если ваш VMOD выполняет асинхронную фоновую работу, вы можете удерживать ссылку на VCL, чтобы предотвратить его слишком быстрое охлаждение и получить те же гарантии, что и у бэкэндов с активными запросами, например. Для этого необходимо получить ссылку, вызвав VRT_VCL_Prevent_Discard при получении события VCL_EVENT_WARM, и позже вызвав VRT_VCL_Allow_Discard после завершения фоновой задачи. Получение события VCL_EVENT_COLD служит сигналом для завершения любой фоновой задачи, связанной с VCL.
Вы можете найти примеры ссылок на VCL в vmod-debug:
priv_vcl->vclref = VRT_VCL_Prevent_Discard(ctx, "vmod-debug"); ... VRT_VCL_Allow_Discard(&ctx, &priv_vcl->vclref);
В этой упрощённой версии вы можете видеть, что вам, по крайней мере, нужна связанная с VCL структура данных, например, PRIV_VCL, или объект VMOD, чтобы отслеживать ссылку и затем её высвободить. Вы также должны предоставить описание; оно будет отображено пользователю, если они попытаются сделать VCL тёплым, пока он охлаждается:
$ varnishadm vcl.list
available auto/cooling 0 vcl1
active auto/warm 0 vcl2
$ varnishadm vcl.state vcl1 warm
Command failed with error code 300
Failed <vcl.state vcl1 auto>
Message:
VCL vcl1 is waiting for:
- vmod-debug
В случае, если правильное высвобождение ресурсов может занять некоторое время, вы можете использовать асинхронного работника, либо создав поток и отслеживая его, либо используя рабочие потоки Varnish.
Когда следует блокировать, а когда нет
Varnish — сильно многопоточная система, поэтому по умолчанию VMOD должны реализовывать собственные блокировки для защиты общих ресурсов.
При загрузке или разгрузке VCL функции события и priv->free выполняются последовательно в одном потоке, и гарантированно не будет никакой другой активности, связанной с этим конкретным VCL, а также нет активности init/fini в любом другом VCL или VMOD в этот момент.
Это означает, что инициализация VMOD и любые функции инициализации/завершения объекта уже упорядочены в разумной последовательности и не потребуют блокировок, если они не обращаются к глобальному состоянию, специфичному для VMOD, и общедоступному для других VCL.
Поток в других VCL, которые также импортируют этот VMOD, будет происходить во время выполнения задач управления.
Счётчики статистики
Начиная с Varnish 6.0, VMODы могут определять собственные счётчики, которые отображаются в varnishstat.
Если вы используете autotools, см. макрос VARNISH_COUNTERS в файле varnish.m4 для получения информации о настройке сборки.
Счётчики определяются в файле .vsc. Макрос VARNISH_COUNTERS вызывает vsctool.py, чтобы преобразовать файл foo.vsc в файлы VSC_foo.c и VSC_foo.h, точно так же, как vmodtool.py преобразует foo.vcc в файлы vcc_foo_if.c и vcc_foo_if.h. Аналогично файлам VCC, сгенерированные файлы VSC предоставляют структуру и функции, которые вы можете использовать в коде вашего VMOD для создания и удаления определённых вами счётчиков. Инструмент vsctool.py также генерирует файл VSC_foo.rst, который вы можете включить в свою документацию для описания счётчиков вашего VMOD.
Файл .vsc выглядит следующим образом:
.. varnish_vsc_begin:: xkey
:oneliner: xkey Counters
:order: 70
Metrics from vmod_xkey
.. varnish_vsc:: g_keys
:type: gauge
:oneliner: Number of surrogate keys
Number of surrogate keys in use. Increases after a request that includes a new key in the xkey header. Decreases when a key is purged or when all cache objects associated with a key expire.
.. varnish_vsc_end:: xkey
Счётчики могут иметь следующие параметры:
- type
-
Тип метрики. Может быть одним из
counter,gauge, илиbitmap. - ctype
-
Тип счётчика в коде C. Может быть только
uint64_tи не требует указания. - level
-
Уровень подробности счётчика. varnishstat будет отображать только счётчики с уровнем подробности, превышающим текущий. Может быть одним из
info,diag, илиdebug. - oneliner
-
Краткое, однострочное описание счётчика.
- group
-
Не знаю, что это делает.
- format
-
Может быть одним из
integer,bytes,bitmap, илиduration.
После этих параметров счётчик может иметь более подробное описание, хотя это описание должно быть в одной строке в файле .vsc.
Вы должны вызвать VSC_*_New() при загрузке вашего VMOD и VSC_*_Destroy() при его выгрузке. См. сгенерированный файл VSC_*.h для подробной информации о структуре, содержащей ваши счётчики.
Copyright © 2006 Verdens Gang AS
Copyright © 2006–2020 Varnish Software AS
Licensed under the BSD-2-Clause License.
https://varnish-cache.org/docs/7.4/reference/vmod.html