首页 文章 精选 留言 我的

精选列表

搜索[基础搭建],共10000篇文章
优秀的个人博客,低调大师

【Java】留下没有基础眼泪的面试题

前言 只有光头才能变强 本文力求简单讲清每个知识点,希望大家看完能有所收获 一、如何减少线程上下文切换 使用多线程时,不是多线程能提升程序的执行速度,使用多线程是为了更好地利用CPU资源! 程序在执行时,多线程是CPU通过给每个线程分配CPU时间片来实现的,时间片是CPU分配给每个线程执行的时间,因时间片非常短,所以CPU通过不停地切换线程执行。 线程不是越多就越好的,因为线程上下文切换是有性能损耗的,在使用多线程的同时需要考虑如何减少上下文切换 一般来说有以下几条经验 无锁并发编程。多线程竞争时,会引起上下文切换,所以多线程处理数据时,可以用一些办法来避免使用锁,如将数据的ID按照Hash取模分段,不同的线程处理不同段的数据 CAS算法。Java的Atomic包使用CAS算法来更新数据,而不需要加锁。 控制线程数量。避免创建不需要的线程,比如任务很少,但是创建了很多线程来处理,这样会造成大量线程都处于等待状态 协程。在单线程里实现多任务的调度,并在单线程里维持多个任务间的切换 协程可以看成是用户态自管理的“线程”。不会参与CPU时间调度,没有均衡分配到时间。非抢占式的 还可以考虑我们的应用是IO密集型的还是CPU密集型的。 如果是IO密集型的话,线程可以多一些。 如果是CPU密集型的话,线程不宜太多。 参考资料: 多线程编程-减少上下文切换(1):https://blog.csdn.net/yxpjx/article/details/52081034 多线程上下文切换优化与注意:https://www.cnblogs.com/signheart/p/3e3379943de1c36d5bcc7d8cee4b9825.html 二、计算机网络 2.1MAC地址已经是唯一了,为什么需要IP地址? 或者可以反过来问:已经有IP地址了,为什么需要MAC地址??在zhihu上还蛮多类似的问题的: 我来简单总结一下为什么有了MAC(IP)还需要IP(MAC): MAC是链路层,IP是网络层,每一层干每一层的事儿,之所以在网络上分链路层、网络层(...,就是将问题简单化。 历史的兼容问题。 已经有IP地址了,为什么需要MAC地址?? 现阶段理由:DHCP基于MAC地址分配IP。 MAC地址已经是唯一了,为什么需要IP地址? MAC无网段概念,非类聚,不好管理。 如果有更好的看法,不妨在评论区下留言哦~ 参考资料: MAC地址唯一,不能满足通信需求吗?为什么需要IP?https://www.wukong.com/answer/6549169419812077827/ 有了 IP 地址,为什么还要用 MAC 地址?https://www.zhihu.com/question/21546408 2.2TCP状态 TCP 每个状态说一下,TIME-WAIT状态说一下 TCP总共有11个状态,状态之间的转换是这样的: 流程图: 下面我简单总结一下每个状态: CLOSED:初始状态,表示TCP连接是“关闭着的”或“未打开的”。 LISTEN:表示服务器端的某个SOCKET处于监听状态,可以接受客户端的连接。 SYN-SENT:表示客户端已发送SYN报文。当客户端SOCKET执行connect()进行连接时,它首先发送SYN报文,然后随即进入到SYN_SENT状态。 SYN_RCVD:表示服务器接收到了来自客户端请求连接的SYN报文。当TCP连接处于此状态时,再收到客户端的ACK报文,它就会进入到ESTABLISHED状态。 ESTABLISHED:表示TCP连接已经成功建立。 FIN-WAIT-1:第一次主动请求关闭连接,等待对方的ACK响应。 CLOSE_WAIT:对方发了一个FIN报文给自己,回应一个ACK报文给对方。此时进入CLOSE_WAIT状态。 接下来呢,你需要检查自己是否还有数据要发送给对方,如果没有的话,那你也就可以close()这个SOCKET并发送FIN报文给对方,即关闭自己到对方这个方向的连接 FIN-WAIT-2:主动关闭端接到ACK后,就进入了FIN-WAIT-2。在这个状态下,应用程序还有接受数据的能力,但是已经无法发送数据。 LAST_ACK:当被动关闭的一方在发送FIN报文后,等待对方的ACK报文的时候,就处于LAST_ACK 状态 CLOSED:当收到对方的ACK报文后,也就可以进入到CLOSED状态了。 TIME_WAIT:表示收到了对方的FIN报文,并发送出了ACK报文。TIME_WAIT状态下的TCP连接会等待2*MSL CLOSING:罕见的状态。表示双方都正在关闭SOCKET连接 TIME_WAIT状态一般用来处理以下两个问题: 关闭TCP连接时,确保最后一个ACK正常运输(或者可以认为是:等待以便重传ACK) 网络上可能会有残余的数据包,为了能够正常处理这些残余的数据包。使用TIME-WAIT状态可以确保在创建新连接时,先前网络中残余的数据都丢失了。 TIME_WAIT过多怎么解决? 如果在高并发,多短链接情景下,TIME_WAIT就会过多。 可以通过调整内核参数解决:vi /etc/sysctl.conf 加入以下内容设置: reuse是表示是否允许重新应用处于TIME-WAIT状态的socket用于新的TCP连接; recyse是加速TIME-WAIT sockets回收 我们可以知道TIME_WAIT状态是主动关闭连接的一方出现的,我们不要轻易去使用上边两个参数。先看看是不是可以重用TCP连接来尽量避免这个问题(比如我们HTTP的KeepAlive)~ 参考资料: TCP/IP详解--TCP连接中TIME_WAIT状态过多:https://blog.csdn.net/yusiguyuan/article/details/21445883 TCP连接的状态详解以及故障排查:https://blog.csdn.net/hguisu/article/details/38700899 TCP的11种状态:https://www.cnblogs.com/qingergege/p/6603488.html 2.3TCP滑动窗口 TCP是一个可靠的传输协议,它要保证所有的数据包都可以到达,这需要重传机制来支撑。 重传机制有以下几种: 超时重传 快速重传 SACK 方法 滑动窗口可以说是TCP非常重要的一个知识点。TCP的滑动窗口主要有两个作用: 提供TCP的可靠性 提供TCP的流控特性 简略滑动窗口示意图: 详细滑动窗口示意图: 1已收到ack确认的数据。 2发还没收到ack的。 3在窗口中还没有发出的(接收方还有空间)。 4窗口以外的数据(接收方没空间) 接受端控制发送端的图示: 2.4拥塞控制 TCP不是一个自私的协议,当拥塞发生的时候,要做自我牺牲。就像交通阻塞一样,每个车都应该把路让出来,而不要再去抢路了 拥塞控制主要是四个算法: 1)慢启动, 2)拥塞避免, 3)拥塞发生, 4)快速恢复 拥塞控制的作用: 拥塞的判断: 重传定时器超时 收到三个相同(重复)的 ACK 强烈建议阅读: TCP 的那些事儿(上):https://coolshell.cn/articles/11564.html TCP 的那些事儿(下):https://coolshell.cn/articles/11609.html 参考资料: TCP连续ARQ协议和滑动窗口协议:https://www.cnblogs.com/blythe/articles/7348812.html 运输层 TCP/IP(十一)TCP滑动窗口和拥塞控制:https://blog.csdn.net/endlu/article/details/51140213 TCP-IP详解:滑动窗口(Sliding Window):https://blog.csdn.net/wdscq1234/article/details/52444277 TCP拥塞控制-慢启动、拥塞避免、快重传、快启动:https://blog.csdn.net/jtracydy/article/details/52366461 TCP协议的滑动窗口具体是怎样控制流量的?https://www.zhihu.com/question/32255109 三、操作系统 3.1僵尸进程和孤儿进程是什么(区别) unix/linux环境下 僵尸进程: 父进程创建出子进程,子进程退出了,父进程没有调用wait或waitId获取子进程的信息(状态),子进程的描述符仍在系统中。 孤儿进程: 父进程退出,子进程仍在运行中。这些子进程就叫做孤儿进程,孤儿进程将被init进程(进程号为1)所收养,并由init进程对它们完成状态收集工作 僵尸进程危害: 系统进程表是一项有限资源,如果系统进程表被僵尸进程耗尽的话,系统就可能无法创建新的进程。 一个父进程创建了很多子进程,就是不回收,会造成内存资源的浪费。 解决僵尸进程的手段: 杀掉父进程,余下的僵尸进程会成为孤儿进程,最后被init进程管理 子进程退出时向父进程发送SIGCHILD信号,父进程处理SIGCHILD信号。在信号处理函数中调用wait进行处理僵尸进程 fork两次:原理是将子进程成为孤儿进程,从而其的父进程变为init进程,通过init进程可以处理僵尸进程 参考资料: 僵尸进程和僵死进程有什么区别?https://www.zhihu.com/question/26432067/answer/70643183 孤儿进程与僵尸进程[总结]:http://www.cnblogs.com/Anker/p/3271773.html 3.2操作系统进程间通信的方式有哪些? 首先要知道的是:进程和线程的关注点是不一样的: 进程间资源是独立的,关注的是通讯问题。 线程间资源是共享的,关注的是安全问题。 操作系统进程间通信的方式有哪些? 管道(pipe):管道是一种半双工的通信方式,数据只能单向流动,而且只能在具有亲缘关系的进程间使用。进程的亲缘关系通常是指父子进程关系。 有名管道(named pipe):有名管道也是半双工的通信方式,但是它允许无亲缘关系进程之间的通信。 消息队列(message queue):消息队列是消息的链表,存放在内核中并由消息队列表示符标示。消息队列克服了信号传递信息少,管道只能承载无格式字节流以及缓冲区大小受限制等缺点。 共享内存(shared memory):共享内存就是映射一段内被其它进程所访问的内存,共享内存由一个进程创建,但是多个进程都可以访问。共享内存是最快的IPC,它是针对其它进程通信方式运行效率低的而专门设计的。它往往与其它通信机制。如信号量,配合使用,来实现进程间的同步和通信。 套接字(socket):套接字也是进程间的通信机制,与其它通信机制不同的是,它可以用于不同机器间的进程通信。 信号(signal):信号是一种比较复杂的通信方式,用于通知接受进程进程某个时间已经发生。 信号量(semaphore):信号量是一个计数器,可以用来控制多个进程对共享资源的访问。 它常作为一种锁的机制,防止某进程正在访问共享资源时,其它进程也访问该资源。因此它主要作为不同进程或者同一进程之间不同线程之间同步的手段。 3.3操作系统线程间通信的方式有哪些? 操作系统线程间通信的方式有哪些?(可以直接理解成:线程之间同步的方式有哪些) 锁机制:包括互斥锁、条件变量、读写锁 信号量机制(Semaphore):包括无名线程信号量和命名线程信号量 信号机制(Signal):类似进程间的信号处理 线程间的通信目的主要是用于线程同步。 参考资料: 线程通信与进程通信的区别:https://www.cnblogs.com/xh0102/p/5710074.html 操作系统——进程,线程,锁:https://www.cnblogs.com/biterror/p/6909653.html 操作系统进程、线程:http://www.cnblogs.com/wxquare/p/5168745.html 进程间的五种通信方式介绍:https://blog.csdn.net/wh_sjc/article/details/70283843 扩展阅读: 进程间的五种通信方式介绍(详情介绍):https://blog.csdn.net/wh_sjc/article/details/70283843 Linux内核调度分析(进程调度):https://cloud.tencent.com/developer/article/1027448 3.4操作系统进程调度算法有哪些? 操作系统进程调度算法有哪些? 先来先服务算法(FCFS) 谁先来,就谁先执行 短进程/作业优先算法(SJF) 谁用的时间少、就先执行谁 最高响应比优先算法(HRN) 对FCFS方式和SJF方式的一种综合平衡 最高优先数算法 系统把处理机分配给就绪队列中优先数最高的进程 基于时间片的轮转调度算法 每个进程所享受的CPU处理时间都是一致的 最短剩余时间优先算法 短作业优先算法的升级版,只不过它是抢占式的 多级反馈排队算法 设置多个就绪队列,分别赋予不同的优先级,如逐级降低,队列1的优先级最高 参考笔记: 操作系统第四篇【处理机调度】 四、拓展阅读 此部分是看别人的博文已经写得很好了,分享给大家~ 4.1ConcurrentHashMap中的扩容是否需要对整个表上锁? ConcurrentHashMap中的扩容是否需要对整个表上锁? 总结(摘抄)要点: 通过给每个线程分配桶区间(默认一个线程分配的桶是16个),避免线程间的争用。 通过为每个桶节点加锁,避免 putVal 方法导致数据不一致。 同时,在扩容的时候,也会将链表拆成两份,这点和 HashMap 的 resize 方法类似。 参考资料: 并发编程——ConcurrentHashMap扩容逐行分析https://www.jianshu.com/p/2829fe36a8dd 《Java源码分析》:ConcurrentHashMap JDK1.8:https://blog.csdn.net/u010412719/article/details/52145145 4.2什么是一致性Hash算法(原理)? 什么是一致性Hash算法(原理)? 总结(摘抄)要点: 一致性Hash算法将整个哈希值空间组织成一个虚拟的圆环,好处就是提高容错性和可扩展性。 对于节点的增减都只需重定位环空间中的一小部分数据。 参考资料: 一致 Hash 算法分析:https://crossoverjie.top/2018/01/08/Consistent-Hash/ 面试必备:什么是一致性Hash算法?https://zhuanlan.zhihu.com/p/34985026 4.3MySQL date、datetime和timestamp类型的区别 MySQL date、datetime和timestamp类型的区别 总结(摘抄)要点: date精确到天,datetime和timestamp精确到秒 datetime和timestamp的区别: timestamp会跟随设置的时区变化而变化,而datetime保存的是绝对值不会变化 timestamp储存占用4个字节,datetime储存占用8个字节 可表示的时间范围不同,timestamp只能到表示到2038年,datetime可到9999年 参考资料: MySQL date、datetime和timestamp类型的区别:https://zhuanlan.zhihu.com/p/23663741 4.4判断一个链表是否有环/相交 判断一个链表是否有环(实际上就是看看有无遍历到重复的节点),解决方式(3种): for遍历两次 使用hashSet做缓存,记录已遍历过的节点 使用两个指针,一前一后遍历,总会出现前指针==后指针的情况 参考资料: 漫画算法:如何判断链表有环?http://blog.jobbole.com/106227/ 判断两个无环链表是否相交,解决方式(2种): 将第一个链表尾部的next指针指向第二个链表,两个链表组成一个链表。 判断这一个链表是否有环,有环则相交,无环则不相交 直接判断两个链表的尾节点是否相等,如果相等则相交,否则不相交 判断两个有环链表是否相交(注:当一个链表中有环,一个链表中没有环时,两个链表必不相交): 找到第一个链表的环点,然后将环断开(当然不要忘记了保存它的下一个节点),然后再来遍历第二个链表,如果发现第二个链表从有环变成了无环,那么他们就是相交的嘛,否则就是不相交的了。 参考资料: 判断两个链表是否相交并找出交点:https://blog.csdn.net/jiary5201314/article/details/50990349 判断单链表是否存在环,判断两个链表是否相交问题详解:http://www.cppblog.com/humanchao/archive/2008/04/17/47357.html 4.5keepAlive含义 HTTP协议的Keep-Alive意图在于连接复用,同一个连接上串行方式传递请求-响应数据 TCP的KeepAlive机制意图在于保活、心跳,检测连接错误 参考资料: 聊聊 TCP 中的 KeepAlive 机制:http://www.importnew.com/27624.html 最后 如果大家有更好的理解方式或者文章有错误的地方还请大家不吝在评论区留言,大家互相学习交流~~~ 如果想看更多的原创技术文章,欢迎大家关注我的微信公众号:Java3y。Java技术群讨论:742919422。公众号还有海量的视频资源哦,关注即可免费领取。 可能感兴趣的链接: 文章的目录导航(微信公众号端):https://zhongfucheng.bitcron.com/post/shou-ji/wen-zhang-dao-hang 文章的目录导航(PC端):http://www.zhongfucheng.bitcron.com/post/shou-ji/pcduan-wen-zhang-dao-hang 海量精美脑图:http://www.zhongfucheng.bitcron.com/post/shou-ji/nao-tu-da-quan

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

python超详细的基础笔记你学会了么

python简介 python是一种面向对象的解释型计算机程序设计语言,python的是吉多·范罗苏姆(Guido van Rossum)于1989年发明 任何语言都有优缺点,python也不例外,python的优点是简单易懂、可移植性、可扩展性、可嵌入性,python的缺点,一就是运行速度慢,因为python是解释型语言,代码在执行过程中会一行一行翻译成cpu能理解的机器码;二是代码不能加密,如果要发布python程序,实际上就是发布源代码。 python是跨平台的,它可以运行在Windows、Linux、Mac系统中,要开始学习python程序,首先需要把python安装到电脑上,从python的官网下载需要安装的软件版本,www.python.org,Windows系统下安装完毕后 通过cmd命令调取python,exit()退出 第一个python程序 通过python交互器执行程序,最后用exit()退出python,我们第一个python程序完成,唯一的缺憾是没有保存下来,下次运行还需要再输入一遍代码。 通过print()在括号中加入字符串就可以向屏幕上输出指定的文字 再python交互式命令行中写程序,好处是一下就能得到结果,坏处是没法保存,所以实际开发中我们会使用IDE或文本编辑器来写代码,写完后保存为一个python文件,这样程序就能反复运行,创建一个hello.py文件,并输入print("hello world") 进入指定目录通过python hello.py命令打开程序 如果你在学习Python的过程中遇见了很多疑问和难题,可以加-q-u-n227 -435-450里面有软件视频资料免费 变量 在python中变量的定义规则是 变量名只能是 字母、数字或下划线的任意组合 变量名的第一个字符不能是数字 python中的关键字不能声明为变量名 定义变量 name = "Zyy" 上面的代码声明了一个变量,变量名为: name,变量name的值为:"Zyy" python的输入和输出 用print()在括号中加入字符串,就可以向屏幕上输出指定的文字 print()可以接受多个字符串,用逗号","隔开,就可以连成一串,print()会依次打印每个字符串,遇到逗号会输出一个空格,print()也可以打印整数,或者计算结果,也可以组合使用 print()输出 输入字符使用input() input()输入 python的数据类型 可以使用内部函数type()来查看数据的类型 字符串(str) 整数型(int) 布尔型(bool) 浮点型(float) 列表(list) 元组(tuple) 字典(dict) 集合(set) 空值(None) 运算符 算数运算+ 加法 - 减法 * 乘法 / 除(使用/除时,结果为float类型) //地板除(结果为整数int) % 取余数 ** 次幂(2**2 表示2的2次幂结果4) 比较运算,输出结果为bool== 等于 != 不等于(python3.0之后不可以写作<>) > 大于 < 小于 >= 大于等于 <=小于等于 赋值运算= 简单的赋值运算符+=加法赋值运算符 c+=a相当于c=c+a-=减法赋值运算符 c-=a相当于c=c-a*=乘法赋值运算符 c*=a相当于c=c*a/=除法赋值运算符 c/=a相当于c=c/a%=取余赋值运算符 c%=a相当于c=c%a除此之外还有**= //= 逻辑运算符and 布尔与 两者都是True才是True,否则为Falseor 布尔或 两者都是False才是False,否则为Truenot 布尔非 非True就是False,非False就是True 成员运算in 如果在指定的序列找到值,则返回True,否则为Falsenot in 如果在指定的序列中没有找到值,返回True,否则为False 身份运算is is是判断两个标识符是不是引用一个对象is not is not 是判断两个标识符是不是引用不同对象 判断语句和循环语句 python的语法比较简单,采用缩进方式;以#开头表示注释,批量注释使用'''。。。''',其他每一行都是一个语句,当语句以冒号:结尾时,缩进的语句视为代码块(不要tab键和空格混用,python是区分大小写的)。 判断语句简单的if判断语句为if 条件:#条件为True执行结果else: #否则执行结果if中还可以使用elif做更细致的判断,elif 是else if的缩写,if语句是从上往下判断,如果某个判断上是True,就会执行相应的结果,执行完毕后会忽略掉接下来的elif和else 循环语句forfor...in....语句可以循环遍历list或tuple,又称作迭代,for x in ... 就是把每个元素带入变量x,然后执行缩进 循环语句whilewhile循环是,只要条件满足,就不断循环,条件不满足时退出。在循环中,可以使用break和continue,需要配合if语句来使用,break是退出循环,continue是跳过当前循环 循环案例

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

3.2 自定义控件基础 之 View的测量

本文对应项目的码云地址:https://gitee.com/wanchuanxy/AndroidHeroesTest/tree/master/3/SystemWidget 在现实生活中,如果我们去画一个图形,就必须知道它的大小和位置。Android系统在绘制View之前也必须对View进行测量,即告诉系统该画一个多大的View。这个过程在onMeasure()方法中进行。 Android系统给我们提供了一个设计短小精悍却功能强大的类----MeasureSpec类,我们可通过它来测量View。MeasureSpec是一个32位的值,其中高2位为测量的模式,低30位为测量的大小,在计算中使用位运算的原因是为了提高并优化速率。 测量模式为以下三种。 EXACTLY 即精确值模式,当我们将控件的layout_width或layout_height属性设定为具体数值时,比如android:layout_width="100dp",或者指定为match_parent属性时(占据父View的大小),系统使用的是EXACTLY模式。 AT_MOST 即最大值模式,当控件的layout_width或layout_height属性设定为wrap_content时,控件大小一般随着控件的子控件或内容的变化而变化,此时控件的尺寸只要不超过父控件允许的最大尺寸即可。 UNSPECIFIED 这个属性比较奇怪——它不指定其大小测量模式,View想多大就多大,通常在自定义View时才会使用。 View类默认的onMeasure()方法只支持EXACTLY模式,所以如果在自定义控件的时候不重写onMeasure()方法的话,就只能使用EXACTLY模式。控件可以响应你指定的具体宽高值或者是match_parent属性。而如果要让自定义View支持wrap_content属性,那就必须重写onMeasure()方法来指定wrap_content时的大小。 通过MeasureSpec这一个类,我们就获取了View的测量模式和View想要绘制的大小。有了这些信息,我们就可以控制View最后显示的大小。 下面来看一个简单的实例演示如何进行View的测量。首先要重写onMeasure()方法,该方法如下所示。 @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); } 在IDE中按住Ctrl+鼠标左键点击 super.onMeasure()查看源代码。可以发现系统最终会调用setMeasuredDimension(int measuredWidth, int measuredHeight)方法将测量后的宽高值设置进去,从而完成测量工作。所以在重写onMeasure()方法后,最重要最的工作就是把测量后的宽高值作为参数传给setMeasuredDimension()方法。 通过上面的分析,重写的onMeasure()方法代码如下所示。 @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { setMeasuredDimension( measureWidth(widthMeasureSpec), measureHeight(heightMeasureSpec)); } 在onMeasure()方法中,我们调用自定义的measureWidth()方法和measureHeight()方法分别对宽高进行重定义,参数则是宽和高的MeasureSpec对象,MeasureSpec对象根据前面的介绍可以知道它包含了测量的模式和测量值的大小。 下面我们就以measureWidth()方法为例,讲解如何自定义测量值。 第一步,从MeasureSpec对象中提取出具体的测量模式和大小,代码如下所示。 int specMode = MeasureSpec.getMode(widthMeasureSpec); int specSize = MeasureSpec.getSize(widthMeasureSpec); 接下来通过判断测量的模式,给出不同的测量值。 当specMode为EXACTLY时,直接使用指定的specSize即可; 当specMode为其他两种模式时,需要给它一个默认的大小。 特别地,如果指定wrap_content属性,即AT_MOST模式,则需要提取出我们指定的大小与specSize中最小的一个来作为最后的测量值,measureWidth()方法的代码如下。这段代码基本可以作为模板代码。 private int measureWidth(int widthMeasureSpec) { int result = 0; int specMode = MeasureSpec.getMode(widthMeasureSpec); int specSize = MeasureSpec.getSize(widthMeasureSpec); if (specMode == MeasureSpec.EXACTLY) { result = specSize; } else { result = 200; if (specMode == MeasureSpec.AT_MOST) { result = Math.min(result, specSize); } } return result; } measureHeight()与measureWidth()方法基本一致,不再给出代码,通过这两个方法,我们就完成了对宽高值得自定义。最后可以在程序中验证以上分析。 在布局文件中首先指定确定的宽高值400px,即EXACTLY模式: <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <com.imooc.systemwidget.TeachingView android:layout_width="400px" android:layout_height="400px" /> </LinearLayout> 程序效果如下图所示: 当指定宽高属性为match_parent时,运行效果如下图所示: 当指定宽高属性为wrap_content时,如果不写onMeasure()方法,那么系统就不知道该使用默认多大尺寸。因此它就会默认填充整个父布局,所以重写onMeasure()方法的目的就是为了能够给View一个wrap_content属性下的默认大小,其运行效果如下图所示: 布局代码: <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <com.imooc.systemwidget.TeachingView android:layout_width="wrap_content" android:layout_height="wrap_content" /> </LinearLayout> 在onDraw()方法中添加测试代码(最下面三行): @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.drawColor(Color.BLUE);//绘制背景;将此行注释,界面将为透明,看不到canvas的大小 //下面三行code乃调试用 int width = getWidth(); int height = getHeight(); Log.d("xys", "width : " + width + " height : " + height); } } 运行后可见: 200即我们刚刚自定义的测量方法中的默认值。 可以发现,当指定wrap_content属性时,View就会获得一个默认值200px,而不是再填充父布局了。 通过这个实例,相信大家对View的测量不再陌生了,它并不是什么高深莫测的东西,它的整个过程与我们在生活中精确绘图是一样的。 本文对应View.java 全文: package com.imooc.systemwidget; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.util.AttributeSet; import android.util.Log; import android.view.View; //思路:1.在onMeasure中对setMeasuredDimension做个自定义 // 2.绘制; 完; 注意布局xml写法; public class TeachingView extends View { //三个重载构造函数 public TeachingView(Context context) { super(context); } public TeachingView(Context context, AttributeSet attrs) { super(context, attrs); } public TeachingView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { // protected final void setMeasuredDimension(int measuredWidth, int measuredHeight) setMeasuredDimension( //引用 measureWidth(widthMeasureSpec), measureHeight(heightMeasureSpec)); } //自定义两个测量方法 private int measureWidth(int measureSpec) { int result = 0; int specMode = MeasureSpec.getMode(measureSpec); int specSize = MeasureSpec.getSize(measureSpec); if (specMode == MeasureSpec.EXACTLY) { result = specSize; } else { result = 200; if (specMode == MeasureSpec.AT_MOST) { result = Math.min(result, specSize); } } return result; } private int measureHeight(int measureSpec) { int result = 0; int specMode = MeasureSpec.getMode(measureSpec); int specSize = MeasureSpec.getSize(measureSpec); if (specMode == MeasureSpec.EXACTLY) { result = specSize; } else { result = 200; if (specMode == MeasureSpec.AT_MOST) { result = Math.min(result, specSize); } } return result; } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.drawColor(Color.BLUE);//绘制背景;将此行注释,界面将为透明,看不到canvas的大小 //下面三行code乃调试用 int width = getWidth(); int height = getHeight(); Log.d("xys", "width : " + width + " height : " + height); } } 内容参考自Blankj

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

Java并发基础:了解无锁CAS就从源码分析

CAS的全称为Compare And Swap,直译就是比较交换。是一条CPU的原子指令,其作用是让CPU先进行比较两个值是否相等,然后原子地更新某个位置的值,其实现方式是基于硬件平台的汇编指令,在intel的CPU中,使用的是cmpxchg指令,就是说CAS是靠硬件实现的,从而在硬件层面提升效率。 CSA 原理 利用CPU的CAS指令,同时借助JNI来完成Java的非阻塞算法,其它原子操作都是利用类似的特性完成的。在 java.util.concurrent 下面的源码中,Atomic, ReentrantLock 都使用了Unsafe类中的方法来保证并发的安全性。 CAS操作是原子性的,所以多线程并发使用CAS更新数据时,可以不使用锁,JDK中大量使用了CAS来更新数据而防止加锁来保持原子更新。 CAS 操作包含三个操作数 :内存偏移量位置(V)、预期原值(A)和新值(B)。 如果内存位置的值与预期原值相匹配,那么处理器会自动将该位置值更新为新值 。否则,处理器不做任何操作。 源码分析 下面来看一下 java.util.concurrent.atomic.AtomicInteger.java,getAndIncrement(),getAndDecrement()是如何利用CAS实现原子性操作的。 AtomicInteger 源码解析 // 使用 unsafe 类的原子操作方式 private static final Unsafe unsafe = Unsafe.getUnsafe(); private static final long valueOffset; static { try { //计算变量 value 在类对象中的偏移量 valueOffset = unsafe.objectFieldOffset(AtomicInteger.class.getDeclaredField("value")); } catch (Exception ex) { throw new Error(ex); } } valueOffset 字段表示 "value" 内存位置,在compareAndSwap 方法 ,第二个参数会用到. 关于偏移量 Unsafe 调用C 语言可以通过偏移量对变量进行操作 //volatile变量value private volatile int value; /** * 创建具有给定初始值的新 AtomicInteger * * @param initialValue 初始值 */ public AtomicInteger(int initialValue) { value = initialValue; } //返回当前的值 public final int get() { return value; } //原子更新为新值并返回旧值 public final int getAndSet(int newValue) { return unsafe.getAndSetInt(this, valueOffset, newValue); } //最终会设置成新值 public final void lazySet(int newValue) { unsafe.putOrderedInt(this, valueOffset, newValue); } //如果输入的值等于预期值,则以原子方式更新为新值 public final boolean compareAndSet(int expect, int update) { return unsafe.compareAndSwapInt(this, valueOffset, expect, update); } //方法相当于原子性的 ++i public final int getAndIncrement() { //三个参数,1、当前的实例 2、value实例变量的偏移量 3、递增的值。 return unsafe.getAndAddInt(this, valueOffset, 1); } //方法相当于原子性的 --i public final int getAndDecrement() { //三个参数,1、当前的实例 2、value实例变量的偏移量 3、递减的值。 return unsafe.getAndAddInt(this, valueOffset, -1); } 实现逻辑封装在 Unsafe 中 getAndAddInt 方法,继续往下看,Unsafe 源码解析 Unsafe 源码解析 在JDK8中追踪可见sun.misc.Unsafe这个类是无法看见源码的,打开openjdk8源码看 文件:openjdk-8-src-b132-03_mar_2014.zip 目录:openjdk\jdk\src\share\classes\sun\misc\Unsafe.java 通常我们最好也不要使用Unsafe类,除非有明确的目的,并且也要对它有深入的了解才行。要想使用Unsafe类需要用一些比较tricky的办法。Unsafe类使用了单例模式,需要通过一个静态方法getUnsafe()来获取。但Unsafe类做了限制,如果是普通的调用的话,它会抛出一个SecurityException异常;只有由主类加载器加载的类才能调用这个方法。 下面是sun.misc.Unsafe.java类源码 //获取Unsafe实例静态方法 @CallerSensitive public static Unsafe getUnsafe() { Class<?> caller = Reflection.getCallerClass(); if (!VM.isSystemDomainLoader(caller.getClassLoader())) throw new SecurityException("Unsafe"); return theUnsafe; } 网上也有一些办法来用主类加载器加载用户代码,最简单方法是利用Java反射,方法如下: private static Unsafe unsafe; static { try { //通过反射获取rt.jar下的Unsafe类 Field field = Unsafe.class.getDeclaredField("theUnsafe"); field.setAccessible(true); unsafe = (Unsafe) field.get(null); } catch (Exception e) { System.out.println("Get Unsafe instance occur error" + e); } } 获取到Unsafe实例之后,我们就可以为所欲为了。Unsafe类提供了以下这些功能: https://www.cnblogs.com/pkufork/p/java_unsafe.html //native硬件级别的原子操作 //类似的有compareAndSwapInt,compareAndSwapLong,compareAndSwapBoolean,compareAndSwapChar等等。 public final native boolean compareAndSwapInt(Object o, long offset,int expected,int x); //内部使用自旋的方式进行CAS更新(while循环进行CAS更新,如果更新失败,则循环再次重试) public final int getAndAddInt(Object o, long offset, int delta) { int v; do { //获取对象内存地址偏移量上的数值v v = getIntVolatile(o, offset); //如果现在还是v,设置为 v + delta,否则返回false,继续循环再次重试. } while (!compareAndSwapInt(o, offset, v, v + delta)); return v; } 利用 Unsafe 类的 JNI compareAndSwapInt 方法实现,使用CAS实现一个原子操作更新, compareAndSwapInt 四个参数: 1、当前的实例2、实例变量的内存地址偏移量3、预期的旧值4、要更新的值 unsafe.cpp 深层次解析 // unsafe.cpp /* * 这个看起来好像不像一个函数,不过不用担心,不是重点。UNSAFE_ENTRY 和 UNSAFE_END 都是宏, * 在预编译期间会被替换成真正的代码。下面的 jboolean、jlong 和 jint 等是一些类型定义(typedef): * * 省略部分内容 */ UNSAFE_ENTRY(jboolean, Unsafe_CompareAndSwapInt(JNIEnv *env, jobject unsafe, jobject obj, jlong offset, jint e, jint x)) UnsafeWrapper("Unsafe_CompareAndSwapInt"); oop p = JNIHandles::resolve(obj); // 根据偏移量,计算 value 的地址。这里的 offset 就是 AtomaicInteger 中的 valueOffset jint* addr = (jint *) index_oop_from_field_offset_long(p, offset); // 调用 Atomic 中的函数 cmpxchg,该函数声明于 Atomic.hpp 中 return (jint)(Atomic::cmpxchg(x, addr, e)) == e; UNSAFE_END // atomic.cpp unsigned Atomic::cmpxchg(unsigned int exchange_value, volatile unsigned int* dest, unsigned int compare_value) { assert(sizeof(unsigned int) == sizeof(jint), "more work to do"); /* * 根据操作系统类型调用不同平台下的重载函数,这个在预编译期间编译器会决定调用哪个平台下的重载 * 函数。相关的预编译逻辑如下: * * atomic.inline.hpp: * #include "runtime/atomic.hpp" * * // Linux * #ifdef TARGET_OS_ARCH_linux_x86 * # include "atomic_linux_x86.inline.hpp" * #endif * * // 省略部分代码 * * // Windows * #ifdef TARGET_OS_ARCH_windows_x86 * # include "atomic_windows_x86.inline.hpp" * #endif * * // BSD * #ifdef TARGET_OS_ARCH_bsd_x86 * # include "atomic_bsd_x86.inline.hpp" * #endif * * 接下来分析 atomic_windows_x86.inline.hpp 中的 cmpxchg 函数实现 */ return (unsigned int)Atomic::cmpxchg((jint)exchange_value, (volatile jint*)dest, (jint)compare_value); } 上面的分析看起来比较多,不过主流程并不复杂。如果不纠结于代码细节,还是比较容易看懂的。接下来,我会分析 Windows 平台下的 Atomic::cmpxchg 函数。继续往下看吧。 // atomic_windows_x86.inline.hpp #define LOCK_IF_MP(mp) __asm cmp mp, 0 \ __asm je L0 \ __asm _emit 0xF0 \ __asm L0: inline jint Atomic::cmpxchg (jint exchange_value, volatile jint* dest, jint compare_value) { // alternative for InterlockedCompareExchange int mp = os::is_MP(); __asm { mov edx, dest mov ecx, exchange_value mov eax, compare_value LOCK_IF_MP(mp) cmpxchg dword ptr [edx], ecx } } 上面的代码由 LOCK_IF_MP 预编译标识符和 cmpxchg 函数组成。为了看到更清楚一些,我们将 cmpxchg 函数中的 LOCK_IF_MP 替换为实际内容。如下: inline jint Atomic::cmpxchg (jint exchange_value, volatile jint* dest, jint compare_value) { // 判断是否是多核 CPU int mp = os::is_MP(); __asm { // 将参数值放入寄存器中 mov edx, dest // 注意: dest 是指针类型,这里是把内存地址存入 edx 寄存器中 mov ecx, exchange_value mov eax, compare_value // LOCK_IF_MP cmp mp, 0 /* * 如果 mp = 0,表明是线程运行在单核 CPU 环境下。此时 je 会跳转到 L0 标记处, * 也就是越过 _emit 0xF0 指令,直接执行 cmpxchg 指令。也就是不在下面的 cmpxchg 指令 * 前加 lock 前缀。 */ je L0 /* * 0xF0 是 lock 前缀的机器码,这里没有使用 lock,而是直接使用了机器码的形式。至于这样做的 * 原因可以参考知乎的一个回答: * https://www.zhihu.com/question/50878124/answer/123099923 */ _emit 0xF0 L0: /* * 比较并交换。简单解释一下下面这条指令,熟悉汇编的朋友可以略过下面的解释: * cmpxchg: 即“比较并交换”指令 * dword: 全称是 double word,在 x86/x64 体系中,一个 * word = 2 byte,dword = 4 byte = 32 bit * ptr: 全称是 pointer,与前面的 dword 连起来使用,表明访问的内存单元是一个双字单元 * [edx]: [...] 表示一个内存单元,edx 是寄存器,dest 指针值存放在 edx 中。 * 那么 [edx] 表示内存地址为 dest 的内存单元 * * 这一条指令的意思就是,将 eax 寄存器中的值(compare_value)与 [edx] 双字内存单元中的值 * 进行对比,如果相同,则将 ecx 寄存器中的值(exchange_value)存入 [edx] 内存单元中。 */ cmpxchg dword ptr [edx], ecx } } 到这里 CAS 的实现过程就讲了,CAS 的实现离不开处理器的支持。以上这么多代码,其实核心代码就是一条带 lock 前缀的 cmpxchg 指令,即lock cmpxchg dword ptr [edx], ecx。 通过上述的分析,可以发现AtomicInteger原子类的内部几乎是基于前面分析过Unsafe类中的CAS相关操作的方法实现的,这也同时证明AtomicInteger getAndIncrement自增操作实现过程,是基于无锁实现的。 CAS的ABA问题及其解决方案 假设这样一种场景,当第一个线程执行CAS(V,E,U)操作。在获取到当前变量V,准备修改为新值U前,另外两个线程已连续修改了两次变量V的值,使得该值又恢复为旧值,这样的话,我们就无法正确判断这个变量是否已被修改过,如下图: 这就是典型的CAS的ABA问题,一般情况这种情况发现的概率比较小,可能发生了也不会造成什么问题,比如说我们对某个做加减法,不关心数字的过程,那么发生ABA问题也没啥关系。但是在某些情况下还是需要防止的,那么该如何解决呢?在Java中解决ABA问题,我们可以使用以下原子类 AtomicStampedReference类 AtomicStampedReference原子类是一个带有时间戳的对象引用,在每次修改后,AtomicStampedReference不仅会设置新值而且还会记录更改的时间。当AtomicStampedReference设置对象值时,对象值以及时间戳都必须满足期望值才能写入成功,这也就解决了反复读写时,无法预知值是否已被修改的窘境 底层实现为: 通过Pair私有内部类存储数据和时间戳, 并构造volatile修饰的私有实例 接着看 java.util.concurrent.atomic.AtomicStampedReference类的compareAndSet()方法的实现: private static class Pair<T> { final T reference; final int stamp; //最好不要重复的一个数据,决定数据是否能设置成功,时间戳会重复 private Pair(T reference, int stamp) { this.reference = reference; this.stamp = stamp; } static <T> Pair<T> of(T reference, int stamp) { return new Pair<T>(reference, stamp); } } 同时对当前数据和当前时间进行比较,只有两者都相等是才会执行casPair()方法, 单从该方法的名称就可知是一个CAS方法,最终调用的还是Unsafe类中的compareAndSwapObject方法 到这我们就很清晰AtomicStampedReference的内部实现思想了, 通过一个键值对Pair存储数据和时间戳,在更新时对数据和时间戳进行比较, 只有两者都符合预期才会调用Unsafe的compareAndSwapObject方法执行数值和时间戳替换,也就避免了ABA的问题。 /** * 原子更新带有版本号的引用类型。 * 该类将整数值与引用关联起来,可用于原子的更数据和数据的版本号。 * 可以解决使用CAS进行原子更新时,可能出现的ABA问题。 */ public class AtomicStampedReference<V> { //静态内部类Pair将对应的引用类型和版本号stamp作为它的成员 private static class Pair<T> { //最好不要重复的一个数据,决定数据是否能设置成功,建议时间戳 final T reference; final int stamp; private Pair(T reference, int stamp) { this.reference = reference; this.stamp = stamp; } //根据reference和stamp来生成一个Pair的实例 static <T> Pair<T> of(T reference, int stamp) { return new Pair<T>(reference, stamp); } } //作为一个整体的pair变量被volatile修饰 private volatile Pair<V> pair; //构造方法,参数分别是初始引用变量的值和初始版本号 public AtomicStampedReference(V initialRef, int initialStamp) { pair = Pair.of(initialRef, initialStamp); } .... private static final sun.misc.Unsafe UNSAFE = sun.misc.Unsafe.getUnsafe(); private static final long pairOffset = objectFieldOffset(UNSAFE, "pair", AtomicStampedReference.class); //获取pair成员的偏移地址 static long objectFieldOffset(sun.misc.Unsafe UNSAFE, String field, Class<?> klazz) { try { return UNSAFE.objectFieldOffset(klazz.getDeclaredField(field)); } catch (NoSuchFieldException e) { NoSuchFieldError error = new NoSuchFieldError(field); error.initCause(e); throw error; } } } /** * @param 期望(老的)引用 * @param (新的)引用数据 * @param 期望(老的)标志stamp(时间戳)值 * @param (新的)标志stamp(时间戳)值 * @return 是否成功 */ public boolean compareAndSet(V expectedReference,V newReference,int expectedStamp,int newStamp) { Pair<V> current = pair; return // 期望(老的)引用 == 当前引用 expectedReference == current.reference && // 期望(老的)标志stamp(时间戳)值 == 当前标志stamp(时间戳)值 expectedStamp == current.stamp && // (新的)引用数据 == 当前引用数据 并且 (新的)标志stamp(时间戳)值 ==当前标志stamp(时间戳)值 ((newReference == current.reference && newStamp == current.stamp) || #原子更新值 casPair(current, Pair.of(newReference, newStamp))); } //当引用类型的值与期望的一致的时候,原子的更改版本号为新的值。该方法只修改版本号,不修改引用变量的值,成功返回true public boolean attemptStamp(V expectedReference, int newStamp) { Pair<V> current = pair; return expectedReference == current.reference && (newStamp == current.stamp || casPair(current, Pair.of(expectedReference, newStamp))); } /** * CAS真正实现方法 */ private boolean casPair(Pair<V> cmp, Pair<V> val) { return UNSAFE.compareAndSwapObject(this, pairOffset, cmp, val); } 期望 Pair cmp(A) == 当前内存存偏移量位置 Pair(V),就更新值 Pair val(B)成功返回true 否则 false public static void main(String[] args) { AtomicStampedReference<Integer> num = new AtomicStampedReference<Integer>(1, 0); Integer i = num.getReference(); int stamped = num.getStamp(); if (num.compareAndSet(i, i + 1, stamped, stamped + 1)) { System.out.println("测试成功"); } } 通过以上原子更新方法,可见 AtomicStampedReference就是利用了Unsafe的CAS方法+Volatile关键字对存储实际的引用变量和int的版本号的Pair实例进行更新。 参考:https://www.cnblogs.com/nullllun/p/9039049.html https://blog.csdn.net/a67474506/article/details/48310515 Contact 作者:鹏磊 出处:http://www.ymq.io/2018/05/09/dubbo 版权归作者所有,转载请注明出处 Wechat:关注公众号,搜云库,专注于开发技术的研究与知识分享

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

IT基础设施:使用netdata监控CentOS7性能

背景 作为一个Linux狗,必须要掌握一个专门的系统监控工具,能随时了解系统资源的占用情况,如应用的内存使用规律,应用的网络峰值时段,CPU使用情况等信息,对优化应用性能,保证服务器健康运行有着极为重要的作用。 工具 netdata Netdata是一款秒级数据收集与可视化呈现的Linux服务器性能监测工具,他具有这样一些特性: 高实时性:Netdata是用纯C编写的,关键系统插件也是用C语言编写的。 它的速度只能与本机控制台系统管理工具进行比较。当netdata在现代计算机上运行时(即使在CELERON处理器上),大多数图表查询都会在不到3毫秒的时间内得到回复! 不占用系统IO:除了日志系统外,netdata将不会使用任何磁盘的IO资源,您也可以通过配置文件禁用掉日志系统。 不需要root权限 自带Web服务系统 开箱即用,上手不需要写任何配置 可视化的QOS 安装便捷,根据安装文档指示,有些系统可以直接从软件库中安装,树莓派上我通过克隆安装成功,CentOS上有一键安装脚本 告警系统,通过配置文件,我们可以配置netdata在某些指标达到阀值的时候进行告警。 nginx 鼎鼎大名的代理服务器,不用多说。 过程 本次安装的机器是CentOS7 64位,我们选择64位的安装脚本 bash <(curl -Ss https://my-netdata.io/kickstart-static64.sh) 接下来它会自动下载安装包 --- Checking the latest version of static build... --- [/home]# /usr/bin/curl https://raw.githubusercontent.com/firehol/binary-packages/master/netdata-latest.gz.run % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 59 100 59 0 0 51 0 0:00:01 0:00:01 --:--:-- 51 OK --- Downloading static netdata binary: netdata-v1.10.0-531-g8f851356-x86_64-20180727-042835.gz.run --- [/home]# /usr/bin/curl https://raw.githubusercontent.com/firehol/binary-packages/master/netdata-v1.10.0-531-g8f851356-x86_64-20180727-042835.gz.run % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 5602k 100 5602k 0 0 19712 0 0:04:51 0:04:51 --:--:-- 32001 OK --- Installing netdata --- [/home]# sh /tmp/netdata-v1.10.0-531-g8f851356-x86_64-20180727-042835.gz.run ^ |.-. .-. .-. .-. . netdata | '-' '-' '-' '-' real-time performance monitoring, done right! +----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+---> (C) Copyright 2017, Costa Tsaousis All rights reserved Released under GPL v3+ You are about to install netdata to this system. netdata will be installed at: /opt/netdata The following changes will be made to your system: # USERS / GROUPS User 'netdata' and group 'netdata' will be added, if not present. # LOGROTATE This file will be installed if logrotate is present. - /etc/logrotate.d/netdata # SYSTEM INIT This file will be installed if this system runs with systemd: - /etc/systemd/system/netdata.service or, for older Centos, Debian/Ubuntu or OpenRC Gentoo: - /etc/init.d/netdata will be created This package can also update a netdata installation that has been created with another version of it. Your netdata configuration will be retained. After installation, netdata will be (re-)started. netdata re-distributes a lot of open source software components. Check its full license at: https://github.com/firehol/netdata/blob/master/LICENSE.md Please type y to accept, n otherwise: 输入y确认安装,下面列出了详细的安装过程。 Creating directory /opt/netdata Verifying archive integrity... 100% All good. Uncompressing netdata, the real-time performance and health monitoring system 100% --- Checking new configuration files --- [/opt/netdata]# mkdir -p etc/netdata OK [/opt/netdata]# cp etc.new/netdata/node.d.conf etc/netdata/node.d.conf OK [/opt/netdata]# mkdir -p etc/netdata/health.d OK [/opt/netdata]# cp etc.new/netdata/health.d/nginx.conf etc/netdata/health.d/nginx.conf OK [/opt/netdata]# cp etc.new/netdata/health.d/tcp_listen.conf etc/netdata/health.d/tcp_listen.conf OK [/opt/netdata]# cp etc.new/netdata/health.d/zfs.conf etc/netdata/health.d/zfs.conf OK [/opt/netdata]# cp etc.new/netdata/health.d/apache.conf etc/netdata/health.d/apache.conf OK [/opt/netdata]# cp etc.new/netdata/health.d/named.conf etc/netdata/health.d/named.conf OK [/opt/netdata]# cp etc.new/netdata/health.d/nginx_plus.conf etc/netdata/health.d/nginx_plus.conf OK [/opt/netdata]# cp etc.new/netdata/health.d/squid.conf etc/netdata/health.d/squid.conf OK [/opt/netdata]# cp etc.new/netdata/health.d/udp_errors.conf etc/netdata/health.d/udp_errors.conf OK [/opt/netdata]# cp etc.new/netdata/health.d/tcp_resets.conf etc/netdata/health.d/tcp_resets.conf OK [/opt/netdata]# cp etc.new/netdata/health.d/portcheck.conf etc/netdata/health.d/portcheck.conf OK [/opt/netdata]# cp etc.new/netdata/health.d/elasticsearch.conf etc/netdata/health.d/elasticsearch.conf OK [/opt/netdata]# cp etc.new/netdata/health.d/ceph.conf etc/netdata/health.d/ceph.conf OK [/opt/netdata]# cp etc.new/netdata/health.d/isc_dhcpd.conf etc/netdata/health.d/isc_dhcpd.conf OK [/opt/netdata]# cp etc.new/netdata/health.d/bcache.conf etc/netdata/health.d/bcache.conf OK [/opt/netdata]# cp etc.new/netdata/health.d/qos.conf etc/netdata/health.d/qos.conf OK [/opt/netdata]# cp etc.new/netdata/health.d/stiebeleltron.conf etc/netdata/health.d/stiebeleltron.conf OK [/opt/netdata]# cp etc.new/netdata/health.d/retroshare.conf etc/netdata/health.d/retroshare.conf OK [/opt/netdata]# cp etc.new/netdata/health.d/mysql.conf etc/netdata/health.d/mysql.conf OK [/opt/netdata]# cp etc.new/netdata/health.d/beanstalkd.conf etc/netdata/health.d/beanstalkd.conf OK [/opt/netdata]# cp etc.new/netdata/health.d/postgres.conf etc/netdata/health.d/postgres.conf OK [/opt/netdata]# cp etc.new/netdata/health.d/tcp_orphans.conf etc/netdata/health.d/tcp_orphans.conf OK [/opt/netdata]# cp etc.new/netdata/health.d/haproxy.conf etc/netdata/health.d/haproxy.conf OK [/opt/netdata]# cp etc.new/netdata/health.d/entropy.conf etc/netdata/health.d/entropy.conf OK [/opt/netdata]# cp etc.new/netdata/health.d/cpu.conf etc/netdata/health.d/cpu.conf OK [/opt/netdata]# cp etc.new/netdata/health.d/ipfs.conf etc/netdata/health.d/ipfs.conf OK [/opt/netdata]# cp etc.new/netdata/health.d/varnish.conf etc/netdata/health.d/varnish.conf OK [/opt/netdata]# cp etc.new/netdata/health.d/disks.conf etc/netdata/health.d/disks.conf OK [/opt/netdata]# cp etc.new/netdata/health.d/tcp_conn.conf etc/netdata/health.d/tcp_conn.conf OK [/opt/netdata]# cp etc.new/netdata/health.d/btrfs.conf etc/netdata/health.d/btrfs.conf OK [/opt/netdata]# cp etc.new/netdata/health.d/lighttpd.conf etc/netdata/health.d/lighttpd.conf OK [/opt/netdata]# cp etc.new/netdata/health.d/net.conf etc/netdata/health.d/net.conf OK [/opt/netdata]# cp etc.new/netdata/health.d/softnet.conf etc/netdata/health.d/softnet.conf OK [/opt/netdata]# cp etc.new/netdata/health.d/redis.conf etc/netdata/health.d/redis.conf OK [/opt/netdata]# cp etc.new/netdata/health.d/web_log.conf etc/netdata/health.d/web_log.conf OK [/opt/netdata]# cp etc.new/netdata/health.d/memory.conf etc/netdata/health.d/memory.conf OK [/opt/netdata]# cp etc.new/netdata/health.d/ipmi.conf etc/netdata/health.d/ipmi.conf OK [/opt/netdata]# cp etc.new/netdata/health.d/ram.conf etc/netdata/health.d/ram.conf OK [/opt/netdata]# cp etc.new/netdata/health.d/netfilter.conf etc/netdata/health.d/netfilter.conf OK [/opt/netdata]# cp etc.new/netdata/health.d/tcp_mem.conf etc/netdata/health.d/tcp_mem.conf OK [/opt/netdata]# cp etc.new/netdata/health.d/mongodb.conf etc/netdata/health.d/mongodb.conf OK [/opt/netdata]# cp etc.new/netdata/health.d/boinc.conf etc/netdata/health.d/boinc.conf OK [/opt/netdata]# cp etc.new/netdata/health.d/swap.conf etc/netdata/health.d/swap.conf OK [/opt/netdata]# cp etc.new/netdata/health.d/backend.conf etc/netdata/health.d/backend.conf OK [/opt/netdata]# cp etc.new/netdata/health.d/ipc.conf etc/netdata/health.d/ipc.conf OK [/opt/netdata]# cp etc.new/netdata/health.d/fronius.conf etc/netdata/health.d/fronius.conf OK [/opt/netdata]# cp etc.new/netdata/health.d/apcupsd.conf etc/netdata/health.d/apcupsd.conf OK [/opt/netdata]# cp etc.new/netdata/health.d/mdstat.conf etc/netdata/health.d/mdstat.conf OK [/opt/netdata]# cp etc.new/netdata/health.d/couchdb.conf etc/netdata/health.d/couchdb.conf OK [/opt/netdata]# cp etc.new/netdata/health.d/memcached.conf etc/netdata/health.d/memcached.conf OK [/opt/netdata]# cp etc.new/netdata/health.d/megacli.conf etc/netdata/health.d/megacli.conf OK [/opt/netdata]# cp etc.new/netdata/health.d/fping.conf etc/netdata/health.d/fping.conf OK [/opt/netdata]# cp etc.new/netdata/health.d/httpcheck.conf etc/netdata/health.d/httpcheck.conf OK [/opt/netdata]# cp etc.new/netdata/health.d/bind_rndc.conf etc/netdata/health.d/bind_rndc.conf OK [/opt/netdata]# cp etc.new/netdata/python.d.conf etc/netdata/python.d.conf OK [/opt/netdata]# cp etc.new/netdata/health_alarm_notify.conf etc/netdata/health_alarm_notify.conf OK [/opt/netdata]# cp etc.new/netdata/health_email_recipients.conf etc/netdata/health_email_recipients.conf OK [/opt/netdata]# cp etc.new/netdata/apps_groups.conf etc/netdata/apps_groups.conf OK [/opt/netdata]# mkdir -p etc/netdata/python.d OK [/opt/netdata]# cp etc.new/netdata/python.d/nginx.conf etc/netdata/python.d/nginx.conf OK [/opt/netdata]# cp etc.new/netdata/python.d/dovecot.conf etc/netdata/python.d/dovecot.conf OK [/opt/netdata]# cp etc.new/netdata/python.d/apache.conf etc/netdata/python.d/apache.conf OK [/opt/netdata]# cp etc.new/netdata/python.d/exim.conf etc/netdata/python.d/exim.conf OK [/opt/netdata]# cp etc.new/netdata/python.d/rabbitmq.conf etc/netdata/python.d/rabbitmq.conf OK [/opt/netdata]# cp etc.new/netdata/python.d/spigotmc.conf etc/netdata/python.d/spigotmc.conf OK [/opt/netdata]# cp etc.new/netdata/python.d/nginx_plus.conf etc/netdata/python.d/nginx_plus.conf OK [/opt/netdata]# cp etc.new/netdata/python.d/squid.conf etc/netdata/python.d/squid.conf OK [/opt/netdata]# cp etc.new/netdata/python.d/w1sensor.conf etc/netdata/python.d/w1sensor.conf OK [/opt/netdata]# cp etc.new/netdata/python.d/tomcat.conf etc/netdata/python.d/tomcat.conf OK [/opt/netdata]# cp etc.new/netdata/python.d/fail2ban.conf etc/netdata/python.d/fail2ban.conf OK [/opt/netdata]# cp etc.new/netdata/python.d/postfix.conf etc/netdata/python.d/postfix.conf OK [/opt/netdata]# cp etc.new/netdata/python.d/powerdns.conf etc/netdata/python.d/powerdns.conf OK [/opt/netdata]# cp etc.new/netdata/python.d/ntpd.conf etc/netdata/python.d/ntpd.conf OK [/opt/netdata]# cp etc.new/netdata/python.d/portcheck.conf etc/netdata/python.d/portcheck.conf OK [/opt/netdata]# cp etc.new/netdata/python.d/dns_query_time.conf etc/netdata/python.d/dns_query_time.conf OK [/opt/netdata]# cp etc.new/netdata/python.d/elasticsearch.conf etc/netdata/python.d/elasticsearch.conf OK [/opt/netdata]# cp etc.new/netdata/python.d/freeradius.conf etc/netdata/python.d/freeradius.conf OK [/opt/netdata]# cp etc.new/netdata/python.d/ceph.conf etc/netdata/python.d/ceph.conf OK [/opt/netdata]# cp etc.new/netdata/python.d/isc_dhcpd.conf etc/netdata/python.d/isc_dhcpd.conf OK [/opt/netdata]# cp etc.new/netdata/python.d/nsd.conf etc/netdata/python.d/nsd.conf OK [/opt/netdata]# cp etc.new/netdata/python.d/logind.conf etc/netdata/python.d/logind.conf OK [/opt/netdata]# cp etc.new/netdata/python.d/samba.conf etc/netdata/python.d/samba.conf OK [/opt/netdata]# cp etc.new/netdata/python.d/retroshare.conf etc/netdata/python.d/retroshare.conf OK [/opt/netdata]# cp etc.new/netdata/python.d/phpfpm.conf etc/netdata/python.d/phpfpm.conf OK [/opt/netdata]# cp etc.new/netdata/python.d/mysql.conf etc/netdata/python.d/mysql.conf OK [/opt/netdata]# cp etc.new/netdata/python.d/smartd_log.conf etc/netdata/python.d/smartd_log.conf OK [/opt/netdata]# cp etc.new/netdata/python.d/postgres.conf etc/netdata/python.d/postgres.conf OK [/opt/netdata]# cp etc.new/netdata/python.d/haproxy.conf etc/netdata/python.d/haproxy.conf OK [/opt/netdata]# cp etc.new/netdata/python.d/cpufreq.conf etc/netdata/python.d/cpufreq.conf OK [/opt/netdata]# cp etc.new/netdata/python.d/ipfs.conf etc/netdata/python.d/ipfs.conf OK [/opt/netdata]# cp etc.new/netdata/python.d/varnish.conf etc/netdata/python.d/varnish.conf OK [/opt/netdata]# cp etc.new/netdata/python.d/hddtemp.conf etc/netdata/python.d/hddtemp.conf OK [/opt/netdata]# cp etc.new/netdata/python.d/puppet.conf etc/netdata/python.d/puppet.conf OK [/opt/netdata]# cp etc.new/netdata/python.d/unbound.conf etc/netdata/python.d/unbound.conf OK [/opt/netdata]# cp etc.new/netdata/python.d/redis.conf etc/netdata/python.d/redis.conf OK [/opt/netdata]# cp etc.new/netdata/python.d/web_log.conf etc/netdata/python.d/web_log.conf OK [/opt/netdata]# cp etc.new/netdata/python.d/dnsdist.conf etc/netdata/python.d/dnsdist.conf OK [/opt/netdata]# cp etc.new/netdata/python.d/mongodb.conf etc/netdata/python.d/mongodb.conf OK [/opt/netdata]# cp etc.new/netdata/python.d/boinc.conf etc/netdata/python.d/boinc.conf OK [/opt/netdata]# cp etc.new/netdata/python.d/springboot.conf etc/netdata/python.d/springboot.conf OK [/opt/netdata]# cp etc.new/netdata/python.d/litespeed.conf etc/netdata/python.d/litespeed.conf OK [/opt/netdata]# cp etc.new/netdata/python.d/icecast.conf etc/netdata/python.d/icecast.conf OK [/opt/netdata]# cp etc.new/netdata/python.d/example.conf etc/netdata/python.d/example.conf OK [/opt/netdata]# cp etc.new/netdata/python.d/mdstat.conf etc/netdata/python.d/mdstat.conf OK [/opt/netdata]# cp etc.new/netdata/python.d/couchdb.conf etc/netdata/python.d/couchdb.conf OK [/opt/netdata]# cp etc.new/netdata/python.d/chrony.conf etc/netdata/python.d/chrony.conf OK [/opt/netdata]# cp etc.new/netdata/python.d/memcached.conf etc/netdata/python.d/memcached.conf OK [/opt/netdata]# cp etc.new/netdata/python.d/megacli.conf etc/netdata/python.d/megacli.conf OK [/opt/netdata]# cp etc.new/netdata/python.d/traefik.conf etc/netdata/python.d/traefik.conf OK [/opt/netdata]# cp etc.new/netdata/python.d/httpcheck.conf etc/netdata/python.d/httpcheck.conf OK [/opt/netdata]# cp etc.new/netdata/python.d/ovpn_status_log.conf etc/netdata/python.d/ovpn_status_log.conf OK [/opt/netdata]# cp etc.new/netdata/python.d/sensors.conf etc/netdata/python.d/sensors.conf OK [/opt/netdata]# cp etc.new/netdata/python.d/bind_rndc.conf etc/netdata/python.d/bind_rndc.conf OK [/opt/netdata]# cp etc.new/netdata/python.d/go_expvar.conf etc/netdata/python.d/go_expvar.conf OK [/opt/netdata]# cp etc.new/netdata/python.d/beanstalk.conf etc/netdata/python.d/beanstalk.conf OK [/opt/netdata]# cp etc.new/netdata/charts.d.conf etc/netdata/charts.d.conf OK [/opt/netdata]# cp etc.new/netdata/stream.conf etc/netdata/stream.conf OK [/opt/netdata]# mkdir -p etc/netdata/statsd.d OK [/opt/netdata]# cp etc.new/netdata/statsd.d/example.conf etc/netdata/statsd.d/example.conf OK [/opt/netdata]# mkdir -p etc/netdata/node.d OK [/opt/netdata]# cp etc.new/netdata/node.d/named.conf.md etc/netdata/node.d/named.conf.md OK [/opt/netdata]# cp etc.new/netdata/node.d/README.md etc/netdata/node.d/README.md OK [/opt/netdata]# cp etc.new/netdata/node.d/sma_webbox.conf.md etc/netdata/node.d/sma_webbox.conf.md OK [/opt/netdata]# cp etc.new/netdata/node.d/stiebeleltron.conf.md etc/netdata/node.d/stiebeleltron.conf.md OK [/opt/netdata]# cp etc.new/netdata/node.d/snmp.conf.md etc/netdata/node.d/snmp.conf.md OK [/opt/netdata]# cp etc.new/netdata/node.d/fronius.conf.md etc/netdata/node.d/fronius.conf.md OK [/opt/netdata]# mkdir -p etc/netdata/charts.d OK [/opt/netdata]# cp etc.new/netdata/charts.d/nginx.conf etc/netdata/charts.d/nginx.conf OK [/opt/netdata]# cp etc.new/netdata/charts.d/nut.conf etc/netdata/charts.d/nut.conf OK [/opt/netdata]# cp etc.new/netdata/charts.d/libreswan.conf etc/netdata/charts.d/libreswan.conf OK [/opt/netdata]# cp etc.new/netdata/charts.d/apache.conf etc/netdata/charts.d/apache.conf OK [/opt/netdata]# cp etc.new/netdata/charts.d/exim.conf etc/netdata/charts.d/exim.conf OK [/opt/netdata]# cp etc.new/netdata/charts.d/squid.conf etc/netdata/charts.d/squid.conf OK [/opt/netdata]# cp etc.new/netdata/charts.d/tomcat.conf etc/netdata/charts.d/tomcat.conf OK [/opt/netdata]# cp etc.new/netdata/charts.d/postfix.conf etc/netdata/charts.d/postfix.conf OK [/opt/netdata]# cp etc.new/netdata/charts.d/phpfpm.conf etc/netdata/charts.d/phpfpm.conf OK [/opt/netdata]# cp etc.new/netdata/charts.d/mysql.conf etc/netdata/charts.d/mysql.conf OK [/opt/netdata]# cp etc.new/netdata/charts.d/cpufreq.conf etc/netdata/charts.d/cpufreq.conf OK [/opt/netdata]# cp etc.new/netdata/charts.d/hddtemp.conf etc/netdata/charts.d/hddtemp.conf OK [/opt/netdata]# cp etc.new/netdata/charts.d/cpu_apps.conf etc/netdata/charts.d/cpu_apps.conf OK [/opt/netdata]# cp etc.new/netdata/charts.d/load_average.conf etc/netdata/charts.d/load_average.conf OK [/opt/netdata]# cp etc.new/netdata/charts.d/opensips.conf etc/netdata/charts.d/opensips.conf OK [/opt/netdata]# cp etc.new/netdata/charts.d/apcupsd.conf etc/netdata/charts.d/apcupsd.conf OK [/opt/netdata]# cp etc.new/netdata/charts.d/example.conf etc/netdata/charts.d/example.conf OK [/opt/netdata]# cp etc.new/netdata/charts.d/mem_apps.conf etc/netdata/charts.d/mem_apps.conf OK [/opt/netdata]# cp etc.new/netdata/charts.d/ap.conf etc/netdata/charts.d/ap.conf OK [/opt/netdata]# cp etc.new/netdata/charts.d/sensors.conf etc/netdata/charts.d/sensors.conf OK [/opt/netdata]# cp etc.new/netdata/fping.conf etc/netdata/fping.conf OK [/opt/netdata]# rm -rf etc.new OK --- Add user netdata to required user groups --- Adding netdata user group ... [/opt/netdata]# groupadd -r netdata OK Adding netdata user account with home /opt/netdata ... [/opt/netdata]# useradd -r -g netdata -c netdata -s /usr/sbin/nologin --no-create-home -d /opt/netdata netdata OK Group 'docker' does not exist. Adding netdata user to the nginx group ... [/opt/netdata]# usermod -a -G nginx netdata OK Group 'varnish' does not exist. Group 'haproxy' does not exist. Adding netdata user to the adm group ... [/opt/netdata]# usermod -a -G adm netdata OK Group 'nsd' does not exist. Group 'proxy' does not exist. Group 'squid' does not exist. Group 'ceph' does not exist. Adding netdata user to the nobody group ... [/opt/netdata]# usermod -a -G nobody netdata OK --- Check SSL certificates paths --- Creating /opt/netdata/.curlrc with cacert=/etc/ssl/certs/ca-bundle.crt --- Install logrotate configuration for netdata --- [/opt/netdata]# cp system/netdata.logrotate /etc/logrotate.d/netdata OK [/opt/netdata]# chmod 644 /etc/logrotate.d/netdata OK --- Install netdata at system init --- Installing systemd service... [/opt/netdata]# cp system/netdata.service /etc/systemd/system/netdata.service OK [/opt/netdata]# systemctl daemon-reload OK [/opt/netdata]# systemctl enable netdata Created symlink from /etc/systemd/system/multi-user.target.wants/netdata.service to /etc/systemd/system/netdata.service. OK --- creating quick links --- [/opt/netdata]# ln -s bin sbin OK [/opt/netdata/usr]# ln -s ../bin bin OK [/opt/netdata/usr]# ln -s ../bin sbin OK [/opt/netdata/usr]# ln -s . local OK [/opt/netdata]# ln -s etc/netdata netdata-configs OK [/opt/netdata]# ln -s usr/share/netdata/web netdata-web-files OK [/opt/netdata]# ln -s usr/libexec/netdata netdata-plugins OK [/opt/netdata]# ln -s var/lib/netdata netdata-dbs OK [/opt/netdata]# ln -s var/cache/netdata netdata-metrics OK [/opt/netdata]# ln -s var/log/netdata netdata-logs OK --- fix permissions --- [/opt/netdata]# chmod g+rx\,o+rx /opt OK [/opt/netdata]# chown -R netdata:netdata /opt/netdata OK --- fix plugin permissions --- [/opt/netdata]# chown root:netdata usr/libexec/netdata/plugins.d/apps.plugin OK [/opt/netdata]# chmod 4750 usr/libexec/netdata/plugins.d/apps.plugin OK [/opt/netdata]# chown root:netdata usr/libexec/netdata/plugins.d/cgroup-network OK [/opt/netdata]# chmod 4750 usr/libexec/netdata/plugins.d/cgroup-network OK [/opt/netdata]# chown root:netdata bin/fping OK [/opt/netdata]# chmod 4750 bin/fping OK --- starting netdata --- --- Start netdata --- [/opt/netdata]# /usr/bin/systemctl stop netdata OK [/opt/netdata]# /usr/bin/systemctl restart netdata OK ------------------------------------------------------------------------------- Downloading default configuration from netdata... [/opt/netdata]# curl -s -o /opt/netdata/etc/netdata/netdata.conf.new http://localhost:19999/netdata.conf OK [/opt/netdata]# mv /opt/netdata/etc/netdata/netdata.conf.new /opt/netdata/etc/netdata/netdata.conf OK OK New configuration saved for you to edit at /opt/netdata/etc/netdata/netdata.conf [/opt/netdata]# chown netdata:netdata /opt/netdata/etc/netdata/netdata.conf OK [/opt/netdata]# chmod 0664 /opt/netdata/etc/netdata/netdata.conf OK ^ |.-. .-. .-. .-. .-. . netdata .-. .- | '-' '-' '-' '-' '-' is installed and running now! -' '-' +----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+---> OK 安装后默认是通过http://xxx:19999/访问 由于netdata没有帐号密码体系,为保护服务器隐私,我们要使用nginx反代,通过域名访问,并使用账号密码授权。 首先,我们安装apache工具集,我们需要其中的htpasswd为我们生成用户信息(PS:网上找到的资料是apache2-utils,但我们在CentOS7的源中已经搜索不到这个包)。 yum install httpd-tools -y 安装过程如下: Loaded plugins: fastestmirror, langpacks Repository epel is listed more than once in the configuration Loading mirror speeds from cached hostfile Resolving Dependencies --> Running transaction check ---> Package httpd-tools.x86_64 0:2.4.6-80.el7.centos.1 will be installed --> Processing Dependency: libaprutil-1.so.0()(64bit) for package: httpd-tools-2.4.6-80.el7.centos.1.x86_64 --> Processing Dependency: libapr-1.so.0()(64bit) for package: httpd-tools-2.4.6-80.el7.centos.1.x86_64 --> Running transaction check ---> Package apr.x86_64 0:1.4.8-3.el7_4.1 will be installed ---> Package apr-util.x86_64 0:1.5.2-6.el7 will be installed --> Finished Dependency Resolution Dependencies Resolved ============================================================================================================================================================ Package Arch Version Repository Size ============================================================================================================================================================ Installing: httpd-tools x86_64 2.4.6-80.el7.centos.1 updates 90 k Installing for dependencies: apr x86_64 1.4.8-3.el7_4.1 os 103 k apr-util x86_64 1.5.2-6.el7 os 92 k Transaction Summary ============================================================================================================================================================ Install 1 Package (+2 Dependent packages) Total download size: 285 k Installed size: 584 k Is this ok [y/d/N]: y Downloading packages: (1/3): apr-util-1.5.2-6.el7.x86_64.rpm | 92 kB 00:00:00 (2/3): apr-1.4.8-3.el7_4.1.x86_64.rpm | 103 kB 00:00:00 (3/3): httpd-tools-2.4.6-80.el7.centos.1.x86_64.rpm | 90 kB 00:00:00 ------------------------------------------------------------------------------------------------------------------------------------------------------------ Total 1.7 MB/s | 285 kB 00:00:00 Running transaction check Running transaction test Transaction test succeeded Running transaction Installing : apr-1.4.8-3.el7_4.1.x86_64 1/3 Installing : apr-util-1.5.2-6.el7.x86_64 2/3 Installing : httpd-tools-2.4.6-80.el7.centos.1.x86_64 3/3 Verifying : httpd-tools-2.4.6-80.el7.centos.1.x86_64 1/3 Verifying : apr-util-1.5.2-6.el7.x86_64 2/3 Verifying : apr-1.4.8-3.el7_4.1.x86_64 3/3 Installed: httpd-tools.x86_64 0:2.4.6-80.el7.centos.1 Dependency Installed: apr.x86_64 0:1.4.8-3.el7_4.1 apr-util.x86_64 0:1.5.2-6.el7 Complete! 接下来创建目录,创建账号 mkdir /usr/local/nginx htpasswd -c /usr/local/nginx/passwd.db username pwd re-type pwd 添加一个nginx的配置vim /etc/nginx/conf.d/netdata.conf,内容如下 upstream netdatahttp { server 127.0.0.1:19999; } server { listen *:80; server_name netdata.xxx.com; auth_basic "netdata"; auth_basic_user_file /usr/local/nginx/passwd.db; location / { proxy_pass http://netdatahttp; proxy_redirect off; proxy_set_header Host $host; proxy_set_header X-Real_IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } } 打开域名测试一下效果 要求输入账号密码 输入密码后 总览 应用的内存使用情况 引用 1.netdata官方安装指南2.Running behind nginx(通过 nginx 保护 netdata)3.netdata开源地址

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

C++程序设计基础(5)sizeof的使用

1.知识点 (1)sizeof是一个单目运算发,而不是一个函数,其用于获取操作数所占内存空间的字节数。 (2)sizeof的操作数可以使类型名,也可以是表达式,如果是类型名则直接获得该类型所占字节数,如果是表达式,则先分析表达式结果的类型,再根据类型确定所占字节数,并不对表达式进行实际计算。 1 int a = 1; 2 double b = 1.5; 3 sizeof(int);//结果为4 4 sizeof(a); //结果为4 5 sizeof(b); //结果为8 (3)sizeof很少单独使用,而是和内存分配或者计算法数组长度等需求进行配合使用。 1 //与内存空间分配配合使用 2 int *ptr = (int *)malloc(sizeof(int) * 20); 3 //与计算数组长度配合使用 4 int count = sizeof(darray) / sizeof(double); (4)数组名作为操作数时,将获得整个数组所占空间,当数组名作为实参传递给子函数时,此时数组名已经成为了指针,其计算结果将是指针的所占空间。 void subfunc(double darray[]) { cout << sizeof(darray) / sizeof(double) << endl; //输出4/8=0 } int main(int argc, char *argv[]) { double darray[20]; cout << sizeof(darray) / sizeof(double) << endl; //输出16/8=20 subfunc(darray); getchar(); return 0; } (5)在计算字符串长度时要用strlen。sizeof是一个运算符,用于获取类型或表达式的所占内存大小;strlen是一个函数,用于计算字符串中字符的个数,其中字符串结尾符\0不会被计算在内。 2.面试题 2.1不能使用sizeof计算的表达式 1 struct baby 2 { 3 unsigned int gender : 1; 4 unsigned int weight : 5; 5 unsigned int week : 7; 6 unsigned int blood : 3; 7 unsigned int height : 8; 8 }; 9 int triple(int number) { 10 return 3 * number; 11 } 12 int main(int argc, char *argv[]) { 13 sizeof(baby); //A 14 sizeof(baby.gender);//B 15 sizeof(triple);//C 16 sizeof(triple(3));//D 17 sizeof(show());//E 18 19 getchar(); 20 return 0; 21 } 答案:正确:A,D;错误:B,C,E. (1)sizeof计算结构体是结果是结构体的所占内存空间,结构体中使用了位域定义成员,要求一个位域成员不能横跨两个字节,故可以算出该结构体的字节数为4,A正确。 (2)sizeof计算的结果是字节数,但是不允许计算结构体中某个位域成员的所占空间,当然如果不是位域定义的是可以计算的。故B错。 (3)不允许计算函数名的所占字节数大小,有点莫名其妙,C错。 (4)允许计算表达函数表达式,其结果是函数返回值的类型的字节数,即该题的int大小,D正确。 (5)函数返回值类型不确定使,不允许通过sizeof计算,故E错误。 2.2sizeof计算结构体是的内存对其问题 写出下面两个结构体的sizeof计算结果 struct s1{ char a;//1 short b;//4 int c;//8 double d;//16,16刚好是double大小的整数倍 }; struct s2 { char a;//1 short b;//4 double c;//16(从9开始排) int d;//20(该结果不是double的整数倍,故需要加到24) }; 数据对其总结:(1)每个成员在内存中的起始位置都必须是自身大小的整数倍。 (2)最终结构体计算结果必须是占字节数最大的成员的整数倍。 答案:16,24。 2.3结构体嵌套时的sizeof计算 1 struct s1 { 2 int a; 3 }; 4 struct s2 { 5 char a[4]; 6 }; 7 struct s3{ 8 char a[4]; 9 char b; 10 }; 11 struct s4 { 12 s1 a; 13 char b; 14 }; 15 struct s5{ 16 s2 a; 17 char b; 18 }; 含复杂结构体的数据对其总结:在数据对其时,要以结构体中最深层的基本数据类型为准。例如:如果结构体成员是一个数组,应以数组的元素的类型作为数据对其的标准,如果结构体成员是其他结构体,应以内层结构体中的基本元素类型成员作为外层结构体数据对齐的标准。故答案如下 1 sizeof(struct s1)=4; 2 sizeof(struct s2)=4; 3 sizeof(struct s3)=5; 4 sizeof(struct s4)=8; 5 sizeof(struct s5)=5;

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

基础学python之文本和编码问题

字符串是个相当简单的概念:一个字符串是一个字符序列。问题出在”字符”的定义上。 在2015 年,”字符”的最佳定义是Unicode字符。因此,从Python 3 的str对象中获取 的元素是Unicode字符 Unicode 标准把字符的标识和具体的字节表述进行了如下的明确区分。 字符的标识,即码位,是0~1 114 111的数字(十进制),在Unicode标准中以4~6个十六进制数字表示,而且加前缀U+。例如,字母A的码位是U+0041,欧元符号的码位是U+20AC,高音谱号的码位是U+1D11E. 在Unicode 6.3标准中,约10% 的有效码位有对应的字符。 字符的具体表述取决于所用的编码。编码是在码位和字节序列之间转换时使用的算法。在UTF-8编码中,A(U+0041)的码位编码成单个字节\x41,而在UTF-16LE编码中编码成两个字节\x41\x00。再举个例子,欧元符号(U+20AC)在UTF-8编码中是三个字节——\xe2\x82\xac,而在UTF-16LE中编码成两个字节:\xac\x20. 把码位转换成字节序列的过程是编码,使用encode;把字节序列转换成码位的过程是解码,使用decode. 非英语用户常常会搞反所谓的编码解码,可以这样理解: 把Unicode字符串想成“人类可读”的文本.那么, 把字节序列变成人类可读的文本字符串就是解码 而把字符串变成用于存储或传输的字节序列就是编码 所以,我们在做爬虫的时候,遇到乱码的情况,可以先去看看编码格式是否正确!

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

Python基础内容:怎样快速理解if __name__ == 'main'语句

name 是当前模块名,当模块被直接运行时模块名为 main 。这句话的意思就是,当模块被直接运行时,以下代码块将被运行,当模块是被导入时,代码块不被运行。 相信好多初学者在学习python的过程中,经常会遇到if name == ‘main’语句,可能你知道它的作用,也可能很模糊,今天就给大家分享下我的理解。 我们先新建一个text的py文件,并写入以下内容并运行 然后呢,在同一个文件夹中在新建一个py文件text1,写入一行代码:import text 然后运行看看结果 与之前test.py代码运行结果比较,只有输出学习Python,也就是if name==”main“: 之前的语句被执行,之后的没有被执行。 为什么会这样呢?别急,我们稍微处理下代码就可以看明白了: 在 if name==”main“之前加入一行代码:print(name),即打印出name,然后我们在重新分别执行2个代码看看 这就很清楚了,在text中name变量的值为main,而在text1中,name的值为text,明显不满足if语句,因此,后面的代码无法执行! 仔细想想,它的原理也就是: 每个python模块(文件)都包含内置的变量name,当该模块被执行的时候,name就等于文件名。而import到其他模块(文件)中,则name等于当前的模块名,而main等于当前文件名,所以直接执行模块的时候if name==”main“为真,可以执行;import到其他模块(文件)中,if name==”main“为假,那当然就不执行对应的代码了。 简单说就是:name是当前的模块名字,在当前文件时可以被执行,而模块被导入时,代码不被运行! 喜欢就关注下呗( ̄ε  ̄)

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

深度学习之 TensorFlow(一):基础库包的安装

1.TensorFlow 简介:TensorFlow 是谷歌公司开发的深度学习框架,也是目前深度学习的主流框架之一。 2.TensorFlow 环境的准备: 本人使用 macOS,Python 版本直接使用 anaconda 的集成包,我们使用 anaconda 来管理环境,为 TensorFlow 创建独立的 Python 环境。 创建一个名为 tensorflow 的 Python 环境: conda create --name tensorflow python=3.6 激活环境: source activate tensorflow 退出环境: source deactivate tensorflow 然后我们在 tensorflow 环境下基于 pip 来安装 TensorFlow: 安装 TensorFlow: pip install tensorflow 安装完 TensorFlow 后我们试着进入 Python 环境来运行 TensorFlow 测试是否安装成功: 输入一个例子: 至此,我们 TensorFlow 便安装成功了。 3.安装其他依赖的模块: (1)numpy numpy 是用来存储和处理大型矩阵的科学计算包,比 Python 自身的嵌套列表结构 list 要高效的多。 安装: pip install numpy --upgrade (2) matplotlib matplotlib 是 Python 最著名的绘图表,它提供了一整套和 MATLAB 相似的命令 API,十分适合交互式地进行制图。 安装: pip install matplotlib --upgrade (3) jupyter jupyter notebook 是 ipython 的升级版,能够在浏览器中创建和共享代码、方程、说明文档。 安装: pip install jupyter --upgrade (4) scikit-image scikit-image 有一组图像处理的算法,可以使过滤一张图片变得很简单,非常适合用于对图像的预处理。 安装: pip install scikit-image --upgrade (5) librosa librosa 是用 Python 进行音频提取的第三方库,有很多方式可以提取音频特征。 安装: pip install librosa --upgrade (6) nltk nltk 模块中包含着大量的语料库,可以很方便地完成很多自然语言处理的任务,包括分词、词性标注、命名实体识别及句法分析。 安装: pip install nltk --upgrade 安装完成后,需要导入 nltk 工具包,下载 nltk 数据源: import nltk nltk.download() (7) keras Keras 是第一个被添加到 TensorFlow 核心中的高级别框架,成为 TensorFlow 的默认 API。 安装: pip install keras --upgrade (8) tflearn TFLearn 是另一个支持 TensorFlow 的第三方框架。 安装: pip install git+https://github.com/tflearn/tflearn.git

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

Unity 基础之 Visual Studio 2017 常用快捷键

下面为大家介绍下使用visual studio 使用频率特别多的快捷键,提高开发效率(使用版本visual studio 2017) 2018/11/07更新使用F1跳转官方文档说明 CTR+K +CTR+F 自动编写格式 CTR+R CTR+R选中与之相关的字段重新命名,修改后回车 ALT+Enter Enter 根据提示转换响应的格式 (新版本的很多自动化功能都是这个组合键) CTR+X剪切 Ctr+F查询本页相关字段 注释,取消注释CTR+K CTR+C 和CTR+K CTR+U 按住ALT+鼠标选中需要缩进的位置,然后进行多行缩进 光标放到指定的关键字 使用按键F1跳转到微软官方文档(前提是C#等官方的关键字)

资源下载

更多资源
腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

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应用均可从中受益。

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。

用户登录
用户注册