首页 文章 精选 留言 我的

精选列表

搜索[通用文字识别],共10000篇文章
优秀的个人博客,低调大师

通用的底层埋点都是怎么做的?

想要在程序里监控数据库的操作耗时,想要在底层框架中自动传递链路跟踪信息,这些需求经常会碰到,特别是在构建基础框架的时候。 核心目标只有一个,那就是在底层封装好,不用上层使用人员关心。今天跟大家聊聊常用的底层扩展埋点方式是怎么处理的。 框架自带扩展点 如果你使用的框架在设计的时候,就预留了扩展点就很方便了。比如 Mybatis 的拦截器,我们可以在拦截器中对 Sql 进行监控,改写。 比如阿里的 Sentinel 框架,可以通过 SPI 来扩展 Slot,调整编排顺序,新增自定义的 Slot 来实现限流告警等。 开源框架的质量参差不齐,有在早期设计比较好的,留足了各种扩展点,方便使用者。也有一些没有考虑那么全面,导致你在使用的时候需要进行扩展,发现找不到扩展点,对于框架本身没有提供扩展点的场景,请接着看下面。 修改源码 如果框架没有扩展点,最直接的方式就是修改开源框架的源码来扩展自己想要的功能,通常的做法就是克隆源码到自己的私有仓库中,然后修改,测试,重新打包使用。 像我们之前用了 XXL-JOB 做任务调度,也是修改了某些代码,在界面上扩展了监控通知的配置信息,默认是只支持邮箱,可以扩展出手机,钉钉等。 修改源码不好的点在于需要跟原框架的版本进行对齐,如果不对齐,随便改都没事。不对齐意味着修复了某些 bug 和新增了某些功能,就无法使用了。要对齐,就需要不断的将新版本的代码合并到你自己的分支上。 还有很多公司,就是基于开源的版本,构建了公司内部自己的版本,后续直接就是跟着内部的使用需求去扩展和维护了,不会跟社区的版本进行同步,如果你们有专门的团队去做这件事情,也是一种方式。 同名文件覆盖 改源码的方式需要经常同步新版本的代码,有的时候往往只想修改某一个类而已,比如对底层的某些操作进行埋点监控,如果框架本身没有提供扩展点的话只能改源码来实现。 其实还有个投机取巧的方式,就是在项目中创建一个跟你要修改的一模一样的类,包名+类目都一样,方法名也一样,方法的实现你可以改。这样就能覆盖 jar 包中的类了,还是跟类加载顺序有关系,先加载你自己定义的。 这样的方式好处在于不用经常去同步新版本的代码,如果你用的框架版本升级了,只要包名和类名不变,你这个覆盖的只是那个类而已,新增的功能和修复的 bug 都不会有影响。 切面拦截 切面在做很多统一处理的时候非常有用,同样在做底层埋点的场景也适用。 比如我们要对项目中 Mongodb 的所有操作都进行埋点监控,可以修改 MongoDB 的驱动源码,可以创建同名文件进行覆盖,方式有很多种,找到一个合适,又能实现需求的最重要。 以 Spring 中操作 Mongodb 来说明,在 Spring Data Mongodb 中会 MongoTemplate 来操作 Mongodb。最简单的方式就是直接对 MongoTemplate 类进行埋点,这样所有的操作都可以监控起来。 用切面直接切到 MongoTemplate 的所有方法上,然后进行埋点,就很简单了。 @Aspectpublic class MongoTemplateAspect { @Pointcut("execution(* org.springframework.data.mongodb.core.MongoTemplate.*(..))") public void pointcut() {} @Around("pointcut()") public Object around(final ProceedingJoinPoint pjp) throws Throwable { String callMethod = pjp.getSignature().getDeclaringType().getSimpleName() + "." + pjp.getSignature().getName(); Map<String, Object> data = new HashMap<>(); data.put("params", JsonUtils.toJson(pjp.getArgs())); return CatTransactionManager.newTransaction(() -> { try { return pjp.proceed(); } catch (Throwable throwable) { throw new RuntimeException(throwable); } }, "Mongo", callMethod, data); }} 又比如,你还想监控 Redis 相关的,Redis 用的也是跟 Spring 整合的框架,那么也有 RedisTemplate 这个类,同样也可以用切面来实现。 基于 Template 类来埋点,相对比较上层,如果还想在底层一点进行监控,也就是 Connection 这层,Template 里面的操作都是基于 Connection 来实现的。 同样我们可以用切面来替换 Connection 相关的实现,比如可以用切面切到获取 Connection 的方法,然后替换 Connection 的对象为具备埋点监控的对象。 @Aspectpublic class RedisAspect { @Pointcut("target(org.springframework.data.redis.connection.RedisConnectionFactory)") public void connectionFactory() {} @Pointcut("execution(org.springframework.data.redis.connection.RedisConnection *.getConnection(..))") public void getConnection() {} @Pointcut("execution(org.springframework.data.redis.connection.RedisClusterConnection *.getClusterConnection(..))") public void getClusterConnection() {} @Around("getConnection() && connectionFactory()") public Object aroundGetConnection(final ProceedingJoinPoint pjp) throws Throwable { RedisConnection connection = (RedisConnection) pjp.proceed(); return new CatMonitorRedisConnection(connection); } @Around("getClusterConnection() && connectionFactory()") public Object aroundGetClusterConnection(final ProceedingJoinPoint pjp) throws Throwable { RedisClusterConnection clusterConnection = (RedisClusterConnection) pjp.proceed(); return new CatMonitorRedisClusterConnection(clusterConnection); }} CatMonitorRedisConnection 中对原生的 RedisConnection 做了增强,也不会影响原有的 RedisConnection 的功能。 public class CatMonitorRedisConnection implements RedisConnection { private final RedisConnection connection; private CatMonitorHelper catMonitorHelper; public CatMonitorRedisConnection(RedisConnection connection) { this.connection = connection; this.catMonitorHelper = new CatMonitorHelper(); } @Override public byte[] get(byte[] key) { return catMonitorHelper.execute(RedisCommand.GET, key, () -> connection.get(key)); }} Java Agent Java Agent 可以在运行期将已经加载的类的字节码进行变更,可以加入我们需要进行监控的代码逻辑。无需对原有代码进行改造,零侵入性。 在非常多优秀的开源框架中都看到了 Java Agent 的应用,像 APM 框架 SkyWalking,异步传递上下文 transmittable-thread-local 等。 Java Agent 相对其他的方式来说,还是有一定的门槛,毕竟不是日常开发中经常会用到的技术点。如果想了解这种扩展方式,可以看看一些已经用了的开源框架的源码,就知道大概怎么使用了。下面贴一段 transmittable-thread-local 中对线程池进行扩展的代码吧,主要就是利用了 javassist 操作字节码。 try {final CtMethod afterExecute = clazz.getDeclaredMethod("afterExecute", new CtClass[]{runnableClass, throwableClass});// unwrap runnable if IsAutoWrapperString code = "$1 = com.alibaba.ttl.threadpool.agent.internal.transformlet.impl.Utils.unwrapIfIsAutoWrapper($1);";logger.info("insert code before method " + signatureOfMethod(afterExecute) + " of class " + afterExecute.getDeclaringClass().getName() + ": " + code);afterExecute.insertBefore(code);modified = true;} catch (NotFoundException e) {// clazz does not override afterExecute method, do nothing.} 关于作者:尹吉欢,简单的技术爱好者,《Spring Cloud 微服务-全栈技术与案例解析》, 《Spring Cloud 微服务 入门 实战与进阶》作者, 公众号猿天地发起人。 我整理了一份很全的学习资料,感兴趣的可以微信搜索「猿天地」,回复关键字 「学习资料」获取我整理好了的 Spring Cloud,Spring Cloud Alibaba,Sharding-JDBC 分库分表,任务调度框架 XXL-JOB,MongoDB,爬虫等相关资料。 后台回复学习资料领取学习视频 如有收获,点个在看,诚挚感谢 本文分享自微信公众号 - 猿天地(cxytiandi)。如有侵权,请联系 support@oschina.cn 删除。本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

优秀的个人博客,低调大师

关于Unity 2018的实体组件系统(通用名称ECS)

将介绍如何在Unity上使用实体组件系统(通常称为ECS)。这次的内容是Unity提供的ECS API的基本用法,一个小应用程序和并行化。它不包括与Unity的GameObject / Component的合作,以及实际使用。获取可以使用ECS的编辑器Unity2018 和之后的版本都可以!创建一个可以使用ECS的项目要启用ECS,需要两件事。· 使使用 .NET 4.x· 重写 manifest.json正常启动Unity并打开 Edit> PlayerSettings> PlayerSettings。之后,将Scripting Runtime Version脚本运行时版本更改为Stable (.net 4.x)。接下来是重写manifest.json。由于在项目的Root文件夹/ Packages中有一个名为manifest.json的文件,因此我们将按照https://github.com/Unity-Technologies/EntityComponentSystemSamples/blob/master/TwoStickShooter/Pure/Packages/manifest.json与此处相同的方式重写内容。准备工作完成。最小的ECS项目首先,尝试尽可能地构建最有意义的功能。这次要组织的功能就是这样· 统计每个帧1、 没有使用 ECS的代码 :首先我会试着用MonoBehaviour来组织它。这是一个非常简单的代码。编写完成后,您可以将Counter组件添加到适当的GameObject中。using UnityEngine;public class Counter : MonoBehaviour{ public int count;void Update () { count++; }}接下来,让我们对应于ECS。有三件事要做它是什么?麻烦? ECS就是这样· CountData 计数的值· CountSystem 实际计数· ECSMain 实体ComponentDatas.csusing Unity.Entities; // 实体public struct CountData : IComponentData{public int count;}CountSystem.csusing Unity.Entities; public class CountSystem : ComponentSystem{// System所需的ComponentData列表struct Group{public int Length;public ComponentDataArray<CountData> countData;} [Inject] Group group; // 注入请求的ComponentData // 调用每一帧protected override void OnUpdate(){for(int i=0; i<group.Length; i++){var countData = group.countData[i];countData.count++;group.countData[i] = countData;}}}ECSMain.csusing UnityEngine;using Unity.Entities; public class ECSMain : MonoBehaviour{void Start (){// 获取EntityManagervar entityManager = World.Active.GetOrCreateManager<EntityManager>(); // 定义实体的原型var sampleArchetype = entityManager.CreateArchetype(typeof(CountData)); // 实际上基于原型生成实体entityManager.CreateEntity(sampleArchetype);}}之后,如果您将ECSMain附加到适当的对象并Play,则第一步完成。在Play期间,打开Window > EntityDebugger,当它从Systems列表中找到CountSystem时,它会变白,并且如果实体存在 。如果没有实体,那么您有可能在没有CountData的情况下创建实体,或者您没有首先创建实体。另外,如果您没有系统,则创建ComponentSystem的代码有问题。更多unity2018的功能介绍请到paws3d学习中心查找。

优秀的个人博客,低调大师

foy: 轻量级的基于 nodejs 的通用 build 工具

npm 的 scripts 下写的命令太多就很容易很乱,各种第三方轮子都只能解决一部分问题,总感觉不是很好用,想找个类似 make 的工具只能找到 jake, 可是 jake 的 API 太老,居然很多都不支持 promise, 代码也不多,就干脆自己造轮子了, 感觉效果还行。 项目地址: https://github.com/zaaack/foy gitee 地址: https://gitee.com/zane_young/foy 特点: 基于 promise 的任务和内置工具函数(fs/shell), 无缝支持 async/await 类似于 shelljs 的跨平台 shell dsl, 人人都会写 shell 易学易用,无需为写仅仅几个 build 命令而花费几个小时去寻找和学习第三方包 很小的安装成本 foy: gulp: grunt: 无缝和第三方支持 promise 的工具包整合,不需要封装成插件就能用 使用: 安装 yarn add -D foy # or npm i -D foy # Or Install globally with yarn add -g foy # or npm i -g foy 在项目根目录下增加一个 Foyfile.js (或者 Foyfile.ts, 需要安装 ts-node) import { task, desc, option, strict, fs } from 'foy' task('build', async ctx => { await ctx.exec('tsc') }) desc('Build ts files with tsc') option('-w, --watch', 'watch file changes') strict() // This will throw an error if you passed some options that doesn't defined via `option()` task('build2', async ctx => { await ctx.exec(`tsc ${ctx.options.watch ? '-w' : ''}`) }) task('task', async ctx => { await fs.rmrf('/some/dir/or/file') // Remove directory or file await fs.copy('/src', '/dist') // Copy folder or file let json = await fs.readJson('./xx.json') await ctx.env('NODE_ENV', 'production') await ctx.cd('./src') await ctx.exec('some command') // Execute an command let { stdout } = await ctx.exec('ls', { stdio: 'pipe' }) // Get the stdout, default is empty because it's redirected to current process via `stdio: 'inherit'`. }) 然后就可以运行任务了 # 安装在本地 node_modules 目录下 npx foy build npx foy build1 npx foy task # 安装在全局 foy build foy build1

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册