LINUX.ORG.RU

Cloudflare выпустила первый публичный релиз Pingora v0.1.0

 ,

Cloudflare выпустила первый публичный релиз Pingora v0.1.0

0

4

5 апреля 2024 года Cloudflare представила первый публичный релиз открытого проекта Pingora v0.1.0 (уже v0.1.1). Это асинхронный многопоточный фреймворк на Rust, который помогает создавать прокси-сервисы HTTP. Проект используется для создания сервисов, обеспечивающих значительную часть трафика в Cloudflare (вместо применения Nginx). Исходный код Pingora опубликован на GitHub под лицензией Apache 2.0.

Pingora предоставляет библиотеки и API для создания сервисов поверх HTTP/1 и HTTP/2, TLS или просто TCP/UDP. В качестве прокси-сервера он поддерживает сквозное проксирование HTTP/1 и HTTP/2, gRPC и WebSocket. Поддержка HTTP/3 — в планах. Pingora также включает в себя настраиваемые стратегии балансировки нагрузки и аварийного переключения. Чтобы соответствовать требованиям и безопасности, он поддерживает как широко используемые библиотеки OpenSSL, так и BoringSSL, которые соответствуют требованиям FIPS (федеральных стандартов обработки информации США) и пост-квантового шифрования.

Помимо этих функций, Pingora предоставляет фильтры и обратные вызовы, позволяющие пользователям полностью настраивать то, как сервис должен обрабатывать, преобразовывать и пересылать запросы.

В рабочем режиме Pingora обеспечивает плавный перезапуск без простоев для самостоятельного обновления, не теряя ни одного входящего запроса. Syslog, Prometheus, Sentry, OpenTelemetry и другие необходимые инструменты наблюдения легко интегрируются с Pingora.

Возможности Pingora: использование Async Rust, поддержка HTTP 1/2 end to end proxy, TLS over OpenSSL или BoringSSL, gRPC и проксирование веб-сокетов, Graceful reload, настраиваемые стратегии балансировки нагрузки и аварийного переключения, поддержка различных инструментов мониторинга.

В версии Pingora v0.1.1 исправлены ранее обнаруженные ошибки, улучшена производительность алгоритма pingora-ketama, добавлено больше бенчмарков TinyUFO и тестов для pingora-cache purge, ограничен размер буфера для журналов ошибок InvalidHTTPHeader, а также исправлены опечатки и внесены необходимые исправления в комментариях и документации проекта.

>>> Подробности

★★★★

Проверено: hobbit ()
Последнее исправление: hobbit (всего исправлений: 1)

Ответ на: комментарий от monk

Как QStringList передать в f(vector & v)?

никак. Как и в любом (статически типизированном, в питоне если тайпхинты использовать, то тоже обосрется) другом языке. Даже в чистом c++ ты не сможешь передать std::set (например) туда, где ожидается вектор

arcanis ★★★★
()
Ответ на: комментарий от monk

Принимать итераторы, как минимум? Строки - в зависимости от того, что с ними делается, в любом случае исключение возможности принимать wstring, к примеру, выглядит странно, логичнее было бы basic_string_view. Всех вопросов стыковки разных библиотек так не решить, но часть вполне может убираться.

unC0Rr ★★★★★
()
Ответ на: комментарий от unC0Rr

Принимать итераторы, как минимум?

В смысле? Произвольные? То есть, вместо компактной разделяемой библиотеки делаем мегашаблон, который будет делать по экземпляру кода на каждую комбинацию типа коллекции и типа строки?

Предложи Qt’шникам принимать произвольный итератор в QTableWidget.

monk ★★★★★
()
Ответ на: комментарий от arcanis

Просто ты писал «кутешные, кстати, под стд мимикрируют на ура». Я удивился.

Даже в чистом c++ ты не сможешь передать std::set (например) туда, где ожидается вектор

Это понятно.

monk ★★★★★
()
Ответ на: комментарий от monk

да, неточно выразился, имелось в виду скорее просовывание их в разные и прочие приблуды из стандартной библиотеки

arcanis ★★★★
()
Ответ на: комментарий от monk

Делаешь один метод шаблонным, который только итерируется по коллекции, возможно, с минимальной логикой. Второй принимающий строку. Все. Инстансы шаблонов не будут большими.

PRN
()
Ответ на: комментарий от PRN

Если нужно вернуть коллекцию, еë тип всë равно какой-то конкретный. А если по ней надо по индексу ходить, то всё равно массив нужен, а если брать итератор, то будет лишнее копирование коллекции.

monk ★★★★★
()
Ответ на: комментарий от monk

То есть, можно сделать для инвалидов второй интерфейс, который из всего, что умеет итерироваться преобразует в нужное. Но все варианты это не охватит всë равно.

monk ★★★★★
()
Ответ на: комментарий от monk

Если нужно вернуть коллекцию, еë тип всë равно какой-то конкретный

Если этот тип можно юзать как range, то все тоже самое)

Но все варианты это не охватит всë равно.

И какие же варианты остались? Изначально помню: две коллекции стрингов, но разных типов. Нужен был интерфейс. Вроде задача решена.

PRN
()
Ответ на: комментарий от monk

Если нужно вернуть коллекцию, еë тип всë равно какой-то конкретный

Нет. std::transform умеет в произвольные коллекции через back_inserter

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

Так вектор или массив? Или что угодно с произвольным доступом через итератор?

unC0Rr ★★★★★
()
Ответ на: комментарий от PRN

И какие же варианты остались?

Выглядит примерно так:

extern vector<tuple<string, string, int>> & f(vector<tuple<string, string, int>> &v);

template <typename T>
auto & api_f(T data)
{
  vector<tuple<string, string, int>> v;
  for(auto & x : data) {
    string s1, s2;
    int i;
    tie(s1, s2, i) = x;
    v.push_back(tuple<string, string, int>(s1, s2, i));
  }
  return f(v);
}

Работать будет только с теми коллекциями, элементы которых можно разобрать через std::tie и строки из которых можно преобразовать в std::string. То есть QSqlQuery уже в пролёте.

monk ★★★★★
()
Ответ на: комментарий от unC0Rr

Так вектор или массив? Или что угодно с произвольным доступом через итератор?

С произвольным доступом по номеру элемента.

monk ★★★★★
()
Ответ на: комментарий от unC0Rr

Это называется std::random_access_iterator

Так всё равно нужны границы.

И если так делать, тогда уже код всей функции становится шаблоном. То есть, можно, конечно, писать функции в стиле «всё в заголовочном файле». Типа

template <typename T>
T & f(T v)
{
    n = v.size();
    ... 
    auto r = g(get<0>(v[i]), get<0>(v[j]))
    ...
}

И будет работать с любым типом, у которого есть size(), оператор [] и результат этого оператора достаточно похож на кортеж.

Но тогда эту штуку не упаковать в разделяемую библиотеку.

monk ★★★★★
()
Последнее исправление: monk (всего исправлений: 1)
Ответ на: комментарий от monk

Так всё равно нужны границы.

Для этого у контейнеров и существуют методы begin/end

тогда уже код всей функции становится шаблоном

В любом случае функция, принимающая vector<string>, никак не поможет мне с array<wstring> на руках.

unC0Rr ★★★★★
()
Ответ на: комментарий от unC0Rr

В любом случае функция, принимающая vector, никак не поможет мне с array на руках.

Тоже верно. Поэтому излишнее разнообразие несвязанных типов, делающих одно и то же, в типизированных языках вредно.

Чтобы избежать этого, когда-то придумали ООП. Чтобы можно было писать что-то вроде RandomAccess<ITuple<IString, IString, int>>. Но в Си++, как всегда, всё усложнили. И теперь в тренде утиная типизация и программирование на шаблонах.

monk ★★★★★
()
Ответ на: комментарий от monk

Сам спросил, сам ответил)) Если нужна универсальность использовать интерфейсы). В плюсах еще type traits использовать можно.

PRN
()
Ответ на: комментарий от PRN

Если нужна универсальность использовать интерфейсы

Вот только у std::string, QString, vtkString, … нет общего интерфейса. И такая же фигня с контейнерами.

Поэтому только хардкор, только темплейты и утиная типизация.

А потом ловля UB в коде типа:

struct Point {
    int x;
    int y;
};

struct Shape {
public:
    using VertexList = std::vector<Point>;
    explicit Shape(VertexList v) : vertexes(std::move(v)) {}

    const VertexList& Vertexes() const {
        return vertexes;
    }

private:
    VertexList vertexes;
};


Shape MakeShape() {
    return { Shape::VertexList{ {1,0}, {0,1}, {0,0}, {1,1} } };
}

int main() {
    for (auto v : MakeShape().Vertexes()) {
        std::cout << v.x << " " << v.y << "\n";
    }
}
monk ★★★★★
()
Ответ на: комментарий от monk

Вот только у std::string, QString, vtkString, … нет общего интерфейса

Его всегда можно написать.

А потом ловля UB в коде типа

Если юзаешь временные объекты, пиши для них соответствующие методы)

PRN
()
Ответ на: комментарий от monk

«на коленке» не самый оптимальный, но простенький и рабочий пример. Вместо MyCustomString подставь QString. Логика в конструкторе commonApiAdapter<MyCustomString> усложниться. Скорее всего появиться дополнительный мембер, здесь я плохо помню. Общий смысл не поменяется.

#include <iostream>
#include <string>
#include <list>
#include <vector>

struct MyCustomString
{
    MyCustomString(const char* ch) : _ch{ch} {}
    const char* _ch{};
};

template<class T>
struct commonApiAdapter
{
    commonApiAdapter(const T& s) : _s{s} {}
    commonApiAdapter(T&& s) : _s{std::forward<T>(s)} {}
    std::string_view str() const { return _s; }
    std::string_view _s;
};

template<>
struct commonApiAdapter<MyCustomString>
{
    commonApiAdapter(const MyCustomString& s) : _s{s._ch} {}
    std::string_view str() const { return _s; }
    std::string_view _s;
};

void bar(std::string_view str)
{
    std::cout << str << "\n";
}

template <typename T>
void foo(T&& range)
{
    for (auto&& x : range)
    {
        using typeOfX = decltype(x);
        commonApiAdapter<std::decay_t<typeOfX>> a{std::forward<typeOfX>(x)};
        bar(a.str());
    }
}

int main()
{
    std::vector<std::string> v1{"0", "1"};
    foo(v1);

    std::list<MyCustomString> v2{"2", "3"};
    foo(v2);
}
PRN
()
Ответ на: комментарий от monk

Тем что wchar пытается репрезентовать юникодный символ. На разных платформах они разные с разным размером. В результате int - переносим, wchar - нет).

PRN
()
Ответ на: комментарий от PRN

Еще, как вариант, можно bar перегрузить, если есть возможность. Тогда в commonApiAdapter нет необходимости. Выбирай решение на любой вкус)

void bar(const MyCustomString& str)
{
    bar(str._ch);
}

PRN
()
Последнее исправление: PRN (всего исправлений: 1)
Ответ на: комментарий от PRN

Что-то на void foo(IVec<IString> && range) не заменилось. с template <typename T> void foo(T&& range) и никакого адаптера не нужно.

Если вопрос про преобразование, то вроде можно просто

std::string_view convert(std::string& s);
std::string_view convert(QString& s);
std::string_view convert(const MyCustomString& s);
...

понасоздавать и всё. Но foo имеет утиную типизацию. Из template <typename T> void foo(T&& range) угадать требования к range невозможно.

monk ★★★★★
()
Ответ на: комментарий от PRN

Тем что wchar пытается репрезентовать юникодный символ.

А int пытается репрезентовать целое число. На разных платформах они разные с разным размером.

В результате int - переносим

???

monk ★★★★★
()
Ответ на: комментарий от vbr

Так и на Си++ очень редко шаблонный интерфейс предлагают.

monk ★★★★★
()
Ответ на: комментарий от monk

Если вопрос про преобразование, то вроде можно просто …

Твой «дизайн» говно, хотя бы потому что не работает)

… угадать требования к range невозможно.

Как я писал выше, код написан «на коленке» и простенький.

template <typename T>
    requires std::ranges::range<T>
         and std::convertible_to<std::ranges::range_value_t<T>, commonApiAdapter<std::decay_t<std::ranges::range_value_t<T>>>>
void foo(T&& range)

Концепт для проверки адаптера, тоже можно написать, но мне лень) Так что, остальное сам исправишь))

PRN
()
Ответ на: комментарий от PRN

Твой «дизайн» говно, хотя бы потому что не работает)

https://gcc.godbolt.org/z/zdYr8WTMq

Работает. UB нет.

     and std::convertible_to<std::ranges::range_value_t<T>, commonApiAdapter<std::decay_t<std::ranges::range_value_t<T>>>>

Очень читабельно закодировано «и коллекция содержит строки».

monk ★★★★★
()
Последнее исправление: monk (всего исправлений: 1)
Ответ на: комментарий от PRN

Так wchar тоже не надо сериализовать. Для сериализации UTF-8.

monk ★★★★★
()
Ответ на: комментарий от monk

На godbolt’е его нет.

Во первых есть, во вкладке «Libraries».

А так

std::string_view convert(const QString& s)
{
    return s.toStdString();
}

А во вторых, найдешь в одной строчке UB? xD

PRN
()
Ответ на: комментарий от PRN

А во вторых, найдешь в одной строчке UB? xD

Я надеялся, что в string_view будет копия. А как бы это выглядело в магическом commonApiAdapter?

monk ★★★★★
()
Ответ на: комментарий от monk

Я надеялся, что в string_view будет копия. А как бы это выглядело в магическом commonApiAdapter?

template<>
struct commonApiAdapter<QString>
{
    commonApiAdapter(const QString& s) : _s{s.toStdString()} {}
    std::string_view str() const { return _s; }
    std::string _s;
};

А так, да, надо делать std::string convert(QString & s);

Со string_view все тоже работает.

https://gcc.godbolt.org/z/vP5zhnv35

Промежуточные вычисления могут быть сложнее чем одна переменная. Адаптеры из функций, как из говна пуля. Они не могут сохранить состояние. Только вернуть на стек что-то. Объекты универсальнее.

PRN
()
Ответ на: комментарий от PRN

Со string_view все тоже работает.

Так у тебя внутри объекта string также сохраняется.

А в bar и у меня уже string_view попадает.

Адаптеры из функций, как из говна пуля. Они не могут сохранить состояние. Только вернуть на стек что-то. Объекты универсальнее.

Для преобразований обычно и надо только вернуть. Объекты, разумеется, универсальнее, но заметно многословнее.

monk ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.