WasmHost — это фильтр Easegress, который можно включить в конвейер. В то время как поведение всех других фильтров определяется разработчиками фильтров и может быть настроено только с помощью конфигурации, этот фильтр реализует среду хоста для пользовательского кода WebAssembly, что позволяет пользователям полностью контролировать поведение фильтра.
Можно написать код Wasm в текстовом формате, но это сложно.
Чтобы упростить задачу, MegaEase выпустила несколько SDK, которые помогают пользователям разрабатывать свою логику на высокоуровневых языках. В настоящее время доступны следующие SDK:
Мы можем следовать документации этих SDK, чтобы написать бизнес-логику и скомпилировать её в Wasm.
Возьмём AssemblyScript в качестве примера. Предположим, наша бизнес-логика такова:
Соответствующий код AssemblyScript будет выглядеть так:
export * from '../easegress/proxy'
import { Program, request, LogLevel, log, registerProgramFactory } from '../easegress'
class AddHeaderAndSetBody extends Program {
constructor(params: Map<string, string>) {
super(params)
}
run(): i32 {
super.run()
let v = request.getHeader( "Foo" )
if( v.length > 10 ) {
log( LogLevel.Warning, "The length of Foo is greater than 10" )
}
if( v.length > 0 ) {
request.addHeader( "Wasm-Added", v )
}
request.setBody( String.UTF8.encode("I have a new body now") )
return 0
}
}
registerProgramFactory((params: Map<string, string>) => {
return new AddHeaderAndSetBody(params)
})
В остальной части этого документа мы предполагаем, что результирующий файл Wasm сохранён по адресу /home/megaease/demo.wasm
.
Прежде чем это сделать, мы должны настроить Easegress, следуя шагам в README.md (../README.md#setting-up-easegress).
Давайте сначала создадим HTTPServer, прослушивающий порт 10080 для обработки HTTP-трафика:
$ echo '
kind: HTTPServer
name: server-demo
port: 10080
keepAlive: true
https: false
rules:
- paths:
- pathPrefix: /pipeline
backend: wasm-pipeline' | egctl object create
Затем создайте конвейер wasm-pipeline
, который включает фильтр WasmHost
:
$ echo '
name: wasm-pipeline
kind: HTTPPipeline
flow:
- filter: wasm
- filter: proxy
jumpIf: { fallback: END }
filters:
- name: wasm
kind: WasmHost
maxConcurrency: 2
code: /home/megaease/demo.wasm
timeout: 100ms
- name: proxy
kind: Proxy
mainPool:
servers:
- url: http://127.0.0.1:9095
loadBalance:
policy: roundRobin' | egctl object create
Обратите внимание, что мы используем путь к файлу Wasm в качестве значения code
в спецификации WasmHost
, но значением code
также может быть URL (HTTP/HTTPS) или base64-кодированный код Wasm.
Затем нам нужно настроить бэкенд-сервис, следуя шагам в README.md (../README.md#test).
Теперь давайте отправим несколько запросов на HTTP-сервер и увидим, что заголовки и тело запроса установлены по желанию.
$ curl http://127.0.0.1:10080/pipeline
Your Request
==============
Method: GET
URL : /pipeline
Header:
User-Agent: [curl/7.68.0]
Accept: [*/*]
Accept-Encoding: [gzip]
Body : i have a new body now
$ curl http://127.0.0.1:10080/pipeline **Метод**: GET
**URL**: /pipeline
**Заголовок**:
Accept: [*/*]
Foo: [hello]
Wasm-Added: [hello]
Accept-Encoding: [gzip]
User-Agent: [curl/7.68.0]
**Тело**: у меня новое тело сейчас
Из примера кода AssemblyScript вы уже могли заметить, что конструктор принимает параметр params, который представляет собой карту строки в строку. Пары ключ-значение являются параметрами программы WebAssembly, они могут быть заданы в конфигурации фильтра.
filters:
- name: wasm
kind: WasmHost
parameters: # +
key1: "value1" # +
key2: "value2" # +
И затем считываются WebAssembly:
constructor(params: Map<string, string>) {
super(params)
this.key1 = params.get("key1")
this.key2 = params.get("key2")
}
Когда поле maxConcurrency фильтра WasmHost больше 1 или когда Easegress развёрнут как кластер, один фильтр WasmHost может иметь более одной виртуальной машины Wasm. Поскольку безопасность является принципом проектирования WebAssembly, эти виртуальные машины изолированы и не могут обмениваться данными друг с другом.
Но иногда обмен данными полезен, Easegress предоставляет API для этого:
export * from '{EASEGRESS_SDK_PATH}/easegress/proxy'
import { Program, cluster, registerProgramFactory } from '{EASEGRESS_SDK_PATH}/easegress'
class SharedData extends Program {
run(): i32 {
let counter1 = cluster.AddInteger("counter1", 1)
let counter2 = cluster.AddInteger("counter2", 2)
// ...
return 0
}
}
registerProgramFactory((params: Map<string, string>) => {
return new SharedData(params)
})
Приведённый выше код создаёт два общих счётчика для всех виртуальных машин, counter1 увеличивается на 1 для каждого запроса, а counter2 увеличивается на 2 для каждого запроса.
Мы можем просмотреть общие данные с помощью:
$ egctl wasm list-data wasm-pipeline wasm
counter1: "3"
counter2: "6"
где wasm-pipeline — это имя конвейера, а wasm — имя фильтра.
Общие данные можно изменить с помощью:
$ echo '
counter1: 100
counter2: 101' | egctl wasm apply-data wasm-pipeline wasm
и можно удалить с помощью:
$ egctl wasm delete-data wasm-pipeline wasm
Код Wasm можно обновить без перезапуска Easegress с помощью следующей команды:
$ egctl wasm reload-code
Это отправляет уведомление всем экземплярам WasmHost, и они перезагружают свой код Wasm, если код был изменён.
Из руководства разработчика мы знаем, что конвейер поддерживает механизм JumpIf, который направляет конвейер на переход к другому фильтру в зависимости от результата текущего фильтра.
Этот механизм требует, чтобы мы знали все возможные результаты фильтра перед определением конвейера, но для WasmHost существует сложность: бизнес-логика разрабатывается пользователями после разработки фильтра WasmHost, то есть фильтр не имеет представления о том, какой результат он должен вернуть.
Решение заключается в том, что WasmHost определяет 10 результатов, пустую строку и wasmResult1 — wasmResult9. Как и во всех других фильтрах, пустая строка означает, что всё в порядке, в то время как значение других 9 результатов определяется пользователем.
И в качестве требования пользовательская бизнес-логика должна возвращать целое число в диапазоне [0, 9], WasmHost преобразует 0 в пустую строку, а 1–9 в wasmResult1–wasmResult9 соответственно. Пользователи могут использовать эти результаты для определения JumpIfs конвейера.
Фильтр WasmHost выполняет пользовательский код, поэтому его производительность зависит от сложности пользовательского кода, которую нелегко измерить.
В этом разделе фильтр WasmHost сделан для имитации фильтра Mock, и мы сравним его статистику производительности с реальным фильтром Mock. Ниже приведён код AssemblyScript для фильтра WasmHost:
export * from '../easegress/proxy'
import { Program, response, registerProgramFactory } from
Вы можете оставить комментарий после Вход в систему
Неприемлемый контент может быть отображен здесь и не будет показан на странице. Вы можете проверить и изменить его с помощью соответствующей функции редактирования.
Если вы подтверждаете, что содержание не содержит непристойной лексики/перенаправления на рекламу/насилия/вульгарной порнографии/нарушений/пиратства/ложного/незначительного или незаконного контента, связанного с национальными законами и предписаниями, вы можете нажать «Отправить» для подачи апелляции, и мы обработаем ее как можно скорее.
Опубликовать ( 0 )