物理机实时监控UI之grafana(SimpleJson)+gRPC

在时序分析及监控展示领域,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
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

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

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

相关文章

面试大厂应该注意哪些问题?算法太TM重要了

前言 很多次小伙伴问到学习方法&#xff0c;我也很想写这样的一篇文章来跟大家讨论下关于学习方法这件事情。 其实学习方法这个事情&#xff0c;我没啥发言权&#xff0c;因为我自己本身都是没啥方法可言的&#xff0c;就瞎折腾那种&#xff0c;但是大家想看这样的一篇文章&a…

Linux下GitLab的安装及使用

一、初始GitLab GitLab是利用Ruby on Rails一个开源的版本管理系统&#xff0c;实现一个自托管的Git项目仓库&#xff0c;可通过Web界面进行访问公开的或者私人项目。 与Github类似&#xff0c;GitLab能够浏览源代码&#xff0c;管理缺陷和注释。可以管理团队对仓库的访问&a…

面试大厂应该注意哪些问题?隔壁都馋哭了

前言 说起程序员人们的第一印象就是工资高、加班凶、话少钱多头发少。再加上现在科技互联网公司太吃香&#xff0c;bat、华为小米等公司程序员加班情况被广泛传播&#xff0c;程序员用生命在敲代码的印象刻在了很多人的心里。 与其它行业一样&#xff0c;凡是有高级和普通&…

元类(metaclass)

目录 一、引言二、什么是元类三、为什么用元类四、内置函数exec(储备)五、class创建类5.1 type实现六、自定义元类控制类的创建6.1 应用七、__call__(储备)八、__new__(储备)九、自定义元类控制类的实例化一十、自定义元类后类的继承顺序十一、练习一、引言 元类属于python面向…

Linux环境下使用rpm包安装GitLab

1.安装依赖环境 [rootgitlab ~]# yum install curl openssh-server postfix cronie 2.下载安装GitLab包 我安装的环境是Red Hat Enterprise Linux Server release 7.4 (Maipo) GitLab下载地址:https://mirrors.tuna.tsinghua.edu.cn/gitlab-ce/yum/el7 以上是清华大学开源…

面试字节跳动Android工程师该怎么准备?深度解析,值得收藏

前言 Android高级架构师需要学习哪些知识呢&#xff1f; 下面总结一下我认为作为一个资深开发者需要掌握的技能点。 1.Android开发的几个阶段 我的10年开发生涯中&#xff0c;有9年都是做Android相关开发&#xff0c;以我个人的经历来看&#xff0c;Android开发市场分为以下…

阿里巴巴Android面试都问些什么?系列篇

Google 为了帮助 Android 开发者更快更好地开发 App&#xff0c;推出了一系列组件&#xff0c;这些组件被打包成了一个整体&#xff0c;称作 Android Jetpack&#xff0c;它包含的组件如下图所示&#xff1a; 老的 support 包被整合进了 Jetpack&#xff0c;例如上图 Foundatio…

docker-compose安装elk7.1.1版本

在用docker-compose编排elk三个服务时&#xff0c;碰到了很多坑&#xff0c;网上很多资料编排的版本都不是最新的版本&#xff0c;我们这里用的 elasticsearch&#xff0c;logstash&#xff0c;kibana全都是elastic官方提供的目前最新版本7.1.1&#xff0c;高版本和低版本的一些…

阿里P8成长路线!我的头条面试经历分享,吊打面试官系列!

正式加入字节跳动&#xff0c;分享一点面试小经验 今天正式入职了字节跳动。工号超吉利&#xff0c;尾数是3个6。然后办公环境也很好&#xff0c;这边一栋楼都是办公区域。公司内部配备各种小零食、饮料&#xff0c;还有免费的咖啡。15楼还有健身房。而且公司包三餐来着。下午…

Docker安装部署ELK教程 (Elasticsearch+Kibana+Logstash)

Elasticsearch 是个开源分布式搜索引擎&#xff0c;它的特点有&#xff1a;分布式&#xff0c;零配置&#xff0c;自动发现&#xff0c;索引自动分片&#xff0c;索引副本机制&#xff0c;restful风格接口&#xff0c;多数据源&#xff0c;自动搜索负载等。 Logstash 是一个完…

阿里P8面试官都说太详细了,面试资料分享

背景 知乎客户端中有一个自己维护的 Hybrid 框架&#xff0c;在此基础上开发了一些 Hybrid 页面&#xff0c;当需要前端或者客户端开发接口的时候&#xff0c;就涉及到联调的问题。 和一般的 前端 <> 服务端&#xff0c;或者 客户端 <> 服务端 类似&#xff0c;前…

virtual和override

偶然间看到的题&#xff0c;借此记录。 class Program{static void Main(string[] args){D d new D(); //第一个D是申明类&#xff0c;第二个D是实例类A a d;B b d;C c d;a.F();b.F();c.F();d.F();}class A{public virtual void F() { Console.WriteLine("A.F")…

阿里内部资料!如何试出一个Android开发者真正的水平?系列教学

前言 马爸爸总结了一句话&#xff1a;跳槽&#xff0c;要么是钱不到位&#xff0c;要么是受了委屈。 我给自己这次的跳槽经历做了一个分析&#xff0c;希望能对那些想换工作的朋友有所帮助。 许多朋友想换工作&#xff0c;但是对“换工作”的理解可能仅限于写简历、投简历、…

CentOS7 linux下yum安装redis以及使用

CentOS7 linux下yum安装redis以及使用 1.安装redis数据库 1 yum install redis 2.下载fedora的epel仓库 yum install epel-release 3.启动redis服务 systemctl start redis 4.查看redis状态 systemctl status redis systemctl stop redis 停止服务 systemctl restart r…

Codeforces 1182A Filling Shapes

题目链接&#xff1a;http://codeforces.com/problemset/problem/1182/A 思路&#xff1a;n为奇数时不可能完全填充&#xff0c;ans 0。发现若要完全填充&#xff0c;每俩列可产生俩种情况&#xff0c;所以为 ans 2n/2 AC代码&#xff1a; 1 #include<bits/stdc.h>2 us…

阿里大神最佳总结Flutter进阶学习笔记,技术详细介绍

开头 很多人工作了十年&#xff0c;但只是用一年的工作经验做了十年而已。 高级工程师一直是市场所需要的&#xff0c;然而很多初级工程师在进阶高级工程师的过程中一直是一个瓶颈。 移动研发在最近两年可以说越来越趋于稳定&#xff0c;因为越来越多人开始学习Android开发&…

掌握这些Android开发热门前沿知识,跳槽薪资翻倍

前言 这是一篇软文、但是绝对不是鸡汤&#xff1b;为啥不是呢&#xff1f;因为我文笔太差…偶尔矫情发发牢骚&#xff08;勿喷&#xff09; 说说程序猿行业 现在社会上给IT行业贴上了几个标签&#xff1a;高薪、高危、高大上、秃顶&#xff08;哈哈&#xff09;。这些标签我…

linux环境-docker安装rabbitmq

1、进入docker hub镜像仓库地址&#xff1a;https://hub.docker.com/ 2、搜索rabbitMq&#xff0c;进入官方的镜像&#xff0c;可以看到以下几种类型的镜像&#xff1b;我们选择带有“mangement”的版本&#xff08;包含web管理页面&#xff09;&#xff1b; 3、拉取镜像 doc…

揭秘ARouter路由机制,源码+原理+手写框架

前言 每个程序员都有一个梦想&#xff0c;那就是进一线互联网公司深造&#xff0c;不要跟我说你不想进去&#xff0c;如果给你一个这样的平台&#xff0c;不管是薪资待遇还是接触的高度来说&#xff0c;对我们程序员来说都是一个机会&#xff0c;我以前有一个同事&#xff0c;…

揭秘!双非渣本Android四年磨一剑,学习路线+知识点梳理

第一次观看我文章的朋友&#xff0c;可以关注、点赞、转发一下&#xff0c;每天分享各种干货技术和程序猿趣事 由于涉及到的面试题较多导致篇幅较长&#xff0c;我根据这些面试题所涉及到的常问范围总结了并做出了一份学习进阶路线图​​​​​​​及面试题答案免费分享给大家&…