在时序分析及监控展示领域,Grafana无疑是开源解决方案中的翘楚,其灵活的插件机制,支持各种漂亮的面板、丰富的数据源以及强大的应用。典型的面板有Graph、Text、Singlestat、PieChart、Table、Histogram等,支持的数据源有ES、Graphite、InfluxDB、OpenTSDB、MySQL、Druid 、Prometheus、SimpleJson等,提供的应用有Zabbix、K8s等。但是某公司在分布式集群中物理机监控的数据源为gRPC方式,即连接gRPC即可获取实时物理机监控信息,如CPU,内存,磁盘,负载等信息,这样就能使用后台转发gRPC的消息,这里使用SSM框架的java后台为grafana提供的SimpleJson数据源。

作者撰文时,网上几乎没有分享SimpleJson数据源的java后台API,为此分享给大家,初次分享,不便之处请见谅。

整体架构如下所示:

一、WebAPI

如果要支持SimpleJson,后端WebAPI需要实现4个URL:

/:返回200,用于SimpleJson数据源测试连通性;
/search:返回所有可选的指标;
/query:返回对应指标的时间序列点;
/annotations:返回注解。

    @RequestMapping(value = "/", method = RequestMethod.GET)@ResponseBodypublic Map ReturnTest(HttpServletResponse response){response.setHeader("Access-Control-Allow-Headers", "accept, content-type");response.setHeader("Access-Control-Allow-Methods", "POST");response.setHeader("Access-Control-Allow-Origin", "*");Map<String, Object> map = new HashMap<String, Object>();map.put("result", "200 ok");return map;}
    @RequestMapping(value = "/search", method = RequestMethod.POST)@ResponseBodypublic List Search(HttpServletResponse response) {response.setHeader("Access-Control-Allow-Headers", "accept, content-type");response.setHeader("Access-Control-Allow-Methods", "POST");response.setHeader("Access-Control-Allow-Origin", "*");List<String> result = new ArrayList<String>();result.add("CPU");result.add("RAM");result.add("LOAD");result.add("SWAP");result.add("DISK");result.add("NET");return result;}
`````java@RequestMapping(value = "/query", method = RequestMethod.POST)@ResponseBodypublic List Query(@RequestBody Map<String,Object>  params, HttpServletResponse response) {List<Map> targetList = (List) params.get("targets");List<Map<String, Object>> result = new ArrayList<Map<String, Object>>() ;for (Map targetMap : targetList){String target = (String)targetMap.get("target");Map scopedVars = (Map) params.get("scopedVars");Map IP = (Map) scopedVars.get("IP");String nodeIP = (String) IP.get("text");if (target.equals("CPU")){result.add(nodeMonitorService.getCpuMap(nodeIP));}else if (target.equals("RAM")){result.add(nodeMonitorService.getRamMap(nodeIP));}else if (target.equals("LOAD")) {result.add(nodeMonitorService.getLoadMap(nodeIP));}else if (target.equals("SWAP")){result.add(nodeMonitorService.getSwapMap(nodeIP));}else if(target.equals("DISK")){result = nodeMonitorService.getDiskList(nodeIP);}else if (target.equals("NET")){result = nodeMonitorService.getNetList(nodeIP);}}response.setHeader("Access-Control-Allow-Headers", "accept, content-type");response.setHeader("Access-Control-Allow-Methods", "POST");response.setHeader("Access-Control-Allow-Origin", "*");Collections.sort(result, new Comparator<Map<String, Object>>() {public int compare(Map<String, Object> o1, Map<String, Object> o2) {String name1 = String.valueOf(o1.get("target").toString()) ;String name2 = String.valueOf(o2.get("target").toString()) ; return name1.compareTo(name2);}});return result;}
    @RequestMapping(value = "/annotations", method = RequestMethod.POST)@ResponseBodypublic Map Annotations() {Map<String, Object> map = new HashMap<String, Object>();map.put("result", "200 ok");return map;}

具体参数可以用以下函数替换,如getCupMap:

private Map<String, Object> strjson() {//String str = "{\"A\":{\"tables\":[{\"columns\":[{\"text\":\"序列\",\"sort\":true,\"desc\":true,\"title\":\"序列\",\"style\":{\"alias\":\"\",\"colorMode\":null,\"colors\":[\"rgba(245, 54, 54, 0.9)\",\"rgba(237, 129, 40, 0.89)\",\"rgba(50, 172, 45, 0.97)\"],\"decimals\":2,\"pattern\":\"/.*/\",\"thresholds\":[],\"type\":\"number\",\"unit\":\"short\"},\"hidden\":false,\"$$hashKey\":\"object:644\"},{\"text\":\"水果名称12\",\"title\":\"水果名称12\",\"style\":{\"alias\":\"\",\"colorMode\":null,\"colors\":[\"rgba(245, 54, 54, 0.9)\",\"rgba(237, 129, 40, 0.89)\",\"rgba(50, 172, 45, 0.97)\"],\"decimals\":2,\"pattern\":\"/.*/\",\"thresholds\":[],\"type\":\"number\",\"unit\":\"short\"},\"hidden\":false,\"$$hashKey\":\"object:645\"},{\"text\":\"价钱\",\"title\":\"价钱\",\"style\":{\"alias\":\"\",\"colorMode\":null,\"colors\":[\"rgba(245, 54, 54, 0.9)\",\"rgba(237, 129, 40, 0.89)\",\"rgba(50, 172, 45, 0.97)\"],\"decimals\":2,\"pattern\":\"/.*/\",\"thresholds\":[],\"type\":\"number\",\"unit\":\"short\"},\"hidden\":false,\"$$hashKey\":\"object:646\"},{\"text\":\"重量(kg)\",\"title\":\"重量(kg)\",\"style\":{\"alias\":\"\",\"colorMode\":null,\"colors\":[\"rgba(245, 54, 54, 0.9)\",\"rgba(237, 129, 40, 0.89)\",\"rgba(50, 172, 45, 0.97)\"],\"decimals\":2,\"pattern\":\"/.*/\",\"thresholds\":[],\"type\":\"number\",\"unit\":\"short\"},\"hidden\":false,\"$$hashKey\":\"object:647\"},{\"text\":\"总价钱\",\"title\":\"总价钱\",\"style\":{\"alias\":\"\",\"colorMode\":null,\"colors\":[\"rgba(245, 54, 54, 0.9)\",\"rgba(237, 129, 40, 0.89)\",\"rgba(50, 172, 45, 0.97)\"],\"decimals\":2,\"pattern\":\"/.*/\",\"thresholds\":[],\"type\":\"number\",\"unit\":\"short\"},\"hidden\":false,\"$$hashKey\":\"object:648\"}],\"rows\":[[1,\"水果01\",4,2,8],[2,\"水果02\",5,2,10],[3,\"水果03\",6,2,12],[4,\"水果04\",7,2,14],[5,\"水果05\",8,2,16]]}]}}";Map<String, Object> map = new HashMap<>();JSONArray ja = new JSONArray();for (int i = 0; i < 10; i++) {JSONObject jb = new JSONObject();jb.put("num", 10*i);jb.put("createTime", "2019-05-09T"+(11+i)+":01:01");ja.add(jb);}map.put("reasult", ja);return map;}

注意header里面加上这3条:

        response.setHeader("Access-Control-Allow-Headers", "accept, content-type");response.setHeader("Access-Control-Allow-Methods", "POST");response.setHeader("Access-Control-Allow-Origin", "*");

二、grafana配置

安装grafana,安装SimpleJson插件,在grafana官网,有详细说明。
启动访问,使用admin账户登录,

1、创建数据源:DataSources

type选择SimpleJson类型,URL填入后台服务的API地址,

2、创建面板dashboard

这个面板我已经分享到grafana网站了,可以前去下载:https://grafana.com/dashboards/5075

综上所述,基于SimpleJson数据源,只要配置数据源之后,按正确的方式添加API即可将数据灵活展现在Grafana中,当然SimpleJson只是一个数据源协议载体,理论上可以对接任何类型的后台数据,只要组装成它支持的格式即可。

面板源代码,扩展名成 .json就行,然后import即可:

{"__inputs": [{"name": "DS_DATA-PUBLIC","label": "data-public","description": "由java后台提供物理机信息,java连接物理机上的grpc接口,用于采集传送物理机信息","type": "datasource","pluginId": "grafana-simple-json-datasource","pluginName": "SimpleJson"},{"name": "DS_IP-PUBLIC","label": "ip-public","description": "提供物理机IP","type": "datasource","pluginId": "grafana-simple-json-datasource","pluginName": "SimpleJson"}],"__requires": [{"type": "grafana","id": "grafana","name": "Grafana","version": "5.0.0"},{"type": "datasource","id": "grafana-simple-json-datasource","name": "SimpleJson","version": "1.3.5"},{"type": "panel","id": "graph","name": "Graph","version": "5.0.0"},{"type": "panel","id": "singlestat","name": "Singlestat","version": "5.0.0"},{"type": "panel","id": "text","name": "Text","version": "5.0.0"}],"annotations": {"list": [{"builtIn": 1,"datasource": "-- Grafana --","enable": true,"hide": true,"iconColor": "rgba(0, 211, 255, 1)","name": "Annotations & Alerts","type": "dashboard"}]},"description": "物理机秒级监控页面","editable": true,"gnetId": 5075,"graphTooltip": 2,"id": null,"iteration": 1520931758719,"links": [],"panels": [{"collapsed": false,"gridPos": {"h": 1,"w": 24,"x": 0,"y": 0},"id": 6,"panels": [],"title": "指标","type": "row"},{"content": "# $IP","gridPos": {"h": 3,"w": 3,"x": 0,"y": 1},"id": 4,"links": [],"mode": "markdown","repeat": "IP","repeatDirection": "v","title": "物理机","transparent": false,"type": "text"},{"cacheTimeout": null,"colorBackground": false,"colorValue": true,"colors": ["rgba(0, 190, 250, 0.97)","rgba(237, 129, 40, 0.89)","rgba(245, 54, 54, 0.9)"],"datasource": "${DS_DATA-PUBLIC}","decimals": 2,"format": "percent","gauge": {"maxValue": 100,"minValue": 0,"show": false,"thresholdLabels": false,"thresholdMarkers": true},"gridPos": {"h": 3,"w": 4,"x": 3,"y": 1},"height": "100px","id": 12,"interval": null,"links": [],"mappingType": 1,"mappingTypes": [{"name": "value to text","value": 1},{"name": "range to text","value": 2}],"maxDataPoints": 100,"minSpan": 6,"nullPointMode": "connected","nullText": null,"postfix": "","postfixFontSize": "50%","prefix": "","prefixFontSize": "50%","rangeMaps": [{"from": "null","text": "N/A","to": "null"}],"repeat": "IP","repeatDirection": "v","span": 3,"sparkline": {"fillColor": "rgba(0, 141, 255, 0.1)","full": false,"lineColor": "rgb(0, 133, 253)","show": true},"tableColumn": "","targets": [{"bucketAggs": [{"field": "create_time","id": "2","settings": {"interval": "auto","min_doc_count": 0,"trimEdges": 0},"type": "date_histogram"}],"dsType": "elasticsearch","metrics": [{"field": "value","id": "1","inlineScript": "100-_value","meta": {},"settings": {"script": {"inline": "100-_value"}},"type": "avg"}],"query": "mib:ssCpuIdle AND ip:\"$ip\"","refId": "A","target": "CPU","timeField": "create_time","type": "timeserie"}],"thresholds": "50,80","title": "CPU使用率","type": "singlestat","valueFontSize": "80%","valueMaps": [{"op": "=","text": "N/A","value": "null"}],"valueName": "current"},{"cacheTimeout": null,"colorBackground": false,"colorValue": true,"colors": ["rgba(0, 162, 238, 0.97)","rgba(237, 129, 40, 0.89)","rgba(245, 54, 54, 0.9)"],"datasource": "${DS_DATA-PUBLIC}","format": "percent","gauge": {"maxValue": 100,"minValue": 0,"show": true,"thresholdLabels": false,"thresholdMarkers": true},"gridPos": {"h": 3,"w": 6,"x": 7,"y": 1},"height": "100px","id": 10,"interval": null,"links": [],"mappingType": 1,"mappingTypes": [{"name": "value to text","value": 1},{"name": "range to text","value": 2}],"maxDataPoints": 100,"nullPointMode": "connected","nullText": null,"postfix": "","postfixFontSize": "50%","prefix": "","prefixFontSize": "50%","rangeMaps": [{"from": "null","text": "N/A","to": "null"}],"repeat": "IP","repeatDirection": "v","span": 3,"sparkline": {"fillColor": "rgba(31, 118, 189, 0.18)","full": false,"lineColor": "rgb(31, 120, 193)","show": false},"tableColumn": "","targets": [{"bucketAggs": [{"field": "@timestamp","id": "2","settings": {"interval": "auto","min_doc_count": 0,"trimEdges": 0},"type": "date_histogram"}],"dsType": "elasticsearch","metrics": [{"field": "value","id": "1","inlineScript": "_value*100","meta": {},"settings": {"script": {"inline": "_value*100"}},"type": "avg"}],"query": "mib:disk_percent AND ip:\"$ip\"","refId": "A","target": "RAM","timeField": "create_time","type": "timeserie"}],"thresholds": "70,90","title": "内存使用率","type": "singlestat","valueFontSize": "100%","valueMaps": [{"op": "=","text": "N/A","value": "null"}],"valueName": "avg"},{"aliasColors": {},"bars": false,"dashLength": 10,"dashes": false,"datasource": "${DS_DATA-PUBLIC}","fill": 1,"gridPos": {"h": 9,"w": 12,"x": 0,"y": 4},"hideTimeOverride": false,"id": 2,"legend": {"alignAsTable": true,"avg": true,"current": true,"max": true,"min": true,"rightSide": false,"show": true,"total": false,"values": true},"lines": true,"linewidth": 1,"links": [],"nullPointMode": "null","percentage": false,"pointradius": 5,"points": false,"renderer": "flot","repeat": "IP","repeatDirection": "v","seriesOverrides": [],"spaceLength": 10,"stack": false,"steppedLine": false,"targets": [{"hide": false,"rawQuery": false,"refId": "A","target": "CPU","type": "timeserie"}],"thresholds": [],"timeFrom": null,"timeShift": null,"title": "CPU使用率","tooltip": {"shared": true,"sort": 0,"value_type": "individual"},"transparent": false,"type": "graph","xaxis": {"buckets": null,"mode": "time","name": null,"show": true,"values": []},"yaxes": [{"format": "percent","label": "","logBase": 1,"max": "100","min": "0","show": true},{"format": "percent","label": null,"logBase": 1,"max": "100","min": "0","show": true}]},{"aliasColors": {},"bars": false,"dashLength": 10,"dashes": false,"datasource": "${DS_DATA-PUBLIC}","fill": 1,"gridPos": {"h": 9,"w": 12,"x": 12,"y": 4},"hideTimeOverride": false,"id": 14,"legend": {"alignAsTable": true,"avg": true,"current": true,"max": true,"min": true,"rightSide": false,"show": true,"total": false,"values": true},"lines": true,"linewidth": 1,"links": [],"nullPointMode": "null","percentage": false,"pointradius": 5,"points": false,"renderer": "flot","repeat": "IP","repeatDirection": "v","seriesOverrides": [],"spaceLength": 10,"stack": false,"steppedLine": false,"targets": [{"hide": false,"rawQuery": false,"refId": "A","target": "RAM","type": "timeserie"}],"thresholds": [],"timeFrom": null,"timeShift": null,"title": "RAM使用率","tooltip": {"shared": true,"sort": 0,"value_type": "individual"},"transparent": false,"type": "graph","xaxis": {"buckets": null,"mode": "time","name": null,"show": true,"values": []},"yaxes": [{"format": "percent","label": "","logBase": 1,"max": "100","min": "0","show": true},{"format": "percent","label": null,"logBase": 1,"max": "100","min": "0","show": true}]},{"aliasColors": {},"bars": false,"dashLength": 10,"dashes": false,"datasource": "${DS_DATA-PUBLIC}","fill": 1,"gridPos": {"h": 9,"w": 12,"x": 0,"y": 13},"hideTimeOverride": false,"id": 18,"legend": {"alignAsTable": true,"avg": true,"current": true,"max": true,"min": true,"rightSide": true,"show": true,"total": false,"values": true},"lines": true,"linewidth": 1,"links": [],"nullPointMode": "null","percentage": false,"pointradius": 5,"points": false,"renderer": "flot","repeat": "IP","repeatDirection": "v","seriesOverrides": [],"spaceLength": 10,"stack": false,"steppedLine": false,"targets": [{"hide": false,"rawQuery": false,"refId": "A","target": "DISK","type": "timeserie"}],"thresholds": [],"timeFrom": null,"timeShift": null,"title": "磁盘使用率","tooltip": {"shared": true,"sort": 0,"value_type": "individual"},"transparent": false,"type": "graph","xaxis": {"buckets": null,"mode": "time","name": null,"show": true,"values": []},"yaxes": [{"format": "percent","label": "","logBase": 1,"max": "100","min": "0","show": true},{"format": "percent","label": null,"logBase": 1,"max": "100","min": "0","show": true}]},{"aliasColors": {},"bars": false,"dashLength": 10,"dashes": false,"datasource": "${DS_DATA-PUBLIC}","fill": 1,"gridPos": {"h": 9,"w": 12,"x": 12,"y": 13},"hideTimeOverride": false,"id": 20,"legend": {"alignAsTable": true,"avg": true,"current": true,"max": true,"min": true,"rightSide": true,"show": true,"total": false,"values": true},"lines": true,"linewidth": 1,"links": [],"nullPointMode": "null","percentage": false,"pointradius": 5,"points": false,"renderer": "flot","repeat": "IP","repeatDirection": "v","seriesOverrides": [],"spaceLength": 10,"stack": false,"steppedLine": false,"targets": [{"hide": false,"rawQuery": false,"refId": "A","target": "NET","type": "timeserie"}],"thresholds": [],"timeFrom": null,"timeShift": null,"title": "网络指标","tooltip": {"shared": true,"sort": 0,"value_type": "individual"},"transparent": false,"type": "graph","xaxis": {"buckets": null,"mode": "time","name": null,"show": true,"values": []},"yaxes": [{"format": "bytes","label": "","logBase": 1,"max": null,"min": null,"show": true},{"format": "percent","label": null,"logBase": 1,"max": "100","min": "0","show": true}]},{"aliasColors": {},"bars": false,"dashLength": 10,"dashes": false,"datasource": "${DS_DATA-PUBLIC}","fill": 1,"gridPos": {"h": 9,"w": 12,"x": 0,"y": 22},"hideTimeOverride": false,"id": 16,"legend": {"alignAsTable": true,"avg": true,"current": true,"max": true,"min": true,"rightSide": false,"show": true,"total": false,"values": true},"lines": true,"linewidth": 1,"links": [],"nullPointMode": "null","percentage": false,"pointradius": 5,"points": false,"renderer": "flot","repeat": "IP","repeatDirection": "v","seriesOverrides": [],"spaceLength": 10,"stack": false,"steppedLine": false,"targets": [{"hide": false,"rawQuery": false,"refId": "A","target": "SWAP","type": "timeserie"}],"thresholds": [],"timeFrom": null,"timeShift": null,"title": "虚拟内存(SWAP)使用率","tooltip": {"shared": true,"sort": 0,"value_type": "individual"},"transparent": false,"type": "graph","xaxis": {"buckets": null,"mode": "time","name": null,"show": true,"values": []},"yaxes": [{"format": "percent","label": "","logBase": 1,"max": "100","min": "0","show": true},{"format": "percent","label": null,"logBase": 1,"max": "100","min": "0","show": true}]},{"aliasColors": {},"bars": false,"dashLength": 10,"dashes": false,"datasource": "${DS_DATA-PUBLIC}","fill": 1,"gridPos": {"h": 9,"w": 12,"x": 12,"y": 22},"hideTimeOverride": false,"id": 15,"legend": {"alignAsTable": true,"avg": true,"current": true,"max": true,"min": true,"rightSide": false,"show": true,"total": false,"values": true},"lines": true,"linewidth": 1,"links": [],"nullPointMode": "null","percentage": false,"pointradius": 5,"points": false,"renderer": "flot","repeat": "IP","repeatDirection": "v","seriesOverrides": [],"spaceLength": 10,"stack": false,"steppedLine": false,"targets": [{"hide": false,"rawQuery": false,"refId": "A","target": "LOAD","type": "timeserie"}],"thresholds": [],"timeFrom": null,"timeShift": null,"title": "系统负载","tooltip": {"shared": true,"sort": 0,"value_type": "individual"},"transparent": false,"type": "graph","xaxis": {"buckets": null,"mode": "time","name": null,"show": true,"values": []},"yaxes": [{"format": "none","label": "","logBase": 1,"max": null,"min": "0","show": true},{"format": "percent","label": null,"logBase": 1,"max": "100","min": "0","show": false}]}],"refresh": "5s","schemaVersion": 16,"style": "dark","tags": ["node-panlei"],"templating": {"list": [{"allValue": null,"current": {},"datasource": "${DS_IP-PUBLIC}","hide": 0,"includeAll": false,"label": null,"multi": false,"name": "IP","options": [],"query": "show IP","refresh": 1,"regex": "","sort": 0,"tagValuesQuery": "","tags": [],"tagsQuery": "","type": "query","useTags": false}]},"time": {"from": "now-15m","to": "now-1s"},"timepicker": {"hidden": true,"nowDelay": "1s","refresh_intervals": ["1s","5s","10s","30s","1m","5m","15m","30m","1h","2h","1d"],"time_options": ["5m","15m","1h","6h","12h","24h","2d","7d","30d"]},"timezone": "browser","title": "node-monitor","uid": "VF00gigiz","version": 109
}

作者:风吹散了的回忆
链接:https://www.jianshu.com/p/bbd507a68bb9
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

物理机实时监控UI之grafana(SimpleJson)+gRPC相关推荐

  1. 五分钟搭建基于 Prometheus + Grafana 实时监控系统

    文章目录 Prometheus + Grafana 实时监控系统 Prometheus + Grafana 实时监控系统 依赖镜像包 启动 node-exporter check 端口 node_ex ...

  2. 口罩机远程监控运维解决方案

    口罩机远程监控运维系统解决方案 1.口罩机远程监控运维系统项目需求分析 管理角度分析 1.互联网时代,如何进行口罩机及人员管理的信息化? 2.物联网时代,如何实现口罩机健康及生产状态数字化? 3.智能 ...

  3. 浅谈Telegraf+InfluxDB+Grafana快速搭建简易实时监控系统

    监控从来都是一个很宽泛的问题,任何可能出问题的地方都需要加入监控.全量监控的确是监控的终极目标.在搭建一套监控系统前,需要结合实际的系统情况和发展趋势进行考量.在作者看来,一套监控系统应主要由数据采集 ...

  4. JMeter+InfluxDB+Grafana实现可视化实时监控

    本文我们将介绍如何使用JMeter+InfluxDB+Grafana打造可视化实时监控. 目录 一.简介 概述 简单介绍实现原理 二.indluxdb安装和部署 1.indluxdb下载 2.修改in ...

  5. 【Flink 监控系列】Flink on yarn 任务实时监控最佳实践(Prometheus + Grafana)打造企业级监控方案

    我们都知道 Flink 任务是一个 7*24 小时不停运行的任务,所以对于任务的实时监控就显得尤为重要,因为任务运行的状态对于我们来说是一个黑盒,比如任务是否挂掉,是否存在反压,使用的内存,CPU 等 ...

  6. Telegraf+InfluxDB+Grafana快速搭建实时监控系统 监控postgresql

    Telegraf+InfluxDB+Grafana快速搭建实时监控系统  监控postgresql 转载于:https://www.cnblogs.com/gaoyuechen/p/10081026. ...

  7. Jmeter系列之Jmeter+Grafana+InfluxDB实时监控

    VOL 167 20 2020-10 今天距2021年72天 这是ITester软件测试小栈第167次推文 点击上方蓝字"ITester软件测试小栈"关注我,每周一.三.五早上 0 ...

  8. grafana graphite statsd搭建安装部署 实时监控_亲测成功

    grafana graphite statsd搭建安装部署 实时监控_亲测成功 docker部署grafana graphite stastd实时监控告警配置_亲测成功 下载软件 # 下载carbon ...

  9. (一)性能实时监控平台搭建(Grafana+Influxdb+Jmeter)

    前言 主要介绍使用Docker安装Grafana+Influxdb结合Jmeter搭建可视化监控平台 正文 使用Docker搭建influxdb数据库服务 创建influxdb容器 命令:docker ...

最新文章

  1. java中application后缀_编译JavaApplication源程序文件将产生相应的字节码文件,这些字节码文件的扩展名为...
  2. 读书笔记--MapReduce 适用场景 及 常见应用
  3. Canonical 开源 MicroK8 | 云原生生态周报 Vol. 25
  4. ASP.NET Core的身份认证框架IdentityServer4(3)-术语的解释
  5. hdu 2018多校8
  6. Java多线程(7)--线程池创建线程
  7. c 结构体的简单封装1
  8. java 变量与常量_java的变量和常量
  9. USB接口ID卡读卡器oem软件(vb源代码)
  10. Linux快速查看OpenCV版本
  11. 控制工程实践(7)——PID四种类型控制器(之比例控制器P)
  12. 字节跳动前端实习面试经历分享
  13. it运维工程师的工作是做什么的?累吗?
  14. 可该变某一属性的GAN:Hijack-GAN
  15. java微信红包_Java模拟微信发红包(普通红包、拼手气红包)
  16. 拍案叫绝的算法(二)
  17. 上车短视频赛道:基于uniapp框架快速搭建自己的仿抖音短视频APP
  18. 百度地图定位出现4.9E -324的问题解决
  19. 开放-封闭原则(The Open-Closed Principle)
  20. 挪威石油基金将起诉大众汽车

热门文章

  1. linux 启动/关闭多个py脚本
  2. kotlin 查找id_Kotlin程序查找给定范围内的素数
  3. doublevalue_Java Integer类doubleValue()方法与示例
  4. Java——异常(try...catch...finally)
  5. FreeRTOS在STM32F429上移植
  6. c++ map iterator 获取key_JAVA | Map集合使用详解
  7. 动态规划-01背包问题详解
  8. 数据结构课程设计------c实现散列表(二次探测再哈希)电话簿(文件存储)
  9. HDU - 2973威尔逊定理
  10. 浅谈dup和dup2的用法