предисловие
Когда наше приложение нормально работает в сети, нам не нужно ни о чем беспокоиться в обычных обстоятельствах, но неизбежно будут появляться ошибки; в это время нам нужен соответствующий механизм для обнаружения ошибок в нашей системе. уведомить соответствующий персонал, в противном случае об ошибке не будет известно до тех пор, пока пользователь не предоставит отзыв о том, что произошла ошибка, которая влияет на взаимодействие с пользователем и является неуправляемой, что является неприемлемым.
вводить
Моя команда в настоящее время использует наборы, связанные с 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 для разработки инструмента с более простыми функциями и меньшими затратами на обучение. Если это нормально для внутренних испытаний, исходный код должен быть открытым.
未完待续