架构(十七)翻译监控

news2024/12/23 19:18:08

一、引言

    作者最近做的一个功能是需要监控一个翻译转换,根据国家和语言进行分组,然后定时把监控情况放到ck里面。为什么是分组和定时监控呢?因为调用比较高的系统的qps在单机一万多,70台机器,可怕的高频调用注定他不能实时分析。

二、方案设计

1、需求

    先明确一下功能点,翻译监控很多读者可能不太理解,大家可以类比redis缓存监控,只不过由于高频不能做实时监控,要根据国家、语言把redis缓存进行分组监控,方便监控一段时间内的国家语言维度对应key的缓存访问频率。

2、分析

    首先要增加切点,因为这种监控肯定要方便发布、无需更新pom,所以要在字节码增强里面做

    要实现这样的监控,首先要有一个存储,把国家+语言+key作为唯一键,存储他的频率,这种肯定是需要一个map了。

    还需要定时将map存储的数据发送到ck,那就需要开启一个可配置频率的定时任务。定时任务的开启也是一个问题,因为在javaagent里面使用不了Spring的定时包,原因之前的文章说过。所以必须使用jdk原生的工具,jdk倒是使用延时队列和lock阻塞实现了一个ScheduledThreadPoolExecutor。

    使用ScheduledThreadPoolExecutor要注意它的无界队列,但是他没有提供更改队列数量的方法,那我们有两个方案:一个是使用信号量进行阻塞,防止大量任务进入队列;另外一种是封闭这个线程池,只在开启一次,队列不进行二次任务进入

    这里就带来了并发问题,map在被定时任务读取发送到ck的时候,还有高频的写入操作,加锁就太影响性能了。那么有什么巧妙的设计可以规避吗?可以设置两个map,一个用来读一个用来写,在定时任务读取的时候设置标志位,切换map的使用。

三、代码    

    分析完了还是要在代码中实践,会发现更多问题

1、map存储

   使用了一个AtomicBoolean标识目前使用的map

    

public class MonitorMapHandleUtils {
    private static final ConcurrentHashMap<String, Integer> firstMap = new ConcurrentHashMap<>();

    private static final ConcurrentHashMap<String, Integer> secondMap = new ConcurrentHashMap<>();


    private static AtomicBoolean useFirst = new AtomicBoolean(true);

    private static final String SEMICOLON = ";";

    /**
     * country+ key + locale维度分组
     * 
     * @param key
     */
    public static void pushMap(Object key, Object locale, String country) {

        String key = country + SEMICOLON + key + SEMICOLON + locale;
        if (useFirst.get()) {
            firstMap.compute(key, (k, v) -> (v == null) ? 1 : v + 1);
            return;
        }
        secondMap.compute(key, (k, v) -> (v == null) ? 1 : v + 1);
    }

    public static void runSendMap() {
        if (useFirst.get()) {
            sendMap(firstMap);
            return;
        }
        sendMap(secondMap);
    }

    /**
     * 控制分钟级别,不会有useFirst连续设置的风险
     * 
     * @param map
     */
    protected static void sendMap(ConcurrentHashMap<String, Integer> map) {
        useFirst.set(!useFirst.get());
        map.forEach((k, v) -> MonitorMapHandleUtils.sendCk(k, v));
        map.clear();
    }

    private static void sendCk(String key, Integer count) {
    }
}

2、定时发送

    这里其实是不断的在取延时多久执行,配置中心都是推送客户端缓存的,所以这里的检查不会有多少性能损耗

    使用start开启定时任务,可以思考下为什么要这样做。比如有的同事说为什么不在static静态块里面处理?

    首先即使在静态块处理,这个类也必须是主动使用的,否则不会被按需加载,类的主动使用包括以下几种情况:

创建类的实例。

访问类的静态方法。

访问类的静态字段,除了声明为final的字段,它们是编译时常量。

使用java.lang.reflect包的方法对类进行反射调用。

初始化一个类的子类(首先会初始化父类)。

   加载的时候必须保证所需的包已经加载好了,这里有什么操作?配置中心的首次检查,更新延时时间,所以我们必须让这个定时类的方法被调用,而且是在配置中心包加载好之后才能调用。

    这样的话就要把MonitorMapHandleUtils使用的变量或者方法放在MonitorDynamicScheduledTask,然后调用,这样才能保证配置中心一定是已经加载好的,这取决于调用的时机,只有被调用到的时候这些类才会按需加载,这样代码结构看起来就会比较诡异,互相依赖

    定时类只放开了一个方法,并且调用一次之后就不再允许处理,避免多次调用,所以就不会有无界队列过多任务的风险


public class MonitorDynamicScheduledTask {

    private static final ScheduledExecutorService scheduler = new ScheduledThreadPoolExecutor(1);
    /**
     * 初始延迟时间,单位为分钟
     */
    private static volatile int currentDelay = 240;

    private static AtomicBoolean startFlag = new AtomicBoolean(false);

    /**
     * 开启仅执行一次,并发执行多次也没关系,瞬时不影响
     */
    public static void start() {
        if (startFlag.get()) {
            return;
        }
        MonitorDynamicScheduledTask.checkDelay();
        scheduleTask(currentDelay);
        startFlag.set(true);
    }

    /**
     * 进入队列,不会有递归调用的方法栈问题
     * 
     * @param delayInHours
     */
    private static void scheduleTask(int delayInHours) {
        scheduler.schedule(() -> {
            if (Config.monitorRun()) {
                MonitorMapHandleUtils.runSendMap();

                MonitorDynamicScheduledTask.checkDelay();

                // 重新调度下一次执行
                MonitorDynamicScheduledTask.scheduleTask(currentDelay);
            }
        }, delayInHours, TimeUnit.MINUTES);
    }

    private static void checkDelay() {
        // 检查配置中心是否有更新
        int newDelay = Config.monitorInterval();
        if (newDelay != currentDelay && newDelay > 0) {
            currentDelay = newDelay;
        }
    }
}

四、总结

    翻译监控不难,难的是在agent无侵入的情况下去监控,要考虑性能损耗、类加载时机、包加载时机,即使是简单的并发也要考虑不能用锁造成性能损耗

图片

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1715595.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

基于51单片机的室内空气质量检测-仿真设计

本设计是基于单片机的空气质量检测设计&#xff0c;主要实现以下功能&#xff1a; 可实现通过SGP30测量二氧化碳及甲醛浓度&#xff0c;当超过设置的最大值时&#xff0c;进行报警及通风和净化空气处理 可实现通过MQ-4测量甲烷浓度&#xff0c;当超过设置的最大值时&#xff0…

PIC单片机控制小型三相无刷直流电机

1、使用PIC12F629小型三相无刷直流电机制作电动口罩&#xff0c;涉及到电机的驱动芯片的选型&#xff0c;这里选用国产的MS39549驱动芯片&#xff1b; 2、搭建的电路图如下&#xff1a; 3、单片机给MS39549驱动芯片发送PWM占空比信号&#xff0c;即可实现对电机的转速控制&…

webpack快速入门---webpack的安装和基本使用

webpack是什么 本质上&#xff0c;webpack 是一个用于现代 JavaScript 应用程序的 静态模块打包工具。当 webpack 处理应用程序时&#xff0c;它会在内部从一个或多个入口点构建一个 依赖图(dependency graph)&#xff0c;然后将你项目中所需的每一个模块组合成一个或多个 bund…

How Diffusion Models Work

introduction intuition goal 让神经网络学到图像是什么样的&#xff0c;一种方式是对数据添加不同级别的噪音&#xff0c;让神经网络能够区分细节/总体轮廓 训练一个神经网络去产生精灵 sampling nn

最新淘宝死店全自动采集私信筛选脚本,号称日赚500+【采集软件+使用教程】

原理&#xff1a; 利用脚本自动采集长时间未登录店铺&#xff0c;然后脚本自动私信对应的店铺&#xff0c;看看商家是不是不回消息来判断是否是死店&#xff0c;再下单购买死店的产品&#xff0c;超过48小时不发货就可以联系客服获得赔付&#xff0c;一单利润百分之5%-30%&…

ubuntu系统开启ssh密码登录

文章目录 前言 一、确认否有ssh服务 二、修改/etc/ssh/sshd_config配置文件 三、重启ssh服务 总结 前言 安装好ubuntu系统后&#xff0c;默认是无法通过密码远程shell连接的&#xff0c;需要修改配置文件。 一、确认否有ssh服务 我这边使用的是ubuntu 22.04 LTS的系统&a…

SpringBoot——集成Spring Data JPA保存数据

目录 JPA 项目总结 新建一个SpringBoot项目 pom.xml application.properties配置文件 User实体类 UserRepository接口 SpringbootJpaApplicationTests测试类 测试 JPA 项目在运行过程中会产生很多业务数据&#xff0c;一般我们把数据保存起来的这个过程称为数据持久化。…

应用层协议HTTP与HTTPS

HTTP与HTTPS的介绍 HTTP&#xff08;Hypertext Transfer Protocol&#xff0c;超文本传输协议&#xff09;和HTTPS&#xff08;Hypertext Transfer Protocol Secure&#xff0c;超文本传输安全协议&#xff09;都是用于在Web上传输数据的协议&#xff0c;但它们之间存在一些重要…

筛选的艺术:数组元素的精确提取

新书上架~&#x1f447;全国包邮奥~ python实用小工具开发教程http://pythontoolsteach.com/3 欢迎关注我&#x1f446;&#xff0c;收藏下次不迷路┗|&#xff40;O′|┛ 嗷~~ 目录 一、筛选的基本概念 二、筛选的实际应用案例 1. 筛选能被三整除的元素 2. 筛选小于特定值…

Python系列:教你使用PyMySQL操作MySQL数据库

Python系列 PyMySQL操作MySQL数据库 - 文章信息 - Author: 李俊才 (jcLee95) Visit me at CSDN: https://jclee95.blog.csdn.netMy WebSite&#xff1a;http://thispage.tech/Email: 291148484163.com. Shenzhen ChinaAddress of this article:https://blog.csdn.net/qq_2855…

Go语言GoFly框架快速新增接口/上手写代码

拿到一个新框架大家可能无从下手&#xff0c;因为你对框架设计思路、结构不了解&#xff0c;从而产生恐惧&#xff0c;所以我们框架是通过简单可视化界面安装&#xff0c;安装后即可看到效果&#xff0c;然后点击先点点看各个功能&#xff0c;看现有的功能是怎么写的&#xff0…

《QT实用小工具·六十八》基于QMenu开发的炫酷菜单栏

1、概述 源码放在文章末尾 该项目基于QMenu实现了炫酷的菜单栏效果&#xff0c;包含了如下功能&#xff1a; 1、实现了类似word菜单栏的效果&#xff0c;可以在菜单栏中横向添加不同的菜单 2、鼠标点击菜单可以展开菜单栏&#xff0c;再次点击菜单可以收起菜单栏 3、鼠标点击笑…

基础—SQL—DQL(数据查询语言)基础查询

一、引言 1、介绍&#xff1a; 分类全称描述DQL英文全称&#xff1a;Data Query Language(数据查询语言)主要是学习对数据库表中的记录进行查询的语句 2、讲解 日常的开发中或者对于一个正常的业务系统中&#xff0c;对于查询的操作次数是远远多于数据的增删改的频次。例如…

SFOS2:组件介绍

一、前言 在sailfish os application的开发过程中&#xff0c;几乎是困难重重&#xff0c;因为我暂未找到具有完整性、指导性、易懂性的开发文档&#xff0c;特别是组件的使用&#xff0c;现决定将自己的探究结果记录下来。因此&#xff0c;这篇文章只会具有参考价值&#xff0…

MS Excel: 高亮当前行列 - 保持原有格式不被改变

本文使用条件格式VBA的方法实现高亮当前行列&#xff0c;因为纯VBA似乎会清除原有的高亮格式。效果如下&#xff1a;本文图省事就使用同一种颜色了。 首先最重要的&#xff0c;【选中你期望高亮的单元格区域】&#xff0c;比如可以全选当前sheet的全部区域 然后点击【开始】-【…

关于 Spring 是什么

Spring 是什么 我们通常所说的 Spring 指的是 Spring Framework&#xff08;Spring 框架&#xff09;&#xff0c;它是⼀个开源框架&#xff0c;有着活跃⽽庞⼤的社区&#xff0c;这就是它之所以能⻓久不衰的原因。Spring ⽀持⼴泛的应⽤场景&#xff0c;它可以让 Java 企业级的…

松下MINAS A6B系列旋转电机规格书--A系列

一、松下电机型号的识别方法 二、松下标准型电机型号大全 三、松下电机的规格 四、电机外观 五、XA&#xff0c;XB连接器 六、USB连接器 七、EtherCAT用连接器X2A、X2B 八、IO连接器X4 输入输出信号接口 九、编码器连接器 十、模拟监视器用连接器X7 十一、电源连接器以及端子台…

详解 Spark 的运行架构

一、核心组件 1. Driver Spark 驱动器节点&#xff0c;用于执行 Spark 任务中的 main 方法&#xff0c;负责实际代码的执行工作主要负责&#xff1a; 将用户程序转化为作业 (job)在 Executor 之间调度任务 (task)跟踪 Executor 的执行情况通过 UI 展示查询运行情况 2. Exec…

matlab工具使用记录-编辑器和命令行窗口分开还原

工具&#xff1a;matlab2021b 场景&#xff1a;在使用软件的过程中&#xff0c;我们误操作将matlab的编辑器单独出来了。这时候对软件进行各种操作都还原不回去。 matlab中编辑器和命令行窗口分开了如下图所示。 这时候只需要使用快捷键在编辑器窗口按CtrlshiftD&#xff0c;…

【错题集-编程题】dd 爱旋转(模拟)

牛客对应题目链接&#xff1a;dd爱旋转 (nowcoder.com) 一、分析题目 模拟题&#xff0c;但是需要不能直接无脑模拟&#xff0c;要思考⼀下规律。 顺时针旋转 180&#xff1a;行变换 列变换行变换、列变换的顺序颠倒不会有影响行变换的次数是个数相当于不变 二、代码 #includ…