1 В избранное 0 Ответвления 0

OSCHINA-MIRROR/megaease-easegress

Присоединиться к Gitlife
Откройте для себя и примите участие в публичных проектах с открытым исходным кодом с участием более 10 миллионов разработчиков. Приватные репозитории также полностью бесплатны :)
Присоединиться бесплатно
Клонировать/Скачать
wasmhost.md 11 КБ
Копировать Редактировать Web IDE Исходные данные Просмотреть построчно История
gitlife-traslator Отправлено 29.11.2024 00:57 ea14e4f

WasmHost

WasmHost — это фильтр Easegress, который можно включить в конвейер. В то время как поведение всех других фильтров определяется разработчиками фильтров и может быть настроено только с помощью конфигурации, этот фильтр реализует среду хоста для пользовательского кода WebAssembly, что позволяет пользователям полностью контролировать поведение фильтра.

Напишите бизнес-логику и скомпилируйте её в Wasm

Можно написать код Wasm в текстовом формате, но это сложно.

Чтобы упростить задачу, MegaEase выпустила несколько SDK, которые помогают пользователям разрабатывать свою логику на высокоуровневых языках. В настоящее время доступны следующие SDK:

Мы можем следовать документации этих SDK, чтобы написать бизнес-логику и скомпилировать её в Wasm.

Возьмём AssemblyScript в качестве примера. Предположим, наша бизнес-логика такова:

  1. Получить значение заголовка запроса «Foo».
  2. Если длина значения больше 10, записать предупреждающее сообщение.
  3. Если заголовок существует, скопировать его значение в новый заголовок с именем «Wasm-Added».
  4. Установить тело запроса равным «I have a new body now».

Соответствующий код 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.

Создайте WasmHost

Прежде чем это сделать, мы должны настроить 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, если код был изменён.

Возвращаемое значение кода 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 )

Вы можете оставить комментарий после Вход в систему

1
https://api.gitlife.ru/oschina-mirror/megaease-easegress.git
git@api.gitlife.ru:oschina-mirror/megaease-easegress.git
oschina-mirror
megaease-easegress
megaease-easegress
main