首页 文章 精选 留言 我的

精选列表

搜索[增删改查],共9418篇文章
优秀的个人博客,低调大师

每日一博 | 还在用 ES 查日志吗,快看看石墨文档 Clickhouse 日志架构玩法

1 背景 石墨文档全部应用部署在Kubernetes上,每时每刻都会有大量的日志输出,我们之前主要使用SLS和ES作为日志存储。但是我们在使用这些组件的时候,发现了一些问题。 成本问题: SLS个人觉得是一个非常优秀的产品,速度快,交互方便,但是SLS索引成本比较贵 我们想减少SLS索引成本的时候,发现云厂商并不支持分析单个索引的成本,导致我们无法知道是哪些索引构建的不够合理 ES使用的存储非常多,并且耗费大量的内存 通用问题: 如果业务是混合云架构,或者业务形态有SAAS和私有化两种方式,那么SLS并不能通用 日志和链路,需要用两套云产品,不是很方便 精确度问题:SLS存储的精度只能到秒,但我们实际日志精度到毫秒,如果日志里面有traceid,SLS中无法通过根据traceid信息,将日志根据毫秒时间做排序,不利于排查错误 我们经过一番调研后,发现使用Clickhouse能够很好的解决以上问题,并且Clickhouse省存储空间,非常省钱,所以我们选择了Clickhouse方案存储日志。但当我们深入研究后,Clickhouse作为日志存储有许多落地的细节,但业界并没有很好阐述相关Clickhouse采集日志的整套流程,以及没有一款优秀的Clickhouse日志查询工具帮助分析日志,为此我们写了一套Clickhouse日志系统贡献给开源社区,并将Clickhouse的日志采集架构的经验做了总结。先上个Clickhouse日志查询界面,让大家感受下石墨最懂前端的后端程序员。 2 架构原理图 我们将日志系统分为四个部分:日志采集、日志传输、日志存储、日志管理。 日志采集:LogCollector采用Daemonset方式部署,将宿主机日志目录挂载到LogCollector的容器内,LogCollector通过挂载的目录能够采集到应用日志、系统日志、K8S审计日志等 日志传输:通过不同Logstore映射到Kafka中不同的Topic,将不同数据结构的日志做了分离 日志存储:使用Clickhouse中的两种引擎数据表和物化视图 日志管理:开源的Mogo系统,能够查询日志,设置日志索引,设置LogCollector配置,设置Clickhouse表,设置报警等 以下我们按照这四大部分,阐述其中的架构原理 3 日志采集 3.1 采集方式 Kubernetes容器内日志收集的方式通常有以下三种方案 DaemonSet方式采集:在每个 node 节点上部署LogCollector,并将宿主机的目录挂载为容器的日志目录,LogCollector读取日志内容,采集到日志中心。 网络方式采集:通过应用的日志 SDK,直接将日志内容采集到日志中心 。 SideCar方式采集:在每个 pod 内部署LogCollector,LogCollector只读取这个 pod 内的日志内容,采集到日志中心。 以下是三种采集方式的优缺点: DaemonSet方式 网络方式 SideCar方式 采集日志类型 标准输出+文件 应用日志 部署运维 一般,维护DaemonSet 低,维护配置文件 日志分类存储 可通过容器/路径等映射 业务独立配置 支持集群规模 取决于配置数 无限制 适用场景 日志分类明确、功能较单一 性能要求极高的场景 资源消耗 中 低 我们主要采用DaemonSet方式和网络方式采集日志。DaemonSet方式用于ingress、应用日志的采集,网络方式用于大数据日志的采集。以下我们主要介绍下DeamonSet方式的采集方式。 ​ 3.2 日志输出 从上面的介绍中可以看到,我们的DaemonSet会有两种方式采集日志类型,一种是标准输出,一种是文件。 引用元乙的描述:虽然使用 Stdout 打印日志是 Docker 官方推荐的方式,但大家需要注意:这个推荐是基于容器只作为简单应用的场景,实际的业务场景中我们还是建议大家尽可能使用文件的方式,主要的原因有以下几点: Stdout 性能问题,从应用输出 stdout 到服务端,中间会经过好几个流程(例如普遍使用的JSON LogDriver):应用 stdout -> DockerEngine -> LogDriver -> 序列化成 JSON -> 保存到文件 -> Agent 采集文件 -> 解析 JSON -> 上传服务端。整个流程相比文件的额外开销要多很多,在压测时,每秒 10 万行日志输出就会额外占用 DockerEngine 1 个 CPU 核; Stdout 不支持分类,即所有的输出都混在一个流中,无法像文件一样分类输出,通常一个应用中有 AccessLog、ErrorLog、InterfaceLog(调用外部接口的日志)、TraceLog 等,而这些日志的格式、用途不一,如果混在同一个流中将很难采集和分析; Stdout 只支持容器的主程序输出,如果是 daemon/fork 方式运行的程序将无法使用 stdout; 文件的 Dump 方式支持各种策略,例如同步/异步写入、缓存大小、文件轮转策略、压缩策略、清除策略等,相对更加灵活。 从这个描述中,我们可以看出在docker中输出文件在采集到日志中心是一个更好的实践。所有日志采集工具都支持采集文件日志方式,但是我们在配置日志采集规则的时候,发现开源的一些日志采集工具,例如fluentbit、filebeat在DaemonSet部署下采集文件日志是不支持追加例如pod、namespace、container_name、container_id等label信息,并且也无法通过这些label做些定制化的日志采集。 agent类型 采集方式 daemonset部署 sidecar部署 ilogtail 文件日志 能够追加label信息,能够根据label过滤采集 能够追加label信息,能够根据label过滤采集 fluentbit 文件日志 无法追加label信息,无法根据label过滤采集 能够追加abel信息,能够根据label过滤采集 filebeat 文件日志 无法追加label信息,无法根据label过滤采集 能够追加label信息,能够根据label过滤采集 ilogtail 标准输出 能够追加label信息,能够根据label过滤采集 能够追加label信息,能够根据label过滤采集 fluentbit 标准输出 能够追加label信息,能够根据label过滤采集 能够追加abel信息,能够根据label过滤采集 filebeat 标准输出 能够追加label信息,能够根据label过滤采集 能够追加label信息,能够根据label过滤采集 基于无法追加label信息的原因,我们暂时放弃了DeamonSet部署下文件日志采集方式,采用的是基于DeamonSet部署下标准输出的采集方式。 ​ 3.3 日志目录 以下列举了日志目录的基本情况 目录 描述 类型 /var/log/containers 存放的是软链接,软链到/var/log/pods里的标准输出日志 ​标准输出 /var/log/pods 存放标准输出日志 ​标准输出 /var/log/kubernetes/ master存放Kubernetes 审计输出日志 标准输出 /var/lib/docker/overlay2 存放应用日志文件信息 文件日志 /var/run 获取docker.sock,用于docker通信 文件日志 /var/lib/docker/containers 用于存储容器信息 两种都需要 因为我们采集日志是使用的标准输出模式,所以根据上表我们的LogCollector只需要挂载/var/log,/var/lib/docker/containers两个目录。 3.3.1 标准输出日志目录 应用的标准输出日志存储在/var/log/containers目录下,​文件名是按照K8S日志规范生成的。这里以nginx-ingress的日志作为一个示例。我们通过ls /var/log/containers/ | grep nginx-ingress指令,可以看到nginx-ingress的文件名。 nginx-ingress-controller-mt2wx_kube-system_nginx-ingress-controller-be3741043eca1621ec4415fd87546b1beb29480ac74ab1cdd9f52003cf4abf0a.log ​ 我们参照K8S日志的规范:/var/log/containers/%{DATA:pod_name}_%{DATA:namespace}_%{GREEDYDATA:container_name}-%{DATA:container_id}.log。可以将nginx-ingress日志解析为: pod_name:nginx-ingress-controller-mt2w namespace:kube-system container_name:nginx-ingress-controller container_id:be3741043eca1621ec4415fd87546b1beb29480ac74ab1cdd9f52003cf4abf0a 通过以上的日志解析信息,我们的LogCollector 就可以很方便的追加pod、namespace、container_name、container_id的信息。 ​ 3.3.2 容器信息目录 应用的容器信息存储在/var/lib/docker/containers目录下,目录下的每一个文件夹为容器ID,我们可以通过cat config.v2.json获取应用的docker基本信息。 3.4 LogCollector采集日志 3.4.1 配置 我们LogCollector采用的是fluent-bit,该工具是cncf旗下的,能够更好的与云原生相结合。通过Mogo系统可以选择Kubernetes集群,很方便的设置fluent-bit configmap的配置规则。 3.4.2 数据结构 ​fluent-bit的默认采集数据结构 @timestamp字段:string or float,用于记录采集日志的时间 log字段:string,用于记录日志的完整内容 Clickhouse如果使用@timestamp的时候,因为里面有@特殊字符,会处理的有问题。所以我们在处理fluent-bit的采集数据结构,会做一些映射关系,并且规定双下划线为Mogo系统日志索引,避免和业务日志的索引冲突。 _time_字段:string or float,用于记录采集日志的时间 _log_字段:string,用于记录日志的完整内容 例如你的日志记录的是{"id":1},那么实际fluent-bit采集的日志会是{"_time_":"2022-01-15...","_log_":"{\"id\":1}" 该日志结构会直接写入到kafka中,Mogo系统会根据这两个字段_time_、_log_设置clickhouse中的数据表。 3.4.3 采集 如果我们要采集ingress日志,我们需要在input配置里,设置ingress的日志目录,fluent-bit会把ingress日志采集到内存里。 然后我们在filter配置里,将log改写为_log_ 然后我们在ouput配置里,将追加的日志采集时间设置为_time_,设置好日志写入的kafka borkers和kafka topics,那么fluent-bit里内存的日志就会写入到kafka中 日志写入到Kafka中_log_需要为json,如果你的应用写入的日志不是json,那么你就需要根据fluent-bit的parser文档,调整你的日志写入的数据结构:https://docs.fluentbit.io/manual/pipeline/filters/parser 4 日志传输 Kafka主要用于日志传输。上文说到我们使用fluent-bit采集日志的默认数据结构,在下图kafka工具中我们可以看到日志采集的内容。 在日志采集过程中,会由于不用业务日志字段不一致,解析方式是不一样的。所以我们在日志传输阶段,需要将不同数据结构的日志,创建不同的Clickhouse表,映射到Kafka不同的Topic。这里以ingress为例,那么我们在Clickhouse中需要创建一个ingress_stdout_stream的Kafka引擎表,然后映射到Kafka的ingress-stdout Topic里。 5 日志存储 我们会使用三种表,用于存储一种业务类型的日志。 Kafka引擎表:将数据从Kafka采集到Clickhouse的ingress_stdout_stream数据表中 createtablelogger.ingress_stdout_stream ( _source_String, _pod_name_String, _namespace_String, _node_name_String, _container_name_String, _cluster_String, _log_agent_String, _node_ip_String, _time_Float64, _log_String ) engine=KafkaSETTINGSkafka_broker_list='kafka:9092',kafka_topic_list='ingress-stdout',kafka_group_name='logger_ingress_stdout',kafka_format='JSONEachRow',kafka_num_consumers=1; 物化视图:将数据从ingress_stdout_stream数据表读取出来,_log_根据Mogo配置的索引,提取字段在写入到ingress_stdout结果表里 CREATEMATERIALIZEDVIEWlogger.ingress_stdout_viewTOlogger.ingress_stdoutAS SELECT toDateTime(toInt64(_time_))AS_time_second_, fromUnixTimestamp64Nano(toInt64(_time_*1000000000),'Asia/Shanghai')AS_time_nanosecond_, _pod_name_, _namespace_, _node_name_, _container_name_, _cluster_, _log_agent_, _node_ip_, _source_, _log_AS_raw_log_,JSONExtractInt(_log_,'status')ASstatus,JSONExtractString(_log_,'url')ASurl FROMlogger.ingress_stdout_streamwhere1=1; 结果表:存储最终的数据 createtablelogger.ingress_stdout ( _time_second_DateTime, _time_nanosecond_DateTime64(9,'Asia/Shanghai'), _source_String, _cluster_String, _log_agent_String, _namespace_String, _node_name_String, _node_ip_String, _container_name_String, _pod_name_String, _raw_log_String, statusNullable(Int64), urlNullable(String), ) engine=MergeTreePARTITIONBYtoYYYYMMDD(_time_second_) ORDERBY_time_second_ TTLtoDateTime(_time_second_)+INTERVAL7DAY SETTINGSindex_granularity=8192; 6 总结流程 日志会通过fluent-bit的规则采集到kafka,在这里我们会将日志采集到两个字段里 _time_字段用于存储fluent-bit采集的时间 _log_字段用于存放原始日志 通过mogo,在clickhouse里设置了三个表 app_stdout_stream: 将数据从Kafka采集到Clickhouse的Kafka引擎表 app_stdout_view: 视图表用于存放mogo设置的索引规则 app_stdout:根据app_stdout_view索引解析规则,消费app_stdout_stream里的数据,存放于app_stdout结果表中 最后mogo的UI界面,根据app_stdout的数据,查询日志信息 7 Mogo界面展示 查询日志界面 设置日志采集配置界面 以上文档描述是针对石墨Kubernetes的日志采集,想了解物理机采集日志方案的,可以在下文中找到《Mogo使用文档》的链接,运行docker-compose体验Mogo 全部流程,查询Clickhouse日志。限于篇幅有限,Mogo的日志报警功能,下次在讲解。 ​ 8 资料 github地址: https://github.com/shimohq/mogo Mogo文档:https://mogo.shimo.im Mogo使用文档:https://mogo.shimo.im/doc/AV62KU4AABMRQ fluent-bit文档:https://docs.fluentbit.io/ K8S日志 6 个 K8S 日志系统建设中的典型问题,你遇到过几个:https://developer.aliyun.com/article/718735 一文看懂 K8S 日志系统设计和实践:https://developer.aliyun.com/article/727594 9 个技巧,解决 K8S 中的日志输出问题:https://developer.aliyun.com/article/747821 直击痛点,详解 K8S 日志采集最佳实践:https://developer.aliyun.com/article/749468?spm=a2c6h.14164896.0.0.24031164UoPfIX Clickhouse Clickhouse官方文档:https://clickhouse.com/ Clickhouse作为Kubernetes日志管理解决方案中的存储:http://dockone.io/article/9356 Uber 如何使用 ClickHouse 建立快速可靠且与模式无关的日志分析平台?:https://www.infoq.cn/article/l4thjgnr7hxpkgpmw6dz 干货 | 携程ClickHouse日志分析实践:https://mp.weixin.qq.com/s/IjOWAPOJXANRQqRAMWXmaw 为什么我们要从ES迁移到ClickHouse:https://mp.weixin.qq.com/s/l4RgNQPxvdNIqx52LEgBnQ ClickHouse 在日志存储与分析方面作为 ElasticSearch 和 MySQL 的替代方案:https://mp.weixin.qq.com/s/nJXorcgi0QfXPCKr_HdUZg 快手、携程等公司转战到 ClickHouse,ES 难道不行了?:https://mp.weixin.qq.com/s/hP0ocT-cBCeIl9n1wL_HBg 日志分析下ES/ClickHouse/Loki比较与思考:https://mp.weixin.qq.com/s/n2I94X6tz2jOABzl1djxYg

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

2019年Java中高级面试题总结(7),228道系列查漏补缺!

2019年Java面试题中高级系列228道 Java面试题(一) 第一篇更新1~20题的答案解析 第二篇更新21~50题答案解析 第三篇更新51~95题答案解析 Java面试题(二) 第四篇更新1~20题答案解析 第五篇更新21~50题答案解析 第六篇更新51~80题答案解析 Java 面试题(二) 81、说出几条 Java 中方法重载的最佳实践? 82、在多线程环境下,SimpleDateFormat 是线程安全的吗? 83、Java 中如何格式化一个日期?如格式化为 ddMMyyyy 的形式? 84、Java 中,怎么在格式化的日期中显示时区? 85、Java 中 java.util.Date 与 java.sql.Date 有什么区别? 86、Java 中,如何计算两个日期之间的差距? 87、Java 中,如何将字符串 YYYYMMDD 转换为日期? 89、如何测试静态方法?(答案) 90、怎么利用 JUnit 来测试一个方法的异常? 91、你使用过哪个单元测试库来测试你的 Java 程序? 92、@Before 和 @BeforeClass 有什么区别? 93、怎么检查一个字符串只包含数字?解决方案 94、Java 中如何利用泛型写一个 LRU 缓存? 95、写一段 Java 程序将 byte 转换为 long? 96、在不使用 StringBuffer 的前提下,怎么反转一个字符串? 97、Java 中,怎么获取一个文件中单词出现的最高频率? 98、如何检查出两个给定的字符串是反序的? 99、Java 中,怎么打印出一个字符串的所有排列? 100、Java 中,怎样才能打印出数组中的重复元素? 101、Java 中如何将字符串转换为整数? 102、在没有使用临时变量的情况如何交换两个整数变量的值? 103、接口是什么?为什么要使用接口而不是直接使用具体类? 104、Java 中,抽象类与接口之间有什么不同? 105、除了单例模式,你在生产环境中还用过什么设计模式? 106、你能解释一下里氏替换原则吗? 107、什么情况下会违反迪米特法则?为什么会有这个问题? 108、适配器模式是什么?什么时候使用? 109、什么是“依赖注入”和“控制反转”?为什么有人使用? 110、抽象类是什么?它与接口有什么区别?你为什么要使用过抽象类? 111、构造器注入和 setter 依赖注入,那种方式更好? 112、依赖注入和工程模式之间有什么不同? 113、适配器模式和装饰器模式有什么区别? 114、适配器模式和代理模式之前有什么不同? 115、什么是模板方法模式? 本次更新81~115题的答案解析 81、说出几条 Java 中方法重载的最佳实践? 下面有几条可以遵循的方法重载的最佳实践来避免造成自动装箱的混乱。a)不要重载这样的方法:一个方法接收 int 参数,而另个方法接收 Integer 参数。b)不要重载参数数量一致,而只是参数顺序不同的方法。c)如果重载的方法参数个数多于 5 个,采用可变参数。 82、在多线程环境下,SimpleDateFormat 是线程安全的吗? 不是,非常不幸,DateFormat 的所有实现,包括 SimpleDateFormat 都不是线程安全的,因此你不应该在多线程序中使用,除非是在对外线程安全的环境中使用,如 将 SimpleDateFormat 限制在ThreadLocal 中。如果你不这么做,在解析或者格式化日期的时候,可能会获取到一个不正确的结果。因此,从日期、时间处理的所有实践来说,我强力推荐 joda-time 库。 83、Java 中如何格式化一个日期?如格式化为 ddMMyyyy的形式? Java 中,可以使用 SimpleDateFormat 类或者 joda-time 库来格式日期。DateFormat 类允许你使用多种流行的格式来格式化日期。参见答案中的示例代码,代码中演示了将日期格式化成不同的格式,如 dd-MM-yyyy 或 ddMMyyyy。 84、Java 中,怎么在格式化的日期中显示时区? 使用SimpleDateFormat来实现格式化日期,但是DateFormat 的所有实现,包括 SimpleDateFormat 都不是线程安全的,因此你不应该在多线程序中使用,除非是在对外线程安全的环境中使用,如将SimpleDateFormat 限制在 ThreadLocal 中。如果你不这么做,在解析或者格式化日期的时候,可能会获取到一个不正确的结果。因此,从日期、时间处理的所有实践来说,强力推荐 joda-time 库。 85、Java 中 java.util.Date 与 java.sql.Date 有什么区别? 86、Java 中,如何计算两个日期之间的差距? 87、Java 中,如何将字符串 YYYYMMDD 转换为日期? 89、如何测试静态方法? 可以使用 PowerMock 库来测试静态方法。 90、怎么利用 JUnit 来测试一个方法的异常? 对需要测试异常的代码使用try,catch语句块。比如:public void testException(){try{Long.parseLong(null);} catch(NumberFormatException expected){}}然后使用Junit的fail函数,对于没有抛出预期异常的代码 91、你使用过哪个单元测试库来测试你的 Java 程序? 92、@Before 和 @BeforeClass 有什么区别? @Before :在每个测试方法之前都执行一次, 方法需要声明为public@beforeclass :只在类中执行一次, 必须声明为public static 93、怎么检查一个字符串只包含数字?解决方案 用Java自带的函数、用正则表达式、用ascii码判断 94、Java 中如何利用泛型写一个 LRU 缓存? 这是一种混合的数据结构,我们需要在哈希表的基础上建立一个链表。但是Java已经为我们提供了这种形式的数据结构-LinkedHashMap!它甚至提供可覆盖回收策略的方法。唯一需要我们注意的事情是,改链表的顺序是插入的顺序,而不是访问的顺序。但是,有一个构造函数提供了一个选项,可以使用访问的顺序。 95、写一段 Java 程序将 byte 转换为 long? 96、在不使用 StringBuffer 的前提下,怎么反转一个字符串? 97、Java 中,怎么获取一个文件中单词出现的最高频率? 这是一道算法面试题,Java中文的比较多。1、将文件内容存入String字符串中。2、利用split()函数分割字符串,因为直接替换英文空格或者,逗号分隔就可以了,中文类似,分隔得到一个数组。 3、遍历数组中所有的单词,统计结果Map 中,key=单词,value=单词出现的次数。 4、使用TreeSet类型,对Map中的结果进行排序,依据统计次数。5、输出最高的排序的前N名结果 98、如何检查出两个给定的字符串是反序的? 思路主要是,从开始字符,和另外一个从末尾字符比较,先判断长度是否相同,不同直接不可能反文。然后再比较。 99、Java 中,怎么打印出一个字符串的所有排列? 100、Java 中,怎样才能打印出数组中的重复元素? 101、Java 中如何将字符串转换为整数? String s="123";int i;第一种方法:i=Integer.parseInt(s);第二种方法:i=Integer.valueOf(s).intValue(); 102、在没有使用临时变量的情况如何交换两个整数变量的值? 加减法、乘除法、异或法。欢迎大家关注我的公种浩【程序员追风】,2019年多家公司java面试题整理了1000多道400多页pdf文档,文章都会在里面更新,整理的资料也会放在里面。 103、接口是什么?为什么要使用接口而不是直接使用具体类? 接口用于定义 API。它定义了类必须得遵循的规则。同时,它提供了一种抽象,因为客户端只使用接口,这样可以有多重实现,如 List 接口,你可以使用可随机访问的 ArrayList,也可以使用方便插入和删除的 LinkedList。接口中不允许写代码,以此来保证抽象,但是 Java 8 中你可以在接口声明静态的默认方法,这种方法是具体的。 104、Java 中,抽象类与接口之间有什么不同? Java 中,抽象类和接口有很多不同之处,但是最重要的一个是 Java 中限制一个类只能继承一个类,但是可以实现多个接口。抽象类可以很好的定义一个家族类的默认行为,而接口能更好的定义类型,有助于后面实现多态机制。 105、除了单例模式,你在生产环境中还用过什么设计模式? 这需要根据你的经验来回答。一般情况下,你可以说依赖注入,工厂模式,装饰模式或者观察者模式,随意选择你使用过的一种即可。不过你要准备回答接下的基于你选择的模式的问题。 106、你能解释一下里氏替换原则吗? 首先,这是编译器的要求,如果不这么做,无法通过编译。其次,面向对象的编程,其中继承有个大原则,任何子类的对象都可以当成父类的对象使用。 107、什么情况下会违反迪米特法则?为什么会有这个问题? 迪米特法则建议“只和朋友说话,不要陌生人说话”,以此来减少类之间的耦合。 108、适配器模式是什么?什么时候使用? 适配器模式提供对接口的转换。如果你的客户端使用某些接口,但是你有另外一些接口,你就可以写一个适配去来连接这些接口。 109、什么是“依赖注入”和“控制反转”?为什么有人使用? 控制反转(IOC)是 Spring 框架的核心思想,用我自己的话说,就是你要做一件事,别自己可劲 new 了,你就说你要干啥,然后外包出去就好~依赖注入(DI) 在我浅薄的想法中,就是通过接口的引用和构造方法的表达,将一些事情整好了反过来传给需要用到的地方~ 110、抽象类是什么?它与接口有什么区别?你为什么要使用过抽象类? a.接口用于规范,抽象类用于共性.b.声明方法的存在而不去实现它的类被叫做抽象类c.接口(interface)是抽象类的变体。在接口中,所有方法都是抽象的。 111、构造器注入和 setter 依赖注入,那种方式更好? 每种方式都有它的缺点和优点。构造器注入保证所有的注入都被初始化,但是setter 注入提供更好的灵活性来设置可选依赖。如果使用 XML 来描述依赖,Setter 注入的可读写会更强。经验法则是强制依赖使用构造器注入,可选依赖使用 setter 注入。 112、依赖注入和工程模式之间有什么不同? 虽然两种模式都是将对象的创建从应用的逻辑中分离,但是依赖注入比工程模式更清晰。通过依赖注入,你的类就是 POJO,它只知道依赖而不关心它们怎么获取。使用工厂模式,你的类需要通过工厂来获取依赖。因此,使用 DI 会比使用工厂模式更容易测试。 113、适配器模式和装饰器模式有什么区别? 虽然适配器模式和装饰器模式的结构类似,但是每种模式的出现意图不同。适配器模式被用于桥接两个接口,而装饰模式的目的是在不修改类的情况下给类增加新的功能。 114、适配器模式和代理模式之前有什么不同? 这个问题与前面的类似,适配器模式和代理模式的区别在于他们的意图不同。由于适配器模式和代理模式都是封装真正执行动作的类,因此结构是一致的,但是适配器模式用于接口之间的转换,而代理模式则是增加一个额外的中间层,以便支持分配、控制或智能访问。 115、什么是模板方法模式? 模板方法提供算法的框架,你可以自己去配置或定义步骤。例如,你可以将排序算法看做是一个模板。它定义了排序的步骤,但是具体的比较,可以使用Comparable 或者其语言中类似东西,具体策略由你去配置。列出算法概要的方法就是众所周知的模板方法。 最后 欢迎大家一起交流,喜欢文章记得关注我点个赞哟,感谢支持!

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

2019年总结:Java中高级面试题228道系列(6),查漏补缺!

2019年Java面试题中高级系列228道 Java面试题(一) 第一篇更新1~20题的答案解析 第二篇更新21~50题答案解析 第三篇更新51~95题答案解析 Java面试题(二) 第四篇更新1~20题答案解析 第五篇更新21~50题答案解析 Java面试题(二) 51、ArrayList 与 LinkedList 的不区别? 52、用哪两种方式来实现集合的排序? 53、Java 中怎么打印数组? 54、Java 中的 LinkedList 是单向链表还是双向链表? 55、Java 中的 TreeMap 是采用什么树实现的?(答案) 56、Hashtable 与 HashMap 有什么不同之处? 57、Java 中的 HashSet,内部是如何工作的? 58、写一段代码在遍历 ArrayList 时移除一个元素? 59、我们能自己写一个容器类,然后使用 for-each 循环码? 60、ArrayList 和 HashMap 的默认大小是多数? 61、有没有可能两个不相等的对象有有相同的 hashcode? 62、两个相同的对象会有不同的的 hash code 吗? 63、我们可以在 hashcode() 中使用随机数字吗? 64、Java 中,Comparator 与 Comparable 有什么不同? 66、在我 Java 程序中,我有三个 socket,我需要多少个线程来处理? 67、Java 中怎么创建 ByteBuffer? 68、Java 中,怎么读写 ByteBuffer ? 69、Java 采用的是大端还是小端? 70、ByteBuffer 中的字节序是什么? 71、Java 中,直接缓冲区与非直接缓冲器有什么区别? 72、Java 中的内存映射缓存区是什么? 73、socket 选项 TCP NO DELAY 是指什么? 74、TCP 协议与 UDP 协议有什么区别? 75、Java 中,ByteBuffer 与 StringBuffer 有什么区别?(答案) 76、Java 中,编写多线程程序的时候你会遵循哪些最佳实践? 77、说出几点 Java 中使用 Collections 的最佳实践 78、说出至少 5 点在 Java 中使用线程的最佳实践。 79、说出 5 条 IO 的最佳实践(答案) 80、列出 5 个应该遵循的 JDBC 最佳实践 本篇更新21-50题的答案 51、ArrayList 与 LinkedList 的不区别? 最明显的区别是 ArrrayList 底层的数据结构是数组,支持随机访问,而LinkedList 的底层数据结构书链表,不支持随机访问。使用下标访问一个元素,ArrayList 的时间复杂度是 O(1),而 LinkedList 是 O(n)。 52、用哪两种方式来实现集合的排序? 你可以使用有序集合,如 TreeSet 或 TreeMap,你也可以使用有顺序的的集合,如 list,然后通过 Collections.sort() 来排序。 53、Java 中怎么打印数组? 你可以使用 Arrays.toString() 和 Arrays.deepToString() 方法来打印数组。由于数组没有实现 toString() 方法,所以如果将数组传递给 System.out.println()方法,将无法打印出数组的内容,但是 Arrays.toString() 可以打印每个元素。 54、Java 中的 LinkedList 是单向链表还是双向链表? 是双向链表,你可以检查 JDK 的源码。在 Eclipse,你可以使用快捷键 Ctrl + T,直接在编辑器中打开该类。 55、Java 中的 TreeMap 是采用什么树实现的? Java 中的 TreeMap 是使用红黑树实现的。 56、Hashtable 与 HashMap 有什么不同之处? 这两个类有许多不同的地方,下面列出了一部分:a) Hashtable 是 JDK 1 遗留下来的类,而 HashMap 是后来增加的。b)Hashtable 是同步的,比较慢,但 HashMap 没有同步策略,所以会更快。c)Hashtable 不允许有个空的 key,但是 HashMap 允许出现一个 null key。 57、Java 中的 HashSet,内部是如何工作的? HashSet 的内部采用 HashMap 来实现。由于 Map 需要 key 和 value,所以所有 key 的都有一个默认 value。类似于 HashMap,HashSet 不允许重复的key,只允许有一个 null key,意思就是 HashSet 中只允许存储一个 null 对象。 58、写一段代码在遍历 ArrayList 时移除一个元素? 该问题的关键在于面试者使用的是 ArrayList 的 remove() 还是 Iterator 的remove()方法。这有一段示例代码,是使用正确的方式来实现在遍历的过程中移除元素,而不会出现 ConcurrentModificationException 异常的示例代码。 59、我们能自己写一个容器类,然后使用 for-each 循环码? 可以,你可以写一个自己的容器类。如果你想使用 Java 中增强的循环来遍历,你只需要实现 Iterable 接口。如果你实现 Collection 接口,默认就具有该属性。 60、ArrayList 和 HashMap 的默认大小是多数? 在 Java 7 中,ArrayList 的默认大小是 10 个元素,HashMap 的默认大小是16 个元素(必须是 2 的幂)。这就是 Java 7 中 ArrayList 和 HashMap 类的代码片段: // from ArrayList.java JDK 1.7 private static final int DEFAULT_CAPACITY = 10; //from HashMap.java JDK 7 static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16 61、有没有可能两个不相等的对象有有相同的 hashcode? 有可能,两个不相等的对象可能会有相同的 hashcode 值,这就是为什么在hashmap 中会有冲突。相等 hashcode 值的规定只是说如果两个对象相等,必须有相同的 hashcode 值,但是没有关于不相等对象的任何规定。 62、两个相同的对象会有不同的的 hash code 吗? 不能,根据 hash code 的规定,这是不可能的。欢迎大家关注我的公种浩【程序员追风】,2019年多家公司java面试题整理了1000多道400多页pdf文档,文章都会在里面更新,整理的资料也会放在里面。 63、我们可以在 hashcode() 中使用随机数字吗? 不行,因为对象的 hashcode 值必须是相同的。参见答案获取更多关于 Java 中重写 hashCode() 方法的知识。 64、Java 中,Comparator 与 Comparable 有什么不同? Comparable 接口用于定义对象的自然顺序,而 comparator 通常用于定义用户定制的顺序。Comparable 总是只有一个,但是可以有多个 comparator 来定义对象的顺序。 65、为什么在重写 equals 方法的时候需要重写 hashCode 方法? 因为有强制的规范指定需要同时重写 hashcode 与 equal 是方法,许多容器类,如 HashMap、HashSet 都依赖于 hashcode 与 equals 的规定。 66、在我 Java 程序中,我有三个 socket,我需要多少个线程来处理? 这个需要看你是并行处理还是串行处理了。 67、Java 中怎么创建 ByteBuffer? byte[] bytes = new byte[10]; ByteBuffer buf = ByteBuffer.wrap(bytes) ;``` 68、Java 中,怎么读写 ByteBuffer ? 69、Java 采用的是大端还是小端? 70、ByteBuffer 中的字节序是什么? 71、Java 中,直接缓冲区与非直接缓冲器有什么区别? 72、Java 中的内存映射缓存区是什么? 73、socket 选项 TCP NO DELAY 是指什么? 74、TCP 协议与 UDP 协议有什么区别? 75、Java 中,ByteBuffer 与 StringBuffer 有什么区别? # 76、Java 中,编写多线程程序的时候你会遵循哪些最佳实践? a)给线程命名,这样可以帮助调试。 b)最小化同步的范围,而不是将整个方法同步,只对关键部分做同步。 c)如果可以,更偏向于使用 volatile 而不是 synchronized。 d)使用更高层次的并发工具,而不是使用 wait() 和 notify() 来实现线程间通信,如 BlockingQueue,CountDownLatch 及 Semeaphore。 e)优先使用并发集合,而不是对集合进行同步。并发集合提供更好的可扩展性。 77、说出几点 Java 中使用 Collections 的最佳实践 a)使用正确的集合类,例如,如果不需要同步列表,使用 ArrayList 而不是Vector。 b)优先使用并发集合,而不是对集合进行同步。并发集合提供更好的可扩展性。 c)使用接口代表和访问集合,如使用 List 存储 ArrayList,使用 Map 存储HashMap 等等。 d)使用迭代器来循环集合。 e)使用集合的时候使用泛型。 # 78、说出至少 5 点在 Java 中使用线程的最佳实践。 这个问题与之前的问题类似,你可以使用上面的答案。对线程来说,你应该: a)对线程命名 b)将线程和任务分离,使用线程池执行器来执行 Runnable 或 Callable。 c)使用线程池 # 79、说出 5 条 IO 的最佳实践 IO 对 Java 应用的性能非常重要。理想情况下,你不应该在你应用的关键路径上避免 IO 操作。下面是一些你应该遵循的 Java IO 最佳实践: a)使用有缓冲区的 IO 类,而不要单独读取字节或字符。 b)使用 NIO 和 NIO2 c)在 finally 块中关闭流,或者使用 try-with-resource 语句。 d)使用内存映射文件获取更快的 IO。 # 80、列出 5 个应该遵循的 JDBC 最佳实践 有很多的最佳实践,你可以根据你的喜好来例举。下面是一些更通用的原则: a)使用批量的操作来插入和更新数据 b)使用 PreparedStatement 来避免 SQL 异常,并提高性能。 c)使用数据库连接池 d)通过列名来获取结果集,不要使用列的下标来获取。 # 最后 欢迎大家一起交流,喜欢文章记得点个赞哟,感谢支持!

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

斯诺登说Allo并不安全:FBI随时能查你的聊天记录

Google 最近在 Android 和 iOS 平台上同时推出了一款智能 IM 应用 Allo,该应用结合了 Google Assistant 语音助手和图像识别等人工智能技术,并很快就获得大批用户。但这一 Android 7.0 上的官方 IM 应用也引发了人们对于信息安全的担忧,例如“棱镜们”事件的曝光者,现在旅居俄罗斯的爱德华·斯诺登。 斯诺登最近在 Twitter上发文称:“什么是 Allo?就是一个 Google 用来记录你发送的每条信息的 App,并根据要求将它们提供给警方。” 斯诺登的此番言论还是有依据的。跟 WhatsApp 和苹果的 iMessage 等 IM 应用不同,用户在 Google Allo 上发送的信息将会被存储到 Google 的服务器上,因为 Google 认为用户发送的信息可以用来训练 Google 的机器学习系统,让系统帮助用户作出更合理的回复。 作为一款 IM 应用,Allo 的主要卖点是“智能聊天”。它不仅能让用户与朋友保持联系,还能在应用内搜索信息,并能让用户在聊天时得到人工智能的帮助。例如 Allo 能够自动分析当前对话的上下文和图片信息,自动帮助准备好可能会回复的信息。这个智能回复的功能在手机上无法完成的,需要服务器端的算法进行分析,因此 Allo 需要把信息上传到服务器上。苹果的 Siri 智能语音助手也采用了这个原理,将用户的语音信息上传到云端进行处理,但苹果承诺不会储存用户的语音信息。 在今年 5 月份的 Google I/O 开发者大会上 Google 就已经承认了这一点,但它同时也承诺用户发送的信息只会“短暂”地存储在 Google 的服务器上,并且数据的传输和存储方式都是加密的,同时用户可以选择删除这些信息。 但目前主流的 IM 应用,例如 WhatsApp、iMessage 和微信等都采用了端对端的加密传输方式,也就是说一个用户发送的信息将直接传输给其他另一个用户,信息并不会被存储在提供商的服务器上。 Google Allo 这种将用户发送的信息存储在服务器的做法引发了大量批评,因为这完全与目前的主流信息服务商的隐私策略不符,而且也不符合 Google 一贯的价值观。 另外,斯诺登还担忧警察能够随时查询用户的聊天信息,这也是有可能发生的。例如在美国,FBI 和 NSA 等机构是可以通过“美国外国情报监视法庭”(US foreignintelligence surveillance court)来像科技公司提交数据查阅申请的。根据 Facebook和 Google 等公司披露的数据,仅在 2015 年上述机构就已经发出了超过 1500 份数据拦截申请。 不过在中国,将用户的数据存储在服务器上是官方强制施行的。今年 6 月国家网信办发布了一份《移动互联网应用程序信息服务管理规定》,规定 APP 提供者应当严格落实信息安全管理责任,依法履行“对注册用户进行基于移动电话号码等真实身份信息认证”“记录用户日志信息,并保存六十日”等义务。 “现在我们可以免费下载 Google 邮箱,Google 地图,接下来就是 Google 监控了,这就是 Allo。不要使用 Allo!”斯诺登在 Twitter 上这样警告道。 本文转自d1net(转载)

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

手把手学IOT服务端API编程[8、按设备名查信息]|MVP讲堂

作者:阿里云MVP洵云 上节回顾:手把手学IOT服务端API编程[7、查询设备申请信息]|MVP精选 上节介绍设备申请 信息 查询后,其实在实际使用过程中,有些用户在设备 注册 完成后,有时候用户还需要通过产品key值和设备名称来查询设备的信息,在这种情况下 服务 端提供了相应的 API 接口供用户调用,从而做 自 己的应用;本节就对于有这种需求的情况,如何通过服务端提供接口来实现相应的功能; 接下来我们看一下具体实现; 1、脚本实现: 我们按照接口的要求,在框架页面上,提供产品的key值和设备名称这两个个输入 参数 框给用户输入; 产品KEY:<input type="text" name="pkey6"> 设备名称:<input type="text" name="devname6"> 而在实际的实现代码中,我

资源下载

更多资源
腾讯云软件源

腾讯云软件源

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

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

Sublime Text

Sublime Text

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

用户登录
用户注册