Мао Цзянь: Практика го-служения Билибили (часть 1)

задняя часть Микросервисы Go API

предисловие

В момент, когда микросервисы популярны, bilibili (станция B) также находится под давлением быстрого роста бизнеса, и постоянно оптимизировала историческую систему, и приложила много усилий для так называемой «большой системы и маленькой работы». , особенно Go Как язык разработки, общая поддержка эксплуатации и обслуживания относительно слаба, например, разработка, развертывание, тестирование, интеграция, мониторинг, отладка и т. д. На конференции GopherChina 2017 Мао Цзянь, технический директор Station B, поделился «ямами» на пути микросервисов и своими мыслями о всей структуре микросервисов после окончательной эволюции.

Презентация будет включать в себя следующие части: эволюция услуг станции микро 1.B, доступность 2, промежуточное программное обеспечение 3, непрерывная интеграция и доставка 4, эксплуатация и обслуживание системы 5.....

об авторе

С 2015 года он отвечал за платформу и инфраструктуру UGC на bilibili (станция B), разрабатывал push-сервис с открытым исходным кодом goim для прямых трансляций, распределенное хранилище BFS на станции B и руководил разработкой кэш-прокси на станции B. , bili twemproxy и т. д. Архитектура повторяется и рефакторинг.Последние шесть лет он работал в Cheetah Mobile, работал администратором базы данных MySQL и занимался разработкой C. Среди них он разработал систему push-кластеров gopush для Cheetah Mobile . Например, диагностика производительности службы приложений, исследование ядра, эволюция стабильной серверной архитектуры.

Эволюция микросервисов

оригинальная рама

Когда мы впервые вошли на станцию ​​B, мы столкнулись с некоторыми проблемами в технической архитектуре: во-первых, развертывание было очень неудобным, нам нужно было собрать всю основную станцию ​​без каких-либо зависимостей, затем было два репозитория кода, которые нужно было развернуть Когда пришло время упаковать все куски и кинуть их на него, результат часто не в состоянии встать, кроме того, стоимость тестирования также очень высока. Следствием этого является то, что общая эффективность разработки относительно низкая, т. к. непонятны обязанности, весь код представляет собой ком, и неизвестно, кто за какой модуль отвечает, да еще какие-то публичные части отвечают за многих людей. . Как показано на рисунке 1.

Рисунок 1

концепция обновления

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

фигура 2

С моей точки зрения, верхний уровень — это широта пользователя и учетная запись, а средний сервис — членство, вклад, информация о свойствах пользователя, цепочка отношений, динамические рекомендации и т. д. С точки зрения некоторых вспомогательных сервисов внизу есть проверочный код, поиск IP, push, центр конфигурации, в том числе некоторые сервисы управления протобуфером.

Зачем акцентировать внимание на этом вопросе? Приступая к работе с микросервисами, вы должны понимать обязанности или границы всего бизнеса. Наша первоначальная стратегия заключалась в том, чтобы окружить город сельской местностью и постепенно демонтировать все основные предприятия. Например, история игр пользователя, избранное, комментарии и т.д. Это второстепенные дела, не имеющие прямого отношения к нашей основной линии. Сделайте это в первую очередь. В процессе обновления один должен считаться совместимым, и нельзя сделать один API несовместимым со всеми. До сих пор, когда дело доходит до рефакторинга учетной записи нижнего уровня, это было очень болезненно, потому что в него вовлечено очень много отделов.

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

Третье — изоляция внутренних и внешних сетевых сервисов.За последние 15 лет станция B также столкнулась с некоторыми инцидентами безопасности.Наш КЛЮЧ ПРИЛОЖЕНИЯ просочился обратно от клиента, и некоторые люди запросили некоторые интерфейсы в интрасети. Это инцидент безопасности и угроза безопасности. Почему возникает эта проблема? Поскольку ранее мы не изолировали интрасеть, API-интерфейс интрасети был доступен в общедоступной сети. Потому что мы решили на время разобраться в обязанностях всей службы.

Как показано на рисунке 3, мы начинаем с верхнего уровня, первый — это вход в SLB, а затем возвращаемся к шлюзу после входа. Например, некоторые внешние API, такие как наш мобильный терминал, потому что некоторым предприятиям нужно иметь много агрегаций на одной странице, поэтому мы инкапсулируем их в API. Есть также комментарии пользователей, которые являются атрибутами платформы и могут напрямую предоставлять API внешнему миру. Однако есть некоторые службы, к которым нельзя получить доступ извне, например, наши внутренние службы и операции аудита операций для операционной платформы. Например, если наша операционная платформа хочет управлять учетной записью, она не должна быть внешней в это время.В противном случае, если кто-то обнаружит этот интерфейс, независимо от того, какие средства вы используете, у него должен быть способ привлечь вас. Следовательно, необходимо изолировать внутреннюю и внешнюю сети.После того, как эти роли определены, сервисный слой, по сути, мы видим, что основная часть микросервисов — это непосредственно лицом к лицу, которое является модульной единицей бизнеса. .

изображение 3

Далее поговорим о структуре RPC.Итак, какие функции нужны RPC? В первую очередь нужна сериализация, и первая это использование GOB Моя первая идея это унифицировать язык, и писать как можно больше на Go. Потому что, когда у вас есть короткая бизнес-версия или узкое место, будет сложно обнаружить, что этот человек не умеет писать на Go. После унификации Go мы считаем, что использование GOB наиболее удобно, поскольку он поддерживает все встроенные типы. Во-вторых, контроль тайм-аута. Завис из-за блокировки. Предположим у вас есть провайдер, и он заблокирован.Чем больше вы накопите, тем больше вы вешаете. Так что есть контроль тайм-аута, который включает в себя передачу некоторых контекстных вещей. Как и в случае с только что упомянутой проблемой APM, ею можно управлять с помощью контекста. В-третьих, сделать некоторые перехватчики, поэтому интранет также должен иметь определенный звуковой механизм, включая контроль разрешений, статистику, ограничение тока и т. д. Четвёртое — это сервисная регистрация.Мы много сравнивали в своё время, и в итоге остановились на zookeeper, который тоже постепенно дорабатывается до ZK и делает систему AP. Последнее - это балансировка нагрузки, которая рассматривалась давно.В первые дни я фактически использовал LVS или DNS для такого рода планирования, но это не самое лучшее с точки зрения производительности, потому что если вы хотите использовать LVS , вам нужно После нескольких передач через вашу сеть эффект прямой точки является лучшим. Но из-за стоимости в то время мы внедрили его напрямую с клиентской нагрузкой.

реализация на уровне кода

Я только что упомянул об использовании GOB.После использования GOB наиболее подходящим RPC является использование net rpc из стандартной библиотеки и внесение в него некоторых модификаций.

Во-первых, поддержка контекста, а во-вторых, контроль тайм-аута, что является демонстрацией двух тестов. Рисунок 4-1.

Рис 4-1

Кто-то спросил меня, очень ли сложно преобразовать эту вещь.На самом деле, мы видели исходный код net rpc, и вся реализация очень проста, поэтому нам нужно изменить очень мало кода, и риск относительно невелик. .

Сначала добавляется объект контекста, а первый параметр должен реализовывать контекстный интерфейс, делается всего один шаг такого преобразования. Все наши методы rpc принимают контекст в качестве первого параметра. Как показано на рис. 4-2.

Рисунок 4-2

Рисунок 4-3 также является инъекцией контекста в начале Мы помещаем в него больше вещей, таких как методы, имена и т.д. Наш внешний контекст на самом деле имеет внутри небольшой контекст rpc, в который помещаются некоторые вещи, которые мы можем использовать. Перехватчик на самом деле относительно прост.Сначала я определяю абстракцию с ограниченным потоком, статистикой и надежностью.Затем мы добавляем несколько строк простого кода на серверную часть библиотеки rpc.

Рисунок 4-3

Затем мы также внесли некоторые улучшения. Прежде всего, если вы протестировали net rpc, вы обнаружите, что запрос на получение и бесплатный запрос имеют глобальное получение блокировки, поэтому мы изменили его на оптимизацию на уровне области запроса. В правой части рисунка 4-4 мы поместили ответ и запрос в кодек. Более того, чтобы уменьшить количество объектов, мы не используем указатели, а напрямую используем включения структур, так что давление будет меньше.

Рисунок 4-4

Затем посмотрите на рукопожатие. Как показано на рис. 4-5.

Рисунок 4-5

Как осуществляется планирование? Это балансировка нагрузки. На самом деле это относительно просто: мы определяем интерфейс, а затем можем реализовать такие методы, как широковещательная рассылка, вызов, установка тайм-аута и установка тайм-аута определенного метода. Четвертый — это фактически глобальный тайм-аут по умолчанию.После этого файлы, которые мы настраиваем, имеют адреса, протоколы, группы и веса. То, что мы сделали в первой версии, было стратегией wrr, то есть у меня есть куча клиентов, вы мне говорите, какой вес, а я опрашиваю и планирую согласно весу, потому что вся информация о моем узле есть на zookeeper, пока я регулярно извлекаю его в соответствии с событиями. Все изменения узла, сотрудничество с клиентом, я думаю, что этот код относительно прост для написания.

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

Рисунок 4-6

Мы только что закончили слой службы, теперь давайте посмотрим на слой шлюза. Шлюз должен объединиться, и вернемся к сцене только что, определенная страница на мобильном терминале передала 4 или 5 деловых сторон, что делает невозможным прямое подключение студентов на мобильном терминале. Мы сделаем для него API из уровня шлюза, поэтому стоимость будет очень низкой. Унификация протокола также выполняется на уровне шлюза.

На втором шаге мы сделали параллельную оптимизацию, т.к. мы опираемся на множество бизнес-партнеров, их 4-6, поэтому используем errgroup для параллельного вызова. Есть два способа использования Gateway. Сначала у нас был только один Gateway для всех выходов. Позже мы обнаружили, что он не может работать. на самом деле очень опасно. Поэтому мы сделали некоторую изоляцию, основанную на том, важны ли некоторые бизнес-формы или нет. Он может называться APP Gateway, Member Gateway, и мы все еще делаем некоторую изоляцию. Последние слова — это некоторые автоматические выключатели, переходы на более ранние версии, ограничение тока, высокая доступность и т. д., которые мы сделали на шлюзе. Далее мы сосредоточимся на практике высокой доступности.

Высокая доступность

Во-первых, сделать изоляцию.Давайте посмотрим на рисунок 5. Прежде всего, в соответствии с давлением бизнеса, некоторые службы находятся под очень высоким давлением, а некоторые службы находятся под очень низким давлением.Можно ли его изолировать, чтобы влияние служб с высоким давлением должно быть не быть малой, и тогда стабильность должна быть высокой стабильностью влияния.

Рисунок 5

В первые дни, когда не было сервера, все это фактически было развернуто на одной машине.Возможно, было два сервиса, А и Б. Если у А была проблема, Б страдал. На самом деле, после периода времени без контейнеров стадия использования физических машин очень плохая, вам действительно нужно использовать ручные cgroups, а затем ограничивать каждый ресурс. Таким образом, физическая изоляция — это покупка машин.суровая изоляция, например, у нас есть очереди, в которых может быть много вещей, а в некоторых очередях может быть очень мало вещей, если вы поместите их все в одну тему. , до сих пор имеет влияние. Например, когда мы перекодируем видео, оно будет разделено на сверхдлинные и сверхкороткие файлы. Если ультракороткие и ультрадлинные ставятся в очередь, это на самом деле своего рода легкая-тяжелая изоляция. Как и наши кластеры, есть даже разные развертывания, которые также развернуты кластерами, которые часто упоминает Tencent. 

Второе, о чем следует упомянуть, это тайм-аут.Поскольку самое важное в RPCE — тайм-аут, существует много видов тайм-аута, таких как тайм-аут соединения, тайм-аут чтения, тайм-аут записи и т. д., как показано на рисунке 6. Я начал писать код на Go с Go 1.3 в то время, и обнаружил, что многие места недоступны, что однажды привело к сбою, то есть бизнес определенного машинного зала был подключен к БД. линия была отключена, в результате чего все процессы были заблокированы. Как это проверить конкретно, потому что мы обнаружили, что процессор не высокий, а затем база данных сообщила об ошибке, а затем запрос не мог прийти. Позже мы все же использовали GDB, чтобы настроить его, чтобы увидеть, где сверка запущенных gorutnine застрял.Есть некоторые другие методы. В последующем введении я надеюсь постоянно корректировать этот тайм-аут для наших сервисов на основе данных, которые мы собираем. 

Изображение 6

Третье — ограничение тока.Ограничение по току также очень велико, как показано на рисунке 7. Например, в прошлом году мы должны были сказать, что был бизнес, который был в застое. В чем конкретная проблема? Это апстрим вышележащего Nginx, потому что он не устанавливает тайм-аут апстрима, из-за чего наш переход на сталкивается с тремя или четырьмя сотнями подключений.Потом свитч зависает. Выяснилось, что коммутаторы, о которых говорилось ранее, находились в стадии подготовки, и все они в результате умерли. Итак, мы подытожили позже, все еще нужно ограничить текущую защиту, текущий предел, чтобы избежать волны CC-атак и убить вас напрямую. Поэтому мы сделали для этого распределенное ограничение тока, и есть аналогичные решения. Наши связи ограничены, это важные ресурсы, и на них нужно обращать внимание. Как и в Go, в индикаторе есть ряд соединений, ограничивающих ток, которые можно использовать, чтобы не перетащить слишком много соединений и не убить вас. Как и при регулировании запроса, сразу же корректируйте его трафик при обнаружении ситуации и удаляйте трафик вызываемого вами CC. 

Рисунок 7

Затем упомянуть понижение.Их также много, как показано на рисунке 8. В наши первые дни первым шагом было понижение версии пользовательского интерфейса.Каждый раз, когда у нас случался сбой, мы обнаруживали, что если ваш мобильный терминал не может быть открыт, пользователи будут лихорадочно проводить пальцем по экрану, и он может быть открыт через некоторое время. на самом деле количество запросов в это время увеличится. Позже мы делаем понижение версии на стороне клиента. Например, если вы постоянно чистите, я выставлю TTL. Их можно настроить на стороне клиента. Если вы не можете этого вынести, вы можете отправить 10-секундный или даже 30-секундный сверхдлинный TTL говорит клиенту не запрашивать в это время. Я помню, что Alipay не получил платеж, который казался слишком занятым, чтобы позволить вам заплатить или что-то в этом роде.На самом деле, на стороне клиента был текущий лимит.Это окончательное средство.

Есть функция ухудшилась.Это также относительно просто, например, на одной из наших страниц есть какие-то большие данные или данные, рекомендованные искусственным интеллектом, этот модуль может вызвать определенный эксперимент, который приведет к обрушению данных, поэтому на некоторых пустых окнах это время, или вся страница заполнена. Если вы не можете открыть ее, опыт будет плохим. В настоящее время существует множество методов, таких как возврат другого UR в рекомендуемый пул для аварийного восстановления, по крайней мере, для предотвращения открытия всей страницы. Поэтому, когда ваш интерфейс выплевывается, если зависимая бизнес-сторона зависает, вы должны подумать, есть ли у вас какие-либо средства для понижения версии или возврата некоторых значений по умолчанию или даже статических данных.

Я помню, что JD.com сказал в статье, что если у них будет очень серьезный сбой, страница сведений о продукте может вернуть статическую страницу. Поскольку невозможно изменить содержание многих наших продуктов в режиме реального времени, я думаю, что это тоже способ. Есть также несколько автоматических понижений.На самом деле мы делаем больше понижений, таких как статистические сбои. Например, если я запрашиваю интерфейс, если он имеет высокий процент ошибок или большое количество таймаутов, могу ли я не настроить его? Хотя вы полагаетесь на множество деловых сторон, вы можете понизить рейтинг, но если время истечет, ваша окончательная задержка фактически увеличится, поэтому ее следует выгнать в это время.

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

Рисунок 8

Последнее — отказоустойчивость.Как показано на рисунке 9. Что мы делаем больше с отказоустойчивостью, так это прерыватель цепи, Фактически, мы также обращаемся к фреймворку Java, меняем его на версию Go, а затем делаем прерыватель цепи. На самом деле, его основная идея очень проста, то есть, когда количество моих запросов достигнуто, и моя частота ошибок достигнута, могу ли я не настраивать его, и я могу быстро вернуться, не настроив его, что называется отказоустойчивым . После того, как этап отказоустойчивости завершится, должен ли я добавить немного трафика, чтобы проверить, восстановится ли он? В это время, например, поставить поток в 100 миллисекунд.Если это удастся, я думаю, что сервер стабилен, а затем включить переключатель и поставить весь поток.Если он все еще не работает, этот процесс будет повторил.

Рисунок 9

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

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