Pull to refresh

Comments 44

Прекрасная статья для начинающих и подоспела вовремя. Последние выходные мая — лучше не придумаешь, чтобы написать свое первое приложение на Go.

Tornado решает проблему C10K. Автор слишком быстро отбросил Python.

Автор, похоже, не догадывается, что проблема C10K уже не актуальна, и все решают проблему C10M :) Да и тот же uvloop в python вполне может тягаться с go, а местами даже и выигрывать.
Если внимательно почитать статью по вашей ссылке, то там есть такой текст:
We use Python 3.5, and all servers are single-threaded. Additionally, we use GOMAXPROCS=1 for Go code, nodejs does not use cluster, and all Python servers are single-process.

У Go нет GIL. Когда вы захотите «заюзать» сервер целиком со всеми его ядрами, начнется «балансировщик запросов, разделяемый кэш, ...» и далее по тексту. В Go вам просто не надо будет выставлять GOMAXPROCS=1 и оно «как-то само» по всем ядрам «расползется»…
Я, разумеется, утрирую… но доля истины в моем комментарии есть.
Чудес не бывает. Как-то само, оно, конечно, расползается, но управляет всем по-прежнему Go. В случае python ничто не мешает запустить изначально по процессу на ядро — результат будет тот же самый. GIL работает в рамках одного процесса (блокирует именно потоки выполнения). К тому же только часть пользовательского кода работает за GIL — есть ряд библиотек (тот же NumPy, Pandas), которые на время отключают GIL.
UFO just landed and posted this here
Условия сравнения были далеко не честными и го ограничивали.
Ерунда какая-то с точки зрения бенчмарков. Особенно http — давайте возьмем лучшую по производительности версию для python и один из наиболее медленных вариантов на golang.
Я пишу и на go и на python так что на мой взгляд такие сравнения вредны своим непрофессиональным подходом.
фреймворк является необязательным и не рекомендуется.

Да, на Golang нет особой необходимости в сложных фреймворках.
Но мне нужна была функциональность middleware для сервиса — я выбрал https://github.com/labstack/echo. Да, можно сделать самому, но зачем?..
Не знаю, насколько верное решение, время покажет.

Спасибо за статью.
UFO just landed and posted this here

или вот еще — более конкретные данные

Ну да, тут он вообще с SQL сравнивается. )
А в первом примере JS лидирует, имхо, только за счёт развития SPA. На бэкенде всё-равно PHP в приоритете.

Интересно это конечно всё, но отсутствие фреймворков — проблема, причём реальная. SPA — очень спорная часть жизни веба, с одной стороны это конечно хорошо и тихий переход к вебу как к платформе, но именно это же и убивает лёгкость веба. Тогда уж легче и экономнее будет установить нативное приложение, чем хранить в кеше 1000 строк js кода. Так что в этом моменте я бы поспорил, хотя сам очень люблю SPA.


А вот фреймворки реально нужны, в любом случае. И не потому, что яп не спроектирован под веб, а потому, что хочется иметь модульность проекта, лёгкость работы с ним и низкий порог входа в проект. Фреймворки в каком-то смысле создают стандартны написания и комьюнити, а оно в свою очередь профессионалов, с которыми легко работать именно в контексте этого фреймворка. Ведь в какой-то момент команда может поменяться полностью, и мало кто захочет копаться в нативном громоздком коде, написанным какими-то людьми несколько лет назад по каким-то своим правилам.

Для начала, Go не поддерживает объекты — то, что обозначено O в аббревиатуре ORM.


Что вы имели в виду под «Go не поддерживает объекты»?
Цитата из википедии: «Наличие инкапсуляции достаточно для объектности языка программирования, но ещё не означает его объектной ориентированности — для этого требуется наличие наследования.» Инкапсуляция в Go есть, да, а вот наследования нет. На мой взгляд тут автор слегка «переборщил» — наследование не самая важная часть ORM.
Наследование таблиц/моделей очень помогает при реализации связей One-to-one, например. У нас в проекте есть 3 вида пользователей, каждый из которых использует свой механизм авторизации (требование законов). Так вот базовая часть каждого типа хранится в одной таблице.
Ну если я правильно помню то O в ORM относится как к объекту в целом. Как говорит Википедия оно связывает базы данных с концепциями объектно-ориентированных языков программирования. Но это не означает прямое использование ООП. В Го даже не одна и даже не три ORM библиотеки и не ручаюсь за все но GORM работает просто великолепно
Наследование, а точнее подобие наследования, есть через анонимные структуры. Единственное но, в аргументы к функциям нельзя принимать значение родителя, т.е. не прокатит, скажем, принимать Animal (структуру) даже если структура Dog встраивает Animal.

Вот как это выглядит: https://play.golang.org/p/f5m6WNseR8

Как видно на примере, я определил Animal и его интерфейс, потом создал структуру Cat и Dog. Они приняли в себя структуру Animal анонимно, т.е. утрированно унаследовали поля и методы Animal. Далее проитерировал по слайсу моих домашних питомцев и вызвал методы объектов.

В Go есть ООП, но не такое, как мы привыкли видеть. С другой стороны, никогда не будет сотен слоев абстракций, в которых черт ногу сломит.

Ещё хотелось бы напомнить, что строго определения и стандарта ООП нету.
Спасибо, но это не подобие наследования, это композиция. Другой подход. В каких-то кейсах лучше наследования, в каких-то — хуже. В Go нет наследования, есть композиция. Позволительно ли называть язык объектноориентированным, если он не поддерживает наследование, но имеет интерфейсы и композицию, — я не знаю. Кто-то считает, что наследование — это фундаментальная черта ООП, кто-то считает, что и композиции достаточно. Лично для меня — этот вопрос не важен; если в языке нет инструмента, какой смысл рассуждать об этом? «Если бы у бабушки был <censored>, она была бы дедушкой» )
Скажите, а с какой целью вы в своем примере встраиваете интерфейс IAnimal в структуру Animal? В Go нет надобности как-то объявлять, что структура будет соответствовать какому-либо интерфейсу — если реализовали у структуры все методы интерфейса, значит структура ему соответствует.
Добавлено: и да, в вашем примере нет «анонимных структур» )
Да, это композиция. И да, анонимных структур нету, есть анонимные поля у структур. Как либо объявлять имплементацию интерфейса нет необходимости, вы правы, достаточно реализовать все его методы интерфейса, имплементация неявна. Я пишу на нескольких языках, и не всегда могу быстро переключить контекст и начать писать на Go и мыслить на Go.
Я ответил под вашим постом, потому что многие заявляют как факт: «В Go нету ООП». Окей, пусть сначала принесут сюда стандарт ООП, для начала.
В Ruby 3.0 GIL будет убран. Это основное направление работы в данный момент.
И да, Ruby нигде сейчас не доминирует и даже успел перестать быть мейнстримом.
Эти программы запускаются как единственный процесс, так что кэширование становится тривиальным, а значит, Memcached или Redis не нужны.

Эмм, а аутентификация и сессии пользователей?

Имеется в виду то, что кэширование можно организовать средствами Go. В противовес приложениям, вынужденным запускаться в виде нескольких процессов, для которых необходим внешний кэш, чтобы не дублировать кэшируемые данные.
На один сервер запускается один экземпляр веб-приложения в случае Go. Соответственно, сессии пользователей можно хранить в рамках этого же процесса (map, в самом простом случае).
Разумеется, при горизонтальном масштабировании (на несколько серверов) кэш придется вынести за пределы приложения.

А ещё кеширование можно организовать средствами Си и вызывать из Go. Ощущается странная мания внести вообще всё внутрь своего приложения. Перечисленные инструменты разрабатывались под конкретные задачи и справляются с ними хорошо, так зачем делать велосипед? А отказ от фреймворков подразумевает что делать его придётся с нуля. HTTPS тоже сами делать будете?

Можно и так, если вам это зачем-то нужно. И никто не запрещает использовать Memcache или Redis (или еще что-нибудь современно-экзотическое). Если в этом есть необходимость, пожалуйста — есть готовые библиотеки.

Ну смотрите: сейчас кто то проникнется вашими идеями, начнёт проект на Go. А потом проект взлетит. А потом внезапно придёт осознание что redis таки нужен. А потом nginx с HTTPS. А потом фоновые задачи тоже неплохо бы вынести отдельно (ну там горизонтальное масштабирование и т.п.). И даже жуткий Puppet (ну или не такой жуткий Ansible). И в итоге все описанные преимущества сойдут на нет. А что имеем в итоге? "Ручной" SQL. Ручное управление сессиями. Да вообще всё ручное. И все детали реализации на поверхности.

Давайте все-таки начнем с того, что идеи не мои. Хотя я ими и проникся в процессе перевода и более-менее разделяю. Поэтому постараюсь ответить. HTTPS есть встроенный, если хочется letsencrypt, можно «дернуть» пакет для обновления сертификатов из готовых фреймворков. В конце концов, поставить nginx перед сервисом — дело 5 минут (20 с «гуглением», если не делали такого раньше). Другое дело, если ради повышения производительности (или отказоустойчивости) начинаем горизонтально масштабироваться. Если я правильно понимаю вас, это как раз тот самый случай, когда «внезапно придёт осознание что redis таки нужен». И тут вы, разумеется, правы. Но дело в том, что еще на этапе «redis нам нафик не нужен» можно кэширование организовать интерфейсом, отделив от конкретной реализации, так сказать, сделать задел на будущее. Понадобится вынести кэш в redis для масштабирования или «распила монолита», измените реализацию интерфейса, остальной код трогать не придется. Зато на начальном этапе (пока еще не взлетело) имеем весьма простой деплой и конфигурирование. В простейшем приложении из статьи пример такого подхода — cfg.UI.Assets.
Я к тому, что вообще, вы правы, конечно. Но в частности — не совсем. Ведь, до какой-то степени приложение можно масштабировать и вертикально. И в случае Go вам не придется прилагать для этого особых усилий. В случае, например, того же python вам изначально придется делать то, о чем мы говорим (балансер, кэш, фон, ...) — без этого будет грустно смотреть на загрузку сервера.
Возможно, я не прав — все-таки я сейчас больше админ…

Есть такая замечательная штука как Ansible (несправедливо не упомянутая в статье), которая будет делать всё это за вас. А есть ещё не менее прекрасный Docker. Но на самом деле это всё мелочи. Я обязательно прочитаю остальные части (кстати, неплохо бы их осмысленно озаглавить), и тогда уже задам вопросы по существу. И да, не заметил что перевод.

Справедливости ради, стоит заметить что Керниган и Донован в своей книге отдельно отмечают, что не нужно использовать встроенные механизмы Go для организации очередей и key-value хранилищ, несмотря на соблазн, а обратится к специализированным решениям.
Да, описанный подход со всем внутри одного процесса был очень популярен у явистов в начале веба, когда сервера были большими (в сравнении с количеством посетителей). Сегодня компьютеры стали маленькими (опять же в сравнении с количеством посетителей), но их стало очень-очень много. Тут приходит на ум модель гугла с большими кластерами на относительно дешевом железе со всякой отказоустойчивостью через горизонтальное масштабирование. А горизонтальное масштабирование требует разделения ресурсов в кластере. Именно оттуда и растут ноги у nginx, memcached, rabbitmq, etc — они помогают размазать нагрузку по сотням машин. Часть машин содержит размазанный кеш, часть собирает из него пресловутый HTML, часть раздаёт горячие данные, часть холодные.

Отсюда вывод: да, можно сделать монолит, который будет в 4 раза быстрее на одной машине, чем вот тот стек, что описан в статье, но расти ему будет некуда.

А еще есть база данных, в которую всегда упирается веб, как его не готовь. Вот тут хорошо описано phgrey: Чек-лист по выживанию сайта.

Пример с гуглом не подходит — создатели Го как раз работают в Гугле, и создавали язык специально чтобы разгрузить свои сервера. И у них это в целом получилось, язык нашел свою нишу и используется в Гугле

Сразу вопрос. Какой тип серверов в кластере они смогли разгрузить? Если у вас есть ссылка на статью о том, как им это помогло, то я буду рад проапгрейдиться :)
А у вас подписка на Гугл закончилась?
«Golang in google» = первые результаты
https://www.quora.com/How-is-Go-used-at-Google
Понравилась статья, а именно разумный, хладнокровный вгляд на инструментарий разработки.

Решил написать развёрнутый комментарий. Читал статью с большим интересом, подумал: вдруг она убедит меня в том, что Go нужен? Но по ходу статьи все более становилось похоже что автор убеждает себя. Аргументы, скажем так, несостоятельные. Пройдёмся подробнее.


  1. Многопоточность. GIL — это особенность реализации. Она действительно не позволяет использовать многопоточное программирование, но польза от него в веб-приложениях крайне сомнительная (разве что вам действительно необходимо в рамках одного запроса делать какие-то трудоёмкие и параллелящиеся операции; при этом если используется библиотека типа sklearn или numpy, то там параллелизм будет). Дропбоксовцы пилили свою реализацию питона — "Pyston", и кажется даже без GIL (но это не точно). Она была очень быстрой в бенчмарках, но вот прирост производительности в реальном веб-приложении (ради чего всё и затевалось) оказался неприлично маленьким, в итоге её забросили. Так что не GIL'ом единым. В реальных приложениях всякие UWSGI справляются с задачей превосходно. Кстати, в приведённой статье про C10K перечислены Nginx, Tornado и т.д. как решения данной проблемы. В любом случае, ничего сложного в этом нет.


  2. Фоновые задачи. Да, без них никуда. И да, их как правило следует писать как часть приложения. Но я не вижу ничего плохого (и даже наоборот) в использовании Celery или Resque (да, с redis в качестве бэкенда).

В этом случае та огромная сложность, введенная в первую очередь для возможности использования популярного скриптового языка [для создания веб-прилолжения], оказывается ненужной.

Что?


Особенно учитывая, что Python или Ruby приносят мало выгоды, когда весь вывод — это JSON.

Ну современные СУБД умеют отдавать JSON (тот же Postgres), зачем вообще нужна прослойка в виде Go? Даёшь веб-приложения на PL/SQL!


  1. ORM не нужен. Ок… Только не забывайте предохраняться от SQL-инъекций. При миграции деликатно промолчу.
  2. Фреймворк не нужен. Ок… Только не забывайте предохраняться от XSS, CSRF и т.д.

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

Конечно, лучше когда детали реализации на поверхности. Ну или спрятаны в пакет (особенно бинарный).


То, что начинается с лексического псевдонима для одной строки JavaScript становится слоем в слоях транспайлеров, минимайзеров, поверх хелперов, скрытых где-то в подзависимостях.

Я понимаю что это реверанс в сторону нода, но на клиенте от транспайлинга JS тоже откажемся? Что дальше, нафиг ES6? Вернёмся к ActiveX?


А ещё в статье вообще не описаны недостатки Go. Я сам с ним не знаком, но на мой взгляд это в первую очередь своеобразный синтаксис и ООП (точнее, его отсутствие), вместо которого применяется нечто вроде monkey-патчинга, который с моей точки зрения является особо опасным антипаттерном.


Итог: Я так и не увидел ни одного преимущества Go. Перспектива пилить велосипед на каждый чих меня скорее отталкивает. И всё ради чего? Аргумент "патаму что сложна" меня как то не удовлетворяет.

Я знаю, если вместо того, чтобы пользоваться удобным User.find(:all).filter..., которое обеспечивается чем-то вроде ActiveRecord, писать SQL вручную — это нечто неслыханное в некоторых сообществах, но я все-таки думаю, что такое отношение должно измениться. SQL — прекрасный язык.
Хочется пожать автору руку. Много лет назад тренд развития средств разработки почему-то пошел таким образом, чтобы спрятать SQL с глаз долой, обложив сверху разными прослойками (ORM), дающими лишь жалкое подобие возможностей SQL.

А я все заставить себя не мог перейти на такой orm, думал лучше сам запрос наберу, да наджойню и пофильтрую. Оказывается, не ошибся в целом )

Сам около полугода разрабатываю разного рода сервисы и миддлвари на Go. Всё идёт хорошо.
Что нужно на мой взгляд учесть и с чем сам часто сталкивался:


Если разрабатывается весь сайт в виде монолита, вероятность падения всего ресурса из-за сбоя на маленькой страничке возрастает. Я бы посоветовал значимую функциональную составляющую предметной области (комментарии/загрузку файлов) выделить в отдельный сервис и общаться с ним хоть по какому протоколу, какой больше нравится.


Программировать нужно очень аккуратно. Зависающий при каких-то экзотических условиях мутекс или неиспользование оных, а также некорректное использование тикеров обеспечит вам стабильные падения части вашего ресурса. Поэтому нужно очень тщательно всё тестировать и пользоваться go build -race.


Автоперезапуск упавшей части веб-приложения решается путём создания из них системных сервисов с автоперезапуском при падениях.


А если планируете вести простой блог для себя или сайт-портфолио, то обратите внимание на Hugo, свяжите его с Caddy с плагином http.hugo и наслаждайтесь статическим сайтом, который автоматически генерируется из исходников в виде markdown-страниц

К вопросу о необходисти в БД, то помоему bbolt устраняет проблему выбора БД для многих задач :)
Sign up to leave a comment.

Articles