• 关于 单处理器结构会出现哪些问题 的搜索结果

回答

计算机科学与技术专业课程 课程简介 1.数字逻辑电路: “数字逻辑”是计算机专业本科生的一门主要课程,具有自身的理论体系和很强的实践性。它是计算机组成原理的主要先导课程之一,是计算机应用专业关于计算机系统结构方面的主干课程之一。 课程的主要目的是使学生了解和掌握从对数字系统提出要求开始,一直到用集成电路实现所需逻辑功能为止的整个过程的完整知识。内容有数制和编码、布尔代数和逻辑函数、组合逻辑电路的分析和设计,时序逻辑电路的分析和设计,中、大规模集成电路的应用。通过对该课程的学习,可以为计算机组成原理、微型计算机技术、计算机系统结构等课程打下坚实的基础。 2.计算机组成原理: 本课程是计算机系本科生的一门重要专业基础课。在各门硬件课程中占有举足轻重的地位。它的先修课程是《数字逻辑电路》,后继课程有《微机接口技术》、《计算机系统结构》。从课程地位来说,本课程在先修课和后继课中起着承上启下的作用。主要讲解计算机五大部件的组成及工作原理,逻辑设计与实现方法,整机的互连技术,培养学生具有初步的硬件系统分析、设计、开发和使用的能力。具体内容包括:数制与码制、基本逻辑部件、运算方法与运算器、指令系统与寻址方式,中央处理器(CPU)的工作原理及设计方法。存储系统和输入/输出(I/O)系统等。通过该课程的学习,可以使学生较深地掌握单台计算机的组成及工作原理,进一步加深对先修课程的综合理解及灵活应用,为后继课程的学习建立坚实的基础知识。 3.微机接口技术: 本课程是计算机科学与技术专业学生必修的核心课程之一,它的先修课程为数字逻辑、计算机组成原理。本课程对于训练学生掌握硬件接口设计技术,熟悉微处理器和各种接口芯片的硬件设计和软件调试技术都有重要作用,在软件方面要求掌握汇编语言,在硬件方面要掌握中断、DMA、计数器/定时器等设计技术。通过该课程的学习使学生学会微机接口设计的基本方法和技能。 4.计算机系统结构: 计算机系统结构主要是研究高性能计算机组织与结构的课程。主要包括:计算机系统结构的基本概念、指令的流水处理与向量计算机、高性能微处理器技术、并行处理机结构及算法和多处理机技术。结合现代计算机系统结构的新发展,介绍近几年来计算机系统结构所出现的一些新概念和新技术。 5.数据库概论: 数据库已是计算机系本科生不可缺少的专业基础课,它是计算机应用的重要支柱之一。该课程讲授数据库技术的特点,数据库系统的结构,三种典型数据模型及系统(以关系型系统为主)、数据库规范化理论,数据库的设计与管理,以及数据库技术的新进展等。通过本课程学习,掌握基本概念、理论和方法,学会使用数据库管理系统设计和建立数据库的初步能力,为以后实现一个数据库管理系统及进行系统的理论研究打下基础。 6.算法与数据结构: “数据结构”是计算机程序设计的重要理论技术基础,是计算机科学与技术专业的必修课,是计算机学科其它专业课的先修课程。通过学习本课程使学生掌握数据结构的基本逻辑结构和存储结构及其基本算法的设计方法,并在实际应用中能灵活使用。学会分析研究数据对象的特性,选择合适的逻辑结构、存储结构及设计相应的算法。初步掌握算法的时空分析技巧,同时进行程序设计训练。使学生学会应用抽象数据类型概念进行抽象设计。主要内容有:线性表、链表、栈、队列、数组、广义表、树与二叉树、图、查找、排序、内存管理、文件存储管理。 7.离散数学: “离散数学”是计算机科学与技术专业必修课程,其主要内容包括:命题逻辑;一阶命题逻辑;集合、关系与映射;代数系统、布尔代数 ;图论等。这些内容为学习计算机专业课程,如编译原理、数据结构提供重要的理论工具,同时也是计算机应用不可缺少的理论基础。 离散数学主要培养学生对事物的抽象思维能力和逻辑推理能力,为今后处理离散信息,从事计算机软件的开发和设计,以及计算机的其它实际应用打好数学基础。 8.操作系统: 操作系统是现代计算机系统中不可缺少的重要组成部分。它的先修课程是数据结构和计算机基础,在此基础上讲解操作系统的主要内容:CPU管理、存储器管理、作业管理、I/O设备管理和文件管理。这些基本原理告诉人们作为计算机系统中各种资源的管理者和各种活动的组织者、指挥者,操作系统是如何使整个计算机系统有条不率地高效工作,以及它为用户使用计算机系统提供了哪些便利手段。掌握了这些知识,人们就会对计算机系统的总体框架、工作流程和使用方法有了一个全面的认识,就会清楚后续专业课程所述内容在计算机系统中所处的地位和作用,这样不仅便于理解后续课程内容,而且能使人们把计算机的各部分知识有机地联系起来。此外,由于多处理机系统和计算机网络的盛行,本课程中也包含了对多处理机操作系统和网络操作系统的概述,从而使学习者可以跟上计算机技术的发展速度。 9.数据通信与计算机网: 该课程主要介绍网络基本理论和网络最新实用技术,分基础理论、实用技术和新技术三部分进行讲述。主要讲解计算机网络的功能和组成,数据传输,链路控制,多路复用,差错检测,网络体系结构,网络分层协议及局域网、广域网等。要求学生掌握数据通信的基本原理和计算机网络的体系结构,打下坚实的理论基础,培养实际应用的能力,为今后从事计算机网络的科研和设计工作打下基础。 10.高级语言程序设计: 本课程介绍了C与C++的全集。它从语法入手,同时强调程序设计的基本方法,以使学生能在较短的时间内,掌握C语言的结构化程序设计方法与C++语言的面向对象程序设计方法。主要内容有:1、过程初步;2、过程组织和管理;3、C++的数据类型;4、类与对象;5、继承;6、I/O流。 11.软件工程: 软件工程课程是计算机专业的一门主要专业课程,是培养高水平软件研制和开发人员的一门重程。该课程主要介绍软件工程的概念、原理及典型的方法技术,进述软件生存周期各阶段的任务、过程、方法和工具,讨论了软件工程使用的科学管理技术。 12.数据库应用: 通过实践方式使学生进一步掌握数据库知识和技术,掌握C/S(客户/服务)模式下的大型数据库的设计与实现,培养同行间的合作精神,学习应用合作方法。 13.软件编程实践: 主要介绍最新的常规的软件编程平台、工具和方法。本课程面向应用技术和实用技术,培养学生自学新技术的能力,在WINDOWS下的综合编程能力,实际解决问题能力。 14.计算机网络工程: 计算机技术与通信技术相结合导致了计算机网络的产生。计算机网络已成为当今大型信息系统的基础。-------------------------高等数学、大学英语、概率统计、离散数学、电路、模拟电子、数字电子、数据结构、操作系统、编译原理、计算机网络、数据库原理、软件工程、汇编语言、C++程序设计、接口技术、Java、VC++、计算机病毒分析、信息安全、等。 高数学的是微积分,线性代数,概率论与数理统计。英语是大学英语上下。还有就是专业的计算机知识,数据分析,c语言,java,还有计算机的系统分析,各种软件技术,学会写代码,程序等。

琴瑟 2019-12-02 01:22:34 0 浏览量 回答数 0

回答

一、基础篇 1.1、Java基础 面向对象的特征:继承、封装和多态 final, finally, finalize 的区别 Exception、Error、运行时异常与一般异常有何异同 请写出5种常见到的runtime exception int 和 Integer 有什么区别,Integer的值缓存范围 包装类,装箱和拆箱 String、StringBuilder、StringBuffer 重载和重写的区别 抽象类和接口有什么区别 说说反射的用途及实现 说说自定义注解的场景及实现 HTTP请求的GET与POST方式的区别 Session与Cookie区别 列出自己常用的JDK包 MVC设计思想 equals与==的区别 hashCode和equals方法的区别与联系 什么是Java序列化和反序列化,如何实现Java序列化?或者请解释Serializable 接口的作用 Object类中常见的方法,为什么wait notify会放在Object里边? Java的平台无关性如何体现出来的 JDK和JRE的区别 Java 8有哪些新特性 1.2、Java常见集合 List 和 Set 区别 Set和hashCode以及equals方法的联系 List 和 Map 区别 Arraylist 与 LinkedList 区别 ArrayList 与 Vector 区别 HashMap 和 Hashtable 的区别 HashSet 和 HashMap 区别 HashMap 和 ConcurrentHashMap 的区别 HashMap 的工作原理及代码实现,什么时候用到红黑树 多线程情况下HashMap死循环的问题 HashMap出现Hash DOS攻击的问题 ConcurrentHashMap 的工作原理及代码实现,如何统计所有的元素个数 手写简单的HashMap 看过那些Java集合类的源码 1.3、进程和线程 线程和进程的概念、并行和并发的概念 创建线程的方式及实现 进程间通信的方式 说说 CountDownLatch、CyclicBarrier 原理和区别 说说 Semaphore 原理 说说 Exchanger 原理 ThreadLocal 原理分析,ThreadLocal为什么会出现OOM,出现的深层次原理 讲讲线程池的实现原理 线程池的几种实现方式 线程的生命周期,状态是如何转移的 可参考:《Java多线程编程核心技术》 1.4、锁机制 说说线程安全问题,什么是线程安全,如何保证线程安全 重入锁的概念,重入锁为什么可以防止死锁 产生死锁的四个条件(互斥、请求与保持、不剥夺、循环等待) 如何检查死锁(通过jConsole检查死锁) volatile 实现原理(禁止指令重排、刷新内存) synchronized 实现原理(对象监视器) synchronized 与 lock 的区别 AQS同步队列 CAS无锁的概念、乐观锁和悲观锁 常见的原子操作类 什么是ABA问题,出现ABA问题JDK是如何解决的 乐观锁的业务场景及实现方式 Java 8并法包下常见的并发类 偏向锁、轻量级锁、重量级锁、自旋锁的概念 可参考:《Java多线程编程核心技术》 1.5、JVM JVM运行时内存区域划分 内存溢出OOM和堆栈溢出SOE的示例及原因、如何排查与解决 如何判断对象是否可以回收或存活 常见的GC回收算法及其含义 常见的JVM性能监控和故障处理工具类:jps、jstat、jmap、jinfo、jconsole等 JVM如何设置参数 JVM性能调优 类加载器、双亲委派模型、一个类的生命周期、类是如何加载到JVM中的 类加载的过程:加载、验证、准备、解析、初始化 强引用、软引用、弱引用、虚引用 Java内存模型JMM 1.6、设计模式 常见的设计模式 设计模式的的六大原则及其含义 常见的单例模式以及各种实现方式的优缺点,哪一种最好,手写常见的单利模式 设计模式在实际场景中的应用 Spring中用到了哪些设计模式 MyBatis中用到了哪些设计模式 你项目中有使用哪些设计模式 说说常用开源框架中设计模式使用分析 动态代理很重要!!! 1.7、数据结构 树(二叉查找树、平衡二叉树、红黑树、B树、B+树) 深度有限算法、广度优先算法 克鲁斯卡尔算法、普林母算法、迪克拉斯算法 什么是一致性Hash及其原理、Hash环问题 常见的排序算法和查找算法:快排、折半查找、堆排序等 1.8、网络/IO基础 BIO、NIO、AIO的概念 什么是长连接和短连接 Http1.0和2.0相比有什么区别,可参考《Http 2.0》 Https的基本概念 三次握手和四次挥手、为什么挥手需要四次 从游览器中输入URL到页面加载的发生了什么?可参考《从输入URL到页面加载发生了什么》 二、数据存储和消息队列 2.1、数据库 MySQL 索引使用的注意事项 DDL、DML、DCL分别指什么 explain命令 left join,right join,inner join 数据库事物ACID(原子性、一致性、隔离性、持久性) 事物的隔离级别(读未提交、读以提交、可重复读、可序列化读) 脏读、幻读、不可重复读 数据库的几大范式 数据库常见的命令 说说分库与分表设计 分库与分表带来的分布式困境与应对之策(如何解决分布式下的分库分表,全局表?) 说说 SQL 优化之道 MySQL遇到的死锁问题、如何排查与解决 存储引擎的 InnoDB与MyISAM区别,优缺点,使用场景 索引类别(B+树索引、全文索引、哈希索引)、索引的原理 什么是自适应哈希索引(AHI) 为什么要用 B+tree作为MySQL索引的数据结构 聚集索引与非聚集索引的区别 遇到过索引失效的情况没,什么时候可能会出现,如何解决 limit 20000 加载很慢怎么解决 如何选择合适的分布式主键方案 选择合适的数据存储方案 常见的几种分布式ID的设计方案 常见的数据库优化方案,在你的项目中数据库如何进行优化的 2.2、Redis Redis 有哪些数据类型,可参考《Redis常见的5种不同的数据类型详解》 Redis 内部结构 Redis 使用场景 Redis 持久化机制,可参考《使用快照和AOF将Redis数据持久化到硬盘中》 Redis 集群方案与实现 Redis 为什么是单线程的? 缓存雪崩、缓存穿透、缓存预热、缓存更新、缓存降级 使用缓存的合理性问题 Redis常见的回收策略 2.3、消息队列 消息队列的使用场景 消息的重发补偿解决思路 消息的幂等性解决思路 消息的堆积解决思路 自己如何实现消息队列 如何保证消息的有序性 三、开源框架和容器 3.1、SSM/Servlet Servlet的生命周期 转发与重定向的区别 BeanFactory 和 ApplicationContext 有什么区别 Spring Bean 的生命周期 Spring IOC 如何实现 Spring中Bean的作用域,默认的是哪一个 说说 Spring AOP、Spring AOP 实现原理 动态代理(CGLib 与 JDK)、优缺点、性能对比、如何选择 Spring 事务实现方式、事务的传播机制、默认的事务类别 Spring 事务底层原理 Spring事务失效(事务嵌套),JDK动态代理给Spring事务埋下的坑,可参考《JDK动态代理给Spring事务埋下的坑!》 如何自定义注解实现功能 Spring MVC 运行流程 Spring MVC 启动流程 Spring 的单例实现原理 Spring 框架中用到了哪些设计模式 Spring 其他产品(Srping Boot、Spring Cloud、Spring Secuirity、Spring Data、Spring AMQP 等) 有没有用到Spring Boot,Spring Boot的认识、原理 MyBatis的原理 可参考《为什么会有Spring》 可参考《为什么会有Spring AOP》 3.2、Netty 为什么选择 Netty 说说业务中,Netty 的使用场景 原生的 NIO 在 JDK 1.7 版本存在 epoll bug 什么是TCP 粘包/拆包 TCP粘包/拆包的解决办法 Netty 线程模型 说说 Netty 的零拷贝 Netty 内部执行流程 Netty 重连实现 3.3、Tomcat Tomcat的基础架构(Server、Service、Connector、Container) Tomcat如何加载Servlet的 Pipeline-Valve机制 可参考:《四张图带你了解Tomcat系统架构!》 四、分布式 4.1、Nginx 请解释什么是C10K问题或者知道什么是C10K问题吗? Nginx简介,可参考《Nginx简介》 正向代理和反向代理. Nginx几种常见的负载均衡策略 Nginx服务器上的Master和Worker进程分别是什么 使用“反向代理服务器”的优点是什么? 4.2、分布式其他 谈谈业务中使用分布式的场景 Session 分布式方案 Session 分布式处理 分布式锁的应用场景、分布式锁的产生原因、基本概念 分布是锁的常见解决方案 分布式事务的常见解决方案 集群与负载均衡的算法与实现 说说分库与分表设计,可参考《数据库分库分表策略的具体实现方案》 分库与分表带来的分布式困境与应对之策 4.3、Dubbo 什么是Dubbo,可参考《Dubbo入门》 什么是RPC、如何实现RPC、RPC 的实现原理,可参考《基于HTTP的RPC实现》 Dubbo中的SPI是什么概念 Dubbo的基本原理、执行流程 五、微服务 5.1、微服务 前后端分离是如何做的? 微服务哪些框架 Spring Could的常见组件有哪些?可参考《Spring Cloud概述》 领域驱动有了解吗?什么是领域驱动模型?充血模型、贫血模型 JWT有了解吗,什么是JWT,可参考《前后端分离利器之JWT》 你怎么理解 RESTful 说说如何设计一个良好的 API 如何理解 RESTful API 的幂等性 如何保证接口的幂等性 说说 CAP 定理、BASE 理论 怎么考虑数据一致性问题 说说最终一致性的实现方案 微服务的优缺点,可参考《微服务批判》 微服务与 SOA 的区别 如何拆分服务、水平分割、垂直分割 如何应对微服务的链式调用异常 如何快速追踪与定位问题 如何保证微服务的安全、认证 5.2、安全问题 如何防范常见的Web攻击、如何方式SQL注入 服务端通信安全攻防 HTTPS原理剖析、降级攻击、HTTP与HTTPS的对比 5.3、性能优化 性能指标有哪些 如何发现性能瓶颈 性能调优的常见手段 说说你在项目中如何进行性能调优 六、其他 6.1、设计能力 说说你在项目中使用过的UML图 你如何考虑组件化、服务化、系统拆分 秒杀场景如何设计 可参考:《秒杀系统的技术挑战、应对策略以及架构设计总结一二!》 6.2、业务工程 说说你的开发流程、如何进行自动化部署的 你和团队是如何沟通的 你如何进行代码评审 说说你对技术与业务的理解 说说你在项目中遇到感觉最难Bug,是如何解决的 介绍一下工作中的一个你认为最有价值的项目,以及在这个过程中的角色、解决的问题、你觉得你们项目还有哪些不足的地方 6.3、软实力 说说你的优缺点、亮点 说说你最近在看什么书、什么博客、在研究什么新技术、再看那些开源项目的源代码 说说你觉得最有意义的技术书籍 工作之余做什么事情、平时是如何学习的,怎样提升自己的能力 说说个人发展方向方面的思考 说说你认为的服务端开发工程师应该具备哪些能力 说说你认为的架构师是什么样的,架构师主要做什么 如何看待加班的问题

徐刘根 2020-03-31 11:22:08 0 浏览量 回答数 0

问题

Vue面试题汇总【精品问答】

问问小秘 2020-05-25 18:02:28 7911 浏览量 回答数 2

新用户福利专场,云服务器ECS低至96.9元/年

新用户福利专场,云服务器ECS低至96.9元/年

问题

【精品问答】带你进入数据库领域

谙忆 2020-04-07 20:45:48 12 浏览量 回答数 1

问题

分布式事务了解吗?你们是如何解决分布式事务问题的?【Java问答学堂】58期

剑曼红尘 2020-07-16 15:11:28 5 浏览量 回答数 1

问题

【精品问答】前端开发必懂之JS技术二百问

茶什i 2019-12-01 22:05:04 146 浏览量 回答数 0

问题

【精品问答】Java技术1000问(1)

问问小秘 2019-12-01 21:57:43 35864 浏览量 回答数 11

问题

剖析短视频分发过程中的用户体验优化技术点

樰篱 2019-12-01 21:50:09 2644 浏览量 回答数 0

回答

1 js 的基本数据类型? 2 JavaScript 有几种类型的值? 3 什么是堆?什么是栈?它们之间有什么区别和联系? 4 内部属性 [Class] 是什么? 5 介绍 js 有哪些内置对象? 6 undefined 与 undeclared 的区别? 7 null 和 undefined 的区别? 8 如何获取安全的 undefined 值? 9 说几条写 JavaScript 的基本规范? 10 JavaScript 原型,原型链? 有什么特点? 11 js 获取原型的方法? 12 在 js 中不同进制数字的表示方式? 13 js 中整数的安全范围是多少? 14 typeof NaN 的结果是什么? 15 isNaN 和 Number.isNaN 函数的区别? 16 Array 构造函数只有一个参数值时的表现? 17 其他值到字符串的转换规则? 18 其他值到数字值的转换规则? 19 其他值到布尔类型的值的转换规则? 20 {} 和 [] 的 valueOf 和 toString 的结果是什么? 21 什么是假值对象? 22 ~ 操作符的作用? 23 解析字符串中的数字和将字符串强制类型转换为数字的返回结果都是数字,它们之间的区别是什么? 24 + 操作符什么时候用于字符串的拼接? 25 什么情况下会发生布尔值的隐式强制类型转换? 26 || 和 && 操作符的返回值? 27 Symbol 值的强制类型转换? 28 == 操作符的强制类型转换规则? 29 如何将字符串转化为数字,例如 '12.3b'? 30 如何将浮点数点左边的数每三位添加一个逗号,如 12000000.11 转化为『12,000,000.11』? 31 常用正则表达式? 32 生成随机数的各种方法? 33 如何实现数组的随机排序? 34 javascript 创建对象的几种方式? 35 JavaScript 继承的几种实现方式? 36 寄生式组合继承的实现? 37 Javascript 的作用域链? 38 谈谈 This 对象的理解。 39 eval 是做什么的? 40 什么是 DOM 和 BOM? 41 写一个通用的事件侦听器函数。 42 事件是什么?IE 与火狐的事件机制有什么区别? 如何阻止冒泡? 43 三种事件模型是什么? 44 事件委托是什么? 45 ['1', '2', '3'].map(parseInt) 答案是多少? 46 什么是闭包,为什么要用它? 47 javascript 代码中的 'use strict'; 是什么意思 ? 使用它区别是什么? 48 如何判断一个对象是否属于某个类? 49 instanceof 的作用? 50 new 操作符具体干了什么呢?如何实现? 51 Javascript 中,有一个函数,执行时对象查找时,永远不会去查找原型,这个函数是? 52 对于 JSON 的了解? 53 [].forEach.call($$(''),function(a){a.style.outline='1px solid #'+(~~(Math.random()(1<<24))).toString(16)}) 能解释一下这段代码的意思吗? 54 js 延迟加载的方式有哪些? 55 Ajax 是什么? 如何创建一个 Ajax? 56 谈一谈浏览器的缓存机制? 57 Ajax 解决浏览器缓存问题? 58 同步和异步的区别? 59 什么是浏览器的同源政策? 60 如何解决跨域问题? 61 服务器代理转发时,该如何处理 cookie? 62 简单谈一下 cookie ? 63 模块化开发怎么做? 64 js 的几种模块规范? 65 AMD 和 CMD 规范的区别? 66 ES6 模块与 CommonJS 模块、AMD、CMD 的差异。 67 requireJS 的核心原理是什么?(如何动态加载的?如何避免多次加载的?如何 缓存的?) 68 JS 模块加载器的轮子怎么造,也就是如何实现一个模块加载器? 69 ECMAScript6 怎么写 class,为什么会出现 class 这种东西? 70 documen.write 和 innerHTML 的区别? 71 DOM 操作——怎样添加、移除、移动、复制、创建和查找节点? 72 innerHTML 与 outerHTML 的区别? 73 .call() 和 .apply() 的区别? 74 JavaScript 类数组对象的定义? 75 数组和对象有哪些原生方法,列举一下? 76 数组的 fill 方法? 77 [,,,] 的长度? 78 JavaScript 中的作用域与变量声明提升? 79 如何编写高性能的 Javascript ? 80 简单介绍一下 V8 引擎的垃圾回收机制 81 哪些操作会造成内存泄漏? 82 需求:实现一个页面操作不会整页刷新的网站,并且能在浏览器前进、后退时正确响应。给出你的技术实现方案? 83 如何判断当前脚本运行在浏览器还是 node 环境中?(阿里) 84 把 script 标签放在页面的最底部的 body 封闭之前和封闭之后有什么区别?浏览器会如何解析它们? 85 移动端的点击事件的有延迟,时间是多久,为什么会有? 怎么解决这个延时? 86 什么是“前端路由”?什么时候适合使用“前端路由”?“前端路由”有哪些优点和缺点? 87 如何测试前端代码么? 知道 BDD, TDD, Unit Test 么? 知道怎么测试你的前端工程么(mocha, sinon, jasmin, qUnit..)? 88 检测浏览器版本版本有哪些方式? 89 什么是 Polyfill ? 90 使用 JS 实现获取文件扩展名? 91 介绍一下 js 的节流与防抖? 92 Object.is() 与原来的比较操作符 '==='、'==' 的区别? 93 escape,encodeURI,encodeURIComponent 有什么区别? 94 Unicode 和 UTF-8 之间的关系? 95 js 的事件循环是什么? 96 js 中的深浅拷贝实现? 97 手写 call、apply 及 bind 函数 98 函数柯里化的实现 99 99. 为什么 0.1 + 0.2 != 0.3?如何解决这个问题? 100 原码、反码和补码的介绍 101 toPrecision 和 toFixed 和 Math.round 的区别? 102 什么是 XSS 攻击?如何防范 XSS 攻击? 103 什么是 CSP? 104 什么是 CSRF 攻击?如何防范 CSRF 攻击? 105 什么是 Samesite Cookie 属性? 106 什么是点击劫持?如何防范点击劫持? 107 SQL 注入攻击? 108 什么是 MVVM?比之 MVC 有什么区别?什么又是 MVP ? 109 vue 双向数据绑定原理? 110 Object.defineProperty 介绍? 111 使用 Object.defineProperty() 来进行数据劫持有什么缺点? 112 什么是 Virtual DOM?为什么 Virtual DOM 比原生 DOM 快? 113 如何比较两个 DOM 树的差异? 114 什么是 requestAnimationFrame ? 115 谈谈你对 webpack 的看法 116 offsetWidth/offsetHeight,clientWidth/clientHeight 与 scrollWidth/scrollHeight 的区别? 117 谈一谈你理解的函数式编程? 118 异步编程的实现方式? 119 Js 动画与 CSS 动画区别及相应实现 120 get 请求传参长度的误区 121 URL 和 URI 的区别? 122 get 和 post 请求在缓存方面的区别 123 图片的懒加载和预加载 124 mouseover 和 mouseenter 的区别? 125 js 拖拽功能的实现 126 为什么使用 setTimeout 实现 setInterval?怎么模拟? 127 let 和 const 的注意点? 128 什么是 rest 参数? 129 什么是尾调用,使用尾调用有什么好处? 130 Symbol 类型的注意点? 131 Set 和 WeakSet 结构? 132 Map 和 WeakMap 结构? 133 什么是 Proxy ? 134 Reflect 对象创建目的? 135 require 模块引入的查找方式? 136 什么是 Promise 对象,什么是 Promises/A+ 规范? 137 手写一个 Promise 138 如何检测浏览器所支持的最小字体大小? 139 怎么做 JS 代码 Error 统计? 140 单例模式模式是什么? 141 策略模式是什么? 142 代理模式是什么? 143 中介者模式是什么? 144 适配器模式是什么? 145 观察者模式和发布订阅模式有什么不同? 146 Vue 的生命周期是什么? 147 Vue 的各个生命阶段是什么? 148 Vue 组件间的参数传递方式? 149 computed 和 watch 的差异? 150 vue-router 中的导航钩子函数 151 两个router 的区别? 152 vue 常用的修饰符? 153 computed 和 watch 区别? 154 keep-alive 组件有什么作用? 155 vue 中 mixin 和 mixins 区别? 156 开发中常用的几种 Content-Type ? 157 如何封装一个 javascript 的类型判断函数? 158 如何判断一个对象是否为空对象? 159 使用闭包实现每隔一秒打印 1,2,3,4 160 手写一个 jsonp 161 手写一个观察者模式? 162 EventEmitter 实现 163 一道常被人轻视的前端 JS 面试题 164 如何确定页面的可用性时间,什么是 Performance API? 165 js 中的命名规则 166 js 语句末尾分号是否可以省略? 167 Object.assign() 168 Math.ceil 和 Math.floor 169 js for 循环注意点 170 一个列表,假设有 100000 个数据,这个该怎么办? 171 js 中倒计时的纠偏实现? 172 进程间通信的方式? 173 如何查找一篇英文文章中出现频率最高的单词? 174 174道 JavaScript 面试题,合集

剑曼红尘 2020-04-02 14:05:35 0 浏览量 回答数 0

问题

Web测试方法

技术小菜鸟 2019-12-01 21:41:32 7022 浏览量 回答数 1

回答

在开始谈我对架构本质的理解之前,先谈谈对今天技术沙龙主题的个人见解,千万级规模的网站感觉数量级是非常大的,对这个数量级我们战略上 要重 视 它 , 战术上又 要 藐 视 它。先举个例子感受一下千万级到底是什么数量级?现在很流行的优步(Uber),从媒体公布的信息看,它每天接单量平均在百万左右, 假如每天有10个小时的服务时间,平均QPS只有30左右。对于一个后台服务器,单机的平均QPS可以到达800-1000,单独看写的业务量很简单 。为什么我们又不能说轻视它?第一,我们看它的数据存储,每天一百万的话,一年数据量的规模是多少?其次,刚才说的订单量,每一个订单要推送给附近的司机、司机要并发抢单,后面业务场景的访问量往往是前者的上百倍,轻松就超过上亿级别了。 今天我想从架构的本质谈起之后,希望大家理解在做一些建构设计的时候,它的出发点以及它解决的问题是什么。 架构,刚开始的解释是我从知乎上看到的。什么是架构?有人讲, 说架构并不是一 个很 悬 乎的 东西 , 实际 上就是一个架子 , 放一些 业务 和算法,跟我们的生活中的晾衣架很像。更抽象一点,说架构其 实 是 对 我 们 重复性业务 的抽象和我 们 未来 业务 拓展的前瞻,强调过去的经验和你对整个行业的预见。 我们要想做一个架构的话需要哪些能力?我觉得最重要的是架构师一个最重要的能力就是你要有 战 略分解能力。这个怎么来看呢: 第一,你必须要有抽象的能力,抽象的能力最基本就是去重,去重在整个架构中体现在方方面面,从定义一个函数,到定义一个类,到提供的一个服务,以及模板,背后都是要去重提高可复用率。 第二, 分类能力。做软件需要做对象的解耦,要定义对象的属性和方法,做分布式系统的时候要做服务的拆分和模块化,要定义服务的接口和规范。 第三, 算法(性能),它的价值体现在提升系统的性能,所有性能的提升,最终都会落到CPU,内存,IO和网络这4大块上。 这一页PPT举了一些例子来更深入的理解常见技术背后的架构理念。 第一个例子,在分布式系统我们会做 MySQL分 库 分表,我们要从不同的库和表中读取数据,这样的抽象最直观就是使用模板,因为绝大多数SQL语义是相同的,除了路由到哪个库哪个表,如果不使用Proxy中间件,模板就是性价比最高的方法。 第二看一下加速网络的CDN,它是做速度方面的性能提升,刚才我们也提到从CPU、内存、IO、网络四个方面来考虑,CDN本质上一个是做网络智能调度优化,另一个是多级缓存优化。 第三个看一下服务化,刚才已经提到了,各个大网站转型过程中一定会做服务化,其实它就是做抽象和做服务的拆分。第四个看一下消息队列,本质上还是做分类,只不过不是两个边际清晰的类,而是把两个边际不清晰的子系统通过队列解构并且异步化。新浪微博整体架构是什么样的 接下我们看一下微博整体架构,到一定量级的系统整个架构都会变成三层,客户端包括WEB、安卓和IOS,这里就不说了。接着还都会有一个接口层, 有三个主要作用: 第一个作用,要做 安全隔离,因为前端节点都是直接和用户交互,需要防范各种恶意攻击; 第二个还充当着一个 流量控制的作用,大家知道,在2014年春节的时候,微信红包,每分钟8亿多次的请求,其实真正到它后台的请求量,只有十万左右的数量级(这里的数据可能不准),剩余的流量在接口层就被挡住了; 第三,我们看对 PC 端和移 动 端的需求不一样的,所以我们可以进行拆分。接口层之后是后台,可以看到微博后台有三大块: 一个是 平台服 务, 第二, 搜索, 第三, 大数据。到了后台的各种服务其实都是处理的数据。 像平台的业务部门,做的就是 数据存储和读 取,对搜索来说做的是 数据的 检 索,对大数据来说是做的数据的 挖掘。微博其实和淘宝是很类似 微博其实和淘宝是很类似的。一般来说,第一代架构,基本上能支撑到用户到 百万 级别,到第二代架构基本能支撑到 千万 级别都没什么问题,当业务规模到 亿级别时,需要第三代的架构。 从 LAMP 的架构到面向服 务 的架构,有几个地方是非常难的,首先不可能在第一代基础上通过简单的修修补补满足用户量快速增长的,同时线上业务又不能停, 这是我们常说的 在 飞 机上 换 引擎的 问题。前两天我有一个朋友问我,说他在内部推行服务化的时候,把一个模块服务化做完了,其他部门就是不接。我建议在做服务化的时候,首先更多是偏向业务的梳理,同时要找准一个很好的切入点,既有架构和服务化上的提升,业务方也要有收益,比如提升性能或者降低维护成本同时升级过程要平滑,建议开始从原子化服务切入,比如基础的用户服务, 基础的短消息服务,基础的推送服务。 第二,就是可 以做无状 态 服 务,后面会详细讲,还有数据量大了后需要做数据Sharding,后面会将。 第三代 架构 要解决的 问题,就是用户量和业务趋于稳步增加(相对爆发期的指数级增长),更多考虑技术框架的稳定性, 提升系统整体的性能,降低成本,还有对整个系统监控的完善和升级。 大型网站的系统架构是如何演变的 我们通过通过数据看一下它的挑战,PV是在10亿级别,QPS在百万,数据量在千亿级别。我们可用性,就是SLA要求4个9,接口响应最多不能超过150毫秒,线上所有的故障必须得在5分钟内解决完。如果说5分钟没处理呢?那会影响你年终的绩效考核。2015年微博DAU已经过亿。我们系统有上百个微服务,每周会有两次的常规上线和不限次数的紧急上线。我们的挑战都一样,就是数据量,bigger and bigger,用户体验是faster and faster,业务是more and more。互联网业务更多是产品体验驱动, 技 术 在 产 品 体验上最有效的贡献 , 就是你的性能 越来越好 。 每次降低加载一个页面的时间,都可以间接的降低这个页面上用户的流失率。微博的技术挑战和正交分解法解析架构 下面看一下 第三代的 架构 图 以及 我 们 怎么用正交分解法 阐 述。 我们可以看到我们从两个维度,横轴和纵轴可以看到。 一个 维 度 是 水平的 分层 拆分,第二从垂直的维度会做拆分。水平的维度从接口层、到服务层到数据存储层。垂直怎么拆分,会用业务架构、技术架构、监控平台、服务治理等等来处理。我相信到第二代的时候很多架构已经有了业务架构和技术架构的拆分。我们看一下, 接口层有feed、用户关系、通讯接口;服务层,SOA里有基层服务、原子服务和组合服务,在微博我们只有原子服务和组合服务。原子服务不依赖于任何其他服务,组合服务由几个原子服务和自己的业务逻辑构建而成 ,资源层负责海量数据的存储(后面例子会详细讲)。技 术框架解决 独立于 业务 的海量高并发场景下的技术难题,由众多的技术组件共同构建而成 。在接口层,微博使用JERSY框架,帮助你做参数的解析,参数的验证,序列化和反序列化;资源层,主要是缓存、DB相关的各类组件,比如Cache组件和对象库组件。监 控平台和服 务 治理 , 完成系统服务的像素级监控,对分布式系统做提前诊断、预警以及治理。包含了SLA规则的制定、服务监控、服务调用链监控、流量监控、错误异常监控、线上灰度发布上线系统、线上扩容缩容调度系统等。 下面我们讲一下常见的设计原则。 第一个,首先是系统架构三个利器: 一个, 我 们 RPC 服 务组 件 (这里不讲了), 第二个,我们 消息中 间 件 。消息中间件起的作用:可以把两个模块之间的交互异步化,其次可以把不均匀请求流量输出为匀速的输出流量,所以说消息中间件 异步化 解耦 和流量削峰的利器。 第三个是配置管理,它是 代码级灰度发布以及 保障系统降级的利器。 第二个 , 无状态 , 接口 层 最重要的就是无状 态。我们在电商网站购物,在这个过程中很多情况下是有状态的,比如我浏览了哪些商品,为什么大家又常说接口层是无状态的,其实我们把状态从接口层剥离到了数据层。像用户在电商网站购物,选了几件商品,到了哪一步,接口无状态后,状态要么放在缓存中,要么放在数据库中, 其 实 它并不是没有状 态 , 只是在 这 个 过 程中我 们 要把一些有状 态 的 东 西抽离出来 到了数据层。 第三个, 数据 层 比服 务层 更需要 设计,这是一条非常重要的经验。对于服务层来说,可以拿PHP写,明天你可以拿JAVA来写,但是如果你的数据结构开始设计不合理,将来数据结构的改变会花费你数倍的代价,老的数据格式向新的数据格式迁移会让你痛不欲生,既有工作量上的,又有数据迁移跨越的时间周期,有一些甚至需要半年以上。 第四,物理结构与逻辑结构的映射,上一张图看到两个维度切成十二个区间,每个区间代表一个技术领域,这个可以看做我们的逻辑结构。另外,不论后台还是应用层的开发团队,一般都会分几个垂直的业务组加上一个基础技术架构组,这就是从物理组织架构到逻辑的技术架构的完美的映射,精细化团队分工,有利于提高沟通协作的效率 。 第五, www .sanhao.com 的访问过程,我们这个架构图里没有涉及到的,举个例子,比如当你在浏览器输入www.sanhao网址的时候,这个请求在接口层之前发生了什么?首先会查看你本机DNS以及DNS服务,查找域名对应的IP地址,然后发送HTTP请求过去。这个请求首先会到前端的VIP地址(公网服务IP地址),VIP之后还要经过负载均衡器(Nginx服务器),之后才到你的应用接口层。在接口层之前发生了这么多事,可能有用户报一个问题的时候,你通过在接口层查日志根本发现不了问题,原因就是问题可能发生在到达接口层之前了。 第六,我们说分布式系统,它最终的瓶颈会落在哪里呢?前端时间有一个网友跟我讨论的时候,说他们的系统遇到了一个瓶颈, 查遍了CPU,内存,网络,存储,都没有问题。我说你再查一遍,因为最终你不论用上千台服务器还是上万台服务器,最终系统出瓶颈的一定会落在某一台机(可能是叶子节点也可能是核心的节点),一定落在CPU、内存、存储和网络上,最后查出来问题出在一台服务器的网卡带宽上。微博多级双机房缓存架构 接下来我们看一下微博的Feed多级缓存。我们做业务的时候,经常很少做业务分析,技术大会上的分享又都偏向技术架构。其实大家更多的日常工作是需要花费更多时间在业务优化上。这张图是统计微博的信息流前几页的访问比例,像前三页占了97%,在做缓存设计的时候,我们最多只存最近的M条数据。 这里强调的就是做系统设计 要基于用 户 的 场 景 , 越细致越好 。举了一个例子,大家都会用电商,电商在双十一会做全国范围内的活动,他们做设计的时候也会考虑场景的,一个就是购物车,我曾经跟相关开发讨论过,购物车是在双十一之前用户的访问量非常大,就是不停地往里加商品。在真正到双十一那天他不会往购物车加东西了,但是他会频繁的浏览购物车。针对这个场景,活动之前重点设计优化购物车的写场景, 活动开始后优化购物车的读场景。 你看到的微博是由哪些部分聚合而成的呢?最右边的是Feed,就是微博所有关注的人,他们的微博所组成的。微博我们会按照时间顺序把所有关注人的顺序做一个排序。随着业务的发展,除了跟时间序相关的微博还有非时间序的微博,就是会有广告的要求,增加一些广告,还有粉丝头条,就是拿钱买的,热门微博,都会插在其中。分发控制,就是说和一些推荐相关的,我推荐一些相关的好友的微博,我推荐一些你可能没有读过的微博,我推荐一些其他类型的微博。 当然对非时序的微博和分发控制微博,实际会起多个并行的程序来读取,最后同步做统一的聚合。这里稍微分享一下, 从SNS社交领域来看,国内现在做的比较好的三个信息流: 微博 是 基于弱关系的媒体信息流 ; 朋友圈是基于 强 关系的信息流 ; 另外一个做的比 较 好的就是今日 头 条 , 它并不是基于关系来构建信息流 , 而是基于 兴趣和相关性的个性化推荐 信息流 。 信息流的聚合,体现在很多很多的产品之中,除了SNS,电商里也有信息流的聚合的影子。比如搜索一个商品后出来的列表页,它的信息流基本由几部分组成:第一,打广告的;第二个,做一些推荐,热门的商品,其次,才是关键字相关的搜索结果。 信息流 开始的时候 很 简单 , 但是到后期会 发现 , 你的 这 个流 如何做控制分发 , 非常复杂, 微博在最近一两年一直在做 这样 的工作。刚才我们是从业务上分析,那么技术上怎么解决高并发,高性能的问题?微博访问量很大的时候,底层存储是用MySQL数据库,当然也会有其他的。对于查询请求量大的时候,大家知道一定有缓存,可以复用可重用的计算结果。可以看到,发一条微博,我有很多粉丝,他们都会来看我发的内容,所以 微博是最适合使用 缓 存 的系统,微博的读写比例基本在几十比一。微博使用了 双 层缓 存,上面是L1,每个L1上都是一组(包含4-6台机器),左边的框相当于一个机房,右边又是一个机房。在这个系统中L1缓存所起的作用是什么? 首先,L1 缓 存增加整个系 统 的 QPS, 其次 以低成本灵活扩容的方式 增加 系统 的 带宽 。想象一个极端场景,只有一篇博文,但是它的访问量无限增长,其实我们不需要影响L2缓存,因为它的内容存储的量小,但它就是访问量大。这种场景下,你就需要使用L1来扩容提升QPS和带宽瓶颈。另外一个场景,就是L2级缓存发生作用,比如我有一千万个用户,去访问的是一百万个用户的微博 ,这个时候,他不只是说你的吞吐量和访问带宽,就是你要缓存的博文的内容也很多了,这个时候你要考虑缓存的容量, 第二 级缓 存更多的是从容量上来 规划,保证请求以较小的比例 穿透到 后端的 数据 库 中 ,根据你的用户模型你可以估出来,到底有百分之多少的请求不能穿透到DB, 评估这个容量之后,才能更好的评估DB需要多少库,需要承担多大的访问的压力。另外,我们看双机房的话,左边一个,右边一个。 两个机房是互 为 主 备 , 或者互 为热备 。如果两个用户在不同地域,他们访问两个不同机房的时候,假设用户从IDC1过来,因为就近原理,他会访问L1,没有的话才会跑到Master,当在IDC1没找到的时候才会跑到IDC2来找。同时有用户从IDC2访问,也会有请求从L1和Master返回或者到IDC1去查找。 IDC1 和 IDC2 ,两个机房都有全量的用户数据,同时在线提供服务,但是缓存查询又遵循最近访问原理。还有哪些多级缓存的例子呢?CDN是典型的多级缓存。CDN在国内各个地区做了很多节点,比如在杭州市部署一个节点时,在机房里肯定不止一台机器,那么对于一个地区来说,只有几台服务器到源站回源,其他节点都到这几台服务器回源即可,这么看CDN至少也有两级。Local Cache+ 分布式 缓 存,这也是常见的一种策略。有一种场景,分布式缓存并不适用, 比如 单 点 资 源 的爆发性峰值流量,这个时候使用Local Cache + 分布式缓存,Local Cache 在 应用 服 务 器 上用很小的 内存资源 挡住少量的 极端峰值流量,长尾的流量仍然访问分布式缓存,这样的Hybrid缓存架构通过复用众多的应用服务器节点,降低了系统的整体成本。 我们来看一下 Feed 的存 储 架构,微博的博文主要存在MySQL中。首先来看内容表,这个比较简单,每条内容一个索引,每天建一张表,其次看索引表,一共建了两级索引。首先想象一下用户场景,大部分用户刷微博的时候,看的是他关注所有人的微博,然后按时间来排序。仔细分析发现在这个场景下, 跟一个用户的自己的相关性很小了。所以在一级索引的时候会先根据关注的用户,取他们的前条微博ID,然后聚合排序。我们在做哈希(分库分表)的时候,同时考虑了按照UID哈希和按照时间维度。很业务和时间相关性很高的,今天的热点新闻,明天就没热度了,数据的冷热非常明显,这种场景就需要按照时间维度做分表,首先冷热数据做了分离(可以对冷热数据采用不同的存储方案来降低成本),其次, 很容止控制我数据库表的爆炸。像微博如果只按照用户维度区分,那么这个用户所有数据都在一张表里,这张表就是无限增长的,时间长了查询会越来越慢。二级索引,是我们里面一个比较特殊的场景,就是我要快速找到这个人所要发布的某一时段的微博时,通过二级索引快速定位。 分布式服务追踪系统 分布式追踪服务系统,当系统到千万级以后的时候,越来越庞杂,所解决的问题更偏向稳定性,性能和监控。刚才说用户只要有一个请求过来,你可以依赖你的服务RPC1、RPC2,你会发现RPC2又依赖RPC3、RPC4。分布式服务的时候一个痛点,就是说一个请求从用户过来之后,在后台不同的机器之间不停的调用并返回。 当你发现一个问题的时候,这些日志落在不同的机器上,你也不知道问题到底出在哪儿,各个服务之间互相隔离,互相之间没有建立关联。所以导致排查问题基本没有任何手段,就是出了问题没法儿解决。 我们要解决的问题,我们刚才说日志互相隔离,我们就要把它建立联系。建立联系我们就有一个请求ID,然后结合RPC框架, 服务治理功能。假设请求从客户端过来,其中包含一个ID 101,到服务A时仍然带有ID 101,然后调用RPC1的时候也会标识这是101 ,所以需要 一个唯一的 请求 ID 标识 递归迭代的传递到每一个 相关 节点。第二个,你做的时候,你不能说每个地方都加,对业务系统来说需要一个框架来完成这个工作, 这 个框架要 对业务 系 统 是最低侵入原 则 , 用 JAVA 的 话 就可以用 AOP,要做到零侵入的原则,就是对所有相关的中间件打点,从接口层组件(HTTP Client、HTTP Server)至到服务层组件(RPC Client、RPC Server),还有数据访问中间件的,这样业务系统只需要少量的配置信息就可以实现全链路监控 。为什么要用日志?服务化以后,每个服务可以用不同的开发语言, 考虑多种开发语言的兼容性 , 内部定 义标 准化的日志 是唯一且有效的办法。最后,如何构建基于GPS导航的路况监控?我们刚才讲分布式服务追踪。分布式服务追踪能解决的问题, 如果 单一用 户发现问题 后 , 可以通 过请 求 ID 快速找到 发 生 问题 的 节 点在什么,但是并没有解决如何发现问题。我们看现实中比较容易理解的道路监控,每辆车有GPS定位,我想看北京哪儿拥堵的时候,怎么做? 第一个 , 你肯定要知道每个 车 在什么位置,它走到哪儿了。其实可以说每个车上只要有一个标识,加上每一次流动的信息,就可以看到每个车流的位置和方向。 其次如何做 监 控和 报 警,我们怎么能了解道路的流量状况和负载,并及时报警。我们要定义这条街道多宽多高,单位时间可以通行多少辆车,这就是道路的容量。有了道路容量,再有道路的实时流量,我们就可以基于实习路况做预警? 对应于 分布式系 统 的话如何构建? 第一 , 你要 定义 每个服 务节 点它的 SLA A 是多少 ?SLA可以从系统的CPU占用率、内存占用率、磁盘占用率、QPS请求数等来定义,相当于定义系统的容量。 第二个 , 统计 线 上 动态 的流量,你要知道服务的平均QPS、最低QPS和最大QPS,有了流量和容量,就可以对系统做全面的监控和报警。 刚才讲的是理论,实际情况肯定比这个复杂。微博在春节的时候做许多活动,必须保障系统稳定,理论上你只要定义容量和流量就可以。但实际远远不行,为什么?有技术的因素,有人为的因素,因为不同的开发定义的流量和容量指标有主观性,很难全局量化标准,所以真正流量来了以后,你预先评估的系统瓶颈往往不正确。实际中我们在春节前主要采取了三个措施:第一,最简单的就是有降 级 的 预 案,流量超过系统容量后,先把哪些功能砍掉,需要有明确的优先级 。第二个, 线上全链路压测,就是把现在的流量放大到我们平常流量的五倍甚至十倍(比如下线一半的服务器,缩容而不是扩容),看看系统瓶颈最先发生在哪里。我们之前有一些例子,推测系统数据库会先出现瓶颈,但是实测发现是前端的程序先遇到瓶颈。第三,搭建在线 Docker 集群 , 所有业务共享备用的 Docker集群资源,这样可以极大的避免每个业务都预留资源,但是实际上流量没有增长造成的浪费。 总结 接下来说的是如何不停的学习和提升,这里以Java语言为例,首先, 一定要 理解 JAVA;第二步,JAVA完了以后,一定要 理 解 JVM;其次,还要 理解 操作系统;再次还是要了解一下 Design Pattern,这将告诉你怎么把过去的经验抽象沉淀供将来借鉴;还要学习 TCP/IP、 分布式系 统、数据结构和算法。

hiekay 2019-12-02 01:39:25 0 浏览量 回答数 0

问题

一般实现分布式锁都有哪些方式?使用 Redis 如何设计分布式锁?使用 zk 来设计分布式锁可以吗?

剑曼红尘 2020-07-14 09:42:35 19 浏览量 回答数 1

问题

Java技术1000问(3)【精品问答】

问问小秘 2020-06-02 14:27:10 42 浏览量 回答数 1

回答

微服务 (MicroServices) 架构是当前互联网业界的一个技术热点,圈里有不少同行朋友当前有计划在各自公司开展微服务化体系建设,他们都有相同的疑问:一个微服务架构有哪些技术关注点 (technical concerns)?需要哪些基础框架或组件来支持微服务架构?这些框架或组件该如何选型?笔者之前在两家大型互联网公司参与和主导过大型服务化体系和框架建设,同时在这块也投入了很多时间去学习和研究,有一些经验和学习心得,可以和大家一起分享。 服务注册、发现、负载均衡和健康检查和单块 (Monolithic) 架构不同,微服务架构是由一系列职责单一的细粒度服务构成的分布式网状结构,服务之间通过轻量机制进行通信,这时候必然引入一个服务注册发现问题,也就是说服务提供方要注册通告服务地址,服务的调用方要能发现目标服务,同时服务提供方一般以集群方式提供服务,也就引入了负载均衡和健康检查问题。根据负载均衡 LB 所在位置的不同,目前主要的服务注册、发现和负载均衡方案有三种: 第一种是集中式 LB 方案,如下图 Fig 1,在服务消费者和服务提供者之间有一个独立的 LB,LB 通常是专门的硬件设备如 F5,或者基于软件如 LVS,HAproxy 等实现。LB 上有所有服务的地址映射表,通常由运维配置注册,当服务消费方调用某个目标服务时,它向 LB 发起请求,由 LB 以某种策略(比如 Round-Robin)做负载均衡后将请求转发到目标服务。LB 一般具备健康检查能力,能自动摘除不健康的服务实例。服务消费方如何发现 LB 呢?通常的做法是通过 DNS,运维人员为服务配置一个 DNS 域名,这个域名指向 LB。 Fig 1, 集中式 LB 方案 集中式 LB 方案实现简单,在 LB 上也容易做集中式的访问控制,这一方案目前还是业界主流。集中式 LB 的主要问题是单点问题,所有服务调用流量都经过 LB,当服务数量和调用量大的时候,LB 容易成为瓶颈,且一旦 LB 发生故障对整个系统的影响是灾难性的。另外,LB 在服务消费方和服务提供方之间增加了一跳 (hop),有一定性能开销。 第二种是进程内 LB 方案,针对集中式 LB 的不足,进程内 LB 方案将 LB 的功能以库的形式集成到服务消费方进程里头,该方案也被称为软负载 (Soft Load Balancing) 或者客户端负载方案,下图 Fig 2 展示了这种方案的工作原理。这一方案需要一个服务注册表 (Service Registry) 配合支持服务自注册和自发现,服务提供方启动时,首先将服务地址注册到服务注册表(同时定期报心跳到服务注册表以表明服务的存活状态,相当于健康检查),服务消费方要访问某个服务时,它通过内置的 LB 组件向服务注册表查询(同时缓存并定期刷新)目标服务地址列表,然后以某种负载均衡策略选择一个目标服务地址,最后向目标服务发起请求。这一方案对服务注册表的可用性 (Availability) 要求很高,一般采用能满足高可用分布式一致的组件(例如 Zookeeper, Consul, Etcd 等)来实现。 Fig 2, 进程内 LB 方案 进程内 LB 方案是一种分布式方案,LB 和服务发现能力被分散到每一个服务消费者的进程内部,同时服务消费方和服务提供方之间是直接调用,没有额外开销,性能比较好。但是,该方案以客户库 (Client Library) 的方式集成到服务调用方进程里头,如果企业内有多种不同的语言栈,就要配合开发多种不同的客户端,有一定的研发和维护成本。另外,一旦客户端跟随服务调用方发布到生产环境中,后续如果要对客户库进行升级,势必要求服务调用方修改代码并重新发布,所以该方案的升级推广有不小的阻力。 进程内 LB 的案例是 Netflix 的开源服务框架,对应的组件分别是:Eureka 服务注册表,Karyon 服务端框架支持服务自注册和健康检查,Ribbon 客户端框架支持服务自发现和软路由。另外,阿里开源的服务框架 Dubbo 也是采用类似机制。 第三种是主机独立 LB 进程方案,该方案是针对第二种方案的不足而提出的一种折中方案,原理和第二种方案基本类似,不同之处是,他将 LB 和服务发现功能从进程内移出来,变成主机上的一个独立进程,主机上的一个或者多个服务要访问目标服务时,他们都通过同一主机上的独立 LB 进程做服务发现和负载均衡,见下图 Fig 3。 Fig 3 主机独立 LB 进程方案 该方案也是一种分布式方案,没有单点问题,一个 LB 进程挂了只影响该主机上的服务调用方,服务调用方和 LB 之间是进程内调用,性能好,同时,该方案还简化了服务调用方,不需要为不同语言开发客户库,LB 的升级不需要服务调用方改代码。该方案的不足是部署较复杂,环节多,出错调试排查问题不方便。 该方案的典型案例是 Airbnb 的 SmartStack 服务发现框架,对应组件分别是:Zookeeper 作为服务注册表,Nerve 独立进程负责服务注册和健康检查,Synapse/HAproxy 独立进程负责服务发现和负载均衡。Google 最新推出的基于容器的 PaaS 平台 Kubernetes,其内部服务发现采用类似的机制。 服务前端路由微服务除了内部相互之间调用和通信之外,最终要以某种方式暴露出去,才能让外界系统(例如客户的浏览器、移动设备等等)访问到,这就涉及服务的前端路由,对应的组件是服务网关 (Service Gateway),见图 Fig 4,网关是连接企业内部和外部系统的一道门,有如下关键作用: 服务反向路由,网关要负责将外部请求反向路由到内部具体的微服务,这样虽然企业内部是复杂的分布式微服务结构,但是外部系统从网关上看到的就像是一个统一的完整服务,网关屏蔽了后台服务的复杂性,同时也屏蔽了后台服务的升级和变化。安全认证和防爬虫,所有外部请求必须经过网关,网关可以集中对访问进行安全控制,比如用户认证和授权,同时还可以分析访问模式实现防爬虫功能,网关是连接企业内外系统的安全之门。限流和容错,在流量高峰期,网关可以限制流量,保护后台系统不被大流量冲垮,在内部系统出现故障时,网关可以集中做容错,保持外部良好的用户体验。监控,网关可以集中监控访问量,调用延迟,错误计数和访问模式,为后端的性能优化或者扩容提供数据支持。日志,网关可以收集所有的访问日志,进入后台系统做进一步分析。 Fig 4, 服务网关 除以上基本能力外,网关还可以实现线上引流,线上压测,线上调试 (Surgical debugging),金丝雀测试 (Canary Testing),数据中心双活 (Active-Active HA) 等高级功能。 网关通常工作在 7 层,有一定的计算逻辑,一般以集群方式部署,前置 LB 进行负载均衡。 开源的网关组件有 Netflix 的 Zuul,特点是动态可热部署的过滤器 (filter) 机制,其它如 HAproxy,Nginx 等都可以扩展作为网关使用。 在介绍过服务注册表和网关等组件之后,我们可以通过一个简化的微服务架构图 (Fig 5) 来更加直观地展示整个微服务体系内的服务注册发现和路由机制,该图假定采用进程内 LB 服务发现和负载均衡机制。在下图 Fig 5 的微服务架构中,服务简化为两层,后端通用服务(也称中间层服务 Middle Tier Service)和前端服务(也称边缘服务 Edge Service,前端服务的作用是对后端服务做必要的聚合和裁剪后暴露给外部不同的设备,如 PC,Pad 或者 Phone)。后端服务启动时会将地址信息注册到服务注册表,前端服务通过查询服务注册表就可以发现然后调用后端服务;前端服务启动时也会将地址信息注册到服务注册表,这样网关通过查询服务注册表就可以将请求路由到目标前端服务,这样整个微服务体系的服务自注册自发现和软路由就通过服务注册表和网关串联起来了。如果以面向对象设计模式的视角来看,网关类似 Proxy 代理或者 Façade 门面模式,而服务注册表和服务自注册自发现类似 IoC 依赖注入模式,微服务可以理解为基于网关代理和注册表 IoC 构建的分布式系统。 Fig 5, 简化的微服务架构图 服务容错当企业微服务化以后,服务之间会有错综复杂的依赖关系,例如,一个前端请求一般会依赖于多个后端服务,技术上称为 1 -> N 扇出 (见图 Fig 6)。在实际生产环境中,服务往往不是百分百可靠,服务可能会出错或者产生延迟,如果一个应用不能对其依赖的故障进行容错和隔离,那么该应用本身就处在被拖垮的风险中。在一个高流量的网站中,某个单一后端一旦发生延迟,可能在数秒内导致所有应用资源 (线程,队列等) 被耗尽,造成所谓的雪崩效应 (Cascading Failure,见图 Fig 7),严重时可致整个网站瘫痪。 Fig 6, 服务依赖 Fig 7, 高峰期单个服务延迟致雪崩效应 经过多年的探索和实践,业界在分布式服务容错一块探索出了一套有效的容错模式和最佳实践,主要包括: Fig 8, 弹性电路保护状态图 电路熔断器模式 (Circuit Breaker Patten), 该模式的原理类似于家里的电路熔断器,如果家里的电路发生短路,熔断器能够主动熔断电路,以避免灾难性损失。在分布式系统中应用电路熔断器模式后,当目标服务慢或者大量超时,调用方能够主动熔断,以防止服务被进一步拖垮;如果情况又好转了,电路又能自动恢复,这就是所谓的弹性容错,系统有自恢复能力。下图 Fig 8 是一个典型的具备弹性恢复能力的电路保护器状态图,正常状态下,电路处于关闭状态 (Closed),如果调用持续出错或者超时,电路被打开进入熔断状态 (Open),后续一段时间内的所有调用都会被拒绝 (Fail Fast),一段时间以后,保护器会尝试进入半熔断状态 (Half-Open),允许少量请求进来尝试,如果调用仍然失败,则回到熔断状态,如果调用成功,则回到电路闭合状态。舱壁隔离模式 (Bulkhead Isolation Pattern),顾名思义,该模式像舱壁一样对资源或失败单元进行隔离,如果一个船舱破了进水,只损失一个船舱,其它船舱可以不受影响 。线程隔离 (Thread Isolation) 就是舱壁隔离模式的一个例子,假定一个应用程序 A 调用了 Svc1/Svc2/Svc3 三个服务,且部署 A 的容器一共有 120 个工作线程,采用线程隔离机制,可以给对 Svc1/Svc2/Svc3 的调用各分配 40 个线程,当 Svc2 慢了,给 Svc2 分配的 40 个线程因慢而阻塞并最终耗尽,线程隔离可以保证给 Svc1/Svc3 分配的 80 个线程可以不受影响,如果没有这种隔离机制,当 Svc2 慢的时候,120 个工作线程会很快全部被对 Svc2 的调用吃光,整个应用程序会全部慢下来。限流 (Rate Limiting/Load Shedder),服务总有容量限制,没有限流机制的服务很容易在突发流量 (秒杀,双十一) 时被冲垮。限流通常指对服务限定并发访问量,比如单位时间只允许 100 个并发调用,对超过这个限制的请求要拒绝并回退。回退 (fallback),在熔断或者限流发生的时候,应用程序的后续处理逻辑是什么?回退是系统的弹性恢复能力,常见的处理策略有,直接抛出异常,也称快速失败 (Fail Fast),也可以返回空值或缺省值,还可以返回备份数据,如果主服务熔断了,可以从备份服务获取数据。Netflix 将上述容错模式和最佳实践集成到一个称为 Hystrix 的开源组件中,凡是需要容错的依赖点 (服务,缓存,数据库访问等),开发人员只需要将调用封装在 Hystrix Command 里头,则相关调用就自动置于 Hystrix 的弹性容错保护之下。Hystrix 组件已经在 Netflix 经过多年运维验证,是 Netflix 微服务平台稳定性和弹性的基石,正逐渐被社区接受为标准容错组件。 服务框架微服务化以后,为了让业务开发人员专注于业务逻辑实现,避免冗余和重复劳动,规范研发提升效率,必然要将一些公共关注点推到框架层面。服务框架 (Fig 9) 主要封装公共关注点逻辑,包括: Fig 9, 服务框架 服务注册、发现、负载均衡和健康检查,假定采用进程内 LB 方案,那么服务自注册一般统一做在服务器端框架中,健康检查逻辑由具体业务服务定制,框架层提供调用健康检查逻辑的机制,服务发现和负载均衡则集成在服务客户端框架中。监控日志,框架一方面要记录重要的框架层日志、metrics 和调用链数据,还要将日志、metrics 等接口暴露出来,让业务层能根据需要记录业务日志数据。在运行环境中,所有日志数据一般集中落地到企业后台日志系统,做进一步分析和处理。REST/RPC 和序列化,框架层要支持将业务逻辑以 HTTP/REST 或者 RPC 方式暴露出来,HTTP/REST 是当前主流 API 暴露方式,在性能要求高的场合则可采用 Binary/RPC 方式。针对当前多样化的设备类型 (浏览器、普通 PC、无线设备等),框架层要支持可定制的序列化机制,例如,对浏览器,框架支持输出 Ajax 友好的 JSON 消息格式,而对无线设备上的 Native App,框架支持输出性能高的 Binary 消息格式。配置,除了支持普通配置文件方式的配置,框架层还可集成动态运行时配置,能够在运行时针对不同环境动态调整服务的参数和配置。限流和容错,框架集成限流容错组件,能够在运行时自动限流和容错,保护服务,如果进一步和动态配置相结合,还可以实现动态限流和熔断。管理接口,框架集成管理接口,一方面可以在线查看框架和服务内部状态,同时还可以动态调整内部状态,对调试、监控和管理能提供快速反馈。Spring Boot 微框架的 Actuator 模块就是一个强大的管理接口。统一错误处理,对于框架层和服务的内部异常,如果框架层能够统一处理并记录日志,对服务监控和快速问题定位有很大帮助。安全,安全和访问控制逻辑可以在框架层统一进行封装,可做成插件形式,具体业务服务根据需要加载相关安全插件。文档自动生成,文档的书写和同步一直是一个痛点,框架层如果能支持文档的自动生成和同步,会给使用 API 的开发和测试人员带来极大便利。Swagger 是一种流行 Restful API 的文档方案。当前业界比较成熟的微服务框架有 Netflix 的 Karyon/Ribbon,Spring 的 Spring Boot/Cloud,阿里的 Dubbo 等。 运行期配置管理服务一般有很多依赖配置,例如访问数据库有连接字符串配置,连接池大小和连接超时配置,这些配置在不同环境 (开发 / 测试 / 生产) 一般不同,比如生产环境需要配连接池,而开发测试环境可能不配,另外有些参数配置在运行期可能还要动态调整,例如,运行时根据流量状况动态调整限流和熔断阀值。目前比较常见的做法是搭建一个运行时配置中心支持微服务的动态配置,简化架构如下图 (Fig 10): Fig 10, 服务配置中心 动态配置存放在集中的配置服务器上,用户通过管理界面配置和调整服务配置,具体服务通过定期拉 (Scheduled Pull) 的方式或者服务器推 (Server-side Push) 的方式更新动态配置,拉方式比较可靠,但会有延迟同时有无效网络开销 (假设配置不常更新),服务器推方式能及时更新配置,但是实现较复杂,一般在服务和配置服务器之间要建立长连接。配置中心还要解决配置的版本控制和审计问题,对于大规模服务化环境,配置中心还要考虑分布式和高可用问题。 配置中心比较成熟的开源方案有百度的 Disconf,360 的 QConf,Spring 的 Cloud Config 和阿里的 Diamond 等。 Netflix 的微服务框架Netflix 是一家成功实践微服务架构的互联网公司,几年前,Netflix 就把它的几乎整个微服务框架栈开源贡献给了社区,这些框架和组件包括: Eureka: 服务注册发现框架Zuul: 服务网关Karyon: 服务端框架Ribbon: 客户端框架Hystrix: 服务容错组件Archaius: 服务配置组件Servo: Metrics 组件Blitz4j: 日志组件下图 Fig 11 展示了基于这些组件构建的一个微服务框架体系,来自 recipes-rss。 Fig 11, 基于 Netflix 开源组件的微服务框架 Netflix 的开源框架组件已经在 Netflix 的大规模分布式微服务环境中经过多年的生产实战验证,正逐步被社区接受为构造微服务框架的标准组件。Pivotal 去年推出的 Spring Cloud 开源产品,主要是基于对 Netflix 开源组件的进一步封装,方便 Spring 开发人员构建微服务基础框架。对于一些打算构建微服务框架体系的公司来说,充分利用或参考借鉴 Netflix 的开源微服务组件 (或 Spring Cloud),在此基础上进行必要的企业定制,无疑是通向微服务架构的捷径。 原文地址:https://www.infoq.cn/article/basis-frameworkto-implement-micro-service#anch130564%20%EF%BC%8C

auto_answer 2019-12-02 01:55:22 0 浏览量 回答数 0

问题

“Ceph浅析”系列之七——关于Ceph的若干想法:报错

kun坤 2020-06-08 11:04:40 6 浏览量 回答数 1

问题

搜索引擎背后的经典数据结构和算法 6月10日 【今日算法】

游客ih62co2qqq5ww 2020-06-15 07:32:11 0 浏览量 回答数 0

问题

10个迷惑新手的Cocoa,Objective-c开发难点和问题? 400 报错

爱吃鱼的程序员 2020-05-31 00:44:29 0 浏览量 回答数 1

问题

Servlet 3.0 新特性详解? 400 报错

爱吃鱼的程序员 2020-06-04 11:52:09 3 浏览量 回答数 1

问题

【精品问答】python技术1000问(1)

问问小秘 2019-12-01 21:57:48 448858 浏览量 回答数 12

回答

Go 的优势在于能够将简单的和经过验证的想法结合起来,同时避免了其他语言中出现的许多问题。本文概述了 Go 背后的一些设计原则和工程智慧,作者认为,Go 语言具备的所有这些优点,将共同推动其成为接替 Java 并主导下一代大型软件开发平台的最有力的编程语言候选。很多优秀的编程语言只是在个别领域比较强大,如果将所有因素都纳入考虑,没有其他语言能够像 Go 语言一样“全面开花”,在大型软件工程方面,尤为如此。 基于现实经验 Go 是由经验丰富的软件行业老手一手创建的,长期以来,他们对现有语言的各种缺点有过切身体会的痛苦经历。几十年前,Rob Pike 和 Ken Thompson 在 Unix、C 和 Unicode 的发明中起到了重要作用。Robert Griensemer 在为 JavaScript 和 Java 开发 V8 和 HotSpot 虚拟机之后,在编译器和垃圾收集方面拥有数十年的经验。有太多次,他们不得不等待 Google 规模的 C++/Java 代码库进行编译。于是,他们开始着手创建新的编程语言,将他们半个世纪以来的编写代码所学到的一切经验包含进去。 专注于大型工程 小型工程项目几乎可以用任何编程语言来成功构建。当成千上万的开发人员在数十年的持续时间压力下,在包含数千万行代码的大型代码库上进行协作时,就会发生真正令人痛苦的问题。这样会导致一些问题,如下: 较长的编译时间导致中断开发。代码库由几个人 / 团队 / 部门 / 公司所拥有,混合了不同的编程风格。公司雇佣了数千名工程师、架构师、测试人员、运营专家、审计员、实习生等,他们需要了解代码库,但也具备广泛的编码经验。依赖于许多外部库或运行时,其中一些不再以原始形式存在。在代码库的生命周期中,每行代码平均被重写 10 次,被弄得千疮百痍,而且还会发生技术偏差。文档不完整。 Go 注重减轻这些大型工程的难题,有时会以使小型工程变得更麻烦为代价,例如,代码中到处都需要几行额外的代码行。 注重可维护性 Go 强调尽可能多地将工作转给自动化的代码维护工具中。Go 工具链提供了最常用的功能,如格式化代码和导入、查找符号的定义和用法、简单的重构以及代码异味的识别。由于标准化的代码格式和单一的惯用方式,机器生成的代码更改看起来非常接近 Go 中人为生成的更改并使用类似的模式,从而允许人机之间更加无缝地协作。 保持简单明了 初级程序员为简单的问题创建简单的解决方案。高级程序员为复杂的问题创建复杂的解决方案。伟大的程序员找到复杂问题的简单解决方案。 ——Charles Connell 让很多人惊讶的一点是,Go 居然不包含他们喜欢的其他语言的概念。Go 确实是一种非常小巧而简单的语言,只包含正交和经过验证的概念的最小选择。这鼓励开发人员用最少的认知开销来编写尽可能简单的代码,以便许多其他人可以理解并使用它。 使事情清晰明了 良好的代码总是显而易见的,避免了那些小聪明、难以理解的语言特性、诡异的控制流和兜圈子。 许多语言都致力提高编写代码的效率。然而,在其生命周期中,人们阅读代码的时间却远远超过最初编写代码所需的时间(100 倍)。例如,审查、理解、调试、更改、重构或重用代码。在查看代码时,往往只能看到并理解其中的一小部分,通常不会有完整的代码库概述。为了解释这一点,Go 将所有内容都明确出来。 错误处理就是一个例子。让异常在各个点中断代码并在调用链上冒泡会更容易。Go 需要手动处理和返回每个错误。这使得它可以准确地显示代码可以被中断的位置以及如何处理或包装错误。总的来说,这使得错误处理编写起来更加繁琐,但是也更容易理解。 简单易学 Go 是如此的小巧而简单,以至于人们可以在短短几天内就能研究通整个语言及其基本概念。根据我们的经验,培训用不了一个星期(相比于掌握其他语言需要几个月),初学者就能够理解 Go 专家编写的代码,并为之做出贡献。为了方便吸引更多的用户,Go 网站提供了所有必要的教程和深入研究的文章。这些教程在浏览器中运行,允许人们在将 Go 安装到本地计算机上之前就能够学习和使用 Go。 解决之道 Go 强调的是团队之间的合作,而不是个人的自我表达。 在 Go(和 Python)中,所有的语言特性都是相互正交和互补的,通常有一种方法可以做一些事情。如果你想让 10 个 Python 或 Go 程序员来解决同一个问题,你将会得到 10 个相对类似的解决方案。不同的程序员在彼此的代码库中感觉更自在。在查看其他人的代码时,国骂会更少,而且人们的工作可以更好地融合在一起,从而形成了一致的整体,人人都为之感到自豪,并乐于工作。这还避免了大型工程的问题,如: 开发人员认为良好的工作代码很“混乱”,并要求在开始工作之前进行重写,因为他们的思维方式与原作者不同。 不同的团队成员使用不同的语言子集来编写相同代码库的部分内容。 ![image.png](https://ucc.alicdn.com/pic/developer-ecology/e64418f1455d46aaacfdd03fa949f16d.png) 简单、内置的并发性 Go 专为现代多核硬件设计。 目前使用的大多数编程语言(Java、JavaScript、Python、Ruby、C、C++)都是 20 世纪 80 年代到 21 世纪初设计的,当时大多数 CPU 只有一个计算内核。这就是为什么它们本质上是单线程的,并将并行化视为边缘情况的马后炮。通过现成和同步点之类的附加组件来实现,而这些附加组件既麻烦又难以正确使用。第三方库虽然提供了更简单的并发形式,如 Actor 模型,但是总有多个可用选项,结果导致了语言生态系统的碎片化。今天的硬件拥有越来越多的计算内核,软件必须并行化才能高效运行。Go 是在多核处理器时代编写的,并且在语言中内置了简单、高级的 CSP 风格并发性。 面向计算的语言原语 就深层而言,计算机系统接收数据,对其进行处理(通常要经过几个步骤),然后输出结果数据。例如,Web 服务器从客户端接收 HTTP 请求,并将其转换为一系列数据库或后端调用。一旦这些调用返回,它就将接收到的数据转换成 HTML 或 JSON 并将其输出给调用者。Go 的内置语言原语直接支持这种范例: 结构表示数据 读和写代表流式 IO 函数过程数据 goroutines 提供(几乎无限的)并发性 在并行处理步骤之间传输管道数据 因为所有的计算原语都是由语言以直接形式提供的,因此 Go 源代码更直接地表达了服务器执行的操作。 OO — 好的部分 更改基类中的某些内容的副作用 面向对象非常有用。过去几十年来,面向对象的使用富有成效,并让我们了解了它的哪些部分比其他部分能够更好地扩展。Go 在面向对象方面采用了一种全新的方法,并记住了这些知识。它保留了好的部分,如封装、消息传递等。Go 还避免了继承,因为它现在被认为是有害的,并为组合提供了一流的支持。 现代标准库 目前使用的许多编程语言(Java、JavaScript、Python、Ruby)都是在互联网成为当今无处不在的计算平台之前设计的。因此,这些语言的标准库只提供了相对通用的网络支持,而这些网络并没有针对现代互联网进行优化。Go 是十年前创建的,当时互联网已全面发展。Go 的标准库允许在没有第三方库的情况下创建更复杂的网络服务。这就避免了第三方库的常见问题: 碎片化:总是有多个选项实现相同的功能。 膨胀:库常常实现的不仅仅是它们的用途。 依赖地狱:库通常依赖于特定版本的其他库。 未知质量:第三方代码的质量和安全性可能存在问题。 未知支持:第三方库的开发可能随时停止支持。 意外更改:第三方库通常不像标准库那样严格地进行版本控制。 关于这方面更多的信息请参考 Russ Cox 提供的资料 标准化格式 Gofmt 的风格没有人会去喜欢,但人人都会喜欢 gofmt。 ——Rob Pike Gofmt 是一种以标准化方式来格式化 Go 代码的程序。它不是最漂亮的格式化方式,但却是最简单、最不令人生厌的格式化方式。标准化的源代码格式具有惊人的积极影响: 集中讨论重要主题: 它消除了围绕制表符和空格、缩进深度、行长、空行、花括号的位置等一系列争论。 开发人员在彼此的代码库中感觉很自在, 因为其他代码看起来很像他们编写的代码。每个人都喜欢自由地按照自己喜欢的方式进行格式化代码,但如果其他人按照自己喜欢的方式格式化了代码,这么做很招人烦。 自动代码更改并不会打乱手写代码的格式,例如引入了意外的空白更改。 许多其他语言社区现在正在开发类似 gofmt 的东西。当作为第三方解决方案构建时,通常会有几个相互竞争的格式标准。例如,JavaScript 提供了 Prettier 和 StandardJS。这两者都可以用,也可以只使用其中的一个。但许多 JS 项目并没有采用它们,因为这是一个额外的决策。Go 的格式化程序内置于该语言的标准工具链中,因此只有一个标准,每个人都在使用它。 快速编译 ![image.png](https://ucc.alicdn.com/pic/developer-ecology/8a76f3f07f484266af42781d9e7b8692.png) 对于大型代码库来说,它们长时间的编译是促使 Go 诞生的原因。Google 主要使用的是 C++ 和 Java,与 Haskell、Scala 或 Rust 等更复杂的语言相比,它们的编译速度相对较快。尽管如此,当编译大型代码库时,即使是少量的缓慢也会加剧编译的延迟,从而激怒开发人员,并干扰流程。Go 的设计初衷是为了提高编译效率,因此它的编译器速度非常快,几乎没有编译延迟的现象。这给 Go 开发人员提供了与脚本类语言类似的即时反馈,还有静态类型检查的额外好处。 交叉编译 由于语言运行时非常简单,因此它被移植到许多平台,如 macOS、Linux、Windows、BSD、ARM 等。Go 可以开箱即用地为所有这些平台编译二进制文件。这使得从一台机器进行部署变得很容易。 快速执行 Go 的运行速度接近于 C。与 JITed 语言(Java、JavaScript、Python 等)不同,Go 二进制文件不需要启动或预热的时间,因为它们是作为编译和完全优化的本地代码的形式发布的。Go 的垃圾收集器仅引入微秒量级的可忽略的停顿。除了快速的单核性能外,Go 还可以轻松利用所有的 CPU 内核。 内存占用小 像 JVM、Python 或 Node 这样的运行时不仅仅在运行时加载程序代码,每次运行程序时,它们还会加载大型且高度复杂的基础架构,以进行编译和优化程序。如此一来,它们的启动时间就变慢了,并且还占用了大量内存(数百兆字节)。而 Go 进程的开销更小,因为它们已经完全编译和优化,只需运行即可。Go 还以非常节省内存的方式来存储数据。在内存有限且昂贵的云环境中,以及在开发过程中,这一点非常重要。我们希望在一台机器上能够快速启动整个堆栈,同时将内存留给其他软件。 部署规模小 Go 的二进制文件大小非常简洁。Go 应用程序的 Docker 镜像通常比用 Java 或 Node 编写的等效镜像要小 10 倍,这是因为它无需包含编译器、JIT,以及更少的运行时基础架构的原因。这些特点,在部署大型应用程序时很重要。想象一下,如果要将一个简单的应用程序部署到 100 个生产服务器上会怎么样?如果使用 Node/JVM 时,我们的 Docker 注册表就必须提供 100 个 docker 镜像,每个镜像 200MB,那么一共就需要 20GB。要完成这些部署就需要一些时间。想象一下,如果我们想每天部署 100 次的话,如果使用 Go 服务,那么 Docker 注册表只需提供 10 个 docker 镜像,每个镜像只有 20MB,共只需 2GB 即可。大型 Go 应用程序可以更快、更频繁地部署,从而使得重要更新能够更快地部署到生产环境中。 独立部署 Go 应用程序部署为一个包含所有依赖项的单个可执行文件,并无需安装特定版本的 JVM、Node 或 Python 运行时;也不必将库下载到生产服务器上,更无须对运行 Go 二进制文件的机器进行任何更改。甚至也不需要讲 Go 二进制文件包装到 Docker 来共享他们。你需要做的是,只是将 Go 二进制文件放到服务器上,它就会在那里运行,而不用关心服务器运行的是什么。前面所提到的那些,唯一的例外是使用net和os/user包时针对对glibc的动态链接。 供应依赖关系 Go 有意识避免使用第三方库的中央存储库。Go 应用程序直接链接到相应的 Git 存储库,并将所有相关代码下载(供应)到自己的代码库中。这样做有很多好处: 在使用第三方代码之前,我们可以对其进行审查、分析和测试。该代码就和我们自己的代码一样,是我们应用程序的一部分,应该遵循相同的质量、安全性和可靠性标准。 无需永久访问存储依赖项的各个位置。从任何地方(包括私有 Git repos)获取第三方库,你就能永久拥有它们。 经过验收后,编译代码库无需进一步下载依赖项。 若互联网某处的代码存储库突然提供不同的代码,这也并不足为奇。 即使软件包存储库速度变慢,或托管包不复存在,部署也不会因此中断。 兼容性保证 Go 团队承诺现有的程序将会继续适用于新一代语言。这使得将大型项目升级到最新版本的编译器会非常容易,并且可从它们带来的许多性能和安全性改进中获益。同时,由于 Go 二进制文件包含了它们需要的所有依赖项,因此可以在同一服务器上并行运行使用不同版本的 Go 编译器编译的二进制文件,而无需进行复杂的多个版本的运行时设置或虚拟化。 文档 在大型工程中,文档对于使软件可访问性和可维护性非常重要。与其他特性类似,Go 中的文档简单实用: 由于它是嵌入到源代码中的,因此两者可以同时维护。 它不需要特殊的语法,文档只是普通的源代码注释。 可运行单元测试通常是最好的文档形式。因此 Go 要求将它们嵌入到文档中。 所有的文档实用程序都内置在工具链中,因此每个人都使用它们。 Go linter 需要导出元素的文档,以防止“文档债务”的积累。 商业支持的开源 当商业实体在开放式环境下开发时,那么一些最流行的、经过彻底设计的软件就会出现。这种设置结合了商业软件开发的优势——一致性和精细化,使系统更为健壮、可靠、高效,并具有开放式开发的优势,如来自许多行业的广泛支持,多个大型实体和许多用户的支持,以及即使商业支持停止的长期支持。Go 就是这样发展起来的。 缺点 当然,Go 也并非完美无缺,每种技术选择都是有利有弊。在决定选择 Go 之前,有几个方面需要进行考虑考虑。 未成熟 虽然 Go 的标准库在支持许多新概念(如 HTTP 2 Server push 等)方面处于行业领先地位,但与 JVM 生态系统中的第三方库相比,用于外部 API 的第三方 Go 库可能不那么成熟。 即将到来的改进 由于清楚几乎不可能改变现有的语言元素,Go 团队非常谨慎,只在新特性完全开发出来后才添加新特性。在经历了 10 年的有意稳定阶段之后,Go 团队正在谋划对语言进行一系列更大的改进,作为 Go 2.0 之旅的一部分。 无硬实时 虽然 Go 的垃圾收集器只引入了非常短暂的停顿,但支持硬实时需要没有垃圾收集的技术,例如 Rust。 结语 本文详细介绍了 Go 语言的一些优秀的设计准则,虽然有的准则的好处平常看起来没有那么明显。但当代码库和团队规模增长几个数量级时,这些准则可能会使大型工程项目免于许多痛苦。总的来说,正是这些设计准则让 Go 语言成为了除 Java 之外的编程语言里,用于大型软件开发项目的绝佳选择。

有只黑白猫 2020-01-07 14:11:38 0 浏览量 回答数 0

回答

遍历一个 List 有哪些不同的方式?每种方法的实现原理是什么?Java 中 List 遍历的最佳实践是什么? 遍历方式有以下几种: for 循环遍历,基于计数器。在集合外部维护一个计数器,然后依次读取每一个位置的元素,当读取到最后一个元素后停止。 迭代器遍历,Iterator。Iterator 是面向对象的一个设计模式,目的是屏蔽不同数据集合的特点,统一遍历集合的接口。Java 在 Collections 中支持了 Iterator 模式。 foreach 循环遍历。foreach 内部也是采用了 Iterator 的方式实现,使用时不需要显式声明 Iterator 或计数器。优点是代码简洁,不易出错;缺点是只能做简单的遍历,不能在遍历过程中操作数据集合,例如删除、替换。 最佳实践:Java Collections 框架中提供了一个 RandomAccess 接口,用来标记 List 实现是否支持 Random Access。 如果一个数据集合实现了该接口,就意味着它支持 Random Access,按位置读取元素的平均时间复杂度为 O(1),如ArrayList。如果没有实现该接口,表示不支持 Random Access,如LinkedList。 推荐的做法就是,支持 Random Access 的列表可用 for 循环遍历,否则建议用 Iterator 或 foreach 遍历。 说一下 ArrayList 的优缺点 ArrayList的优点如下: ArrayList 底层以数组实现,是一种随机访问模式。ArrayList 实现了 RandomAccess 接口,因此查找的时候非常快。ArrayList 在顺序添加一个元素的时候非常方便。 ArrayList 的缺点如下: 删除元素的时候,需要做一次元素复制操作。如果要复制的元素很多,那么就会比较耗费性能。插入元素的时候,也需要做一次元素复制操作,缺点同上。 ArrayList 比较适合顺序添加、随机访问的场景。 如何实现数组和 List 之间的转换? 数组转 List:使用 Arrays. asList(array) 进行转换。List 转数组:使用 List 自带的 toArray() 方法。 代码示例: ArrayList 和 LinkedList 的区别是什么? 数据结构实现:ArrayList 是动态数组的数据结构实现,而 LinkedList 是双向链表的数据结构实现。随机访问效率:ArrayList 比 LinkedList 在随机访问的时候效率要高,因为 LinkedList 是线性的数据存储方式,所以需要移动指针从前往后依次查找。增加和删除效率:在非首尾的增加和删除操作,LinkedList 要比 ArrayList 效率要高,因为 ArrayList 增删操作要影响数组内的其他数据的下标。内存空间占用:LinkedList 比 ArrayList 更占内存,因为 LinkedList 的节点除了存储数据,还存储了两个引用,一个指向前一个元素,一个指向后一个元素。线程安全:ArrayList 和 LinkedList 都是不同步的,也就是不保证线程安全; 综合来说,在需要频繁读取集合中的元素时,更推荐使用 ArrayList,而在插入和删除操作较多时,更推荐使用 LinkedList。 补充:数据结构基础之双向链表 双向链表也叫双链表,是链表的一种,它的每个数据结点中都有两个指针,分别指向直接后继和直接前驱。所以,从双向链表中的任意一个结点开始,都可以很方便地访问它的前驱结点和后继结点。 ArrayList 和 Vector 的区别是什么? 这两个类都实现了 List 接口(List 接口继承了 Collection 接口),他们都是有序集合 线程安全:Vector 使用了 Synchronized 来实现线程同步,是线程安全的,而 ArrayList 是非线程安全的。性能:ArrayList 在性能方面要优于 Vector。扩容:ArrayList 和 Vector 都会根据实际的需要动态的调整容量,只不过在 Vector 扩容每次会增加 1 倍,而 ArrayList 只会增加 50%。 Vector类的所有方法都是同步的。可以由两个线程安全地访问一个Vector对象、但是一个线程访问Vector的话代码要在同步操作上耗费大量的时间。 Arraylist不是同步的,所以在不需要保证线程安全时时建议使用Arraylist。 插入数据时,ArrayList、LinkedList、Vector谁速度较快?阐述 ArrayList、Vector、LinkedList 的存储性能和特性? ArrayList、LinkedList、Vector 底层的实现都是使用数组方式存储数据。数组元素数大于实际存储的数据以便增加和插入元素,它们都允许直接按序号索引元素,但是插入元素要涉及数组元素移动等内存操作,所以索引数据快而插入数据慢。 Vector 中的方法由于加了 synchronized 修饰,因此 Vector 是线程安全容器,但性能上较ArrayList差。 LinkedList 使用双向链表实现存储,按序号索引数据需要进行前向或后向遍历,但插入数据时只需要记录当前项的前后项即可,所以 LinkedList 插入速度较快。 多线程场景下如何使用 ArrayList? ArrayList 不是线程安全的,如果遇到多线程场景,可以通过 Collections 的 synchronizedList 方法将其转换成线程安全的容器后再使用。例如像下面这样: 为什么 ArrayList 的 elementData 加上 transient 修饰? ArrayList 中的数组定义如下: private transient Object[] elementData; 再看一下 ArrayList 的定义: public class ArrayList extends AbstractList implements List<E>, RandomAccess, Cloneable, java.io.Serializable 可以看到 ArrayList 实现了 Serializable 接口,这意味着 ArrayList 支持序列化。transient 的作用是说不希望 elementData 数组被序列化,重写了 writeObject 实现: 每次序列化时,先调用 defaultWriteObject() 方法序列化 ArrayList 中的非 transient 元素,然后遍历 elementData,只序列化已存入的元素,这样既加快了序列化的速度,又减小了序列化之后的文件大小。 List 和 Set 的区别 List , Set 都是继承自Collection 接口 List 特点:一个有序(元素存入集合的顺序和取出的顺序一致)容器,元素可以重复,可以插入多个null元素,元素都有索引。常用的实现类有 ArrayList、LinkedList 和 Vector。 Set 特点:一个无序(存入和取出顺序有可能不一致)容器,不可以存储重复元素,只允许存入一个null元素,必须保证元素唯一性。Set 接口常用实现类是 HashSet、LinkedHashSet 以及 TreeSet。 另外 List 支持for循环,也就是通过下标来遍历,也可以用迭代器,但是set只能用迭代,因为他无序,无法用下标来取得想要的值。 Set和List对比 Set:检索元素效率低下,删除和插入效率高,插入和删除不会引起元素位置改变。 List:和数组类似,List可以动态增长,查找元素效率高,插入删除元素效率低,因为会引起其他元素位置改变 Set接口 说一下 HashSet 的实现原理? HashSet 是基于 HashMap 实现的,HashSet的值存放于HashMap的key上,HashMap的value统一为PRESENT,因此 HashSet 的实现比较简单,相关 HashSet 的操作,基本上都是直接调用底层 HashMap 的相关方法来完成,HashSet 不允许重复的值。 HashSet如何检查重复?HashSet是如何保证数据不可重复的? 向HashSet 中add ()元素时,判断元素是否存在的依据,不仅要比较hash值,同时还要结合equles 方法比较。 HashSet 中的add ()方法会使用HashMap 的put()方法。 HashMap 的 key 是唯一的,由源码可以看出 HashSet 添加进去的值就是作为HashMap 的key,并且在HashMap中如果K/V相同时,会用新的V覆盖掉旧的V,然后返回旧的V。所以不会重复( HashMap 比较key是否相等是先比较hashcode 再比较equals )。 以下是HashSet 部分源码: hashCode()与equals()的相关规定: 如果两个对象相等,则hashcode一定也是相同的 两个对象相等,对两个equals方法返回true 两个对象有相同的hashcode值,它们也不一定是相等的 综上,equals方法被覆盖过,则hashCode方法也必须被覆盖 hashCode()的默认行为是对堆上的对象产生独特值。如果没有重写hashCode(),则该class的两个对象无论如何都不会相等(即使这两个对象指向相同的数据)。 ** ==与equals的区别** ==是判断两个变量或实例是不是指向同一个内存空间 equals是判断两个变量或实例所指向的内存空间的值是不是相同 ==是指对内存地址进行比较 equals()是对字符串的内容进行比较3.==指引用是否相同 equals()指的是值是否相同 HashSet与HashMap的区别 Queue BlockingQueue是什么? Java.util.concurrent.BlockingQueue是一个队列,在进行检索或移除一个元素的时候,它会等待队列变为非空;当在添加一个元素时,它会等待队列中的可用空间。BlockingQueue接口是Java集合框架的一部分,主要用于实现生产者-消费者模式。我们不需要担心等待生产者有可用的空间,或消费者有可用的对象,因为它都在BlockingQueue的实现类中被处理了。Java提供了集中BlockingQueue的实现,比如ArrayBlockingQueue、LinkedBlockingQueue、PriorityBlockingQueue,、SynchronousQueue等。 在 Queue 中 poll()和 remove()有什么区别? 相同点:都是返回第一个元素,并在队列中删除返回的对象。 不同点:如果没有元素 poll()会返回 null,而 remove()会直接抛出 NoSuchElementException 异常。 代码示例: Queue queue = new LinkedList (); queue. offer("string"); // add System. out. println(queue. poll()); System. out. println(queue. remove()); System. out. println(queue. size()); Map接口 说一下 HashMap 的实现原理? HashMap概述: HashMap是基于哈希表的Map接口的非同步实现。此实现提供所有可选的映射操作,并允许使用null值和null键。此类不保证映射的顺序,特别是它不保证该顺序恒久不变。 HashMap的数据结构: 在Java编程语言中,最基本的结构就是两种,一个是数组,另外一个是模拟指针(引用),所有的数据结构都可以用这两个基本结构来构造的,HashMap也不例外。HashMap实际上是一个“链表散列”的数据结构,即数组和链表的结合体。 HashMap 基于 Hash 算法实现的 当我们往Hashmap中put元素时,利用key的hashCode重新hash计算出当前对象的元素在数组中的下标存储时,如果出现hash值相同的key,此时有两种情况。(1)如果key相同,则覆盖原始值;(2)如果key不同(出现冲突),则将当前的key-value放入链表中获取时,直接找到hash值对应的下标,在进一步判断key是否相同,从而找到对应值。理解了以上过程就不难明白HashMap是如何解决hash冲突的问题,核心就是使用了数组的存储方式,然后将冲突的key的对象放入链表中,一旦发现冲突就在链表中做进一步的对比。 需要注意Jdk 1.8中对HashMap的实现做了优化,当链表中的节点数据超过八个之后,该链表会转为红黑树来提高查询效率,从原来的O(n)到O(logn) HashMap在JDK1.7和JDK1.8中有哪些不同?HashMap的底层实现 在Java中,保存数据有两种比较简单的数据结构:数组和链表。数组的特点是:寻址容易,插入和删除困难;链表的特点是:寻址困难,但插入和删除容易;所以我们将数组和链表结合在一起,发挥两者各自的优势,使用一种叫做拉链法的方式可以解决哈希冲突。 JDK1.8之前 JDK1.8之前采用的是拉链法。拉链法:将链表和数组相结合。也就是说创建一个链表数组,数组中每一格就是一个链表。若遇到哈希冲突,则将冲突的值加到链表中即可。 JDK1.8之后 相比于之前的版本,jdk1.8在解决哈希冲突时有了较大的变化,当链表长度大于阈值(默认为8)时,将链表转化为红黑树,以减少搜索时间。 JDK1.7 VS JDK1.8 比较 JDK1.8主要解决或优化了一下问题: resize 扩容优化引入了红黑树,目的是避免单条链表过长而影响查询效率,红黑树算法请参考解决了多线程死循环问题,但仍是非线程安全的,多线程时可能会造成数据丢失问题。 HashMap的put方法的具体流程? 当我们put的时候,首先计算 key的hash值,这里调用了 hash方法,hash方法实际是让key.hashCode()与key.hashCode()>>>16进行异或操作,高16bit补0,一个数和0异或不变,所以 hash 函数大概的作用就是:高16bit不变,低16bit和高16bit做了一个异或,目的是减少碰撞。按照函数注释,因为bucket数组大小是2的幂,计算下标index = (table.length - 1) & hash,如果不做 hash 处理,相当于散列生效的只有几个低 bit 位,为了减少散列的碰撞,设计者综合考虑了速度、作用、质量之后,使用高16bit和低16bit异或来简单处理减少碰撞,而且JDK8中用了复杂度 O(logn)的树结构来提升碰撞下的性能。 putVal方法执行流程图 ①.判断键值对数组table[i]是否为空或为null,否则执行resize()进行扩容; ②.根据键值key计算hash值得到插入的数组索引i,如果table[i]==null,直接新建节点添加,转向⑥,如果table[i]不为空,转向③; ③.判断table[i]的首个元素是否和key一样,如果相同直接覆盖value,否则转向④,这里的相同指的是hashCode以及equals; ④.判断table[i] 是否为treeNode,即table[i] 是否是红黑树,如果是红黑树,则直接在树中插入键值对,否则转向⑤; ⑤.遍历table[i],判断链表长度是否大于8,大于8的话把链表转换为红黑树,在红黑树中执行插入操作,否则进行链表的插入操作;遍历过程中若发现key已经存在直接覆盖value即可; ⑥.插入成功后,判断实际存在的键值对数量size是否超多了最大容量threshold,如果超过,进行扩容。 HashMap的扩容操作是怎么实现的? ①.在jdk1.8中,resize方法是在hashmap中的键值对大于阀值时或者初始化时,就调用resize方法进行扩容; ②.每次扩展的时候,都是扩展2倍; ③.扩展后Node对象的位置要么在原位置,要么移动到原偏移量两倍的位置。 在putVal()中,我们看到在这个函数里面使用到了2次resize()方法,resize()方法表示的在进行第一次初始化时会对其进行扩容,或者当该数组的实际大小大于其临界值值(第一次为12),这个时候在扩容的同时也会伴随的桶上面的元素进行重新分发,这也是JDK1.8版本的一个优化的地方,在1.7中,扩容之后需要重新去计算其Hash值,根据Hash值对其进行分发,但在1.8版本中,则是根据在同一个桶的位置中进行判断(e.hash & oldCap)是否为0,重新进行hash分配后,该元素的位置要么停留在原始位置,要么移动到原始位置+增加的数组大小这个位置上 HashMap是怎么解决哈希冲突的? 答:在解决这个问题之前,我们首先需要知道什么是哈希冲突,而在了解哈希冲突之前我们还要知道什么是哈希才行; 什么是哈希? Hash,一般翻译为“散列”,也有直接音译为“哈希”的,这就是把任意长度的输入通过散列算法,变换成固定长度的输出,该输出就是散列值(哈希值);这种转换是一种压缩映射,也就是,散列值的空间通常远小于输入的空间,不同的输入可能会散列成相同的输出,所以不可能从散列值来唯一的确定输入值。简单的说就是一种将任意长度的消息压缩到某一固定长度的消息摘要的函数。 所有散列函数都有如下一个基本特性**:根据同一散列函数计算出的散列值如果不同,那么输入值肯定也不同。但是,根据同一散列函数计算出的散列值如果相同,输入值不一定相同**。 什么是哈希冲突? 当两个不同的输入值,根据同一散列函数计算出相同的散列值的现象,我们就把它叫做碰撞(哈希碰撞)。 HashMap的数据结构 在Java中,保存数据有两种比较简单的数据结构:数组和链表。数组的特点是:寻址容易,插入和删除困难;链表的特点是:寻址困难,但插入和删除容易;所以我们将数组和链表结合在一起,发挥两者各自的优势,使用一种叫做链地址法的方式可以解决哈希冲突: 这样我们就可以将拥有相同哈希值的对象组织成一个链表放在hash值所对应的bucket下,但相比于hashCode返回的int类型,我们HashMap初始的容量大小DEFAULT_INITIAL_CAPACITY = 1 << 4(即2的四次方16)要远小于int类型的范围,所以我们如果只是单纯的用hashCode取余来获取对应的bucket这将会大大增加哈希碰撞的概率,并且最坏情况下还会将HashMap变成一个单链表,所以我们还需要对hashCode作一定的优化 hash()函数 上面提到的问题,主要是因为如果使用hashCode取余,那么相当于参与运算的只有hashCode的低位,高位是没有起到任何作用的,所以我们的思路就是让hashCode取值出的高位也参与运算,进一步降低hash碰撞的概率,使得数据分布更平均,我们把这样的操作称为扰动,在JDK 1.8中的hash()函数如下: static final int hash(Object key) { int h; return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);// 与自己右移16位进行异或运算(高低位异或) } 这比在JDK 1.7中,更为简洁,相比在1.7中的4次位运算,5次异或运算(9次扰动),在1.8中,只进行了1次位运算和1次异或运算(2次扰动); JDK1.8新增红黑树 通过上面的链地址法(使用散列表)和扰动函数我们成功让我们的数据分布更平均,哈希碰撞减少,但是当我们的HashMap中存在大量数据时,加入我们某个bucket下对应的链表有n个元素,那么遍历时间复杂度就为O(n),为了针对这个问题,JDK1.8在HashMap中新增了红黑树的数据结构,进一步使得遍历复杂度降低至O(logn); 总结 简单总结一下HashMap是使用了哪些方法来有效解决哈希冲突的: 使用链地址法(使用散列表)来链接拥有相同hash值的数据;使用2次扰动函数(hash函数)来降低哈希冲突的概率,使得数据分布更平均;引入红黑树进一步降低遍历的时间复杂度,使得遍历更快; **能否使用任何类作为 Map 的 key? **可以使用任何类作为 Map 的 key,然而在使用之前,需要考虑以下几点: 如果类重写了 equals() 方法,也应该重写 hashCode() 方法。 类的所有实例需要遵循与 equals() 和 hashCode() 相关的规则。 如果一个类没有使用 equals(),不应该在 hashCode() 中使用它。 用户自定义 Key 类最佳实践是使之为不可变的,这样 hashCode() 值可以被缓存起来,拥有更好的性能。不可变的类也可以确保 hashCode() 和 equals() 在未来不会改变,这样就会解决与可变相关的问题了。 为什么HashMap中String、Integer这样的包装类适合作为K? 答:String、Integer等包装类的特性能够保证Hash值的不可更改性和计算准确性,能够有效的减少Hash碰撞的几率 都是final类型,即不可变性,保证key的不可更改性,不会存在获取hash值不同的情况 内部已重写了equals()、hashCode()等方法,遵守了HashMap内部的规范(不清楚可以去上面看看putValue的过程),不容易出现Hash值计算错误的情况; 如果使用Object作为HashMap的Key,应该怎么办呢? 答:重写hashCode()和equals()方法 重写hashCode()是因为需要计算存储数据的存储位置,需要注意不要试图从散列码计算中排除掉一个对象的关键部分来提高性能,这样虽然能更快但可能会导致更多的Hash碰撞; 重写equals()方法,需要遵守自反性、对称性、传递性、一致性以及对于任何非null的引用值x,x.equals(null)必须返回false的这几个特性,目的是为了保证key在哈希表中的唯一性; HashMap为什么不直接使用hashCode()处理后的哈希值直接作为table的下标 答:hashCode()方法返回的是int整数类型,其范围为-(2 ^ 31)~(2 ^ 31 - 1),约有40亿个映射空间,而HashMap的容量范围是在16(初始化默认值)~2 ^ 30,HashMap通常情况下是取不到最大值的,并且设备上也难以提供这么多的存储空间,从而导致通过hashCode()计算出的哈希值可能不在数组大小范围内,进而无法匹配存储位置; 那怎么解决呢? HashMap自己实现了自己的hash()方法,通过两次扰动使得它自己的哈希值高低位自行进行异或运算,降低哈希碰撞概率也使得数据分布更平均; 在保证数组长度为2的幂次方的时候,使用hash()运算之后的值与运算(&)(数组长度 - 1)来获取数组下标的方式进行存储,这样一来是比取余操作更加有效率,二来也是因为只有当数组长度为2的幂次方时,h&(length-1)才等价于h%length,三来解决了“哈希值与数组大小范围不匹配”的问题; HashMap 的长度为什么是2的幂次方 为了能让 HashMap 存取高效,尽量较少碰撞,也就是要尽量把数据分配均匀,每个链表/红黑树长度大致相同。这个实现就是把数据存到哪个链表/红黑树中的算法。 这个算法应该如何设计呢? 我们首先可能会想到采用%取余的操作来实现。但是,重点来了:“取余(%)操作中如果除数是2的幂次则等价于与其除数减一的与(&)操作(也就是说 hash%length==hash&(length-1)的前提是 length 是2的 n 次方;)。” 并且 采用二进制位操作 &,相对于%能够提高运算效率,这就解释了 HashMap 的长度为什么是2的幂次方。 那为什么是两次扰动呢? 答:这样就是加大哈希值低位的随机性,使得分布更均匀,从而提高对应数组存储下标位置的随机性&均匀性,最终减少Hash冲突,两次就够了,已经达到了高位低位同时参与运算的目的; HashMap 与 HashTable 有什么区别? 线程安全: HashMap 是非线程安全的,HashTable 是线程安全的;HashTable 内部的方法基本都经过 synchronized 修饰。(如果你要保证线程安全的话就使用 ConcurrentHashMap 吧!); 效率: 因为线程安全的问题,HashMap 要比 HashTable 效率高一点。另外,HashTable 基本被淘汰,不要在代码中使用它; 对Null key 和Null value的支持: HashMap 中,null 可以作为键,这样的键只有一个,可以有一个或多个键所对应的值为 null。但是在 HashTable 中 put 进的键值只要有一个 null,直接抛NullPointerException。 **初始容量大小和每次扩充容量大小的不同 **: ①创建时如果不指定容量初始值,Hashtable 默认的初始大小为11,之后每次扩充,容量变为原来的2n+1。HashMap 默认的初始化大小为16。之后每次扩充,容量变为原来的2倍。②创建时如果给定了容量初始值,那么 Hashtable 会直接使用你给定的大小,而 HashMap 会将其扩充为2的幂次方大小。也就是说 HashMap 总是使用2的幂作为哈希表的大小,后面会介绍到为什么是2的幂次方。 底层数据结构: JDK1.8 以后的 HashMap 在解决哈希冲突时有了较大的变化,当链表长度大于阈值(默认为8)时,将链表转化为红黑树,以减少搜索时间。Hashtable 没有这样的机制。 推荐使用:在 Hashtable 的类注释可以看到,Hashtable 是保留类不建议使用,推荐在单线程环境下使用 HashMap 替代,如果需要多线程使用则用 ConcurrentHashMap 替代。 如何决定使用 HashMap 还是 TreeMap? 对于在Map中插入、删除和定位元素这类操作,HashMap是最好的选择。然而,假如你需要对一个有序的key集合进行遍历,TreeMap是更好的选择。基于你的collection的大小,也许向HashMap中添加元素会更快,将map换为TreeMap进行有序key的遍历。 HashMap 和 ConcurrentHashMap 的区别 ConcurrentHashMap对整个桶数组进行了分割分段(Segment),然后在每一个分段上都用lock锁进行保护,相对于HashTable的synchronized锁的粒度更精细了一些,并发性能更好,而HashMap没有锁机制,不是线程安全的。(JDK1.8之后ConcurrentHashMap启用了一种全新的方式实现,利用CAS算法。) HashMap的键值对允许有null,但是ConCurrentHashMap都不允许。 ConcurrentHashMap 和 Hashtable 的区别? ConcurrentHashMap 和 Hashtable 的区别主要体现在实现线程安全的方式上不同。 底层数据结构: JDK1.7的 ConcurrentHashMap 底层采用 分段的数组+链表 实现,JDK1.8 采用的数据结构跟HashMap1.8的结构一样,数组+链表/红黑二叉树。Hashtable 和 JDK1.8 之前的 HashMap 的底层数据结构类似都是采用 数组+链表 的形式,数组是 HashMap 的主体,链表则是主要为了解决哈希冲突而存在的; 实现线程安全的方式(重要): ① 在JDK1.7的时候,ConcurrentHashMap(分段锁) 对整个桶数组进行了分割分段(Segment),每一把锁只锁容器其中一部分数据,多线程访问容器里不同数据段的数据,就不会存在锁竞争,提高并发访问率。(默认分配16个Segment,比Hashtable效率提高16倍。) 到了 JDK1.8 的时候已经摒弃了Segment的概念,而是直接用 Node 数组+链表+红黑树的数据结构来实现,并发控制使用 synchronized 和 CAS 来操作。(JDK1.6以后 对 synchronized锁做了很多优化) 整个看起来就像是优化过且线程安全的 HashMap,虽然在JDK1.8中还能看到 Segment 的数据结构,但是已经简化了属性,只是为了兼容旧版本;② Hashtable(同一把锁) :使用 synchronized 来保证线程安全,效率非常低下。当一个线程访问同步方法时,其他线程也访问同步方法,可能会进入阻塞或轮询状态,如使用 put 添加元素,另一个线程不能使用 put 添加元素,也不能使用 get,竞争会越来越激烈效率越低。 两者的对比图: HashTable: JDK1.7的ConcurrentHashMap: JDK1.8的ConcurrentHashMap(TreeBin: 红黑二叉树节点 Node: 链表节点): 答:ConcurrentHashMap 结合了 HashMap 和 HashTable 二者的优势。HashMap 没有考虑同步,HashTable 考虑了同步的问题。但是 HashTable 在每次同步执行时都要锁住整个结构。 ConcurrentHashMap 锁的方式是稍微细粒度的。 ConcurrentHashMap 底层具体实现知道吗?实现原理是什么? JDK1.7 首先将数据分为一段一段的存储,然后给每一段数据配一把锁,当一个线程占用锁访问其中一个段数据时,其他段的数据也能被其他线程访问。 在JDK1.7中,ConcurrentHashMap采用Segment + HashEntry的方式进行实现,结构如下: 一个 ConcurrentHashMap 里包含一个 Segment 数组。Segment 的结构和HashMap类似,是一种数组和链表结构,一个 Segment 包含一个 HashEntry 数组,每个 HashEntry 是一个链表结构的元素,每个 Segment 守护着一个HashEntry数组里的元素,当对 HashEntry 数组的数据进行修改时,必须首先获得对应的 Segment的锁。 该类包含两个静态内部类 HashEntry 和 Segment ;前者用来封装映射表的键值对,后者用来充当锁的角色;Segment 是一种可重入的锁 ReentrantLock,每个 Segment 守护一个HashEntry 数组里得元素,当对 HashEntry 数组的数据进行修改时,必须首先获得对应的 Segment 锁。 JDK1.8 在JDK1.8中,放弃了Segment臃肿的设计,取而代之的是采用Node + CAS + Synchronized来保证并发安全进行实现,synchronized只锁定当前链表或红黑二叉树的首节点,这样只要hash不冲突,就不会产生并发,效率又提升N倍。 结构如下: 如果该节点是TreeBin类型的节点,说明是红黑树结构,则通过putTreeVal方法往红黑树中插入节点;如果binCount不为0,说明put操作对数据产生了影响,如果当前链表的个数达到8个,则通过treeifyBin方法转化为红黑树,如果oldVal不为空,说明是一次更新操作,没有对元素个数产生影响,则直接返回旧值;如果插入的是一个新节点,则执行addCount()方法尝试更新元素个数baseCount; 辅助工具类 Array 和 ArrayList 有何区别? Array 可以存储基本数据类型和对象,ArrayList 只能存储对象。Array 是指定固定大小的,而 ArrayList 大小是自动扩展的。Array 内置方法没有 ArrayList 多,比如 addAll、removeAll、iteration 等方法只有 ArrayList 有。 对于基本类型数据,集合使用自动装箱来减少编码工作量。但是,当处理固定大小的基本数据类型的时候,这种方式相对比较慢。 如何实现 Array 和 List 之间的转换? Array 转 List: Arrays. asList(array) ;List 转 Array:List 的 toArray() 方法。 comparable 和 comparator的区别? comparable接口实际上是出自java.lang包,它有一个 compareTo(Object obj)方法用来排序comparator接口实际上是出自 java.util 包,它有一个compare(Object obj1, Object obj2)方法用来排序 一般我们需要对一个集合使用自定义排序时,我们就要重写compareTo方法或compare方法,当我们需要对某一个集合实现两种排序方式,比如一个song对象中的歌名和歌手名分别采用一种排序方法的话,我们可以重写compareTo方法和使用自制的Comparator方法或者以两个Comparator来实现歌名排序和歌星名排序,第二种代表我们只能使用两个参数版的Collections.sort(). 方法如何比较元素? TreeSet 要求存放的对象所属的类必须实现 Comparable 接口,该接口提供了比较元素的 compareTo()方法,当插入元素时会回调该方法比较元素的大小。TreeMap 要求存放的键值对映射的键必须实现 Comparable 接口从而根据键对元素进 行排 序。 Collections 工具类的 sort 方法有两种重载的形式, 第一种要求传入的待排序容器中存放的对象比较实现 Comparable 接口以实现元素的比较; 第二种不强制性的要求容器中的元素必须可比较,但是要求传入第二个参数,参数是Comparator 接口的子类型(需要重写 compare 方法实现元素的比较),相当于一个临时定义的排序规则,其实就是通过接口注入比较元素大小的算法,也是对回调模式的应用(Java 中对函数式编程的支持)。

剑曼红尘 2020-03-24 14:41:57 0 浏览量 回答数 0

问题

【精品问答】Java必备核心知识1000+(附源码)

问问小秘 2019-12-01 22:00:28 870 浏览量 回答数 1

问题

为什么对基础设施的监控变得如此重要?

忆远0711 2019-12-01 21:46:44 8511 浏览量 回答数 1

问题

迷你书下载 精彩片段: 恶名昭著的指针究竟是什么:报错

kun坤 2020-06-09 15:10:04 4 浏览量 回答数 1

回答

服务器和操作系统 1、主板的两个芯片分别是什么芯片,具备什么作用? 北桥:离CPU近,负责CPU、内存、显卡之间的通信。 南桥:离CPU远,负责I/O总线之间的通信。 2、什么是域和域控制器? 将网络中的计算机逻辑上组织到一起,进行集中管理,这种集中管理的环境称为域。 在域中,至少有一台域控制器,域控制器中保存着整个域的用户账号和安全数据,安装了活动目录的一台计算机为域控制器,域管理员可以控制每个域用户的行为。 3、现在有300台虚拟机在云上,你如何进行管理? 1)设定堡垒机,使用统一账号登录,便于安全与登录的考量。 2)使用ansiable、puppet进行系统的统一调度与配置的统一管理。 3)建立简单的服务器的系统、配置、应用的cmdb信息管理。便于查阅每台服务器上的各种信息记录。 4、简述raid0 raid1 raid5 三种工作模式的工作原理及特点 磁盘冗余阵列(Redundant Arrays of Independent Disks,RAID),把硬盘整合成一个大磁盘,在大磁盘上再分区,存放数据、多块盘放在一起可以有冗余(备份)。 RAID整合方式有很多,常用的:0 1 5 10 RAID 0:可以是一块盘和N个盘组合 优点:读写快,是RAID中最好的 缺点:没有冗余,一块坏了数据就全没有了 RAID 1:只能2块盘,盘的大小可以不一样,以小的为准 10G+10G只有10G,另一个做备份。它有100%的冗余,缺点:浪费资源,成本高 RAID 5 :3块盘,容量计算10*(n-1),损失一块盘 特点:读写性能一般,读还好一点,写不好 总结: 冗余从好到坏:RAID1 RAID10 RAID 5 RAID0 性能从好到坏:RAID0 RAID10 RAID5 RAID1 成本从低到高:RAID0 RAID5 RAID1 RAID10 5、linux系统里,buffer和cache如何区分? buffer和cache都是内存中的一块区域,当CPU需要写数据到磁盘时,由于磁盘速度比较慢,所以CPU先把数据存进buffer,然后CPU去执行其他任务,buffer中的数据会定期写入磁盘;当CPU需要从磁盘读入数据时,由于磁盘速度比较慢,可以把即将用到的数据提前存入cache,CPU直接从Cache中拿数据要快的多。 6、主机监控如何实现? 数据中心可以用zabbix(也可以是nagios或其他)监控方案,zabbix图形界面丰富,也自带很多监控模板,特别是多个分区、多个网卡等自动发现并进行监控做得非常不错,不过需要在每台客户机(被监控端)安装zabbix agent。 如果在公有云上,可以使用云监控来监控主机的运行。 网络 7、主机与主机之间通讯的三要素有什么? IP地址、子网掩码、IP路由 8、TCP和UDP都可以实现客户端/服务端通信,这两个协议有何区别? TCP协议面向连接、可靠性高、适合传输大量数据;但是需要三次握手、数据补发等过程,耗时长、通信延迟大。 UDP协议面向非连接、可靠性低、适合传输少量数据;但是连接速度快、耗时短、延迟小。 9、简述TCP协议三次握手和四次分手以及数据传输过程 三次握手: (1)当主机A想同主机B建立连接,主机A会发送SYN给主机B,初始化序列号seq=x。主机A通过向主机B发送SYS报文段,实现从主机A到主机B的序列号同步,即确定seq中的x。 (2)主机B接收到报文后,同意与A建立连接,会发送SYN、ACK给主机A。初始化序列号seq=y,确认序号ack=x+1。主机B向主机A发送SYN报文的目的是实现从主机B到主机A的序列号同步,即确定seq中的y。 (3)主机A接收到主机B发送过来的报文后,会发送ACK给主机B,确认序号ack=y+1,建立连接完成,传输数据。 四次分手: (1)当主机A的应用程序通知TCP数据已经发送完毕时,TCP向主机B发送一个带有FIN附加标记的报文段,初始化序号seq=x。 (2)主机B收到这个FIN报文段,并不立即用FIN报文段回复主机A,而是想主机A发送一个确认序号ack=x+1,同时通知自己的应用程序,对方要求关闭连接(先发ack是防止主机A重复发送FIN报文)。 (3)主机B发送完ack确认报文后,主机B 的应用程序通知TCP我要关闭连接,TCP接到通知后会向主机A发送一个带有FIN附加标记的报文段,初始化序号seq=x,ack=x+1。 (4)主机A收到这个FIN报文段,向主机B发送一个ack确认报文,ack=y+1,表示连接彻底释放。 10、SNAT和DNAT的区别 SNAT:内部地址要访问公网上的服务时(如web访问),内部地址会主动发起连接,由路由器或者防火墙上的网关对内部地址做个地址转换,将内部地址的私有IP转换为公网的公有IP,网关的这个地址转换称为SNAT,主要用于内部共享IP访问外部。 DNAT:当内部需要提供对外服务时(如对外发布web网站),外部地址发起主动连接,由路由器或者防火墙上的网关接收这个连接,然后将连接转换到内部,此过程是由带有公网IP的网关替代内部服务来接收外部的连接,然后在内部做地址转换,此转换称为DNAT,主要用于内部服务对外发布。 数据库 11、叙述数据的强一致性和最终一致性 强一致性:在任何时刻所有的用户或者进程查询到的都是最近一次成功更新的数据。强一致性是程度最高一致性要求,也是最难实现的。关系型数据库更新操作就是这个案例。 最终一致性:和强一致性相对,在某一时刻用户或者进程查询到的数据可能都不同,但是最终成功更新的数据都会被所有用户或者进程查询到。当前主流的nosql数据库都是采用这种一致性策略。 12、MySQL的主从复制过程是同步的还是异步的? 主从复制的过程是异步的复制过程,主库完成写操作并计入binlog日志中,从库再通过请求主库的binlog日志写入relay中继日志中,最后再执行中继日志的sql语句。 **13、MySQL主从复制的优点 ** 如果主服务器出现问题,可以快速切换到从服务器提供的服务; 可以在从服务器上执行查询操作,降低主服务器的访问压力; 可以在从服务器上执行备份,以避免备份期间影响主服务器的服务。 14、redis有哪些数据类型? (一)String 最常规的set/get操作,value可以是String也可以是数字。一般做一些复杂的计数功能的缓存。 (二)hash 这里value存放的是结构化的对象,比较方便的就是操作其中的某个字段。做单点登录的时候,就是用这种数据结构存储用户信息,以cookieId作为key,设置30分钟为缓存过期时间,能很好的模拟出类似session的效果。 (三)list 使用List的数据结构,可以做简单的消息队列的功能。另外还有一个就是,可以利用lrange命令,做基于redis的分页功能,性能极佳,用户体验好。 (四)set 因为set堆放的是一堆不重复值的集合。所以可以做全局去重的功能。为什么不用JVM自带的Set进行去重?因为我们的系统一般都是集群部署,使用JVM自带的Set,比较麻烦,难道为了一个做一个全局去重,再起一个公共服务,太麻烦了。 另外,就是利用交集、并集、差集等操作,可以计算共同喜好,全部的喜好,自己独有的喜好等功能。 (五)Zset Zset多了一个权重参数score,集合中的元素能够按score进行排列。可以做排行榜应用,取TOP N操作。另外,sorted set可以用来做延时任务。最后一个应用就是可以做范围查找。 15、叙述分布式数据库及其使用场景? 分布式数据库应该是数据访问对应用透明,每个分片默认采用主备架构,提供灾备、恢复、监控、不停机扩容等整套解决方案,适用于TB或PB级的海量数据场景。 应用 16、Apache、Nginx、Lighttpd都有哪些特点? Apache特点:1)几乎可以运行在所有的计算机平台上;2)支持最新的http/1.1协议;3)简单而且强有力的基于文件的配置(httpd.conf);4)支持通用网关接口(cgi);5)支持虚拟主机;6)支持http认证,7)集成perl;8)集成的代理服务器;9)可以通过web浏览器监视服务器的状态,可以自定义日志;10)支持服务器端包含命令(ssi);11)支持安全socket层(ssl);12)具有用户绘画过程的跟踪能力;13)支持fastcgi;14)支持java servlets Nginx特点:nginx是一个高性能的HTTP和反向代理服务器,同时也是一个IMAP/POP3/SMTP代理服务器,处理静态文件,索引文件以及自动索引,无缓存的反向代理加速,简单的负载均衡和容错,具有很高的稳定性,支持热部署。 Lighttpd特点:是一个具有非常低的内存开销,CPU占用率低,效能好,以及丰富的模块,Lighttpd是众多opensource轻量级的webserver中较为优秀的一个,支持fastcgi,cgi,auth,输出压缩,url重写,alias等重要功能。 17、LVS、NGINX、HAPROXY的优缺点? LVS优点:具有很好的可伸缩性、可靠性、可管理性。抗负载能力强、对内存和CPU资源消耗比较低。工作在四层上,仅作分发,所以它几乎可以对所有的应用做负载均衡,且没有流量的产生,不会受到大流量的影响。 LVS缺点:软件不支持正则表达式处理,不能做动静分离,如果web应用比较庞大,LVS/DR+KEEPALIVED实施和管理比较复杂。相对而言,nginx和haproxy就简单得多。 nginx优点:工作在七层之上,可以针对http应用做一些分流的策略。比如针对域名、目录结构。它的正则规则比haproxy更为强大和灵活。对网络稳定性依赖非常小。理论上能PING就能进行负载均衡。配置和测试简单,可以承担高负载压力且稳定。nginx可以通过端口检测到服务器内部的故障。比如根据服务器处理网页返回的状态码、超时等。并且可以将返回错误的请求重新发送给另一个节点,同时nginx不仅仅是负载均衡器/反向代理软件。同时也是功能强大的web服务器,可以作为中层反向代理、静态网页和图片服务器使用。 nginx缺点:不支持URL检测,仅支持HTTP和EMAIL,对session的保持,cookie的引导能力相对欠缺。 Haproxy优点:支持虚拟主机、session的保持、cookie的引导;同时支持通过获取指定的url来检测后端服务器的状态。支持TCP协议的负载均衡;单纯从效率上讲比nginx更出色,且负载策略非常多。 aproxy缺点:扩展性能差;添加新功能很费劲,对不断扩展的新业务很难对付。 18、什么是中间件?什么是jdk? 中间件介绍: 中间件是一种独立的系统软件或服务程序,分布式应用软件借助这种软件在不同的技术之间共享资源 中间件位于客户机/ 服务器的操作系统之上,管理计算机资源和网络通讯 是连接两个独立应用程序或独立系统的软件。相连接的系统,即使它们具有不同的接口 但通过中间件相互之间仍能交换信息。执行中间件的一个关键途径是信息传递 通过中间件,应用程序可以工作于多平台或OS环境。 jdk:jdk是Java的开发工具包 它是一种用于构建在 Java 平台上发布的应用程序、applet 和组件的开发环境 19、日志收集、日志检索、日志展示的常用工具有哪些? ELK或EFK。 Logstash:数据收集处理引擎。支持动态的从各种数据源搜集数据,并对数据进行过滤、分析、丰富、统一格式等操作,然后存储以供后续使用。 Kibana:可视化化平台。它能够搜索、展示存储在 Elasticsearch 中索引数据。使用它可以很方便的用图表、表格、地图展示和分析数据。 Elasticsearch:分布式搜索引擎。具有高可伸缩、高可靠、易管理等特点。可以用于全文检索、结构化检索和分析,并能将这三者结合起来。Elasticsearch 基于 Lucene 开发,现在使用最广的开源搜索引擎之一,Wikipedia 、StackOverflow、Github 等都基于它来构建自己的搜索引擎。 Filebeat:轻量级数据收集引擎。基于原先 Logstash-fowarder 的源码改造出来。换句话说:Filebeat就是新版的 Logstash-fowarder,逐渐取代其位置。 20、什么是蓝绿发布和灰度发布? 蓝绿:旧版本-新版本 灰度:新旧版本各占一定比例,比例可自定义 两种发布都通过devops流水线实现

剑曼红尘 2020-03-23 15:51:44 0 浏览量 回答数 0

问题

大数据时代——数据存储技术百问

yq传送门 2019-12-01 20:27:42 31965 浏览量 回答数 35

回答

简介 ES是一个基于RESTful web接口并且构建在Apache Lucene之上的开源分布式搜索引擎。 同时ES还是一个分布式文档数据库,其中每个字段均可被索引,而且每个字段的数据均可被搜索,能够横向扩展至数以百计的服务器存储以及处理PB级的数据。 可以在极短的时间内存储、搜索和分析大量的数据。通常作为具有复杂搜索场景情况下的核心发动机。 ES就是为高可用和可扩展而生的。一方面可以通过升级硬件来完成系统扩展,称为垂直或向上扩展(Vertical Scale/Scaling Up)。 另一方面,增加更多的服务器来完成系统扩展,称为水平扩展或者向外扩展(Horizontal Scale/Scaling Out)。尽管ES能够利用更强劲的硬件,但是垂直扩展毕竟还是有它的极限。真正的可扩展性来自于水平扩展,通过向集群中添加更多的节点来分担负载,增加可靠性。ES天生就是分布式的,它知道如何管理多个节点来完成扩展和实现高可用性。意味应用不需要做任何的改动。 Gateway,代表ES索引的持久化存储方式。在Gateway中,ES默认先把索引存储在内存中,然后当内存满的时候,再持久化到Gateway里。当ES集群关闭或重启的时候,它就会从Gateway里去读取索引数据。比如LocalFileSystem和HDFS、AS3等。 DistributedLucene Directory,它是Lucene里的一些列索引文件组成的目录。它负责管理这些索引文件。包括数据的读取、写入,以及索引的添加和合并等。 River,代表是数据源。是以插件的形式存在于ES中。  Mapping,映射的意思,非常类似于静态语言中的数据类型。比如我们声明一个int类型的变量,那以后这个变量只能存储int类型的数据。比如我们声明一个double类型的mapping字段,则只能存储double类型的数据。 Mapping不仅是告诉ES,哪个字段是哪种类型。还能告诉ES如何来索引数据,以及数据是否被索引到等。 Search Moudle,搜索模块,支持搜索的一些常用操作 Index Moudle,索引模块,支持索引的一些常用操作 Disvcovery,主要是负责集群的master节点发现。比如某个节点突然离开或进来的情况,进行一个分片重新分片等。这里有个发现机制。 发现机制默认的实现方式是单播和多播的形式,即Zen,同时也支持点对点的实现。另外一种是以插件的形式,即EC2。 Scripting,即脚本语言。包括很多,这里不多赘述。如mvel、js、python等。    Transport,代表ES内部节点,代表跟集群的客户端交互。包括 Thrift、Memcached、Http等协议 RESTful Style API,通过RESTful方式来实现API编程。 3rd plugins,代表第三方插件。 Java(Netty),是开发框架。 JMX,是监控。 使用案例 1、将ES作为网站的主要后端系统 比如现在搭建一个博客系统,对于博客帖子的数据可以直接在ES上存储,并且使用ES来进行检索,统计。ES提供了持久化的存储、统计和很多其他数据存储的特性。 注意:但是像其他的NOSQL数据存储一样,ES是不支持事务的,如果要事务机制,还是考虑使用其他的数据库做真实库。 2、将ES添加到现有系统 有些时候不需要ES提供所有数据的存储功能,只是想在一个数据存储的基础之上使用ES。比如已经有一个复杂的系统在运行,但是现在想加一个搜索的功能,就可以使用该方案。 3、将ES作为现有解决方案的后端部分 因为ES是开源的系统,提供了直接的HTTP接口,并且现在有一个大型的生态系统在支持他。比如现在我们想部署大规模的日志框架、用于存储、搜索和分析海量的事件,考虑到现有的工具可以写入和读取ES,可以不需要进行任何开发,配置这些工具就可以去运作。 设计结构 1、逻辑设计 文档 文档是可以被索引的信息的基本单位,它包含几个重要的属性: 是自我包含的。一篇文档同时包含字段和他们的取值。 是层次型的。文档中还可以包含新的文档,一个字段的取值可以是简单的,例如location字段的取值可以是字符串,还可以包含其他字段和取值,比如可以同时包含城市和街道地址。 拥有灵活的结构。文档不依赖于预先定义的模式。也就是说并非所有的文档都需要拥有相同的字段,并不受限于同一个模式 {   "name":"meeting",   "location":"office",   "organizer":"yanping" } {   "name":"meeting",   "location":{     "name":"sheshouzuo",        "date":"2019-6-28"   },   "memebers":["leio","shiyi"] } 类型 类型是文档的逻辑容器,类似于表格是行的容器。在不同的类型中,最好放入不同的结构的文档。 字段 ES中,每个文档,其实是以json形式存储的。而一个文档可以被视为多个字段的集合。 映射 每个类型中字段的定义称为映射。例如,name字段映射为String。 索引 索引是映射类型的容器一个ES的索引非常像关系型世界中的数据库,是独立的大量文档集合。   关系型数据库与ES的结构上的对比 2、物理设计 节点 一个节点是一个ES的实例,在服务器上启动ES之后,就拥有了一个节点,如果在另一个服务器上启动ES,这就是另一个节点。甚至可以在一台服务器上启动多个ES进程,在一台服务器上拥有多个节点。多个节点可以加入同一个集群。 当ElasticSearch的节点启动后,它会利用多播(multicast)(或者单播,如果用户更改了配置)寻找集群中的其它节点,并与之建立连接。这个过程如下图所示: 节点主要有3种类型,第一种类型是client_node,主要是起到请求分发的作用,类似路由。第二种类型是master_node,是主的节点,所有的新增,删除,数据分片都是由主节点操作(elasticsearch底层是没有更新数据操作的,上层对外提供的更新实际上是删除了再新增),当然也能承担搜索操作。第三种类型是date_node,该类型的节点只能做搜索操作,具体会分配到哪个date_node,就是由client_node决定,而data_node的数据都是从master_node同步过来的 分片 一个索引可以存储超出单个结点硬件限制的大量数据。比如,一个具有10亿文档的索引占据1TB的磁盘空间,而任一节点都没有这样大的磁盘空间;或者单个节点处理搜索请求,响应太慢。   为了解决这个问题,ES提供了将索引划分成多份的能力,这些份就叫做分片。当你创建一个索引的时候,你可以指定你想要的分片的数量。每个分片本身也是一个功能完善并且独立的“索引”,这个“索引”可以被放置到集群中的任何节点上。 分片之所以重要,主要有两方面的原因:   1、允许你水平分割/扩展你的内容容量 允许你在分片(潜在地,位于多个节点上)之上进行分布式的、并行的操作,进而提高性能/吞吐量 至于一个分片怎样分布,它的文档怎样聚合回搜索请求,是完全由ES管理的,对于作为用户的你来说,这些都是透明的。   2、在一个网络/云的环境里,失败随时都可能发生,在某个分片/节点不知怎么的就处于离线状态,或者由于任何原因消失了。这种情况下,有一个故障转移机制是非常有用并且是强烈推荐的。为此目的,ES允许你创建分片的一份或多份拷贝,这些拷贝叫做复制分片,或者直接叫复制。 复制之所以重要,主要有两方面的原因: (1)在分片/节点失败的情况下,提供了高可用性。因为这个原因,注意到复制分片从不与原/主要(original/primary)分片置于同一节点上是非常重要的。 (2)扩展你的搜索量/吞吐量,因为搜索可以在所有的复制上并行运行 总之,每个索引可以被分成多个分片。一个索引也可以被复制0次(意思是没有复制)或多次。一旦复制了,每个索引就有了主分片(作为复制源的原来的分片)和复制分片(主分片的拷贝)之别。分片和复制的数量可以在索引创建的时候指定。在索引创建之后,你可以在任何时候动态地改变复制数量,但是不能改变分片的数量。   默认情况下,ES中的每个索引被分片5个主分片和1个复制,这意味着,如果你的集群中至少有两个节点,你的索引将会有5个主分片和另外5个复制分片(1个完全拷贝),这样的话每个索引总共就有10个分片。一个索引的多个分片可以存放在集群中的一台主机上,也可以存放在多台主机上,这取决于你的集群机器数量。主分片和复制分片的具体位置是由ES内在的策略所决定的。 3、插件HEAD elasticsearch-head是一个界面化的集群操作和管理工具 ● node:即一个 Elasticsearch 的运行实例,使用多播或单播方式发现 cluster 并加入。 ● cluster:包含一个或多个拥有相同集群名称的 node,其中包含一个master node。 ● index:类比关系型数据库里的DB,是一个逻辑命名空间。 ● alias:可以给 index 添加零个或多个alias,通过 alias 使用index 和根据index name 访问index一样,但是,alias给我们提供了一种切换index的能力,比如重建了index,取名● customer_online_v2,这时,有了alias,我要访问新 index,只需要把 alias 添加到新 index 即可,并把alias从旧的 index 删除。不用修改代码。 ● type:类比关系数据库里的Table。其中,一个index可以定义多个type,但一般使用习惯仅配一个type。 ● mapping:类比关系型数据库中的 schema 概念,mapping 定义了 index 中的 type。mapping 可以显示的定义,也可以在 document 被索引时自动生成,如果有新的 field,Elasticsearch 会自动推测出 field 的type并加到mapping中。 ● document:类比关系数据库里的一行记录(record),document 是 Elasticsearch 里的一个 JSON 对象,包括零个或多个field。 ● field:类比关系数据库里的field,每个field 都有自己的字段类型。 ● shard:是一个Lucene 实例。Elasticsearch 基于 Lucene,shard 是一个 Lucene 实例,被 Elasticsearch 自动管理。之前提到,index 是一个逻辑命名空间,shard 是具体的物理概念,建索引、查询等都是具体的shard在工作。shard 包括primary shard 和 replica shard,写数据时,先写到primary shard,然后,同步到replica shard,查询时,primary 和 replica 充当相同的作用。replica shard 可以有多份,也可以没有,replica shard的存在有两个作用,一是容灾,如果primary shard 挂了,数据也不会丢失,集群仍然能正常工作;二是提高性能,因为replica 和 primary shard 都能处理查询。另外,如上图右侧红框所示,shard数和replica数都可以设置,但是,shard 数只能在建立index 时设置,后期不能更改,但是,replica 数可以随时更改。但是,由于 Elasticsearch 很友好的封装了这部分,在使用Elasticsearch 的过程中,我们一般仅需要关注 index 即可,不需关注shard。   shard、node、cluster 在物理上构成了 Elasticsearch 集群,field、type、index 在逻辑上构成一个index的基本概念,在使用 Elasticsearch 过程中,我们一般关注到逻辑概念就好,就像我们在使用MySQL 时,我们一般就关注DB Name、Table和schema即可,而不会关注DBA维护了几个MySQL实例、master 和 slave 等怎么部署的一样。 ES中的索引原理 (1)传统的关系型数据库 二叉树查找效率是logN,同时插入新的节点不必移动全部节点,所以用树型结构存储索引,能同时兼顾插入和查询的性能。因此在这个基础上,再结合磁盘的读取特性(顺序读/随机读),传统关系型数据库采用了B-Tree/B+Tree这样的数据结构做索引 (2)ES 采用倒排索引 那么,倒排索引是个什么样子呢? 首先,来搞清楚几个概念,为此,举个例子: 假设有个user索引,它有四个字段:分别是name,gender,age,address。画出来的话,大概是下面这个样子,跟关系型数据库一样 Term(单词):一段文本经过分析器分析以后就会输出一串单词,这一个一个的就叫做Term Term Dictionary(单词字典):顾名思义,它里面维护的是Term,可以理解为Term的集合 Term Index(单词索引):为了更快的找到某个单词,我们为单词建立索引 Posting List(倒排列表):倒排列表记录了出现过某个单词的所有文档的文档列表及单词在该文档中出现的位置信息,每条记录称为一个倒排项(Posting)。根据倒排列表,即可获知哪些文档包含某个单词。(PS:实际的倒排列表中并不只是存了文档ID这么简单,还有一些其它的信息,比如:词频(Term出现的次数)、偏移量(offset)等,可以想象成是Python中的元组,或者Java中的对象) (PS:如果类比现代汉语词典的话,那么Term就相当于词语,Term Dictionary相当于汉语词典本身,Term Index相当于词典的目录索引) 我们知道,每个文档都有一个ID,如果插入的时候没有指定的话,Elasticsearch会自动生成一个,因此ID字段就不多说了 上面的例子,Elasticsearch建立的索引大致如下: name字段: age字段: gender字段: address字段: Elasticsearch分别为每个字段都建立了一个倒排索引。比如,在上面“张三”、“北京市”、22 这些都是Term,而[1,3]就是Posting List。Posting list就是一个数组,存储了所有符合某个Term的文档ID。 只要知道文档ID,就能快速找到文档。可是,要怎样通过我们给定的关键词快速找到这个Term呢? 当然是建索引了,为Terms建立索引,最好的就是B-Tree索引(MySQL就是B树索引最好的例子)。 我们查找Term的过程跟在MyISAM中记录ID的过程大致是一样的 MyISAM中,索引和数据是分开,通过索引可以找到记录的地址,进而可以找到这条记录 在倒排索引中,通过Term索引可以找到Term在Term Dictionary中的位置,进而找到Posting List,有了倒排列表就可以根据ID找到文档了 (PS:可以这样理解,类比MyISAM的话,Term Index相当于索引文件,Term Dictionary相当于数据文件) (PS:其实,前面我们分了三步,我们可以把Term Index和Term Dictionary看成一步,就是找Term。因此,可以这样理解倒排索引:通过单词找到对应的倒排列表,根据倒排列表中的倒排项进而可以找到文档记录) 为了更进一步理解,用两张图来具现化这一过程: (至于里面涉及的更加高深的数据压缩技巧,以及多个field联合查询利用跳表的数据结构快速做运算来查询,这些大家有兴趣可以自己去了解)

问问小秘 2020-04-29 15:40:48 0 浏览量 回答数 0

问题

【精品问答】Python二级考试题库

珍宝珠 2019-12-01 22:03:38 1146 浏览量 回答数 2

回答

PHP面试干货 1、进程和线程 进程和线程都是由操作系统所体会的程序运行的基本单元,系统利用该基本单元实现系统对应用的并发性。进程和线程的区别在于: 简而言之,一个程序至少有一个进程,一个进程至少有一个线程. 线程的划分尺度小于进程,使得多线程程序的并发性高。 另外,进程在执行过程中拥有独立的内存单元,而多个线程共享内存,从而极大地提高了程序的运行效率。 线程在执行过程中与进程还是有区别的。每个独立的线程有一个程序运行的入口、顺序执行序列和程序的出口。但是线程不能够独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制。 从逻辑角度来看,多线程的意义在于一个应用程序中,有多个执行部分可以同时执行。但操作系统并没有将多个线程看做多个独立的应用,来实现进程的调度和管理以及资源分配。这就是进程和线程的重要区别。 2、apache默认使用进程管理还是线程管理?如何判断并设置最大连接数? 一个进程可以开多个线程 默认是进程管理 默认有一个主进程 Linux: ps -aux | grep httpd | more 一个子进程代表一个用户的连接 Conf/extra/httpd-mpm.conf 多路功能模块 http -l 查询当前apache处于什么模式下 3、单例模式 单例模式需求:只能实例化产生一个对象 如何实现: 私有化构造函数 禁止克隆对象 提供一个访问这个实例的公共的静态方法(通常为getInstance方法),从而返回唯一对象 需要一个保存类的静态属性 class demo { private static $MyObject; //保存对象的静态属性 private function __construct(){ //私有化构造函数 } private function __clone(){ //禁止克隆 } public static function getInstance(){ if(! (self::$MyObject instanceof self)){ self::$MyObject = new self; } return self::$MyObject; } } 4、安装完Apache后,在http.conf中配置加载PHP文件以Apache模块的方式安装PHP,在文件http.conf中首先要用语句LoadModule php5_module "e:/php/php5apache2.dll"动态装载PHP模块,然后再用语句AddType application/x-httpd-php .php 使得Apache把所有扩展名为PHP的文件都作为PHP脚本处理 5、debug_backtrace()函数能返回脚本里的任意行中调用的函数的名称。该函数同时还经常被用在调试中,用来判断错误是如何发生的 function one($str1, $str2) { two("Glenn", "Quagmire"); } function two($str1, $str2) { three("Cleveland", "Brown"); } function three($str1, $str2) { print_r(debug_backtrace()); } one("Peter", "Griffin"); Array ( [0] => Array ( [file] => D:\www\test\result.php [line] => 9 [function] => three [args] => Array ( [0] => Cleveland [1] => Brown ) ) [1] => Array ( [file] => D:\www\test\result.php [line] => 5 [function] => two [args] => Array ( [0] => Glenn [1] => Quagmire ) ) [2] => Array ( [file] => D:\www\test\result.php [line] => 16 [function] => one [args] => Array ( [0] => Peter [1] => Griffin ) ) ) 6、输出用户的IP地址,并且判断用户的IP地址是否在192.168.1.100 — 192.168.1.150之间 echo $ip=getenv('REMOTE_ADDR'); $ip=str_replace('.','',$ip); if($ip<1921681150 && $ip>1921681100) { echo 'ip在192.168.1.100—–192.168.1.150之间'; } else { echo 'ip不在192.168.1.100—–192.168.1.150之间'; } 7、请将2维数组按照name的长度进行重新排序,按照顺序将id赋值 $tarray = array( array('id' => 0, 'name' => '123'), array('id' => 0, 'name' => '1234'), array('id' => 0, 'name' => '1235'), array('id' => 0, 'name' => '12356'), array('id' => 0, 'name' => '123abc') ); foreach($tarray as $key=>$val) { $c[]=$val['name']; } function aa($a,$b) { if(strlen($a)==strlen($b)) return 0; return strlen($a)>strlen($b)?-1:1; } usort($c,'aa'); $len=count($c); for($i=0;$i<$len;$i++) { $t[$i]['id']=$i+1; $t[$i]['name']=$c[$i]; } print_r($t); 8、表单数据提交方式POST和GET的区别,URL地址传递的数据最大长度是多少? POST方式提交数据用户不可见,是数据更安全,最大长度不受限制,而GET方式传值在URL地址可以看到,相对不安全,对大长度是2048字节。 9、SESSION和COOKIE的作用和区别,SESSION信息的存储方式,如何进行遍历 SESSION和COOKIE都能够使值在页面之间进行传递,SESSION存储在服务器端,数据更安全,COOKIE保存在客户端,用户使用手段可以进行修改,SESSION依赖于COOKIE进行传递的。Session遍历使用$_SESSION[]取值,cookie遍历使用$_COOKIE[]取值。 10、什么是数据库索引,主键索引,唯一索引的区别,索引的缺点是什么 索引用来快速地寻找那些具有特定值的记录。 主键索引和唯一索引的区别:主键是一种唯一性索引,但它必须指定为“PRIMARY KEY”,每个表只能有一个主键。唯一索引索引列的所有值都只能出现一次,即必须唯一。 索引的缺点: 1、创建索引和维护索引要耗费时间,这种时间随着数据量的增加而增加。 2、索引需要占用物理空间,除了数据表占数据空间之外,每一个索引还要占一定的物理空间,如果要建立聚簇索引,需要的空间就会更大。 3、当对表中的数据进行增加、删除、修改的时候,索引也要动态的维护,这样就降低了数据的维护速度。 11、数据库设计时,常遇到的性能瓶颈有哪些,常有的解决方案 瓶颈主要有: 1、磁盘搜索 优化方法是:将数据分布在多个磁盘上 2、磁盘读/写 优化方法是:从多个磁盘并行读写。 3、CPU周期 优化方法:扩充内存 4、内存带宽 12、include和require区别 include引入文件的时候,如果碰到错误,会给出提示,并继续运行下边的代码。 require引入文件的时候,如果碰到错误,会给出提示,并停止运行下边的代码。 13、文件上传时设计到点 和文件上传有关的php.ini配置选项(File Uploads): file_uploads=On/Off:文件是否允许上传 upload_max_filesize上传文件时,单个文件的最大大小 post_max_size:提交表单时,整个post表单的最大大小 max_file_uploads =20上传文件的个数 内存占用,脚本最大执行时间也间接影响到文件的上传 14、header常见状态 //200 正常状态 header('HTTP/1.1 200 OK'); // 301 永久重定向,记得在后面要加重定向地址 Location:$url header('HTTP/1.1 301 Moved Permanently'); // 重定向,其实就是302 暂时重定向 header('Location: http://www.maiyoule.com/'); // 设置页面304 没有修改 header('HTTP/1.1 304 Not Modified'); // 显示登录框, header('HTTP/1.1 401 Unauthorized'); header('WWW-Authenticate: Basic realm="登录信息"'); echo '显示的信息!'; // 403 禁止访问 header('HTTP/1.1 403 Forbidden'); // 404 错误 header('HTTP/1.1 404 Not Found'); // 500 服务器错误 header('HTTP/1.1 500 Internal Server Error'); // 3秒后重定向指定地址(也就是刷新到新页面与 <meta http-equiv="refresh" content="10;http://www.maiyoule.com/ /> 相同) header('Refresh: 3; url=http://www.maiyoule.com/'); echo '10后跳转到http://www.maiyoule.com'; // 重写 X-Powered-By 值 header('X-Powered-By: PHP/5.3.0'); header('X-Powered-By: Brain/0.6b'); //设置上下文语言 header('Content-language: en'); // 设置页面最后修改时间(多用于防缓存) $time = time() - 60; //建议使用filetime函数来设置页面缓存时间 header('Last-Modified: '.gmdate('D, d M Y H:i:s', $time).' GMT'); // 设置内容长度 header('Content-Length: 39344'); // 设置头文件类型,可以用于流文件或者文件下载 header('Content-Type: application/octet-stream'); header('Content-Disposition: attachment; filename="example.zip"'); header('Content-Transfer-Encoding: binary'); readfile('example.zip');//读取文件到客户端 //禁用页面缓存 header('Cache-Control: no-cache, no-store, max-age=0, must-revalidate'); header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); header('Pragma: no-cache'); //设置页面头信息 header('Content-Type: text/html; charset=iso-8859-1'); header('Content-Type: text/html; charset=utf-8'); header('Content-Type: text/plain'); header('Content-Type: image/jpeg'); header('Content-Type: application/zip'); header('Content-Type: application/pdf'); header('Content-Type: audio/mpeg'); header('Content-Type: application/x-shockwave-flash'); //.... 至于Content-Type 的值 可以去查查 w3c 的文档库,那里很丰富 15、ORM和ActiveRecord ORM:object relation mapping,即对象关系映射,简单的说就是对象模型和关系模型的一种映射。为什么要有这么一个映射?很简单,因为现在的开发语言基本都是oop的,但是传统的数据库却是关系型的。为了可以靠贴近面向对象开发,我们想要像操作对象一样操作数据库。还可以隔离底层数据库层,我们不需要关心我们使用的是mysql还是其他的关系型数据库 ActiveRecord也属于ORM层,由Rails最早提出,遵循标准的ORM模型:表映射到记录,记录映射到对象,字段映射到对象属性。配合遵循的命名和配置惯例,能够很大程度的快速实现模型的操作,而且简洁易懂。 ActiveRecord的主要思想是: 1. 每一个数据库表对应创建一个类,类的每一个对象实例对应于数据库中表的一行记录;通常表的每个字段在类中都有相应的Field; 2. ActiveRecord同时负责把自己持久化,在ActiveRecord中封装了对数据库的访问,即CURD;; 3. ActiveRecord是一种领域模型(Domain Model),封装了部分业务逻辑; ActiveRecord比较适用于: 1. 业务逻辑比较简单,当你的类基本上和数据库中的表一一对应时, ActiveRecord是非常方便的,即你的业务逻辑大多数是对单表操作; 2. 当发生跨表的操作时, 往往会配合使用事务脚本(Transaction Script),把跨表事务提升到事务脚本中; 3. ActiveRecord最大优点是简单, 直观。 一个类就包括了数据访问和业务逻辑. 如果配合代码生成器使用就更方便了; 这些优点使ActiveRecord特别适合WEB快速开发。 16、斐波那契方法,也就是1 1 2 3 5 8 ……,这里给出两种方法,大家可以对比下,看看哪种快,以及为什么 function fibonacci($n){ if($n == 0){ return 0; } if($n == 1){ return 1; } return fibonacci($n-1)+fibonacci($n-2); } function fibonacci($n){ for($i=0; $i<$n; $i++){ $r[] = $i<2 ? 1 : $r[$i-1]+$r[$i-2]; } return $r[--$i]; } 17、约瑟夫环,也就是常见的数猴子,n只猴子围成一圈,每只猴子下面标了编号,从1开始数起,数到m那么第m只猴子便退出,依次类推,每数到m,那么那个位置的猴子退出,那么最后剩下的猴子下的编号是啥。 function yuesefu($n,$m) { $r=0; for($i=2; $i<=$n; $i++) { $r=($r+$m)%$i; } return $r+1; } 18、冒泡排序,大致是临近的数字两两进行比较,按照从小到大或者从大到小的顺序进行交换,这样一趟过去后,最大或最小的数字被交换到了最后一位,然后再从头开始进行两两比较交换,直到倒数第二位时结束 function bubbleSort($arr){ for($i=0, $len=count($arr); $i<$len; $i++){ for($j=0; $j<$len; $j++){ if($arr[$i]<$arr[$j]){ $tmp = $arr[$j]; $arr[$j] = $arr[$i]; $arr[$i] = $tmp; } } } return $arr; } 19、快速排序,也就是找出一个元素(理论上可以随便找一个)作为基准,然后对数组进行分区操作,使基准左边元素的值都不大于基准值,基准右边的元素值 都不小于基准值,如此作为基准的元素调整到排序后的正确位置。递归快速排序,将其他n-1个元素也调整到排序后的正确位置。最后每个元素都是在排序后的正 确位置,排序完成。所以快速排序算法的核心算法是分区操作,即如何调整基准的位置以及调整返回基准的最终位置以便分治递归。 function quickSort($arr){ $len = count($arr); if($len <=1){ return $arr; } $key = $arr[0]; $leftArr = $rightArr= array(); for($i=1; $i<$len; $i++){ if($arr[$i] <= $key){ $leftArr[] = $arr[$i]; } else{ $rightArr[] = $arr[$i]; } } $leftArr = quickSort($leftArr); $rightArr = quickSort($rightArr); return array_merge($leftArr, array($key), $rightArr); } 20、(递归的)列出目录下所有文件及目录,这里也有两种方法 function listDir($path){ $res = dir($path); while($file = $res->read()){ if($file == '.' || $file == '..'){ continue; } if(is_dir($path . '/' .$file)){ echo $path . '/' .$file . "\r\n"; listDir($path . '/' .$file); } else{ echo $path . '/' .$file . "\r\n"; } } $res->close(); } function listDir($path){ if(is_dir($path)){ if(FALSE !== ($res = opendir($path))){ while(FALSE !== ($file = readdir($res))){ if($file == '.' || $file == '..'){ continue; } $subPath = $path . '/' . $file; if(is_dir($subPath)){ echo $subPath . "\r\n"; listDir($subPath); } else{ echo $subPath . "\r\n"; } } } } } 21、找出相对的目录,比如/a/b/c/d/e.php相对于/a/b/13/34/c.php是/c/d/ function ralativePath($a, $b){ $a = explode('/', dirname($a)); $b = explode('/', dirname($b)); $c = '/'; foreach ($a as $k=> $v){ if($v != $b[$k]){ $c .= $v . '/'; } } echo $c; } 22、快速找出url中php后缀 function get_ext($url){ $data = parse_url($url); return pathinfo($data['path'], PATHINFO_EXTENSION); } 23、正则题,使用正则抓取网页,以网页meta为utf8为准,若是抓取的网页编码为big5之类的,需要转化为utf8再收录 function preg_meta($meta){ $replacement = "\\1utf8\\6\\7"; $pattern = '#(<meta\s+http-equiv=(\'|"|)Content-Type(\'|"|)\s+content=(\'|"|)text/html; charset=)(\w+)(\'|"|)(>)#i'; return preg_replace($pattern, $replacement, $meta); } echo preg_meta("<meta http-equiv=Content-Type content='text/html; charset=big5'><META http-equiv=\"Content-Type\" content='text/html; charset=big5'>"); 24、不用php的反转函数倒序输出字符串,如abc,反序输出cba function revstring($str){ for($i=strlen($str)-1; $i>=0; $i--){ echo $str{$i}; } } revstring('abc'); 25、常见端口 TCP 21端口:FTP 文件传输服务 SSH 22端口:SSH连接linux服务器,通过SSH连接可以远程管理Linux等设备 TCP 23端口:TELNET 终端仿真服务 TCP 25端口:SMTP 简单邮件传输服务 UDP 53端口:DNS 域名解析服务 TCP 80端口:HTTP 超文本传输服务 TCP 110端口:POP3 “邮局协议版本3”使用的端口 TCP 443端口:HTTPS 加密的超文本传输服务 TCP 1521端口:Oracle数据库服务 TCP 1863端口:MSN Messenger的文件传输功能所使用的端口 TCP 3389端口:Microsoft RDP 微软远程桌面使用的端口 TCP 5631端口:Symantec pcAnywhere 远程控制数据传输时使用的端口 UDP 5632端口:Symantec pcAnywhere 主控端扫描被控端时使用的端口 TCP 5000端口:MS SQL Server使用的端口 UDP 8000端口:腾讯QQ 26、linux常用的命令 top linux进程实时监控 ps 在Linux中是查看进程的命令。ps查看正处于Running的进程 mv 为文件或目录改名或将文件由一个目录移入另一个目录中。 find 查找文件 df 可显示所有文件系统对i节点和磁盘块的使用情况。 cat 打印文件类容 chmod 变更文件或目录的权限 chgrp 文件或目录的权限的掌控以拥有者及所诉群组来管理。可以使用chgrp指令取变更文件与目录所属群组 grep 是一种强大的文本搜索工具,它能使用正则表达式搜索文本,并把匹 配的行打印出来。 wc 为统计指定文件中的字节数、字数、行数,并将统计结果显示输出 27、对于大流量的网站,您采用什么样的方法来解决访问量问题 首先,确认服务器硬件是否足够支持当前的流量 其次,优化数据库访问。 第三,禁止外部的盗链。 第四,控制大文件的下载。 第五,使用不同主机分流主要流量 第六,使用流量分析统计软件 28、$_SERVER常用的字段 $_SERVER['PHP_SELF'] #当前正在执行脚本的文件名 $_SERVER['SERVER_NAME'] #当前运行脚本所在服务器主机的名称 $_SERVER['REQUEST_METHOD'] #访问页面时的请求方法。例如:“GET”、“HEAD”,“POST”,“PUT” $_SERVER['QUERY_STRING'] #查询(query)的字符串 $_SERVER['HTTP_HOST'] #当前请求的 Host: 头部的内容 $_SERVER['HTTP_REFERER'] #链接到当前页面的前一页面的 URL 地址 $_SERVER['REMOTE_ADDR'] #正在浏览当前页面用户的 IP 地址 $_SERVER['REMOTE_HOST'] #正在浏览当前页面用户的主机名 $_SERVER['SCRIPT_FILENAME'] #当前执行脚本的绝对路径名 $_SERVER['SCRIPT_NAME'] #包含当前脚本的路径。这在页面需要指向自己时非常有用 $_SERVER['REQUEST_URI'] #访问此页面所需的 URI。例如,“/index.html” 29、安装php扩展 进入扩展的目录 phpize命令得到configure文件 ./configure --with-php-config=/usr/local/php/bin/php-config make & make install 在php.ini中加入扩展名称.so 重启web服务器(nginx/apache) 30、php-fpm与nginx PHP-FPM也是一个第三方的FastCGI进程管理器,它是作为PHP的一个补丁来开发的,在安装的时候也需要和PHP源码一起编译,也就是说PHP-FPM被编译到PHP内核中,因此在处理性能方面更加优秀;同时它在处理高并发方面也比spawn-fcgi引擎好很多,因此,推荐Nginx+PHP/PHP-FPM这个组合对PHP进行解析。 FastCGI 的主要优点是把动态语言和HTTP Server分离开来,所以Nginx与PHP/PHP-FPM经常被部署在不同的服务器上,以分担前端Nginx服务器的压力,使Nginx专一处理静态请求和转发动态请求,而PHP/PHP-FPM服务器专一解析PHP动态请求 #fastcgi FastCGI是一个可伸缩地、高速地在HTTP server和动态脚本语言间通信的接口。多数流行的HTTP server都支持FastCGI,包括Apache、Nginx和lighttpd等,同时,FastCGI也被许多脚本语言所支持,其中就有PHP。 FastCGI是从CGI发展改进而来的。传统CGI接口方式的主要缺点是性能很差,因为每次HTTP服务器遇到动态程序时都需要重新启动脚本解析器来执行解析,然后结果被返回给HTTP服务器。这在处理高并发访问时,几乎是不可用的。另外传统的CGI接口方式安全性也很差,现在已经很少被使用了。 FastCGI接口方式采用C/S结构,可以将HTTP服务器和脚本解析服务器分开,同时在脚本解析服务器上启动一个或者多个脚本解析守护进程。当HTTP服务器每次遇到动态程序时,可以将其直接交付给FastCGI进程来执行,然后将得到的结果返回给浏览器。这种方式可以让HTTP服务器专一地处理静态请求或者将动态脚本服务器的结果返回给客户端,这在很大程度上提高了整个应用系统的性能。 Nginx+FastCGI运行原理 Nginx不支持对外部程序的直接调用或者解析,所有的外部程序(包括PHP)必须通过FastCGI接口来调用。FastCGI接口在Linux下是socket,(这个socket可以是文件socket,也可以是ip socket)。为了调用CGI程序,还需要一个FastCGI的wrapper(wrapper可以理解为用于启动另一个程序的程序),这个wrapper绑定在某个固定socket上,如端口或者文件socket。当Nginx将CGI请求发送给这个socket的时候,通过FastCGI接口,wrapper接纳到请求,然后派生出一个新的线程,这个线程调用解释器或者外部程序处理脚本并读取返回数据;接着,wrapper再将返回的数据通过FastCGI接口,沿着固定的socket传递给Nginx;最后,Nginx将返回的数据发送给客户端,这就是Nginx+FastCGI的整个运作过程。 31、ajax全称“Asynchronous Javascript And XML”(异步JavaScript和XML)

小川游鱼 2019-12-02 01:41:29 0 浏览量 回答数 0

回答

PHP面试干货 1、进程和线程 进程和线程都是由操作系统所体会的程序运行的基本单元,系统利用该基本单元实现系统对应用的并发性。进程和线程的区别在于: 简而言之,一个程序至少有一个进程,一个进程至少有一个线程. 线程的划分尺度小于进程,使得多线程程序的并发性高。 另外,进程在执行过程中拥有独立的内存单元,而多个线程共享内存,从而极大地提高了程序的运行效率。 线程在执行过程中与进程还是有区别的。每个独立的线程有一个程序运行的入口、顺序执行序列和程序的出口。但是线程不能够独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制。 从逻辑角度来看,多线程的意义在于一个应用程序中,有多个执行部分可以同时执行。但操作系统并没有将多个线程看做多个独立的应用,来实现进程的调度和管理以及资源分配。这就是进程和线程的重要区别。 2、apache默认使用进程管理还是线程管理?如何判断并设置最大连接数? 一个进程可以开多个线程 默认是进程管理 默认有一个主进程 Linux: ps -aux | grep httpd | more 一个子进程代表一个用户的连接 Conf/extra/httpd-mpm.conf 多路功能模块 http -l 查询当前apache处于什么模式下 3、单例模式 单例模式需求:只能实例化产生一个对象 如何实现: 私有化构造函数 禁止克隆对象 提供一个访问这个实例的公共的静态方法(通常为getInstance方法),从而返回唯一对象 需要一个保存类的静态属性 class demo { private static $MyObject; //保存对象的静态属性 private function __construct(){ //私有化构造函数 } private function __clone(){ //禁止克隆 } public static function getInstance(){ if(! (self::$MyObject instanceof self)){ self::$MyObject = new self; } return self::$MyObject; } } 4、安装完Apache后,在http.conf中配置加载PHP文件以Apache模块的方式安装PHP,在文件http.conf中首先要用语句LoadModule php5_module "e:/php/php5apache2.dll"动态装载PHP模块,然后再用语句AddType application/x-httpd-php .php 使得Apache把所有扩展名为PHP的文件都作为PHP脚本处理 5、debug_backtrace()函数能返回脚本里的任意行中调用的函数的名称。该函数同时还经常被用在调试中,用来判断错误是如何发生的 function one($str1, $str2) { two("Glenn", "Quagmire"); } function two($str1, $str2) { three("Cleveland", "Brown"); } function three($str1, $str2) { print_r(debug_backtrace()); } one("Peter", "Griffin"); Array ( [0] => Array ( [file] => D:\www\test\result.php [line] => 9 [function] => three [args] => Array ( [0] => Cleveland [1] => Brown ) ) [1] => Array ( [file] => D:\www\test\result.php [line] => 5 [function] => two [args] => Array ( [0] => Glenn [1] => Quagmire ) ) [2] => Array ( [file] => D:\www\test\result.php [line] => 16 [function] => one [args] => Array ( [0] => Peter [1] => Griffin ) ) ) 6、输出用户的IP地址,并且判断用户的IP地址是否在192.168.1.100 — 192.168.1.150之间 echo $ip=getenv('REMOTE_ADDR'); $ip=str_replace('.','',$ip); if($ip<1921681150 && $ip>1921681100) { echo 'ip在192.168.1.100—–192.168.1.150之间'; } else { echo 'ip不在192.168.1.100—–192.168.1.150之间'; } 7、请将2维数组按照name的长度进行重新排序,按照顺序将id赋值 $tarray = array( array('id' => 0, 'name' => '123'), array('id' => 0, 'name' => '1234'), array('id' => 0, 'name' => '1235'), array('id' => 0, 'name' => '12356'), array('id' => 0, 'name' => '123abc') ); foreach($tarray as $key=>$val) { $c[]=$val['name']; } function aa($a,$b) { if(strlen($a)==strlen($b)) return 0; return strlen($a)>strlen($b)?-1:1; } usort($c,'aa'); $len=count($c); for($i=0;$i<$len;$i++) { $t[$i]['id']=$i+1; $t[$i]['name']=$c[$i]; } print_r($t); 8、表单数据提交方式POST和GET的区别,URL地址传递的数据最大长度是多少? POST方式提交数据用户不可见,是数据更安全,最大长度不受限制,而GET方式传值在URL地址可以看到,相对不安全,对大长度是2048字节。 9、SESSION和COOKIE的作用和区别,SESSION信息的存储方式,如何进行遍历 SESSION和COOKIE都能够使值在页面之间进行传递,SESSION存储在服务器端,数据更安全,COOKIE保存在客户端,用户使用手段可以进行修改,SESSION依赖于COOKIE进行传递的。Session遍历使用$_SESSION[]取值,cookie遍历使用$_COOKIE[]取值。 10、什么是数据库索引,主键索引,唯一索引的区别,索引的缺点是什么 索引用来快速地寻找那些具有特定值的记录。 主键索引和唯一索引的区别:主键是一种唯一性索引,但它必须指定为“PRIMARY KEY”,每个表只能有一个主键。唯一索引索引列的所有值都只能出现一次,即必须唯一。 索引的缺点: 1、创建索引和维护索引要耗费时间,这种时间随着数据量的增加而增加。 2、索引需要占用物理空间,除了数据表占数据空间之外,每一个索引还要占一定的物理空间,如果要建立聚簇索引,需要的空间就会更大。 3、当对表中的数据进行增加、删除、修改的时候,索引也要动态的维护,这样就降低了数据的维护速度。 11、数据库设计时,常遇到的性能瓶颈有哪些,常有的解决方案 瓶颈主要有: 1、磁盘搜索 优化方法是:将数据分布在多个磁盘上 2、磁盘读/写 优化方法是:从多个磁盘并行读写。 3、CPU周期 优化方法:扩充内存 4、内存带宽 12、include和require区别 include引入文件的时候,如果碰到错误,会给出提示,并继续运行下边的代码。 require引入文件的时候,如果碰到错误,会给出提示,并停止运行下边的代码。 13、文件上传时设计到点 和文件上传有关的php.ini配置选项(File Uploads): file_uploads=On/Off:文件是否允许上传 upload_max_filesize上传文件时,单个文件的最大大小 post_max_size:提交表单时,整个post表单的最大大小 max_file_uploads =20上传文件的个数 内存占用,脚本最大执行时间也间接影响到文件的上传 14、header常见状态 //200 正常状态 header('HTTP/1.1 200 OK'); // 301 永久重定向,记得在后面要加重定向地址 Location:$url header('HTTP/1.1 301 Moved Permanently'); // 重定向,其实就是302 暂时重定向 header('Location: http://www.maiyoule.com/'); // 设置页面304 没有修改 header('HTTP/1.1 304 Not Modified'); // 显示登录框, header('HTTP/1.1 401 Unauthorized'); header('WWW-Authenticate: Basic realm="登录信息"'); echo '显示的信息!'; // 403 禁止访问 header('HTTP/1.1 403 Forbidden'); // 404 错误 header('HTTP/1.1 404 Not Found'); // 500 服务器错误 header('HTTP/1.1 500 Internal Server Error'); // 3秒后重定向指定地址(也就是刷新到新页面与 <meta http-equiv="refresh" content="10;http://www.maiyoule.com/ /> 相同) header('Refresh: 3; url=http://www.maiyoule.com/'); echo '10后跳转到http://www.maiyoule.com'; // 重写 X-Powered-By 值 header('X-Powered-By: PHP/5.3.0'); header('X-Powered-By: Brain/0.6b'); //设置上下文语言 header('Content-language: en'); // 设置页面最后修改时间(多用于防缓存) $time = time() - 60; //建议使用filetime函数来设置页面缓存时间 header('Last-Modified: '.gmdate('D, d M Y H:i:s', $time).' GMT'); // 设置内容长度 header('Content-Length: 39344'); // 设置头文件类型,可以用于流文件或者文件下载 header('Content-Type: application/octet-stream'); header('Content-Disposition: attachment; filename="example.zip"'); header('Content-Transfer-Encoding: binary'); readfile('example.zip');//读取文件到客户端 //禁用页面缓存 header('Cache-Control: no-cache, no-store, max-age=0, must-revalidate'); header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); header('Pragma: no-cache'); //设置页面头信息 header('Content-Type: text/html; charset=iso-8859-1'); header('Content-Type: text/html; charset=utf-8'); header('Content-Type: text/plain'); header('Content-Type: image/jpeg'); header('Content-Type: application/zip'); header('Content-Type: application/pdf'); header('Content-Type: audio/mpeg'); header('Content-Type: application/x-shockwave-flash'); //.... 至于Content-Type 的值 可以去查查 w3c 的文档库,那里很丰富 15、ORM和ActiveRecord ORM:object relation mapping,即对象关系映射,简单的说就是对象模型和关系模型的一种映射。为什么要有这么一个映射?很简单,因为现在的开发语言基本都是oop的,但是传统的数据库却是关系型的。为了可以靠贴近面向对象开发,我们想要像操作对象一样操作数据库。还可以隔离底层数据库层,我们不需要关心我们使用的是mysql还是其他的关系型数据库 ActiveRecord也属于ORM层,由Rails最早提出,遵循标准的ORM模型:表映射到记录,记录映射到对象,字段映射到对象属性。配合遵循的命名和配置惯例,能够很大程度的快速实现模型的操作,而且简洁易懂。 ActiveRecord的主要思想是: 1. 每一个数据库表对应创建一个类,类的每一个对象实例对应于数据库中表的一行记录;通常表的每个字段在类中都有相应的Field; 2. ActiveRecord同时负责把自己持久化,在ActiveRecord中封装了对数据库的访问,即CURD;; 3. ActiveRecord是一种领域模型(Domain Model),封装了部分业务逻辑; ActiveRecord比较适用于: 1. 业务逻辑比较简单,当你的类基本上和数据库中的表一一对应时, ActiveRecord是非常方便的,即你的业务逻辑大多数是对单表操作; 2. 当发生跨表的操作时, 往往会配合使用事务脚本(Transaction Script),把跨表事务提升到事务脚本中; 3. ActiveRecord最大优点是简单, 直观。 一个类就包括了数据访问和业务逻辑. 如果配合代码生成器使用就更方便了; 这些优点使ActiveRecord特别适合WEB快速开发。 16、斐波那契方法,也就是1 1 2 3 5 8 ……,这里给出两种方法,大家可以对比下,看看哪种快,以及为什么 function fibonacci($n){ if($n == 0){ return 0; } if($n == 1){ return 1; } return fibonacci($n-1)+fibonacci($n-2); } function fibonacci($n){ for($i=0; $i<$n; $i++){ $r[] = $i<2 ? 1 : $r[$i-1]+$r[$i-2]; } return $r[--$i]; } 17、约瑟夫环,也就是常见的数猴子,n只猴子围成一圈,每只猴子下面标了编号,从1开始数起,数到m那么第m只猴子便退出,依次类推,每数到m,那么那个位置的猴子退出,那么最后剩下的猴子下的编号是啥。 function yuesefu($n,$m) { $r=0; for($i=2; $i<=$n; $i++) { $r=($r+$m)%$i; } return $r+1; } 18、冒泡排序,大致是临近的数字两两进行比较,按照从小到大或者从大到小的顺序进行交换,这样一趟过去后,最大或最小的数字被交换到了最后一位,然后再从头开始进行两两比较交换,直到倒数第二位时结束 function bubbleSort($arr){ for($i=0, $len=count($arr); $i<$len; $i++){ for($j=0; $j<$len; $j++){ if($arr[$i]<$arr[$j]){ $tmp = $arr[$j]; $arr[$j] = $arr[$i]; $arr[$i] = $tmp; } } } return $arr; } 19、快速排序,也就是找出一个元素(理论上可以随便找一个)作为基准,然后对数组进行分区操作,使基准左边元素的值都不大于基准值,基准右边的元素值 都不小于基准值,如此作为基准的元素调整到排序后的正确位置。递归快速排序,将其他n-1个元素也调整到排序后的正确位置。最后每个元素都是在排序后的正 确位置,排序完成。所以快速排序算法的核心算法是分区操作,即如何调整基准的位置以及调整返回基准的最终位置以便分治递归。 function quickSort($arr){ $len = count($arr); if($len <=1){ return $arr; } $key = $arr[0]; $leftArr = $rightArr= array(); for($i=1; $i<$len; $i++){ if($arr[$i] <= $key){ $leftArr[] = $arr[$i]; } else{ $rightArr[] = $arr[$i]; } } $leftArr = quickSort($leftArr); $rightArr = quickSort($rightArr); return array_merge($leftArr, array($key), $rightArr); } 20、(递归的)列出目录下所有文件及目录,这里也有两种方法 function listDir($path){ $res = dir($path); while($file = $res->read()){ if($file == '.' || $file == '..'){ continue; } if(is_dir($path . '/' .$file)){ echo $path . '/' .$file . "\r\n"; listDir($path . '/' .$file); } else{ echo $path . '/' .$file . "\r\n"; } } $res->close(); } function listDir($path){ if(is_dir($path)){ if(FALSE !== ($res = opendir($path))){ while(FALSE !== ($file = readdir($res))){ if($file == '.' || $file == '..'){ continue; } $subPath = $path . '/' . $file; if(is_dir($subPath)){ echo $subPath . "\r\n"; listDir($subPath); } else{ echo $subPath . "\r\n"; } } } } } 21、找出相对的目录,比如/a/b/c/d/e.php相对于/a/b/13/34/c.php是/c/d/ function ralativePath($a, $b){ $a = explode('/', dirname($a)); $b = explode('/', dirname($b)); $c = '/'; foreach ($a as $k=> $v){ if($v != $b[$k]){ $c .= $v . '/'; } } echo $c; } 22、快速找出url中php后缀 function get_ext($url){ $data = parse_url($url); return pathinfo($data['path'], PATHINFO_EXTENSION); } 23、正则题,使用正则抓取网页,以网页meta为utf8为准,若是抓取的网页编码为big5之类的,需要转化为utf8再收录 function preg_meta($meta){ $replacement = "\\1utf8\\6\\7"; $pattern = '#(<meta\s+http-equiv=(\'|"|)Content-Type(\'|"|)\s+content=(\'|"|)text/html; charset=)(\w+)(\'|"|)(>)#i'; return preg_replace($pattern, $replacement, $meta); } echo preg_meta("<meta http-equiv=Content-Type content='text/html; charset=big5'><META http-equiv=\"Content-Type\" content='text/html; charset=big5'>"); 24、不用php的反转函数倒序输出字符串,如abc,反序输出cba function revstring($str){ for($i=strlen($str)-1; $i>=0; $i--){ echo $str{$i}; } } revstring('abc'); 25、常见端口 TCP 21端口:FTP 文件传输服务 SSH 22端口:SSH连接linux服务器,通过SSH连接可以远程管理Linux等设备 TCP 23端口:TELNET 终端仿真服务 TCP 25端口:SMTP 简单邮件传输服务 UDP 53端口:DNS 域名解析服务 TCP 80端口:HTTP 超文本传输服务 TCP 110端口:POP3 “邮局协议版本3”使用的端口 TCP 443端口:HTTPS 加密的超文本传输服务 TCP 1521端口:Oracle数据库服务 TCP 1863端口:MSN Messenger的文件传输功能所使用的端口 TCP 3389端口:Microsoft RDP 微软远程桌面使用的端口 TCP 5631端口:Symantec pcAnywhere 远程控制数据传输时使用的端口 UDP 5632端口:Symantec pcAnywhere 主控端扫描被控端时使用的端口 TCP 5000端口:MS SQL Server使用的端口 UDP 8000端口:腾讯QQ 26、linux常用的命令 top linux进程实时监控 ps 在Linux中是查看进程的命令。ps查看正处于Running的进程 mv 为文件或目录改名或将文件由一个目录移入另一个目录中。 find 查找文件 df 可显示所有文件系统对i节点和磁盘块的使用情况。 cat 打印文件类容 chmod 变更文件或目录的权限 chgrp 文件或目录的权限的掌控以拥有者及所诉群组来管理。可以使用chgrp指令取变更文件与目录所属群组 grep 是一种强大的文本搜索工具,它能使用正则表达式搜索文本,并把匹 配的行打印出来。 wc 为统计指定文件中的字节数、字数、行数,并将统计结果显示输出 27、对于大流量的网站,您采用什么样的方法来解决访问量问题 首先,确认服务器硬件是否足够支持当前的流量 其次,优化数据库访问。 第三,禁止外部的盗链。 第四,控制大文件的下载。 第五,使用不同主机分流主要流量 第六,使用流量分析统计软件 28、$_SERVER常用的字段 $_SERVER['PHP_SELF'] #当前正在执行脚本的文件名 $_SERVER['SERVER_NAME'] #当前运行脚本所在服务器主机的名称 $_SERVER['REQUEST_METHOD'] #访问页面时的请求方法。例如:“GET”、“HEAD”,“POST”,“PUT” $_SERVER['QUERY_STRING'] #查询(query)的字符串 $_SERVER['HTTP_HOST'] #当前请求的 Host: 头部的内容 $_SERVER['HTTP_REFERER'] #链接到当前页面的前一页面的 URL 地址 $_SERVER['REMOTE_ADDR'] #正在浏览当前页面用户的 IP 地址 $_SERVER['REMOTE_HOST'] #正在浏览当前页面用户的主机名 $_SERVER['SCRIPT_FILENAME'] #当前执行脚本的绝对路径名 $_SERVER['SCRIPT_NAME'] #包含当前脚本的路径。这在页面需要指向自己时非常有用 $_SERVER['REQUEST_URI'] #访问此页面所需的 URI。例如,“/index.html” 29、安装php扩展 进入扩展的目录 phpize命令得到configure文件 ./configure --with-php-config=/usr/local/php/bin/php-config make & make install 在php.ini中加入扩展名称.so 重启web服务器(nginx/apache) 30、php-fpm与nginx PHP-FPM也是一个第三方的FastCGI进程管理器,它是作为PHP的一个补丁来开发的,在安装的时候也需要和PHP源码一起编译,也就是说PHP-FPM被编译到PHP内核中,因此在处理性能方面更加优秀;同时它在处理高并发方面也比spawn-fcgi引擎好很多,因此,推荐Nginx+PHP/PHP-FPM这个组合对PHP进行解析。 FastCGI 的主要优点是把动态语言和HTTP Server分离开来,所以Nginx与PHP/PHP-FPM经常被部署在不同的服务器上,以分担前端Nginx服务器的压力,使Nginx专一处理静态请求和转发动态请求,而PHP/PHP-FPM服务器专一解析PHP动态请求 #fastcgi FastCGI是一个可伸缩地、高速地在HTTP server和动态脚本语言间通信的接口。多数流行的HTTP server都支持FastCGI,包括Apache、Nginx和lighttpd等,同时,FastCGI也被许多脚本语言所支持,其中就有PHP。 FastCGI是从CGI发展改进而来的。传统CGI接口方式的主要缺点是性能很差,因为每次HTTP服务器遇到动态程序时都需要重新启动脚本解析器来执行解析,然后结果被返回给HTTP服务器。这在处理高并发访问时,几乎是不可用的。另外传统的CGI接口方式安全性也很差,现在已经很少被使用了。 FastCGI接口方式采用C/S结构,可以将HTTP服务器和脚本解析服务器分开,同时在脚本解析服务器上启动一个或者多个脚本解析守护进程。当HTTP服务器每次遇到动态程序时,可以将其直接交付给FastCGI进程来执行,然后将得到的结果返回给浏览器。这种方式可以让HTTP服务器专一地处理静态请求或者将动态脚本服务器的结果返回给客户端,这在很大程度上提高了整个应用系统的性能。 Nginx+FastCGI运行原理 Nginx不支持对外部程序的直接调用或者解析,所有的外部程序(包括PHP)必须通过FastCGI接口来调用。FastCGI接口在Linux下是socket,(这个socket可以是文件socket,也可以是ip socket)。为了调用CGI程序,还需要一个FastCGI的wrapper(wrapper可以理解为用于启动另一个程序的程序),这个wrapper绑定在某个固定socket上,如端口或者文件socket。当Nginx将CGI请求发送给这个socket的时候,通过FastCGI接口,wrapper接纳到请求,然后派生出一个新的线程,这个线程调用解释器或者外部程序处理脚本并读取返回数据;接着,wrapper再将返回的数据通过FastCGI接口,沿着固定的socket传递给Nginx;最后,Nginx将返回的数据发送给客户端,这就是Nginx+FastCGI的整个运作过程。 31、ajax全称“Asynchronous Javascript And XML”(异步JavaScript和XML)

小川游鱼 2019-12-02 01:41:29 0 浏览量 回答数 0
阿里云大学 云服务器ECS com域名 网站域名whois查询 开发者平台 小程序定制 小程序开发 国内短信套餐包 开发者技术与产品 云数据库 图像识别 开发者问答 阿里云建站 阿里云备案 云市场 万网 阿里云帮助文档 免费套餐 开发者工具 云栖号物联网 小程序开发制作 视频内容分析 企业网站制作 视频集锦 代理记账服务 2020阿里巴巴研发效能峰会 企业建站模板 云效成长地图 高端建站 云栖号弹性计算 阿里云云栖号 云栖号案例 云栖号直播