基于Skywalking开发分布式监控(四)一个案例

news2024/11/23 5:09:54

上一篇我们简单介绍了基于SkyWalking自定义增强的基本架构,即通过把Trace数据导入数据加工模块进行加工,进行持久化,并赋能grafana展示。

现在我们给出一个例子,对于量化交易系统,市场交易订单提交,该订单可以走模拟盘也可以走实盘,可以自动提交,也可以走人工提交,订单提交后,会把交易所给到的订单信息反馈回来。 需要监控的需求很简单:可以按,自动实盘/虚拟盘,人工实盘/虚拟盘订单分类监控,提交和反馈流程,满足指标项:

1 每分钟延时、延时百分位(P50/75/90/95/99 MAX)、每分钟请求数,排名前5的慢请求等监控项(metrics)

2 以及按排名前5的慢请求对应的SPAN进行抓取,分析出最慢的SPAN

那么SW原生监控有啥问题呢?
1 需要根据该流程在不同阶段的特征才能定位该流程,按Trace-Span模型来说,即需要一个Trace链根据不同Span提供的特征才能抓取该Trace,SW并不支持

例如 分辨人工/自动订单实际上是按Trace相关EndpointName来的
人工订单走页面,EntrySpan的 endpointName为POST:/api/trade/order/send
但自动订单由程序发起,EntrySpan的 endpointName为“rpc.OrderTradeService.send

而分辨是否走实盘/虚拟盘,则是在后续Span,按tag systemFlag=1或2,来确认

在这里插入图片描述
而SW的搜索显然是不支持的

  1. 问题2 反馈消息是根据交易所API生成的,不是一个标准通讯架构,只能根据自定义用户增强(customize-enhance),生成的localSpan形成跟踪链,那SW原生Trace查询根本没法按endpoint名字搜索,只能按tag搜索,然后按时间取定位,效率非常低
  2. 还有一个上一篇说了,SW对Trace和Span不提供metric聚合项

那增强计算模块怎么解决上述问题
对问题1: 按人工、自动、虚拟、实盘,形成4个搜索项,然后定时(基本)同时执行,把搜索结果叠加到ES索引中,按订单编号trade_id更新索引项,利用ES的向量特征形加上业务标签,供下游按业务标签定位需要的Trace

对问题2: 按预先设计的Tag值标识反馈消息,然后按Tag搜索,把搜索结果叠加到ES索引中,按订单编号trade_id更新索引项,利用ES的向量特征形加上业务标签,供下游按业务标签定位需要的Trace

对问题3 按业务标签计算各监控项(metrics),并按时间点汇总最慢的5个Trace,查找Span

我们按配置config来说明
关于问题1,我们配置了4个搜索项

"tasks" : [
    {  #查找按EndpointName=rpc.OrderTradeService.send查找自动订单,并且在ES索引中增加业务标签 businessTag:: Auto
      "name": "task.QueryTraces",       
      "para" : {
          "serviceName" : "TradeService",
          "endpointName" : "rpc.OrderTradeService.send",
          "businessTag" : { "key": "businessTag", "value": "Auto"},
          "tags" : {},
          "traces_index" :  "traces-"    #索引名,xx-后面跟着日期
      },
      "switch" : "on",      #搜索项有效
      "interval" : "60"      #每隔60秒执行一次
    },
   { #查找按EndpointName=POST:/api/trade/order/send查找人工订单,并且在ES索引中增加业务标签 businessTag:: manual
      "name" : "task.QueryTraces",
      "para" : {
       "serviceName" : "TradeService",
       "endpointName" : "POST:/api/trade/order/send",
        "businessTag" : { "key": "businessTag", "value": "manual"},
        "tags" : {},
        "traces_index" :  "traces-"
      },
      "switch" : "on",
      "interval" : "60"
   },
    {  #查找按tag: systemFlag=1 查找人工订单,并且在ES索引中增加业务标签 systemFlag:: 1 (实盘)
      "name" : "task.QueryTraces",
      "para" : {
          "serviceName" : "TradeService",
          "endpointName" : "",
          "businessTag" : { "key": "systemFlag", "value": "sim"},
          "tags" : { "key": "systemFlag", "value": "1"},
          "traces_index" :  "traces-"
      },
      "switch" : "on",
      "interval" : "60"
    },
   {   #查找按tag: systemFlag=2 查找人工订单,并且在ES索引中增加业务标签 systemFlag:: 2 (实盘)
      "name" : "task.QueryTraces",
      "para" : {
          "serviceName" : "TradeService",
          "endpointName" : "",
          "businessTag" : { "key": "systemFlag", "value": "RealTime"},
          "tags" : { "key": "systemFlag", "value": "2"},
          "traces_index" :  "traces-"
      },
     "switch" : "on",
     "interval" : "60"
    },

task.QueryTraces是查询程序,按每分钟1次的节奏,按Graphql接口查询,需要用到的接口,按ServiceName按SW内置查询searchService接口查ServiceId , 按SW内置查询searchEndpoint接口查EndpointId
然后根据ServiceId , EndpointId调用,或者ServiceId和预置Tag,按SW内置查询接口queryBasicTraces查询相关Traces,注意点如下:
1 查询窗口要注意,也就是要防止Trace形成前执行查询语句,建议做成滑动窗口,可以调节窗口的大小,或者隔几秒多试几次(比如10秒执行3次)
2 要注意应用多页查询,queryBasicTraces有页数限制,一次最多1000条,要查全需要比较完整多页查询结构
查询完更新ES索引之后
在这里插入图片描述
很容易根据业务标签,获取我们所需的Traces

同理对问题2,我们引入配置文件,实际上我们利用FIX报文msgtype=8 报文的特征来标识反馈消息,然后按ordStatus,表示是否是成交或者订单有效的报文,即按tags msgType=8, ordStatus=2/0 查询相关Traces

{
     "name" : "task.QueryTraces",
     "para" : {
       "serviceName" : "APIService",
       "endpointName" : "",
       "businessTag" : { "key": "OrdStatus", "value": "deal"},
       "tags" : [{ "key": "msgType", "value": "8"},{"key": "ordStatus","value": "2"}],
       "traces_index" :  "traces-"
     },
     "switch" : "on",
     "interval" : "60"
   },
   {
     "name" : "task.TracesQueryInfo",
     "para" : {
       "serviceName" : "APIService",
       "endpointName" : "",
       "businessTag" : { "key": "OrdStatus", "value": "effect"},
       "tags" : [{ "key": "msgType", "value": "8"},{"key": "ordStatus","value": "0"}],
       "traces_index" :  "traces-"
     },
     "switch" : "on",
     "interval" : "60"
   },

对于问题3,我们配置两种计算模块: 一是 task.Caculator用于计算各类Metrics,与SW无关,二是 task.SpanInfo计算 ES索引库中 按大于95%分位数延时的慢Traces,逐条查找全部Span

{ # 按业务标签查人工实盘的订单traces(businessTag=manual,systemFlag=RealTime),计算监控项
     "name": "task.Caculator",
     "para" : {
       "businessTags" :[{ "key": "businessTag", "value": "manual"},{"key": "systemFlag","value": "RealTime"}],
       "traces_index" :  "traces-",    # 源索引
       "stat_index" : "traces_index-"   #监控项索引
     },
     "switch" : "on",
     "interval" : "60",
     "delay" : 10      # 比源索引执行慢10秒
   },
   {  # 按业务标签查自动虚拟盘的订单traces(businessTag=auto,systemFlag=sim),计算监控项
     "name": "task.Caculator",
     "para" : {
       "businessTags" :[{ "key": "businessTag", "value": "Auto"},{"key": "systemFlag","value": "sim"}],
       "traces_index" :  "traces-",
       "stat_index" : "traces_index-"
     },
     "switch" : "on",
     "interval" : "60",
     "delay" : 10
   },
   { # 按业务标签查自动实盘的订单traces(businessTag=auto,systemFlag=Realtime),计算监控项
     "name": "task.Caculator",
     "para" : {
       "businessTags" :[{ "key": "businessTag", "value": "Auto"},{"key": "systemFlag","value": "RealTime"}],
       "traces_index" :  "traces-",
       "stat_index" : "traces_index-"
     },
     "switch" : "on",
     "interval" : "60",
     "delay" : 10
   },
   { # 按业务标签查反馈提交有效订单(OrdStatus=effect,systemFlag=Realtime),计算监控项
     "name": "task.Caculator",
     "para" : {
       "businessTags" : { "key": "OrdStatus", "value": "effect"},
       "traces_index" :  "traces-",
       "stat_index" : "traces_index-"
     },
     "switch" : "on",
     "interval" : "60",
     "delay" : 10
   },
   { # 计算 ES索引库中 按大于95%分位数延时的慢Traces,逐条查找全部Span
     "name": "task.SpanInfo",
     "para" : {
       "percentile" : 0.95,
       "traces_index" :  "traces-",
       "span_index" : "traces_index-"
     },
     "switch" : "on",
     "interval" : "60",
     "delay" : 10
   }

我们看一下订单提交计算结果索引
在这里插入图片描述

以及慢Trace相关Span的索引
在这里插入图片描述
关于task.QueryTraces,task.Caculator,task.SpanInfo,主要代码如下
task.QueryTraces

public class QueryTraces extends AbstractTraceQuery implements TaskService,Runnable{
   
    private static final Lock lock = new ReentrantLock();  //对不同任务的竞争性资源加锁
    ObjectMapper objectMapper = new ObjectMapper();

    String serviceName,serviceId,endpointName,endpointId,traces_index;

    ArrayNode businessTags;
    JsonNode businessTag,tags;
    DatasourceService datasource;
    TargetdbService targetdb;

    @Override
    public void run() {

        logger.info("QueryInfo begin...");

        if("".equals(serviceId)){
            //防止获取不到serviceId
        serviceId=this.datasource.queryServiceId(serviceName);
            if("".equals(serviceId)){
                //第二次获取不成功就终止线程
                logger.error("query serviceId fail");
                return;
            }
        }

        if(endpointName.equals("")){
            //检查tags是否为空,为空就终止线程
            if(tags.isNull() || tags.isMissingNode()) {
                logger.error("endpointName & tags is both empty");
                return;
            }
        } else{
            if("".equals(endpointId)){
                //防止获取不到endpointId
                endpointId=this.datasource.queryEndPointId(endpointName,serviceName);
                if("".equals(endpointId)){
                    //第二次获取不成功就终止线程
                    logger.error("query endpointId fail");
                    return;
                }
            }

        }
        targetdb.createForm(traces_index);
        String endTime=getTimeEndPoint(1,40);
        String startTime=getTimeEndPoint(3,41);
        int retry=3;  //重试次数
        int lastArraylistSize=0;
        ArrayNode traceList= JsonNodeFactory.instance.arrayNode();
        logger.info("QueryInfo startTime:: {}  endTime:: {}",startTime,endTime);

        try{
            while(retry>0){
                //查询SW的traces数据,注意有可能需要分页查询
                traceList=getMultiPageResult(datasource,serviceId,endpointId,startTime,endTime,tags);

                logger.info("traceList:: {} retry:: {}",traceList.toString(),retry);

                if(traceList.size()>lastArraylistSize){
                    //如果查到结果,打业务标签,并按TraceId调批量更新目标库
                    lastArraylistSize=traceList.size();
                    Map<String, List<Map<String,Object>>> traceMap = genTraceMap(businessTags, traceList); //结果集合

                    targetdb.updateDate(traces_index,traceMap);
                    //打时间戳
                    logger.info("TracesQuery update is done. {}",System.currentTimeMillis());
                }

                try {
                    // 暂停执行5秒钟
                    Thread.sleep(5000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                retry--;
            }
        }catch (Exception e) {
            e.printStackTrace();
            return;
        }
    }

    @Override
    public void init(JsonNode paraData, DatasourceService datasourceService, TargetdbService targetdbService) {
      ......
    }
}

task.Caculator

public class Caculator extends AbstractTraceQuery implements TaskService,Runnable {
    private final static Logger logger = LoggerFactory.getLogger(TracesQueryInfo.class);
    private static final Lock lock = new ReentrantLock();  //对不同任务的竞争性资源加锁

    String traces_index, stat_index;

    ArrayNode businessTags;
    JsonNode businessTag;
    DatasourceService datasource;
    TargetdbService targetdb;

    private Map<String,Object> traceProcess(Map<String,Object> sourceMap){
        //处理traces查询结果
        AtomicInteger durationSum= new AtomicInteger();
        AtomicInteger count= new AtomicInteger();
        AtomicInteger maxDuration=new AtomicInteger();
        double durationAvg,p50,p75,p90,p95,p99;
        ArrayList<Integer> durationArray = new ArrayList<>();;  //延时集合,用于计算分位数

        sourceMap.entrySet().stream().forEach((Map.Entry<String,Object> entry) -> {
            count.getAndIncrement();

            String traceId = entry.getKey();
            System.out.println("traceId::" + traceId);
            Integer duration = (int) Double.parseDouble(entry.getValue().toString());

            durationSum.addAndGet(duration);
            if (duration > maxDuration.get()) {
                maxDuration.getAndSet(duration);
            }
            durationArray.add(duration);

        });
        durationAvg=(durationSum.get())/(count.get());

        p50=percentile(durationArray.toArray(new Integer[durationArray.size()]),0.5);
        p75=percentile(durationArray.toArray(new Integer[durationArray.size()]),0.75);
        p90=percentile(durationArray.toArray(new Integer[durationArray.size()]),0.90);
        p95=percentile(durationArray.toArray(new Integer[durationArray.size()]),0.95);
        p99=percentile(durationArray.toArray(new Integer[durationArray.size()]),0.99);

        Map<String,Object> resultMap = new HashMap<>();
        resultMap.put("max_resp",maxDuration.get());
        resultMap.put("mean_resp",durationAvg);
        resultMap.put("count",count.get());
        resultMap.put("p50",p50);
        resultMap.put("p75",p75);
        resultMap.put("p90",p90);
        resultMap.put("p95",p95);
        resultMap.put("p99",p99);

        return resultMap;
    }

    @Override
    public void run() {

        if(targetdb.isExisted(traces_index)){

            logger.info("TracesStatInfo begin...");



            String endTime =getTimeUtcEndPoint(1,30);
            String startTime=getTimeUtcEndPoint(2,31);
            logger.info("startTime:: {}  endTime:: {}",startTime,endTime);

            try{
                // 在es trace表中,按bussinesTagList 查找local_time_stamp在当前时间范围内的记录
                logger.info("statQuery queryDate begins ... {}",System.currentTimeMillis());
                Map<String, Object> dataMap=targetdb.queryData(traces_index,businessTags,startTime,endTime,"duration");
                Map<String, Object> resMap = new HashMap<>();
                if(null!=dataMap) {
                    //Map<String, Object> resMap = new HashMap<>();


                    logger.info("TracesStatInfo resultMap:: {} ", dataMap.toString());

                    resMap = traceProcess(dataMap);


                   // targetdb.createForm(stat_index);
                    //targetdb.insertDate(stat_index, seqNo, resMap);

                }else{
                    //找不到置0
                    logger.info("StatInfo resultMap is null ");
                    resMap.put("max_resp", 0);
                    resMap.put("mean_resp", 0);
                    resMap.put("count", 0);
                    resMap.put("p50", 0);
                    resMap.put("p75", 0);
                    resMap.put("p90", 0);
                    resMap.put("p95", 0);
                    resMap.put("p99", 0);
                }

                //打业务标签和时间戳
                resMap = getMapWithTags(businessTags, resMap);
                String seqNo = generateSeqNo(); //生成序号

                // 加锁
                lock.lock();
                targetdb.createForm(stat_index);
                targetdb.insertDate(stat_index, seqNo, resMap)

            }catch(Exception e){
                e.printStackTrace();
               return;
            }finally {
                // 释放锁
                lock.unlock();
            }
        }else{
            logger.info("trace_index {} is not existed",traces_index);
        }
    }

    @Override
    public void init(JsonNode paraData, DatasourceService datasourceService, TargetdbService targetdbService) {
              .....
    }
}

task.SpanInfo

public class SpanInfo extends AbstractTraceQuery implements TaskService,Runnable{
    private final static Logger logger = LoggerFactory.getLogger(SpanQueryInfo.class);
    private static final Lock lock = new ReentrantLock();  //对不同任务的竞争性资源加锁

    String traces_index, span_index;
    DatasourceService datasource;
    TargetdbService targetdb;
    double percentile;

    private Map<String,Object> findTraces(Map<String,Object> sourceMap,double percentile){
        ArrayList<Integer> durationArray = new ArrayList<>();;  //延时集合,用于计算分位数
        Map<String,Object> resultMap = new HashMap<>(); //结果集合
        //计算percentile分位
        sourceMap.entrySet().stream().forEach((Map.Entry<String,Object> entry) ->{
            Integer duration = (int) Double.parseDouble(entry.getValue().toString());
            durationArray.add(duration);
        });
        double percentileData = percentile(durationArray.toArray(new Integer[0]), percentile);
        logger.info("percentileData:: {}",percentileData);
        //查找超过percentile的traceId
        sourceMap.entrySet().stream().forEach((Map.Entry<String,Object> entry) ->{
            double duration = (double) Double.parseDouble(entry.getValue().toString());
            if(duration>=percentileData){
                String traceId=entry.getKey().toString();
                resultMap.put(traceId,duration);
            }
        });
        return resultMap;
    }

    @Override
    public void run() {

        logger.info("SpanInfo begin...");
        //建表
      

        targetdb.createForm(span_index);

        try{
            logger.info("SpanInfo try begin...");



            //找到当前trace_index索引中所有高出95%的值的traceId集合
            Map<String, Object> dataMap=targetdb.queryAllData(traces_index,"duration");
            if(null!=dataMap) {
                logger.info("SpanInfo resultMap:: {} ", dataMap.toString());

                //查找高于percentile分位数的值
                Map<String, Object> resMap = findTraces(dataMap, percentile);

                logger.info("spanInfo foundedMap:: {} ", resMap.toString());

                //遍历查询结果,如果span_index中不存在,则查询span后插入span_index
                resMap.entrySet().stream().forEach((Map.Entry<String, Object> entry) -> {
                    String traceId = entry.getKey();
                    if (targetdb.isNotInTheIndex(span_index, "traceId", traceId)) {
                        //按traceId查询span
                        ArrayNode spanList = datasource.getTraceSpans(traceId);
                        Map<String, List<Map<String, Object>>> spansMap = genSpanMap(traceId, spanList); //组成SpanList

                        //插入span_index
                        targetdb.updateDate(span_index, spansMap);



                    }

                });
            }else{
                logger.info("SpanInfo resultMap is null ");
            }

        }catch(Exception e){
            e.printStackTrace();
            return;
        }
    }

    @Override
    public void init(JsonNode paraData, DatasourceService datasourceService, TargetdbService targetdbService) {
      ....
    }
}

完成索引持久化后,就可以以grafana访问ES库形成展示,这部分不展开,看一下效果
在这里插入图片描述
在这里插入图片描述

姑且算抛砖引玉吧,希望各位大佬也分享一下方案

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

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

相关文章

2024国内知名大厂Java岗面经,java容器面试题

前言 刚刚过去的双十一&#xff0c;让“高性能”“高可用”“亿级”这3个词变成了技术热点词汇&#xff0c;也让很多人再次萌发成为「架构师」的想法。先问大家一个问题&#xff1a;你觉得把代码熟练、完成需求加上点勤奋&#xff0c;就能成为架构师么&#xff1f;如果你这么认…

Ubuntu22.04系统 安装cAdvisor提示找不到 CPU 的挂载点错误解决办法。

如果我们在安装cAdvisor时容器启动不起来 查看日志如下图所示 1、查看cgroup文件系统是v2 还是 v1 mount | grep cgroup 如图所示我的是v2 &#xff0c; cAdvisor 目前的最新版本&#xff08;v0.39.0&#xff09;仍然只支持 cgroup v1&#xff0c;不支持 cgroup v2。因此&#…

PRewrite: Prompt Rewriting with Reinforcement Learning

PRewrite: Prompt Rewriting with Reinforcement Learning 基本信息 2024-01谷歌团队提交到arXiv 博客贡献人 徐宁 作者 Weize Kong&#xff0c;Spurthi Amba Hombaiah&#xff0c;Mingyang Zhang 摘要 工程化的启发式编写对于LLM&#xff08;大型语言模型&#xff09;应…

大数据分析技术工程师CCRC-BDATE

大数据分析技术工程师介绍 大数据始于科技之美&#xff0c;归于创造价值。大数据时代&#xff0c;“谁用好数据&#xff0c;谁就能把握先机、赢得主动”。当下数据驱动的电信、社交媒体、生物医疗、电子政务商务等行业都在产生着海量的数据&#xff0c;随着大规模数据关联、交叉…

vue基本用法

文本插值 {{}} 用来绑定data方法返回的对象属性 v-bind:为标签的属性绑定data方法中返回的属性 事件绑定v-on:xxx 简写为xxx 双向绑定v-model 条件渲染 v-if v-else v-else-if 动态渲染页面元素

兰德:《中国量子技术的产业基础和军事部署报告》

2月1日&#xff0c;美国智库兰德公司发表中国量子技术的产业基础和军事部署报告&#xff0c;该报告强调了美国和中国均视量子科学和技术为确保各自经济和军事领导地位的战略要素。还指出量子科学是一项军民两用的技术。 该报告提到目前美国政府已经为量子科学制定了一项公开的国…

SoraAI优先体验资格注册教程

SoraA1视频工具优先体验资格申请 申请网址&#xff1a;https://openai.com/form/red-teaming-network 申请步骤&#xff1a; 填写基础信息 请使用英文根据内容填写以下内容&#xff0c;名、姓、电子邮件、居住国家、组织隶属关系(如果有)、教育水平 、学位&#xff08;哪个领…

数据库-DDL

show databases; 查询所有数据库 select database(); 查询当前数据库 use 数据库名&#xff1b; 使用数据库 creat database[if not exists] 数据库名…

【python】六个常见爬虫案例【附源码】

大家好&#xff0c;我是博主英杰&#xff0c;整理了几个常见的爬虫案例&#xff0c;分享给大家&#xff0c;适合小白学习 一、爬取豆瓣电影排行榜Top250存储到Excel文件 近年来&#xff0c;Python在数据爬取和处理方面的应用越来越广泛。本文将介绍一个基于Python的爬虫程序&a…

leetcode热题HOT 54. 螺旋矩阵(59. 螺旋矩阵 II)

一、问题描述&#xff1a; 给你一个 m 行 n 列的矩阵 matrix &#xff0c;请按照 顺时针螺旋顺序 &#xff0c;返回矩阵中的所有元素。 二、解题思路&#xff1a; 整体思路就是模拟螺旋遍历矩阵的过程&#xff0c;依次遍历外围边界的元素&#xff0c;并将其按顺序存入结果列表…

vant van-field 密码输入框小程序里隐藏、显示密码bug总结

老规矩先上效果图: vant 输入框组件 密码的隐藏与显示功能&#xff1a; 注: 用password属性控制密码的显示与隐藏 不要用type属性&#xff0c;type属性在真机上有时会没有效果 1、当然如果只用typepassword 不需要切换显示、隐藏也可以使用。 2、如果用到了密码的显示与…

计算机mfc140.dll文件缺失的修复方法分析,一键修复mfc140.dll

电脑显示mfc140.dll文件缺失信息时&#xff0c;不必担心&#xff0c;这通常是个容易解决的小问题。接下来让我们详细探究并解决mfc140.dll文件缺失的状况。以下将详述相应的解决方案&#xff0c;从而帮助您轻松克服这一技术难题。通过几个简单步骤&#xff0c;即可恢复正常使用…

mac使用Vscode运行C语言遇到的问题

mac系统如何使用vscode运行C语言 Unable to start debugging. Program path ‘/Users/ling/Learning/frontEnd/web/Test/main.cpp’ is missing or invalid. LLDB failed with message: Command ‘file-exec-and-symbols’. Target binary ‘/Users/ling/Learning/frontEnd/we…

(2024,SD3,整流流,定制的采样器,DiT)扩展整流流 transformer 以实现高分辨率图像合成

Scaling Rectified Flow Transformers for High-Resolution Image Synthesis 公和众和号&#xff1a;EDPJ&#xff08;进 Q 交流群&#xff1a;922230617 或加 VX&#xff1a;CV_EDPJ 进 V 交流群&#xff09; 目录 0. 摘要 2. 流的无模拟训练 3. 流轨迹 3.1. RF 模型的定…

运维知识点-ACCESS

ACCESS access 扫出后缀为asp的数据库文件 迅雷下载&#xff0c;直接改后缀为.mdbMicrosoft Office Access是由微软发布的关系数据库管理系统。它结合了 MicrosoftJet Database Engine 和 图形用户界面两项特点&#xff0c;是 Microsoft Office 的系统程序之一。 Microsoft Off…

商城|商城小程序|基于微信小程序的智慧商城系统设计与实现(源码+数据库+文档)

商城小程序目录 目录 基于微信小程序的智慧商城系统设计与实现 一、前言 二、系统设计 三、系统功能设计 1、用户信息管理 2、 商品信息管理 3、公告信息管理 4、论坛信息管理 四、数据库设计 1、实体ER图 五、核心代码 六、论文参考 七、最新计算机毕设选题推荐 …

防患未然,OceanBase巡检工具应用实践——《OceanBase诊断系列》之五

1. OceanBase为什么要做巡检功能 尽管OceanBase拥有很好的MySQL兼容性&#xff0c;但在长期的生产环境中&#xff0c;部署不符合标准规范、硬件支持异常&#xff0c;或配置项错误等问题&#xff0c;这些短期不会出现的问题&#xff0c;仍会对数据库集群构成潜在的巨大风险。为…

几种电脑提示mfc140.dll丢失的解决方法,以及如何预防mfc140.dll丢失

mfc140.dll真是一个超级关键的动态链接库文件&#xff01;一旦这个文件不翼而飞&#xff0c;可能会导致一些程序无法顺利运行&#xff0c;甚至给系统带来麻烦。但别担心&#xff01;遇到mfc140.dll文件丢失的情况&#xff0c;我们有一堆应对措施可以立马施行&#xff0c;确保问…

qnx display

05-SA8155 QNX Display框架及代码分析(1)_openwfd-CSDN博客 backlight p: 0 t: 0 00000 SHD -----ONLINE----- 2024/03/06 13:49:22.046 backlight p:1060958 t: 1 00000 ERR backlight_be[backlight_be.c:284]: pthread_create enter 2024/03/06 13…

java多线程编程(四)-----线程池

一.线程池的介绍 java中的池是非常重要的思想方法&#xff0c;比如内存池&#xff0c;进程池&#xff0c;连接池&#xff0c;常量池等等。本篇重点介绍java中的线程池。这里的这些池的概念都是一样的&#xff0c;比如做饭的时候&#xff0c;有烧水&#xff0c;切菜&#xff0c…