当前位置: 首页 > news >正文

鄂尔多斯网站建设公司竞价推广外包公司

鄂尔多斯网站建设公司,竞价推广外包公司,网页设计与网站建设教程,wordpress 多租户随着外卖业务的快速发展#xff0c;业务复杂度不断增加#xff0c;线上系统环境有任何细小波动#xff0c;对整个外卖业务都可能产生巨大的影响#xff0c;甚至形成灾难性的雪崩效应#xff0c;造成巨大的经济损失。每一次客诉、系统抖动等都是对技术人员的重大考验#… 随着外卖业务的快速发展业务复杂度不断增加线上系统环境有任何细小波动对整个外卖业务都可能产生巨大的影响甚至形成灾难性的雪崩效应造成巨大的经济损失。每一次客诉、系统抖动等都是对技术人员的重大考验我们必须立即响应快速解决问题。 如何提高排查问题的效率呢最有效的方式是通过分析系统日志。如果系统日志全面会为我们排查解决线上问题带来绝大的帮助但是要想保证系统日志全面就必须打印出所有的系统或业务日志。这样就会带来另一个问题那就是日志量的暴涨过多的日志除了能够帮助我们解决问题外同时会直接造成系统性能下降极端情况下甚至导致系统宕机。在这种背景下为了兼顾性能和快速响应线上问题我们设计开发了日志级别动态调整组件。通过使用该组件可以在需要解决线上问题时实时调整线上日志输出级别获取全面的Debug日志帮助工程师提高定位问题的效率。 使用场景 场景一 业务依赖复杂。某一时刻依赖的下游服务故障导致请求大量超时尤其是像外卖这种集中性特别明显的业务平均每秒QPS在8000以上1分钟的故障就会集中产生大量的错误日志导致磁盘IO急剧提高耗费大量CPU进而导致整个服务瘫痪。如果该业务不能立即降级怎么办 从代码级别解决问题到发版上线暂且不说流程长、操作麻烦同时还存在引入其它故障的高风险。如果系统恰好使用Log4j版本在极短时间内打印出了海量错误日志会快速耗尽Buffer区内存从而拖慢主线程造成服务性能整体下降甚至还没有来得及修复问题海量日志已经拖垮服务造成服务宕机损失惨重。 场景二 大量的订单、结算等客诉问题反馈过来一线工程师大量精力埋没于排查问题中而排查定位问题的最终手段仍然是依赖线上日志。由于链路较长任一日志的缺失都给问题的排查带来极大的障碍面对运营的催促怎么办 工程师为了以后排查问题的方便在任一可能出现异常的地方都会打印出关键日志然后发版上线。但好不容易解决了本次问题还没来得及收获喜悦就又面临着一个新问题那就是场景三。 场景三 由于线上业务系统默认日志打印级别是INFO级别为了排查问题方便调试型日志都以该级别打印出来。这样的话给系统带来了额外的负担在高峰期大量调试日志时会拖慢系统性能增大出故障的风险怎么办 一方面要快速响应业务另一方面要兼顾系统性能能不能两方面兼顾我们的动态调整日志级别工具正是为了解决这种痛点。 能解决哪些问题 日志降级。 兼容Log4j、Log4j2和Logback主流日志框架如果遇到场景一可以通过我们的日志工具快速调整日志输出级别降低系统日志的输出从而达到日志降级的效果同时能够给RD争取充裕的排查问题时间。规范日志级别滥用帮助工程师快速定位解决线上问题。 使用日志级别动态调整组件可以实时动态调整线上服务的日志打印级别调试型日志可以使用低级别打印出减轻线上服务的负载压力。遇到排查问题时可以临时将日志级别调低快速得到精准化的日志信息排查解决问题。日志级别动态调整组件定位为中间件在设计之初重点考虑了以下几点 1. 低侵入性 接入服务仅需要引入JAR包和XML配置文件即可不存在额外编码工作业务耦合低、接入成本小。安全可靠 更改接入服务的日志输出级别只能通过我们提供的管理系统所有的操作记录有迹可查。引入权限认证确保工程师只能操作自己负责的服务或系统同时会把操作内容实时周知给系统的所有相关责任人避免误伤。可视化操作 操作者可以通过我们提供的管理页面定向修改一个或一批服务节点。提供可视化的操控开关可以随时关闭或开启服务。 调用组件 本组件采用工厂模式实现保障其高可扩展性。目前已实现日志级别动态调整和方法调用处理单元下面主要介绍日志级别动态调整处理单元的实现。 目前美团外卖业务系统基本统一采用的SLF4J日志框架在应用初始化时SLF4J会绑定具体的日志框架如Log4j、Logback或Log4j2等。具体源码如下(slf4j-api-1.7.7) private final static void bind() {try {// 查找classpath下所有的StaticLoggerBinder类。SetURL staticLoggerBinderPathSet findPossibleStaticLoggerBinderPathSet(); reportMultipleBindingAmbiguity(staticLoggerBinderPathSet);// 每一个slf4j桥接包中都有一个org.slf4j.impl.StaticLoggerBinder类该类实现了LoggerFactoryBinder接口。// the next line does the bindingStaticLoggerBinder.getSingleton();INITIALIZATION_STATE SUCCESSFUL_INITIALIZATION;reportActualBinding(staticLoggerBinderPathSet);fixSubstitutedLoggers();... }findPossibleStaticLoggerBinderPathSet方法用来查找当前classpath下所有的org.slf4j.impl.StaticLoggerBinder类。每一个slf4j桥接包中都有一个StaticLoggerBinder类该类实现了LoggerFactoryBinder接口。具体绑定到哪一个日志框架则取决于类加载顺序。 接下来咱们分三部分来说说ChangeLogLevelProcessUnit类 初始化确定所使用的日志框架获取配置文件中所有的Logger内存实例并将它们的引用缓存到Map容器中。String type StaticLoggerBinder.getSingleton().getLoggerFactoryClassStr(); if (LogConstant.LOG4J_LOGGER_FACTORY.equals(type)) { logFrameworkType LogFrameworkType.LOG4J; Enumeration enumeration org.apache.log4j.LogManager.getCurrentLoggers(); while (enumeration.hasMoreElements()) {org.apache.log4j.Logger logger (org.apache.log4j.Logger) enumeration.nextElement();if (logger.getLevel() ! null) {loggerMap.put(logger.getName(), logger);} } org.apache.log4j.Logger rootLogger org.apache.log4j.LogManager.getRootLogger(); loggerMap.put(rootLogger.getName(), rootLogger); } else if (LogConstant.LOGBACK_LOGGER_FACTORY.equals(type)) { logFrameworkType LogFrameworkType.LOGBACK; ch.qos.logback.classic.LoggerContext loggerContext (ch.qos.logback.classic.LoggerContext) LoggerFactory.getILoggerFactory(); for (ch.qos.logback.classic.Logger logger : loggerContext.getLoggerList()) {if (logger.getLevel() ! null) {loggerMap.put(logger.getName(), logger);} } ch.qos.logback.classic.Logger rootLogger (ch.qos.logback.classic.Logger) LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME); loggerMap.put(rootLogger.getName(), rootLogger); } else if (LogConstant.LOG4J2_LOGGER_FACTORY.equals(type)) { logFrameworkType LogFrameworkType.LOG4J2; org.apache.logging.log4j.core.LoggerContext loggerContext (org.apache.logging.log4j.core.LoggerContext) org.apache.logging.log4j.LogManager.getContext(false); MapString, org.apache.logging.log4j.core.config.LoggerConfig map loggerContext.getConfiguration().getLoggers(); for (org.apache.logging.log4j.core.config.LoggerConfig loggerConfig : map.values()) {String key loggerConfig.getName();if (StringUtils.isBlank(key)) {key root;}loggerMap.put(key, loggerConfig); } } else { logFrameworkType LogFrameworkType.UNKNOWN; LOG.error(Log框架无法识别: type{}, type); } 获取Logger列表从本地Map容器取出。private String getLoggerList() { JSONObject result new JSONObject(); result.put(logFramework, logFrameworkType); JSONArray loggerList new JSONArray(); for (ConcurrentMap.EntryString, Object entry : loggerMap.entrySet()) {JSONObject loggerJSON new JSONObject();loggerJSON.put(loggerName, entry.getKey());if (logFrameworkType LogFrameworkType.LOG4J) {org.apache.log4j.Logger targetLogger (org.apache.log4j.Logger) entry.getValue();loggerJSON.put(logLevel, targetLogger.getLevel().toString());} else if (logFrameworkType LogFrameworkType.LOGBACK) {ch.qos.logback.classic.Logger targetLogger (ch.qos.logback.classic.Logger) entry.getValue();loggerJSON.put(logLevel, targetLogger.getLevel().toString());} else if (logFrameworkType LogFrameworkType.LOG4J2) {org.apache.logging.log4j.core.config.LoggerConfig targetLogger (org.apache.logging.log4j.core.config.LoggerConfig) entry.getValue();loggerJSON.put(logLevel, targetLogger.getLevel().toString());} else {loggerJSON.put(logLevel, Logger的类型未知,无法处理!);}loggerList.add(loggerJSON); } result.put(loggerList, loggerList); LOG.info(getLoggerList: result{}, result.toString()); return result.toString(); } 修改Logger的级别。private String setLogLevel(JSONArray data) { LOG.info(setLogLevel: data{}, data); ListLoggerBean loggerList parseJsonData(data); if (CollectionUtils.isEmpty(loggerList)) {return ; } for (LoggerBean loggerbean : loggerList) {Object logger loggerMap.get(loggerbean.getName());if (logger null) {throw new RuntimeException(需要修改日志级别的Logger不存在);}if (logFrameworkType LogFrameworkType.LOG4J) {org.apache.log4j.Logger targetLogger (org.apache.log4j.Logger) logger;org.apache.log4j.Level targetLevel org.apache.log4j.Level.toLevel(loggerbean.getLevel());targetLogger.setLevel(targetLevel);} else if (logFrameworkType LogFrameworkType.LOGBACK) {ch.qos.logback.classic.Logger targetLogger (ch.qos.logback.classic.Logger) logger;ch.qos.logback.classic.Level targetLevel ch.qos.logback.classic.Level.toLevel(loggerbean.getLevel());targetLogger.setLevel(targetLevel);} else if (logFrameworkType LogFrameworkType.LOG4J2) {org.apache.logging.log4j.core.config.LoggerConfig loggerConfig (org.apache.logging.log4j.core.config.LoggerConfig) logger;org.apache.logging.log4j.Level targetLevel org.apache.logging.log4j.Level.toLevel(loggerbean.getLevel());loggerConfig.setLevel(targetLevel);org.apache.logging.log4j.core.LoggerContext ctx (org.apache.logging.log4j.core.LoggerContext) org.apache.logging.log4j.LogManager.getContext(false);ctx.updateLoggers(); // This causes all Loggers to refetch information from their LoggerConfig.} else {throw new RuntimeException(Logger的类型未知,无法处理!);} } return success; } 上面介绍了如何拿到日志配置文件中的Logger以及修改Logger的级别。 通信方式 我们根据Web项目和纯粹RPC项目分别提供HTTP和Thrift两种通信协议。 场景一、Thrift服务 所有的请求信息都包含在JSON String的数据结构里面其中包含有签名信息请求时签名验证失败将直接抛出异常。 引入组件提供的dynamic-invoker.xml配置将会在系统中自动注入开启一个专为日志级别调整的接口服务该接口是一个单纯的Thrift服务能够通过ZooKeeper实现服务注册与发现并且有可视化的开启与关闭管理后台简单明了操作方便。 场景二、HTTP服务 对于一些Web项目暴露一个RPC服务相当不安全。为此我们提供了HTTP协议接口接入流程完全一样在真正修改日志输出级别时会根据系统类型自主判断使用哪种协议有独立实现的签名认证安全可靠。 从2016年9月V1.0版本上线以来陆续接入外卖配送的20多个核心应用覆盖推送、接单、配送调度、斑马配送、活动等核心交易服务。 举例 问题描述发配送服务化项目由于间接依赖引入了Logback日志框架。在项目启动加载时SLF4J动态绑定到Logback框架上但是由于发配送项目使用的Log4j并未配置Logback.xml文件导致在打印日志时SLF4J无法匹配到具体的日志配置从而为项目自动创建了一个日志级别为Debug的ROOT节点所有的日志以该级别打印输出导致发配送服务化项目在中午1130左右高峰期短时间内打印过多的系统日志引起Load飙高重新修改发版上线已经来不及如果不能立即解决势必造成服务化宕机损失非常严重。处理结果使用我们这个日志工具批量将服务化项目所有的日志输出级别调整为ERROR级别大大减少了日志量的输出给工程师留出充裕的的时间完美的解决了该问题避免造成更大的系统故障。后记更重要的是以该工具组件为切入点帮助各业务系统逐渐规范系统日志使用取得很好效果。后续我们规划将其推广成为公司级别的工具为越来越多的项目提供便利。 欢迎感兴趣的同学与我们进一步交流。 Simple Logging Facade for Java (SLF4J)Log4j 2 Architecture - Apache Log4j 2Hash-based message authentication code - Wikipedia
http://www.pierceye.com/news/991386/

相关文章:

  • 县区网站建设运行汇报宝塔 wordpress优化
  • 手机网站判断跳转代码怎么写pc网站怎么做自适应
  • 怎样在一个虚拟服务器里做两个网站西安市城乡建设管理局网站
  • 做网站实训总结查看网站建设的特点
  • 淘宝客网站如何让做量化交易网站开发
  • 青岛市城市建设管理局网站网络营销师培训费用是多少
  • 南昌建站模板深圳全网推广效果如何
  • 做网站的好公司wordpress大前端模板下载
  • 建设网站的申请信用卡吗下载百度免费
  • 徐州企业网站设计做瑜伽网站
  • 网站开发就是ssh吗.net 网站开发书籍
  • 网站名称没有排名上海工商网查询企业章程
  • 网站建设方案报价费用明细价格免费开店的电商平台
  • 济南网络建站模板用c 做的网站怎么打开
  • 网站建设培训课程好人一生平安网站哪个好
  • seo怎么做网站的tdk网站优化的核心不包括
  • 如何做一份网站的数据分析网站营销案例
  • 中小企业网站建设公司个人微信号做网站行吗
  • 网站无法连接服务器哪些国家网站无须备案
  • 重庆做网站设计培训机构排名全国十大教育机构排名
  • 做网站建设销售网络营销推广技巧
  • 南宁网站制作定制北京网站seo服务
  • 门户网站网页设计规范willin kan 让你的wordpress飞起来
  • 建设银行广州招聘网站wordpress dz
  • 如何介绍自己做的网站东莞回收网站设计
  • 北京驾校网站建设厦门网页设计培训班
  • 网络公司给我做网站我有没有源代码版权吗我怎么做个人网站
  • 免费建站网站一站式做网站需要懂那些软件
  • 做新网站怎样提交360寻找销售团队外包
  • 重庆市建设网站wordpress 新闻模版