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

网站界面要素网页设计与制作图片素材

网站界面要素,网页设计与制作图片素材,装修网站有哪些,市场营销推广方案模板一、前言 不久前#xff0c;阿里云 ARMS 团队、编译器团队、MSE 团队携手合作#xff0c;共同发布并开源了 Go 语言的编译时自动插桩技术。该技术以其零侵入的特性#xff0c;为 Go 应用提供了与 Java 监控能力相媲美的解决方案。开发者只需将 go build 替换为新编译命令 o… 一、前言 不久前阿里云 ARMS 团队、编译器团队、MSE 团队携手合作共同发布并开源了 Go 语言的编译时自动插桩技术。该技术以其零侵入的特性为 Go 应用提供了与 Java 监控能力相媲美的解决方案。开发者只需将 go build 替换为新编译命令 otel go build就能实现对 Go 应用的全面监控和治理。 二、问题描述 近期我们收到用户反馈使用 otel go build -race 替代正常的 go build -race 命令后编译生成的程序会导致崩溃。-race[3]是 Go 编译器的一个参数用于检测数据竞争data race问题。通过为每个变量的访问添加额外检查确保多个 goroutine 不会以不安全方式同时访问这些变量。 理论上我们的工具不应影响-race 竞态检查的代码因此出现崩溃的现象是非预期的所以我们花了一些时间排查这个崩溃问题崩溃的堆栈信息如下 (gdb) bt#0 0x000000000041e1c0 in __tsan_func_enter ()#1 0x00000000004ad05a in racecall ()#2 0x0000000000000001 in ?? ()#3 0x00000000004acf99 in racefuncenter ()#4 0x00000000004ae7f1 in runtime.racefuncenter (callpc4317632)#5 0x0000000000a247d8 in ../sdk/trace.(*traceContext).TakeSnapShot (tcoptimized out, ~r0...)#6 0x00000000004a2c25 in runtime.contextPropagate#7 0x0000000000480185 in runtime.newproc1.func1 () #8 0x00000000004800e2 in runtime.newproc1 (fn0xc00030a1f0, callergp0xc0000061e0, callerpc12379404, retVal00xc0002c8f00)#9 0x000000000047fc3f in runtime.newproc.func1 () #10 0x00000000004a992a in runtime.systemstack ()....可以看到崩溃源于 __tsan_func_enter而引发该问题的关键点是 runtime.contextPropagate。我们的工具在 runtime.newproc1 函数的开头插入了以下代码 func newproc1(fn *funcval, callergp *g, callerpc uintptr) (retVal0 *g) { // 我们插入的代码 retVal0.otel_trace_context contextPropagate(callergp.otel_trace_context)...} // 我们插入的代码func contextPropagate(tls interface{}) interface{} { if tls nil { return nil } if taker, ok : tls.(ContextSnapshoter); ok { return taker.TakeSnapShot() } return tls} // 我们插入的代码func (tc *traceContext) TakeSnapShot() interface{} { ...}TakeSnapShot 被 Go 编译器在函数入口和出口分别注入了 racefuncenter() 和 racefuncexit()最终调用 __tsan_func_enter 导致崩溃。由此确定崩溃问题确实是我们的注入代码导致的继续深入排查。 三、排查过程 3.1 崩溃根源 使用 objdump 查看 __tsan_func_enter 的源码看到它接收两个函数参数出错的地方是第一行 mov 0x10(%rdi),%rdx它约等于 rdx *(rdi 0x10)。打印寄存器后发现 rdi 0根据调用约定rdi 存放的是第一个函数参数因此这里的问题就是函数第一个参数 thr 为 0。 // void __tsan_func_enter(ThreadState *thr, void *pc);000000000041e1c0 __tsan_func_enter: 41e1c0: 48 8b 57 10 mov 0x10(%rdi),%rdx 41e1c4: 48 8d 42 08 lea 0x8(%rdx),%rax 41e1c8: a9 f0 0f 00 00 test $0xff0,%eax ...那么第一个参数 thr 是谁传进来的呢接着往上分析调用链。 3.2 调用链分析 出错的整个调用链是 racefuncenter(Go) - racecall(Go) - __tsan_func_enter(C)。需要注意的是前两个函数都是 Go 代码Go 函数调用 Go 函数遵循 Go 的调用约定。在 amd64 平台前九个函数参数使用以下寄存器 另外以下寄存器用于特殊用途 后两个函数一个 Go 代码一个 C 代码Go 调用 C 的情况下遵循 System V AMD64 调用约定在 Linux 平台上使用以下寄存器作为前六个参数 理解了 Go 和 C 的调用约定之后再来看整个调用链的代码 TEXT racefuncenter(SB), NOSPLIT|NOFRAME, $0-0 MOVQ DX, BXx MOVQ g_racectx(R14), RARG0 // RSI存放thr MOVQ R11, RARG1 // RDI存放pc MOVQ $__tsan_func_enter(SB), AX // AX存放__tsan_func_enter函数指针 CALL racecall(SB) MOVQ BX, DX RETTEXT racecall(SB), NOSPLIT|NOFRAME, $0-0 ... CALL AX // 调用__tsan_func_enter函数指针 ...racefuncenter 将 g_racectx(R14) 和 R11 分别放入 C 调用约定的参数寄存器 RSI(RARG0) 和 RDI(RARG1)并将 __tsan_func_enter 放入 Go 调用约定的参数寄存器 RAX然后调用 racecall它进一步调用 __tsan_func_enter(RAX)这一系列操作大致相当于 __tsan_func_enter(g_racectx(R14), R11)。 不难看出问题的根源在于 g_racectx(R14) 为 0。根据 Go 的调用约定 R14 存放当前 goroutine 它不可能为 0 因此出问题的必然是 R14.racectx 字段为 0。为了避免无效努力通过调试器 dlv 二次确认 (dlv) p *(*runtime.g)(R14)runtime.g { racectx: 0, ...}那么为什么当前 R14.racectx 为 0下一步看看 R14 具体的状态。 3.3 协调程度 func newproc(fn *funcval) { gp : getg() pc : sys.GetCallerPC() #1 systemstack(func() { newg : newproc1(fn, gp, pc, false, waitReasonZero) #2 ... })}经过排查在代码 #1 处R14.racectx 是正常的但到了代码 #2 处R14.racectx 就为空了原因是 systemstack 被调用它有一个切换协程的动作具体如下 // func systemstack(fn func())TEXT runtime·systemstack(SB), NOSPLIT, $0-8 ... // 切换到g0协程 MOVQ DX, g(CX) MOVQ DX, R14 // 设置 R14 寄存器 MOVQ (g_schedgobuf_sp)(DX), SP// 在g0协程上运行目标函数fn MOVQ DI, DX MOVQ 0(DI), DI CALL DI// 切换回原始协程 ...原来 systemstack 有一个切换协程的动作会先把当前协程切换成 g0然后执行 fn最后恢复原始协程执行。 在 Go 语言的 GMPGoroutine-Machine-Processor调度模型中每个系统级线程 M 都拥有一个特殊的 g0 协程以及若干用于执行用户任务的普通协程 g。g0 协程主要负责当前 M 上用户 g 的调度工作。由于协程调度是不可抢占的调度过程中会临时切换到系统栈system stack上执行代码。在系统栈上运行的代码是隐式不可抢占的并且垃圾回收器不会扫描系统栈。 到这里我们已经知道执行 newproc1 时的协程总是 g0而 g0.racectx 是在 main 执行开始时被主动设置为 0最终导致程序崩溃 // src/runtime/proc.go#main// The main goroutine.func main() { mp : getg().m// g0 的 racectx 仅用于作为主 goroutine 的父级。 // 不应将其用作其他目的。 mp.g0.racectx 0 ...四、解决方案 到这里基本上可以做一个总结了程序崩溃的原因如下 newproc1 中插入的 contextPropagate 调用 TakeSnapshot而 TakeSnapshot 被 go build -race 强行在函数开始插入了 racefuncenter() 函数调用该函数将使用 racectx。 newproc1 是在 g0 协程执行下运行该协程的 racectx 字段是 0最终导致崩溃。 一个解决办法是给 TakeSnapshot 加上 Go 编译器的特殊指令 //go:norace该指令需紧跟在函数声明后面用于指定该函数的内存访问将被竞态检测器忽略Go 编译器将不会强行插入 racefuncenter()调用。 五、疑惑一 runtime.newproc1 中不只调用了我们注入的 contextPropagate还有其他函数调用为什么这些函数没有被编译器插入 race 检查的代码如 racefuncenter 经过排查后发现Go 编译器会特殊处理 runtime 包针对 runtime 包中的代码设置 NoInstrument 标志从而跳过生成 race 检查的代码 // /src/cmd/internal/objabi/pkgspecial.govar pkgSpecialsOnce sync.OnceValue(func() map[string]PkgSpecial { ... for _, pkg : range runtimePkgs { set(pkg, func(ps *PkgSpecial) { ps.Runtime true ps.NoInstrument true }) } ...})六、疑惑二 理论上插入 //go:norace 之后问题应该得到解决但实际上程序还是发生了崩溃。经过排查发现TakeSnapShot 中有 map 初始化和 map 循环操作这些操作会被编译器展开成 mapinititer() 等函数调用。这些函数直接手动启用了竞态检测器而且无法加上 //go:norace func mapiterinit(t *abi.SwissMapType, m *maps.Map, it *maps.Iter) { if raceenabled m ! nil { // 主动的race检查 callerpc : sys.GetCallerPC() racereadpc(unsafe.Pointer(m), callerpc, abi.FuncPCABIInternal(mapiterinit)) } ...}对此问题的解决办法是在 newproc1 注入的代码里面避免使用 map 数据结构。 七、总结 以上就是 Go 自动插桩工具在使用 go build -race 时出现崩溃的分析全过程。通过对崩溃内容和调用链的排查我们找到了产生问题的根本原因以及相应的解决方案。这将有助于我们在理解运行时机制的基础上更加谨慎地编写注入到运行时的代码。 参考链接 [01] Go 自动插桩开源项目 https://github.com/alibaba/opentelemetry-go-auto-instrumentation [02] 阿里云 ARMS Go Agent 商业版 https://help.aliyun.com/zh/arms/tracing-analysis/monitor-go-applications/ [03] Go 竞态检查 https://go.dev/doc/articles/race_detector
http://www.hkea.cn/news/14530822/

相关文章:

  • 石家庄网站建设时光wordpress 中文标题 404
  • 南昌电子商务网站建设有域名和空间怎么做网站
  • 西部空间官方网站温州设计集团
  • 工作室做网站流程河北网站建设就业考试
  • 最新网站建设哪家公司好wordpress创建配置文件 没反应
  • 济南网站建设哪家便宜网站设计软件有哪些
  • 网站建设运营有限公司兰州市建设厅网站
  • 自己做的网站网页滑动不南宁建设工程质量网站
  • 优质手机网站建设企业专业的免费建站
  • 如何创建一个网站卖东西关闭网站怎么不保存我做的更改
  • 江苏建筑工程网网站优化待遇
  • 商务网站建设的第一步优秀设计作品赏析
  • 温州鹿城区企业网站搭建网站开发需要什么文凭
  • 互联网网站建设门户网网站建设费做什么会计科目
  • 厦门市建设质量安全协会网站广东新闻联播2020
  • 网站搜索引擎优化方案论文深圳做网站设计的公司
  • 江阴建设局网站招考我要买房网
  • 怎么用dw做地图网站天津关键词排名提升
  • asp网站免费模板网页设计师考证试题
  • 怎样用西瓜影音做网站网站关停公告怎么做
  • 镇江本地网站线上营销策划案例
  • 个人网站模板响应式企业形象设计和品牌形象设计
  • 如何做论坛网站 知乎wordpress 后台action
  • 怎样在手机上做自己的网站室内设计导航
  • 做网站 零基础从哪里开始学网站开发常用形状
  • 上海做oocl船的公司网站网页设计素材电影
  • 30秒网站创作图片的软件
  • 知名企业网站分析 比较评估雄县哪里有建设网站的
  • wordpress皮肤设置seo网站排名全选
  • 门户网网站建设功能需求表自助制作网站