Три лица компании Bit Beat

интервью Java

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

Последняя часть, конечно же, технический директор, о котором мы поговорим дальше.Технический директор спокойно посмотрел на резюме программиста Сяо Чжа, а затем сказал: «Я вижу, что ваша предыдущая работа связана с платежами, тогда я Что делать, если вы получили два уведомления об обратном вызове от WeChat или Alipay?
"Маленькая Жа": О, мы обычно делаем идемпотент. Обратный вызов платежа обычно содержит такую ​​информацию, как идентификатор заказа. Нам нужно только судить, был ли обработан тот же самый идентификатор заказа. Если он был обработан, просто проигнорируйте его.
"Директор": Что делать, если в процессе оплаты запасы товаров успешно уменьшаются, а обновление заказа пользователя завершается сбоем?
"Маленькая Жа": обычно мы используем транзакции для обеспечения согласованности данных.
"Директор": Итак, вы используете базу данных MySQL.
"Маленькая Жа":Да.
"Директор": Используете ли вы режим master-slave в MySQL?
"Маленькая Жа": Да, один мастер-ведомый режим, ведущий обеспечивает запись, а подчиненный обеспечивает чтение.
"Директор": У меня есть вопрос здесь.Если вам нужно проверить статус заказа в процессе размещения заказа, если вы читаете подчиненную базу данных в это время, не сможет ли она прочитать последние данные из-за проблемы с задержкой, вызывающей проблемы с данными?
"Маленькая Жа": Если вы хотите рассмотреть проблему задержки, как правило, в сценариях с высокими требованиями к данным в реальном времени, мы будем напрямую читать основную базу данных, чтобы избежать чтения старых данных из-за проблемы с задержкой подчиненной базы данных.
"Директор": Я вижу, что некоторые архитектуры позволяют по умолчанию задерживать один из подчиненных узлов на один час.Как вы думаете, в чем польза от этого?
"Маленькая Жа": Я понимаю это.Если вы однажды случайно удалите или обновите некоторые данные, а затем пожалеете об этом, в это время мы можем найти неправильно обновленные или удаленные данные через этот подчиненный узел отложенной репликации в течение часа.
"Директор": Какой журнал используется для репликации в режиме ведущий-ведомый?
"Маленькая Жа": binlog, в обычных условиях после включения binlog измененный SQL будет отправлен на подчиненные узлы, и каждый подчиненный узел будет выполнять один и тот же SQL в соответствии с содержимым binlog для достижения согласованности данных.
"Директор": Вы сказали, что измененный sql записывается в бинлог, верно, то если я выполню этот sql:

update user set money=money+0.1 where money=rand()

Поскольку rand будет генерировать случайное число, велика вероятность того, что главная библиотека и ведомая библиотека также будут обновлять разные данные при выполнении этого sql, что приведет к несогласованности между ведущей и ведомой?
"Маленькая Жа": Да, на самом деле бинлог не только поддерживает этот режим операторов (запись изменений sql), но и поддерживает режим строк.В режиме строк он уже не записывает измененный SQL, а записывает конкретное "что изменилось в этих данных", так что если используется режим строки, даже случайные числа, такие как rand(), не будут иметь несоответствия ведущий-ведомый.
"Директор": Строковый режим классный, но строчный режим не кажется идеальным.Знаете недостатки строчного режима?
"Маленькая Жа": Вы знаете, построчный режим потребляет больше места для хранения, но мы можем настроить смешанный режим (mixed mode), в этом случае MySQL будет судить по реальной ситуации, например, для SQL, что не вызовет несогласованности master-slave , используйте режим операторов напрямую.SQL, который вызовет несогласованность ведущий-ведомый, будет использовать режим строк, который не только обеспечивает согласованность данных, но и не занимает слишком много места для хранения, поскольку используются все режимы строк.
"Директор":Хорошо,вы установили.Вернёмся к вопросу заказа.Если начальник в один день делает мероприятие и планирует поставить 1000 iPad mini7s,цена на 10% ниже обычной цены,но сообщается что 100000 люди придут его хватать Как сделать так, чтобы ваш интерфейс сопротивлялся жизни?
"Маленькая Жа": Вы говорите про мгновенное убийство (а какой к черту мини7, его еще нет в списке, похоже на фейк, и что значит получить скидку 10%, только кость сломать), нормально, он разделен на интерфейсную часть Ограничение тока и внутреннее ограничение тока.Для внешнего интерфейса, например, после того, как пользователь нажмет кнопку заказа, пусть кнопка будет недоступна, чтобы пользователь не мог нажать во второй раз, чтобы избежать сумасшедших кликов, которые вызывают слишком много бесполезных запросов, бэк-энд Если это так, такой большой запрос точно не пойдет напрямую в базу данных.Запрос может храниться в очереди Redis, а производительность Redis по-прежнему очень силен.
"Директор": Ну, то, что вы сказали, все еще относительно поверхностно. Вы сказали, что кнопка интерфейса неактивна, чтобы избежать второго щелчка пользователя. Что, если пользователь снова обновит страницу?
"Маленькая Жа": Если обновить страницу, то можно запросить у сервера.На каждый запрос не только пускать его в очередь на обработку, но и задавать хеш.Временная сложность хэша O(1), так что когда пользователь обновляет запрос страницы, вы можете определить, можно ли продолжить текущий порядок, в зависимости от того, находится ли заказ пользователя в хэш-таблице Redis.
"Директор": Есть ли способ уменьшить количество запросов, вызванных сумасшедшим обновлением страницы?
"Маленькая Жа": Да, для пользователей, которые уже разместили заказ, вы можете сохранить тег в локальном локальном хранилище браузера, чтобы при следующем обновлении вы могли сначала проверить, есть ли уже соответствующий тег в локальном локальном хранилище. не нужно идти в службу. Если клиент запрашивает, это означает, что заказ был размещен и в настоящее время находится в очереди. Для пользователей, которые не разместили заказ и все еще злонамеренно обновляют, интерфейс может сделать Например, даже если они бешено обновляются, они запрашивают не каждый раз, а каждую 1с.
"Директор": Ну, вы сказали, что сервер использует хэш, чтобы определить, сделал ли пользователь заказ.Например, если пользователь с userid=100 размещает заказ, он сохранит hash[100]=1.Скорость хеш-таблицы не должно быть проблем, но есть ли другой более компактный способ?
"Маленькая Жа": Можно хранить в битмапе, каждый user_id занимает один бит, что очень экономит память.
"Директор": Вы упомянули ранее, что каждый успешный запрос на заказ попадает в очередь.В чем проблема?Всего товаров всего 1000.Если есть 10 000 пользователей, которые отсортированы, то 9 000 пользователей не смогут его захватить.
"Маленькая Жа":(Правда, раньше я получал оплату только от небольшой компании, а заказов было всего 10 в день. Если бы вы меня проверили на мгновенное убийство, если бы не порнография бывшей компании, меня бы убили компанией, и я был бы убит вами сегодня~ ), это правда, но поскольку это событие, а количество продуктов ограничено, мы можем заранее установить общее количество продуктов на redis, чтобы каждый при поступлении запроса соответствующая сумма уменьшается на единицу, а когда сумма равна 0, сообщается пользователю напрямую Если инвентаря нет, нет необходимости входить в очередь сортировки Таким образом, после того, как клиент получит информация о том, что на сервере нет инвентаря, снова устанавливается localStorage, так что он будет возвращаться напрямую независимо от того, разместили ли вы заказ или нет, без запроса сервера, так что даже может перехватить большое количество бесполезных запросов.
"Директор": Вы выглядите довольно хорошо, но кажется, что непротиворечивость данных не может быть гарантирована.Например, успешная установка растрового изображения, не удалось уменьшить инвентарь, не удалось войти в очередь заказов или успешная установка растрового изображения, успешное уменьшение инвентаря , и не удалось войти в очередь заказов.
"Маленькая Жа":(Вы правы 🐶), redis тоже поддерживает транзакции, но не поддерживает откат, поэтому откат нужно реализовывать самостоятельно.Например, при неудачном сокращении инвентаря мы можем восстановить битмап обратно, или если не хотим чтобы восстановить его, мы можем Компенсация используется, чтобы сделать заказ успешным, Например, при возникновении ошибки ошибочный заказ отправляется в другую очередь проверки и компенсации, а затем используется сценарий проверки и компенсации для принятия соответствующих мер компенсации.
"Директор": Вы часто используете Redis в своей производственной среде?
"Маленькая Жа": Их довольно много.
"Директор": Так вы все используете сценарий, когда кеш аннулируется, а затем читается из базы данных?
"Маленькая Жа": Не все, потому что я работаю на стороне C, и трафик все еще относительно велик, порядка 10WQPS, и, по совпадению, большая часть бизнеса, за который я отвечаю, - это чтение сценариев, чтобы обеспечить более быстрое В ответ, Я использую Redis непосредственно на своей стороне, и нет никаких сценариев невозможности чтения базы данных.
"Директор": О, тогда если кеш недействителен, нет данных для чтения.
"Маленькая Жа": Скрипт регулярно сбрасывается, что означает, что некоторые кеши не станут недействительными.Если есть изменения, скрипт сбрасывается автоматически.
"Директор": Круто, кажется, вы очень полагаетесь на redis.Вы сказали, что ваш QPS составляет 10 Вт.Если трафик в один день лопнет, будут ли у вашего сервиса проблемы?
"Маленькая Жа": Burst traffic это действительно так, но наш сервис не только умеет поддерживать 10WQPS, а вообще немного расширяет ресурсы в большую сторону.Например, он реально может поддерживать в 2 раза больше текущего QPS, так что даже если придет Burst трафик, то нет страх. В то же время наш интерфейс также поддерживает ограничение по току, если трафик определенного интерфейса превышает ожидаемый, мы не будем обрабатывать избыточные запросы, чтобы предотвратить бомбардировку сервиса.
"Директор": Какой алгоритм ограничения тока вы используете?
"Маленькая Жа": ведро токенов.
"Директор": Можете ли вы рассказать о принципе ведра для токенов?
"Маленькая Жа":(Опять надо спросить как сделана авиапушка, а я на самом деле шурупы прикрутил), как бы это выразиться, собственно ведро это разрешенный трафик, естественно жетон ставится в ведро , и каждый раз при обработке запроса В это время токен должен быть получен из корзины в первую очередь.Если токен не получен, это означает, что скорость ввода токена, скорее всего, не сможет угнаться за запросом , и ток будет ограничен.
"Директор": Тогда ты знаешь, как это сделать?
"Маленькая Жа": Ну, позвольте мне подумать об этом (они используют пакеты с открытым исходным кодом, кто обычно видит эти~, давайте просто скажем что-то), ведро может быть очередью, а затем запустить процесс, чтобы продолжать помещать его в один конец очереди Токен , с другой стороны, наша программа продолжает получать токен, так что все в порядке?

"Директор": Да-да, но надо запускать отдельный процесс, чтобы поставить токен, а это пустая трата ресурсов, можно подумать, есть ли другие способы, можно прописать, и псевдокод подойдет.
"Маленькая Жа": (Также напишите) Хорошо, я сначала помедитирую и подумаю, когда ты дашь мне песню.

Задумчивый Сяо Чжа выстраивает в уме четкую логическую схему анализа:

  1. Во-первых, емкость корзины должна быть установлена ​​нами, при условии, что она равна m, а во-вторых, сколько токенов должно быть размещено в секунду, что является соответствующим QPS, который также настраивается. во-вторых, это n - скорость размещения.
  2. Интервьюер сказал, что использовать новый процесс для ввода токена — пустая трата ресурсов, поэтому определенно нет необходимости запускать дополнительный процесс для его ввода, то есть помещать его в режиме реального времени каждый раз, когда токен извлекается, поэтому нет необходимости запускать другой процесс, предполагая, что при поступлении нового запроса время запроса в это время является текущим временем.После этого запроса, когда поступает следующий запрос, предыдущее время является временем когда в последний раз был взят жетон.Просто знайте текущее время сейчас и последний раз, когда токен был взят.Разница между последним временем, умноженная на скорость вставки, не является ли это токеном, который должен быть вставлен?
  3. Поэтому разумно рассчитать, сколько токенов нужно ставить каждый раз, когда вы делаете запрос.Этот токен=время*скорость, то есть если можете поставить, то ставьте сразу, а потом берите.Если можете Не вставляйте, не вставляйте, берите напрямую и ограничивайте ток, если он недоступен.

"Маленькая Жа": Посмотрите, работает ли это:

func isLimit() bool {
    var (
       leftToken //剩余的token
       m//桶的容量
    )
    difftime= now-last //时差
    inToken = difftime*n //应该放入的token数
    if inToken + leftToken <= m { //小于桶容量
         leftToken = inToken + leftToken
    } else { //大于桶容量
        leftToken = m
    }
    if leftToken > 0 {
        leftToken--//消耗一个
        return true
    }
    return false //没有token
}

"Директор": (я вообще-то выписал~, да), ядро ​​выписали, но надо учитывать проблему параллелизма, а блокировки нет.
"Маленькая Жа": Действительно (все это называется псевдокодом, кто еще так много думает).
"Директор": ок, продолжим, текущий лимит может ограничивать трафик, превышающий ожидания, тогда рассмотрим такую ​​проблему сейчас, во-первых, трафик нормальный, но есть проблема с сервисом, на который мы рассчитываем, например, 500 в услуга, на которую мы полагаемся, и не может быть в короткие сроки Восстановление, если вы продолжаете просить об этом в это время, это пустая трата времени?
"Маленькая Жа": Это может быть сплавлено.
"Директор": О, давай поговорим об этом конкретно.
"Маленькая Жа":fuse означает, что если проверяющая сторона достигнет стандарта fuse по количеству ошибок в течение определенного периода времени, она отрубит службу напрямую и не вызовет ее, и этот стандарт также настраивается, например, если 100% ошибок происходят в течение 10 с и т. д. .
"Директор": После фьюза, если полагающаяся сторона выздоровеет, будем продолжать фьюз?
"Маленькая Жа":Конечно нет.Когда фьюз срабатывает, это значит, что проблема с проверяющей стороной, но мы не можем держать фьюз.Мы можем пустить в него какой-то трафик в определенное время после фьюза.Например, после фьюза Через 1 минуту пускаем 1% трафика и смотрим.Если проверяющая сторона в это время исправна, то мы продолжим усиливать трафик, пока он не восстановится до 100%, но если проверяющая сторона все еще нехорошо, тогда продолжайте плавить и ждите следующего увеличения громкости Обнюхивание, просто продолжайте повторять попытку Если проверяющая сторона в порядке, нет необходимости в ручном вмешательстве.Если проверяющая сторона не в порядке, она не будет безмозглые запросы.
"Директор": С точки зрения бизнеса, если данные не будут получены во время автоматического выключателя, это не повлияет на пользователей.Есть ли какое-либо решение?
"Маленькая Жа": Да, но это зависит от бизнес-сценария.Мы можем настроить некоторые итоговые данные.После фьюза, хотя мы не можем получить нужные данные через проверяющую сторону, мы можем вернуть статические данные, которые были настроены для этого сценария из начало. , Конечно, практический результат зависит от бизнес-сценария, и некоторые предприятия могут быть не в состоянии.
"Директор": Используете ли вы очереди сообщений в своей повседневной работе?
"Маленькая Жа": Да, в основном кафка.
"Директор": Для решения какой проблемы вы в основном используете kafka?
"Маленькая Жа": снижение пикового трафика, асинхронные задачи.
"Директор": Тогда вы говорите о преимуществах потребительских групп.
"Маленькая Жа": Во-первых, у темы может быть несколько разделов, а затем у группы может быть несколько потребителей. Эти потребители вместе образуют группу потребителей. Потребители в группе потребителей могут использовать разные разделы темы, чтобы достичь эффекта балансировки нагрузки. .
"Директор": Что делает брокер в kafka?
"Маленькая Жа": брокер является агентом сообщения. Производители пишут сообщения в указанную тему в брокерах, а потребители извлекают сообщения указанной темы от брокеров, а затем выполняют бизнес-обработку. Брокер действует как ретрансляционная станция для брокер, чтобы сохранить сообщение в середине.
"Директор": Что означают ISR, AR и OSR в kafka, и поговорим о взаимосвязи между ними.
"Маленькая Жа": AR: все наборы реплик, ISR: все наборы реплик, соответствующие условиям выбора, OSR: наборы реплик, которые слишком сильно отстают или выходят из строя, AR = ISR + OSR, при нормальных обстоятельствах AR должен быть таким же, как ISR, но когда Если реплика-последователь слишком сильно отстает или узел реплики-последователя зависает, он будет перемещен из ISR и помещен в OSR.Выбор кафки также относительно прост, то есть первая реплика в ISR выбирается как новый ведущий узел. Например, сейчас AR=[1,2,3], 1 кладет трубку, затем ISR=[2,3], тогда 2 будет избран новым лидером.
"Директор": Какова роль zookeeper в kafka, могу ли я использовать zookeeper?
"Маленькая Жа": zookeeper — компонент распределенной координации. Более ранние версии kafka использовали zk для хранения метаинформации, статуса потребления потребителя, управления группами и значений смещения. С учетом некоторых факторов самого zk и высокой вероятности единичных проблем во всей архитектуре, роль zookeeper в новой версии постепенно ослабляется. Новый потребитель использует протокол групповой координации внутри kafka, что также снижает зависимость от zookeeper, но брокер по-прежнему зависит от ZK, а zookeeper также используется в kafka для выбора контроллера и определения, жив ли брокер и т. д.
"Директор": Почему кафка такая быстрая?
"Маленькая Жа": Последовательная запись. Поскольку современные операционные системы поддерживают методы упреждающего чтения и записи, последовательная запись на диск в большинстве случаев выполняется быстрее, чем случайная запись в память. Zero-copy: технология Zero-copy уменьшает количество копий. Пакетирование сообщений: объединяйте небольшие запросы, а затем взаимодействуйте в потоковом режиме, уменьшая нагрузку на сеть.
"Директор": Когда потребитель отправляет смещение потребления, используется ли смещение последнего сообщения в настоящее время или отправлено смещение + 1?
"Маленькая Жа": смещение+1.
"Директор": У тебя есть что спросить у меня?
"Маленькая Жа": Какова основная работа этой должности?
"Директор": творог.
"Маленькая Жа": (повезло) Ладно, больше не о чем спрашивать.
"Директор": Хорошо, тогда подожди немного здесь.
"Маленькая Жа": ок, ок (следующий должен быть хр).

В итоге программист Сяо Чжа успешно получил предложение от Bitbeat с повышением зарплаты на 50%.

Наконец

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

Обратите внимание на официальный аккаунт [притворитесь, что разбираетесь в программировании], здесь вас ждет программист Сяожа.