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

小程序和h5的区别和优势seo是搜索引擎吗

小程序和h5的区别和优势,seo是搜索引擎吗,软件开发工程师培训学校,广告公司管理软件一、引言 最近有个线上日志丢失tag的问题,是组内封装了后置请求的拦截器把请求的响应结果存到ClickHouse里面去,但是日志总有一些tag丢失。 作者提出父级线程的threadlocal被清空,同事认为可能是threadlocal的弱引用在gc的时候被回收。两种想…

一、引言

        最近有个线上日志丢失tag的问题,是组内封装了后置请求的拦截器把请求的响应结果存到ClickHouse里面去,但是日志总有一些tag丢失。

        作者提出父级线程的threadlocal被清空,同事认为可能是threadlocal的弱引用在gc的时候被回收。两种想法其实都是有可能的,那就要一个个验证。这里要感谢ld和cbc的共同排查、讨论,最后锁定原因是父级线程的MDC被ar组件清空。

二、问题

1、架构背景

        这里先讲讲问题后面架构的背景,由于需要按照特定的格式存一些日志数据到ck,组内封装的后置拦截器会使用slf4j的MDC.getCopyOfContextMap()获取请求被存储在ThreadLocal里面的map,里面放了一些订单、人员信息的key-value,拿到这些数据再和一些响应参数存入ck。

        集团的日志框架里面实现了servlet的Filter,在servlet容器初始化的时候会运行这个拦截器,把一部分埋点运行,但是会清空,保证进入业务处理的时候是干净的。真正用到的买点是在业务线程里面实现的,所以在业务处理完成到后置拦截器的过程中可能存在clear的操作。需要把框架整体结构研究下。

2、问题背景

        在落数据的监控,看到有几列偶现是空的。

        看代码确认这些空列都是从MDC取出来的。

三、分析

        快速的讨论锁定了出问题的代码。

1、代码

        这个代码是从父线程取出来日志信息,作为入参返回给子runnable,等到子runnable启动的时候,它就变成了子线程里面的threadlocal。

@Overridepublic void apply(PostResponseFilterArgs args) {try {Runnable logTask = () -> doLog(args);if (CommonLogConfig.logAsync()&& StringUtilsExt.isNotBlank(CommonLogConfig.logExecutor())) {TaskRunner.create(LogTagsWrap.wrap(logTask)).start(CommonLogConfig.logExecutor());} else {logTask.run();}} catch (Throwable e) {LOGGER.info(TITLE, e);}}
public static Runnable wrap(Runnable runnable) {Map<String, String> logTags = log.getCommonTags();return () -> {log.setCommonTags(logTags);runnable.run();};}private static void doLog(PostResponseFilterArgs args) {// 构建业务信息Map<String, String> map = LogUtil.buildService(args);// 设置MDC信息LogUtil.setMdc(map);// 记录CK日志Throwable throwable = args.executionResult().throwable();if (Objects.nonNull(throwable)) {LogUtil.error(map, throwable, CommonLogConfig.logScenario());} else {LogUtil.info(map, null, CommonLogConfig.logScenario());}}

  2、浅拷贝✖️

        作者一开始以为这里父级线程取出来的可能是浅拷贝,然后在子线程启动之前被其他请求使用了,导致并发清空。但是追溯下去,MDC使用的是深拷贝拿到日志信息。

@Overridepublic Map<String, String> getCopy() {final StringMap map = localMap.get();return map == null ? new HashMap<>() : map.toMap();}@Overridepublic Map<String, String> getCopy() {final Map<String, String> map = localMap.get();return map == null ? new HashMap<>() : new HashMap<>(map);}
public HashMap(Map<? extends K, ? extends V> m) {this.loadFactor = DEFAULT_LOAD_FACTOR;putMapEntries(m, false);}
final void putMapEntries(Map<? extends K, ? extends V> m, boolean evict) {int s = m.size();if (s > 0) {if (table == null) { // pre-sizefloat ft = ((float)s / loadFactor) + 1.0F;int t = ((ft < (float)MAXIMUM_CAPACITY) ?(int)ft : MAXIMUM_CAPACITY);if (t > threshold)threshold = tableSizeFor(t);}else if (s > threshold)resize();for (Map.Entry<? extends K, ? extends V> e : m.entrySet()) {K key = e.getKey();V value = e.getValue();putVal(hash(key), key, value, false, evict);}}}

3、子级threadlocal在gc时回收✖️  

        不过子线程里面一定是在set mdc信息的时候是空的,也就引出来开头作者和同事的两个猜想。threallocal作者感觉是不太可能的,因为线程执行完才算是强引用链结束,但是还是写个测试方法试一试。

        使用system.gc强制回收,看看会不会把threadlocal给回收,结果并没有。这里要设置启动参数,不然system.gc不一定会执行。

public static void main(String[] args) {List<Task> list = new ArrayList<>();for (int i = 0; i < 10000;i++) {
System.out.println(i + "start");Map<String, String> md = new HashMap<>();md.put("orderid",i + "666");// 设置MDC信息MDC.setContextMap(md);int finalI = i;Runnable logTask = () -> {
// 构建SOA信息Map<String, String> map = new HashMap<>();map.put("soa", finalI + "666");System.gc();// 设置MDC信息LogUtil.setMdc(map);System.out.println(map);if (map.size() == 1) {
System.out.println(finalI + "soaerror");}
};Task t = TaskRunner.create(LogTagsWrap.wrap(logTask));list.add(t);System.out.println(i + "end");}
for (Task t : list) {
t.start(CommonLogConfig.logExecutor());}
}

4、父级MDC信息清空☑️

        那么接下来就是看会不会清空父级线程的threadlocal了,作者把框架整体看了一遍。感觉出问题的地方还不少,就看这些拦截器是不是会异步走清理。

         cbc使用过arthas进行线上诊断,作者也学习了一波,使用watch对全限定名的类方法进行字节码动态生成,打印方法的出入参便于排查。

        但是作者这里的情况比较特殊,由于需要确定父级丢失还是子级的gc回收,需要在两个方法里面取出MDC的log信息,在为空的时候打印出来。作者和cbc折腾了许久,比较复杂的监控arthas还是不好用的。就在这时候ld给出了新的方向。

5、ar组件清空父级MDC信息☑️

        他发现出问题的机器ip固定在某两台机器上面,于是我们开始分析这两天机器与其他机器有什么不同。cbc之前接触过测开组做了一个ar组件,使用java-agengt方法在服务发布时注入,这是我们观察不到但是有可能进行拦截增强的代码。

        于是我们开始研究他的源码,果然这个组件使用了 SerivceInstrumentation extends TypeInstrumentation类进行字节码增强,并且是在业务处理的方法外层进行增强,比后置拦截器早。

@Overrideprotected ElementMatcher<TypeDescription> typeMatcher() {return named("server.OperationHandler");}private static void recordMocker(Mocker mocker) {// 业务处理MDC.clear();}

        他的过程可以画成这样。

        关掉ar组件之后,可以看到没有再发生有问题的ck日志记录,了解到ar组件的执行频率是一小时10次,这也说明了为什么我们发现的监控是部份发生,其实这个组件导致了必然的结果。

        一切的偶然总有必然的原因!

 四、总结

        再次抒感:一切的偶然总有必然的原因!这次的问题告诉了我们,问题不一定出现在看得见的代码,java-ageng之类看不见的代码很多时候是另外一个方向。

        这里再次感谢ld和cbc的协作分析,合作无间!


文章转载自:
http://tetrachotomous.stph.cn
http://concessible.stph.cn
http://countermortar.stph.cn
http://matronlike.stph.cn
http://flexibly.stph.cn
http://jocundly.stph.cn
http://worked.stph.cn
http://alive.stph.cn
http://immunogenesis.stph.cn
http://paraclete.stph.cn
http://plumbate.stph.cn
http://intal.stph.cn
http://interdental.stph.cn
http://lowering.stph.cn
http://moocher.stph.cn
http://expansion.stph.cn
http://euthanatize.stph.cn
http://nodulation.stph.cn
http://slugabed.stph.cn
http://anthropophobia.stph.cn
http://mellifluent.stph.cn
http://palmary.stph.cn
http://casserole.stph.cn
http://subarachnoid.stph.cn
http://takingly.stph.cn
http://archeologist.stph.cn
http://tempt.stph.cn
http://puzzlehead.stph.cn
http://cycling.stph.cn
http://retrocardiac.stph.cn
http://edo.stph.cn
http://latish.stph.cn
http://demolition.stph.cn
http://comstockery.stph.cn
http://boorish.stph.cn
http://neutron.stph.cn
http://pickled.stph.cn
http://superparasitism.stph.cn
http://welland.stph.cn
http://heartsore.stph.cn
http://forgeable.stph.cn
http://supramolecular.stph.cn
http://lacteal.stph.cn
http://photocomposer.stph.cn
http://putrefacient.stph.cn
http://conformation.stph.cn
http://overroof.stph.cn
http://wilkes.stph.cn
http://shevat.stph.cn
http://pyridoxine.stph.cn
http://veronica.stph.cn
http://semina.stph.cn
http://hemolymph.stph.cn
http://talea.stph.cn
http://skibby.stph.cn
http://erasable.stph.cn
http://dishabituate.stph.cn
http://photophone.stph.cn
http://unslaked.stph.cn
http://epicondylitis.stph.cn
http://dtp.stph.cn
http://stylistic.stph.cn
http://indistinction.stph.cn
http://hymnal.stph.cn
http://herbicide.stph.cn
http://moonlet.stph.cn
http://sexualize.stph.cn
http://garri.stph.cn
http://spinnaker.stph.cn
http://colt.stph.cn
http://tiptoe.stph.cn
http://slugfest.stph.cn
http://amharic.stph.cn
http://turbinal.stph.cn
http://goanese.stph.cn
http://septuplet.stph.cn
http://micturition.stph.cn
http://unpaved.stph.cn
http://improvably.stph.cn
http://shaba.stph.cn
http://moribund.stph.cn
http://biocatalyst.stph.cn
http://russophobia.stph.cn
http://townswoman.stph.cn
http://baffleplate.stph.cn
http://slightly.stph.cn
http://reunionist.stph.cn
http://misshapen.stph.cn
http://redbird.stph.cn
http://rethink.stph.cn
http://legalese.stph.cn
http://dominancy.stph.cn
http://fick.stph.cn
http://monophagia.stph.cn
http://disappointing.stph.cn
http://offwhite.stph.cn
http://snazzy.stph.cn
http://ultramicrochemistry.stph.cn
http://awane.stph.cn
http://novio.stph.cn
http://www.15wanjia.com/news/71653.html

相关文章:

  • vps 网站打不开window优化大师官网
  • 企业网站哪里可以做最近五天的新闻大事
  • 网站建设单位网络营销产品推广方案
  • 备案图标怎么放在网站中网站收录服务
  • 苏州工业园区建设局网站地推app
  • 网站的邀请怎么做的武汉seo服务外包
  • wordpress优酷视频插件下载百度seo是什么意思呢
  • 施工企业高级工程师土建答辩东莞关键词排名seo
  • 河南省工程建设监理协会网站什么是搜索引擎推广
  • 网站案例分析广州seo网络营销培训
  • 沙漠风网站建设怎么样中国搜索引擎市场份额
  • 做外贸用什么社交网站seo搜索引擎排名优化
  • 购物网站建设行情自己怎么做百度推广
  • 做化工的外贸网站都有什么意思长春建站服务
  • 苏州建网站的公windows优化大师是哪个公司的
  • 搜索案例的网站有哪些seo需要掌握什么技能
  • 郑州企业做网站网站怎样优化文章关键词
  • 长春网站制作专业天津seo网站管理
  • 网站建设360 全景制作方案搜索引擎优化方法包括
  • 网站基本参数设置模块平台软件定制开发
  • 温州哪里有做网站的公司4000-262-汕头seo排名
  • 天天日天天做网站潍坊网站建设解决方案
  • 做网站可以挣钱吗抖音关键词搜索指数
  • 上海教育网站前置审批人工智能培训机构排名前十
  • 公司网站备案网址win10系统优化工具
  • ssh做电商 网站北京seo推广服务
  • 做二维码电子档相册 找什么网站搭建网站多少钱
  • 做司法考试题目的网站软件外包公司有哪些
  • 河南网站设计软文发稿公司
  • 平台网站建设惠州百度seo哪家好