All streams
Search
Write a publication
Pull to refresh
40
0
Сергей Камардин @gobwas

Пользователь

Send message
nginx распределяет коннекты между экземплярами

Плюс, таймауты на чтение из клиентского коннекта, ограничение доступа к апстриму и т. д.


Можно конечно, переписать на Go логику, отлично работающую в nginx, но не уверен, что это принесет гигантский профит. Возможно, стоит попробовать – но сейчас есть более приоритетные задачи =)

Go умеет SSL, при этом, если я не ошибаюсь, без binding'ов – т.е. своя реализация.

Спасибо! Всегда есть куда развиваться.

Упс, ответил ниже в треде =)

В общении между шиной и клиентами мы не хотим использовать протоколы кровавого энтерпрайза SOAP, JBI, JMS и т. д. В почте у нас нет Java, и большинство вариантов использования покрывает внутренний бинарный протокол IProto. Нам хотелось использовать что-то совсем легковесное и контролирумое чуть более, чем полностью – мы еще не пришли к конечной логике работы системы и можем захотеть ее поменять.


И это не ради мониторинга.

В ближайшее время не планировалось. Если интересно про маршрутизацию и некоторые цифры – есть видео с РИТ2017:


На C++ вроде есть недурственный uWebSockets, но это не точно.

Ну профит в Go здесь как раз в том, что мы можем выборочно оптимизировать узкие места. Например, там, где не требуется высокая эффективность и производительность можно положиться на go runtime, сборщик мусора и т. д.


Были мысли из Go использовать pico http parser, но в итоге написал кусочек функционала на Go и на этом пока вопрос закрылся =)

8 Кбайт – это который в зависимости от операционной системы и версии Go. В последних версиях и в Linux, если я не ошибаюсь, стек начинается с 2 Кбайт.


на процесс выделяется 338 8-байтовых слов

Судя по всему, речь идет об Erlang/Elixir? =)


Получается, (338-223) * 8 = 920 байт стека? Выходит, с учетом кучи (338 * 8 = 2704) разницы нет? )


Вот в ponylang, например, акторы занимают 256 байт памяти… Но это уже совсем другая история =)

Из "неизданного":
image

Извиняюсь, с телефона прочитал "домен" как "демон" =) Вопрос тогда не актуален.

Nginx в первую очередь берет на себя ssl. Плюс, мы запускаем несколько экземпляров сервера на go, чтобы при падении/локе/жестком рестарте одного остальные продолжали работать: nginx распределяет коннекты между экземплярами.


А что за демон для вебсокет-соединений?

Привет, Спасибо!


Теоретически, 3 миллиона соединений на одной машине могут жить. Но для распределения нагрузки и наличия запаса ресурсов мы распределяем соединения на несколько серверов. Сейчас это 8 машин, было 4. Но судя по цифрам, после оптимизаций мы смогли бы держать 3 миллиона соединений на одной машине: не было бы запаса по CPU, но с памятью было бы все ок. Но и там, возможно, можно было бы что-то докрутить.


Что касается адресации – вы, наверное, имеете в виду проблему портов, когда nginx не может спроксировать больше ~64K коннектов на локальный демон? Ее можно решать, как вы правильно сказали, добавлением виртуальных интерфейсов, либо, как это сделали мы – уйти от TCP-сокетов с адресацией по порту, в сторону UNIX-сокетов.


Лимит на открытые файловые дескрипторы – это "ручка", которая настраивается в Linux на процесс или на пользователя.


По цифрам могу сказать про память, что до оптимизаций сервер потреблял ~60Кбайт на соединение, после – 10Кбайт. При этом, можно крутить флажок GOGC в Go, который так же немного влияет на цифры потребления памяти.

Ой, уже кинул ниже )

Еще немного упростил пример:


package main

import (
        "testing"
)

type Fooer interface {
        Foo()
}

type Concrete struct {
        data byte // Just to see in allocation.
}

func (c Concrete) Foo() {}

func HandleFooer(f Fooer) {}

func BenchmarkCallFooer(b *testing.B) {
        for i := 0; i < b.N; i++ {
                c := Concrete{} // Moved to heap.
                Fooer(&c).Foo()
        }
}

func BenchmarkPassFooer(b *testing.B) {
        for i := 0; i < b.N; i++ {
                c := Concrete{} // Not moved to heap.
                HandleFooer(Fooer(&c))
        }
}

Результат:


BenchmarkCallFooer-4    100000000               17.6 ns/op             1 B/op          1 allocs/op
BenchmarkPassFooer-4    500000000                2.99 ns/op            0 B/op          0 allocs/op

Да, видимо, анализатор не учитывает конкретную реализацию Foo() объекта внутри Fooer, и поэтому кладет его на heap.


Попробую создать тикет.


P.S. Спасибо за -m -m! Не знал. =)

Спасибо за перевод и ссылки!


Возник следующий вопрос (больше даже относящийся к статье Russ Cox):


package main

import (
        "testing"
)

type Stringer interface {
        String() string
}

func GetString(s Stringer) string {
        return s.String()
}

type Text struct {
        val string
        pad [24]byte
}

func (t Text) String() string {
        return t.val
}

func BenchmarkGetString(b *testing.B) {
        for i := 0; i < b.N; i++ {
                t := Text{val: "hello"} // Moved to heap, 24 bytes for pad and 8 bytes for string.
                _ = GetString(&t)       // Allocation for Stringer 8 + 8 bytes.
        }
}

Если запустить следующую команду:


go test iface_test.go -gcflags="-m -N -l" -bench=. -benchmem

Мы видим, среди прочего:


./iface_test.go:26: moved to heap: t
...
BenchmarkGetString-4    30000000                56.7 ns/op            48 B/op          1 allocs/op

Т.е. в каждой итерации выделяется память на heap под структуру Text, и интерфейс Stringer. Почему нельзя в данном случае ограничиться стеком?

Как-то стремновато будет выглядеть monkey patching в production коде?


Как-то использовал эту прекрасную либу, но только для того, чтобы делать stub'ы в структурах, при использовании которых хотел избежать интерфейсов.

… из них самый интересный — di.js от Angular, но он мне не подошел и я решил написать свой.
=)

Если по теме – когда-то пилил тоже "свой", с асинхронной загрузкой, ленивым инстанцированием и прочими прелестями:
https://github.com/gobwas/dm.js

Спасибо!

sync.Pool не панацея

Точно! Если можно применить простое не «goroutine-safe» переиспользование – получится быстрее.

Information

Rating
Does not participate
Location
Москва, Москва и Московская обл., Россия
Registered
Activity