предисловие
Когда наше приложение нормально работает в сети, нам не нужно ни о чем беспокоиться в обычных обстоятельствах, но неизбежно будут появляться ошибки; в это время нам нужен соответствующий механизм для обнаружения ошибок в нашей системе. уведомить соответствующий персонал, в противном случае об ошибке не будет известно до тех пор, пока пользователь не предоставит отзыв о том, что произошла ошибка, которая влияет на взаимодействие с пользователем и является неуправляемой, что является неприемлемым.
вводить
Моя команда в настоящее время использует наборы, связанные с Spring Cloud, для разработки микросервисов, поэтому мое введение и практика также выполняются в рамках этого стека технологий, и в то же время можно использовать elasticsearch.
Мы используем Spring MVC для развития бизнеса, притворяясь инфраструктурой удаленного вызова интерфейса restful, и zuul в качестве сервисного шлюза, чтобы открыть интерфейс для внешнего мира. Этот стек технологий очень распространен в командах, разрабатывающих Spring Cloud.
идеи
Потому что в начале мы записывали единый лог доступа на шлюзе и использовали filebeat для синхронизации его с elasticsearch для облегчения последующего запроса и анализа данных, но этого недостаточно, мы хотим иметь возможность напрямую судить по логу, является ли он В конце концов, возникает явное исключение, нам нужна точка или соответствующий порог, чтобы определить, что является ненормальным, могут быть ошибки, и необходимо выполнить соответствующие операции для предупреждения. Поэтому нам нужно написать несколько статей о ведении журналов, чтобы в журналах, которые мы записываем, было достаточно мощной и точной информации, чтобы мы могли судить, является ли это ненормальным, а затем запускать серию операций (сигналы тревоги и т. д.).
После определенного анализа я думаю, что исключение — хороший момент, чтобы судить о том, есть ли ошибка, потому что нет исключения без ошибки, но в запросе должна быть ошибка с перехваченным исключением или без него; поэтому используйте это как точка входа, чтобы пойти глубже думать.
выполнить
Настройка в разработке
Во-первых, наша инфраструктура указывает единый код ошибки для запроса внешнего мира, и в то же время бизнес-уровень выдает исключение для запроса внешнего мира.
Мы определяем это как:
public class DomainServerException extends Exception {
// 平台定义错误码
private int code;
// http status
private int status;
// 具体错误信息,面向开发者的提示, Exception的message用于面向用户的提示
private int error;
// 相关异常的堆栈信息
private int stack;
public DomainServiceException(int code, String message, Throwable throwable) {
super(message, throwable);
this.code = code;
if (isServerError())
this.stack = ExceptionUtils.getStackTrace(throwable);
}
}
Информация о стеке — это поле, добавленное для отслеживания исключений.http status为5**или平台定义错误码为服务器异常Когда соответствующая информация о стеке исключений загружается и значение устанавливается в поле стека. В частности, вDomainServiceExceptionКонструктор выполняет либоspring ErrorController(потому что мы используем исключения для выдачи кодов ошибок, поэтому мыspring MVCдефолтErrorControllerпо индивидуальному заказу).
мыErrorControllerТип возвращаемого значения определяется как
public class HttpErrorResponse implements Serializable {
private Date timestamp;
private Integer status;
private String error;
private String message;
private String stack; // 异常堆栈 方便记录同时在前后端调试的时候信息也更加丰富
private String exception; // 异常类型
private String path; // 错误请求路径
private Integer errorCode; // 平台定义错误码
}
Для случаев ошибки мы бросаемDomainServerExceptionили другое неопрятное исключение,DomainServerExceptionПо умолчанию это наша бизнес-ошибка, и ее также можно использовать как ошибку-исключение, но мы обрабатываем ошибки-исключения какDomainServerExceptionОн передаст верхний стек исключений в конструктор для генерацииDomainServerExceptionобъект исключения (注意:此模式下一定不要去处理你不知道该怎么处理的异常,如果你处理不了就一直往外抛,ErroController能够正确的处理并记录他然后供报警使用).
В этот момент мы бросаемHttpErrorResponseМожет использоваться в двух местах:
- звонки между службами
- Запрос отправлен zuul
-
В первом случае, поскольку мы используем
feignДля совершения удаленных звонков между сервисами переписываемErrorDecoderвыполнятьHttpErrorResponseиDomainServerExceptionилиDomainServerException的子类(оценка типа выполняется через поле исключения) и выбрасывается. Каскадные вызовы и аналогии в конечном итоге перейдут на уровень шлюза для обработки. Таким образом, первый случай в конечном итоге станет вторым случаем. -
Во втором случае мы, поскольку у нас есть определение кода ошибки, и мы также возвращаем ошибку при нормальных обстоятельствах, но нормальный результат не имеет кода ошибки, поэтому мы находимся в
zuulпонялtype为“post”的filter来对返回值进行格式化,同时也对老的平台与新的平台进行输出格式化. Здесь мы оцениваем, является ли контент, возвращаемый службой, ненормальным, и записываем его (сохраняем соответствующую информацию вRequestContext) и, наконец, записать соответствующую информацию в унифицированный фильтр ведения журнала (включая обычный фильтр и фильтр исключений zuul). В то же время, поскольку мы также написали некоторые связующие интерфейсы в Zuul, мы реализовали ZuulErrorController в ErroController, который унаследовал общие службы, а также записал информацию об исключениях.
Хранение журнала и сигнализация
Как записывать лог определился, используем filebeat для передачи данных лога в elasticsearch. Теперь у нас есть код ошибки и информация о стеке в elasticsearch.Очевидно, что информация о стеке - очевидная информация об ошибке.Как только это поле появляется в Ziyao,значит проблема с нашим кодом.По этому можно звонить в полицию . Для информации о коде ошибки это может быть сложнее.В некоторых случаях нам нужно оценить порог.Когда мы превысим порог в некоторых случаях, мы подадим сигнал тревоги (в настоящее время применение этого блока требует дополнительных размышлений)
Инструменты для предупреждений запросов elasticsearch:elastalert, но я не очень холодно отношусь к этому инструменту, и я также устал иметь дело со сложными зависимостями развертывания Python.Я использую golang для разработки инструмента с более простыми функциями и меньшими затратами на обучение. Если это нормально для внутренних испытаний, исходный код должен быть открытым.
未完待续