技术进阶学习汇总

mac2025-02-15  11

文章目录

分布式架构框架中间件数据库、NosqlRPC前端大数据TCP/IPJAVA基础JVMlinux设计模式

分布式架构

分布式事务理论 分布式系统一致性(ACID、CAP、BASE、二段提交、三段提交、TCC、幂等性)原理详解 事务要求:具备ACID的特性,即原子性、一致性、隔离性、持久性分布式事务处理模型:DTS,模型中包含4个角色:应用程序、事务管理器、资源管理器、通信资源管理器四部分;关系简称解释: TX协议定义应用程序与事务管理器之间的接口XA协议定义了事务管理器与资源处理器之间的接口 CAP定理,分区容错性必须实现,所以取舍再一致性与可用性 分区容错性p、一致性c、可用性a BASE理论,平衡cap定理的理论 强一致性、弱一致性、最终一致性 强一致性,多用于金融、财务、订单核心业务等 建议:分布式或多或少无法做到强一致性的,比如串形执行的强事务处理也可能造成因通讯造成极端情况下数据不统一,所以需要的话就需要将强关联的业务代码写到一起实现: 二阶段 2PC(强一致,高并发不推荐,mysql5.5+支持) 一阶段:准备(写日志、锁资源、准备提交)二阶段:都准备好后统一提交,释放资源缺点: 同步阻塞问题,需要锁定从开始到结尾的所有同步执行的资源如果例如单点故障、通讯失败等造成事务执行不一致后出现的异常需要人工干预 三阶段 一、二阶段之间增加一个询问过程阶段,引入超时机制。防止因为超时、宕机、故障等原因没有收到执行者\协调者的消息一致阻塞下去只能减少问题,如果真正执行的时候发生问题就同2pc的第二阶段一样了 TCC(阿里提出,其实不是阶段提交,是根据通讯与业务逻辑处理的) TCC分布式事务详解tcc-transaction框架,中文并且支持rpc协议(dubbo);其他还有ByteTCC、Himly等开源框架,一般通过注解@Confirm、@Cancel等自动感知成功、失败进而自动执行过程描述: Try:完成所有业务检查(一致性)、预留必须业务资源(隔离性) eg:下订单时订单、进销、积分……系统,可以通过数据库增加冻结字段,先暂时保存并只锁定该资源 Confirm:真正执行业务、不做任务业务检查、满足幂等性Cancel:取消业务、释放 Try 阶段预留的业务资源、满足幂等性 减少了阻塞问题,不过在执行2个C的时候也可能造成事务执行不一致的问题注意幂等(携带唯一表示进行业务处理即可)可补偿(根据mq或者定时任务等对记录错误的数据进行事务补偿、人工补偿) 最终一致性 可靠消息模式(最常用) 消息持久化,2种方案: 各自系统自己的消息表(造成耦合)统一的外部消息表(多一步预发送消息提交到消息管理模块) 中间件(MQ) 幂等性 重试机制造成使用唯一键进行滤重使用分布式表使用状态流转的方向性新增、删除、获取一个数据就是幂等性的 mq见kafka详情 缓存一致模式(通过缓存,可以整合入消息模式) 性能要求不是极端:分布式缓存缓存要一次性种植完整,部分存不如不存保持弱一致性 通过业务处理,根据各个应用场景进行选择,需要人工开发 查询模式 任何一个服务操作都需要提供一个查询接口,用来向外部输出操作执行的状态 补偿模式(查询模式后发现数据不一致后执行,类似于TCC) 自动修复(重试、回滚)通知运营、通知技术 异步确保模式 场景:将响应时间要求不高的业务从主干剥离,这个方案最大的好处能够对高并发流量进行消峰,例如:电商系统中的物流、配送,以及支付系统中的计费、入账等如果迟迟没有收到响应,我们通过查询模式和补偿模式来继续未完成的操作 定期核对模式(金融:数据准确;社交:量大) 需要唯一ID(分布式系统需要生成策略)需要记录调用链 专题模式 特殊情况,eg:版本升级、数据迁移等 高并发 名词解释 峰值每秒请求数(QPS): 解释:每秒钟请求或者查询的数量,在互联网领域,指每秒响应请求数(指HTTP请求)公式:峰值每秒请求数(QPS) = (总PV数 * 80%) / (6小时秒数 * 20%);80%的访问量集中在20%的时间QPS达到50,可以称之为小型网站,一般的服务器就可以应付QPS达到100,假设关系型数据库的每次请求在10ms完成,假设单页面只有一个SQL查询,那么100QPS意味着1s完成100次请求,但是此时并不能保证数据库查询能完成100次 优化方案:数据库缓存层,数据库的负载均衡 QPS达到800,假设使用百兆带宽,意味着网站出口的实际带宽是8M左右,假设每个页面只有10k,在这个并发条件下,百兆带宽已经吃完 优化方案:CDN加速,负载均衡 QPS达到1000,假设使用memcache缓存数据库查询数据,每个页面对memcache的请求远大于直接对db的请求,memcache的悲观并发数在2w左右,但有可能在之前内网带宽已经吃光,表现出不稳定, 解决方案:nosql、静态HTML缓存 QPS达到2000,这个级别下,文件系统访问锁都成为了灾难 优化方案:做业务分离,分布式存储 并发连接数:系统同时处理的请求数量吞吐量:单位时间内处理的请求数量(通常由QPS与并发数决定)PV:综合浏览量(page view),即页面浏览量或者点击量,一个访客在24小时内访问的页面数量;同一个人浏览网站同一页面,只记作一次PVUV:独立访客(unique visitor),即一定时间范围内相同访客多次访问网站,只计算为一个独立访客日网站带宽 = PV / 统计时间(换算到s) * 平均页面大小(单位KB) * 8;峰值一般是平均值的倍数,根据实际情况来定 优化方案 缓存降级:目的是保证核心服务可用,即使是有损的 eg:页面非核心服务不展示buttoneg:查询必须携带索引列eg:使用通用内容替代个性化推荐内容eg:降低容灾能力,降低性能,延迟持久化等等 限流 算法 令牌桶:令牌匀速入桶,url请求获取令牌后server进行处理,允许突发增量漏桶:令牌匀速入桶,匀速出筒,不允许突发 应用级限流 Tomcat的Connector其中一种配置有如下几个参数 acceptCount:如果Tomcat的线程都忙于响应,新来的连接会进入队列排队,如果超出排队大小,则拒绝连接;maxConnections:瞬时最大连接数,超出的会排队等待;maxThreads:Tomcat能启动用来处理请求的最大线程数,如果请求处理量一直远远大于最大线程数则可能会僵死。 线程池 单机限流:缓存,使用算法(Guava RateLimiter提供了令牌桶算法实现:平滑突发限流(SmoothBursty)和平滑预热限流(SmoothWarmingUp)实现)分布式限流:redis/nginx + lua脚本 基础优化方案-场景 流量优化:防盗链处理(防止流量被外战使用)前端优化:减少HTTP请求,合并css或js,添加异步请求,启用浏览器缓存和文件压缩服务端优化:页面静态化数据库优化:引入缓存数据库,进行数据\数据库缓存web服务器优化:负载均衡,nginx反向代理 进阶优化方案-场景 前端优化:CDN加速,独立的静态资源服务器服务端优化:并发处理(多线程),队列处理(异步)数据库优化:读写分离,分库分表,分区操作,负载均衡 多数据源,其实就是多个配置,使用@aop或者自定义注解进行拦截处理 web服务器优化:7,4层LVS软件 4层是通过ip+端口及tcp/udp进行负载均衡7层是通过url,http,cookies等应用层进行负载均衡

框架

Springboot

AOP

@Aspect 切面注释@Pointcut(“execution(* cn.zp.…controller..*(…))”) 切入点@Around、before、after等等 执行以下是一个不常用的案例,将不常用的一场进行切面,@AfterThrowing注解的使用 /**

凡是注解了RequestMapping的方法都被拦截 */ @Pointcut("@annotation(org.springframework.web.bind.annotation.RequestMapping)") private void webPointcut() { }

/**

拦截web层异常,记录异常日志,并返回友好信息到前端 方法只拦截Exception

将未做处理的异常统一进行处理 */ @AfterThrowing(pointcut = “webPointcut()”, throwing = “e”) public void handleThrowing(Exception e) { logger.error(JSON.toJSONString(e.getStackTrace())); //通过response和writer将信息输出到浏览器 }

IOC、DI

各种注解Configuation、Bean、Service、Controller、Repository、Component Mybatis 半ORM(对象关系映射)框架一对多、多对一、多对多使用RowBounds对象进行分页tk.mybatis 通用Mapper插件 Shiro 与 Spring Security 对比 shiro四大核心功能 身份认证,支持多数据源(api简单)访问控制(api简单),支持粒度(粗:角色;细:权限)的授权会话管理(session),会话验证(验证器、定时任务等验证是否过期)加密(api简单) shiro其他功能 支持一级缓存多线程支持,即如在一个线程中开启另一个线程,能把权限自动传播过去测试支持“记住我”功能支持授权支持,允许一个用户假装为另一个用户(如果他们允许)的身份进行访问不与任何的框架或者容器捆绑,可以独立运行 shiro核心组件 Subject 主体,即登录用户SecurityManager:安全管理器;即过滤器FilterRealm:域,Shiro从从Realm获取安全数据(如用户、角色、权限) SpringSecurity 比shiro难,如果不使用spring则不考虑shiro的功能它都有,并且支持Oauth、OpenID 一般数据库结构(经典5张表) 用户表、角色表、权限表(资源表)、用户-角色表、角色-权限表 Shiro的实现过程 springboot整合redis 自定义Realm(安全域)继承AuthorizingRealm,实现获取授权信息方法(数据库)、获取身份验证信息(url拦截后身份信息验证)2个方法@Configuration配置,将自己的Realm验证加入容器,将容器加入权限管理,增加拦截器工厂,增加启用注解等配置controller内使用,通过注解:@RequiresRoles(“admin”)角色、@RequiresPermissions(“add”)权限等 Netty

特点

一个高性能、异步事件驱动的NIO框架,它提供了对TCP、UDP和文件传输的支持使用更高效的socket底层避免一些问题,简化了NIO的处理方式对TCP粘包/分包进行自动化处理可使用接受/处理线程池,提高连接效率,对重连、心跳检测的简单支持大量使用了volitale、使用了CAS和原子类、线程安全类的使用、读写锁的使用

序列化

xml - 数据全,全平台支持json - 移动、web端thrift - 完全rpc支持Protobuf - 跨防火墙,多语言支持

IO 一对一(一个线程对应一个连接)

NIO 一对多(一个线程对应多个连接),非阻塞IO

Channel:表示 IO 源与目标打开的连接,是双向的,但不能直接访问数据,只能与Buffer 进行交互。Buffer:与Channel进行交互,数据是从Channel读入缓冲区,从缓冲区写入Channel中的Selector可使一个单独的线程管理多个ChannelPipe:两个线程之间的单向数据连接,数据会被写到sink通道,从source通道读取

使用

服务器端 public class NettyServer { public static void main(String[] args) { ServerBootstrap serverBootstrap = new ServerBootstrap(); NioEventLoopGroup boos = new NioEventLoopGroup(); NioEventLoopGroup worker = new NioEventLoopGroup(); serverBootstrap .group(boos, worker) // 创建分组 .channel(NioServerSocketChannel.class) // 创建频道 .childHandler(new ChannelInitializer<NioSocketChannel>() { @Override protected void initChannel(NioSocketChannel ch) { ch.pipeline().addLast(new StringDecoder()); ch.pipeline().addLast(new SimpleChannelInboundHandler<String>() { @Override protected void channelRead0(ChannelHandlerContext ctx, String msg) { System.out.println(msg); } }); } }) .bind(8000); // 监听8000端口 } } 客户端 public class NettyClient { public static void main(String[] args) throws InterruptedException { Bootstrap bootstrap = new Bootstrap(); NioEventLoopGroup group = new NioEventLoopGroup(); bootstrap .group(group) //组信息 .channel(NioSocketChannel.class) .handler(new ChannelInitializer<Channel>() { @Override protected void initChannel(Channel ch) { ch.pipeline().addLast(new StringEncoder()); } }); //监听url和端口 Channel channel = bootstrap.connect("127.0.0.1", 8000).channel(); while (true) { channel.writeAndFlush(new Date() + ": hello world!"); Thread.sleep(2000); } } } ```

中间件

Nginx

特点 占用内存小、宕机概率低负载均衡非阻塞高并发(官方:5w并发,2-3w没压力) 异步非阻塞事件处理机制:运用了epoll模型,提供了一个队列,排队解决不使用多线程:切换线程占用cpu 正向代理:异步非阻塞接受请求后统一发送到服务器(降低服务器压力),代理客户端反向代理:代理服务端动、静分离

MQ(Kafka) kafka常见问题

分布式发布-订阅消息系统 削峰填谷、缓冲解藕、扩展 名词解释 Producer :消息生产者,就是向kafka broker(服务器)发消息的客户端Consumer、Consumer Group(CG) :消息消费者,向kafka broker取消息的客户端Topic :主题,消息以topic为类别记录,内部包含多个partition(队列)Broker :一台kafka服务器就是一个broker。一个集群由多个broker组成。一个broker可以容纳多个topic;一个非常大的topic可以分布到多个broker上。Partition:一个topic可以分为多个partition,每个partition是一个有序的队列。partition中的每条消息都会被分配一个有序的id(offset)。kafka只保证按一个partition中的顺序将消息发给consumer,不保证一个topic的整体(多个partition间)的顺序Offset:消息id,kafka的存储文件都是按照offset.kafka来命名,eg:the first offset就是00000000000.kafka 主从复制(leader follower) topic的分区拥有若干副本,这个数量是可以配置的,并且是各个节点均匀分布的zk保持连接,如果是follower并且同步延时符合配置要求,则说明是同步节点只有当所有同步节点状态都是committed时,消息才会被发送到consumerleader选举: broker选举:谁先创建了zk内的controller节点,谁就是ISR,同步状态的副本的集合(a set of in-sync replicas),在这个集合中的节点都是和leader保持高度一致的,所以任何follower都可以被选为leader,相当于随机 幂等性 原因 先commit,再执行业务逻辑:提交成功,处理失败 。造成丢失先执行业务逻辑,再commit:提交失败,执行成功。造成重复执行先执行业务逻辑,再commit:提交成功,异步执行fail。造成丢失 Producer重复提交问题 单会话 Kafka增加了pid和seq 1、Producer中每个RecordBatch都有一个单调递增的seq; Broker上每个Topic也会维护pid-seq的映射,并且每Commit都会更新lastSeq。2、当RecordBatch到来时,broker会先检查:如果baseSeq(新消息第一条) > lastSeq(维护的最后一条消息)则保存数据 有序性处理: 1、设置enable.idempotence=true后能够动态调整max-in-flight-request。正常情况下max.in.flight.requests.per.connection大于1。2、当重试请求到来且时,batch 会根据 seq重新添加到队列的合适位置,并把max.in.flight.requests.per.connection设为1,这样它 前面的 batch序号都比它小,只有前面的都发完了,它才能发 多会话 原因:当应用重启时,新的producer并没有old producer的状态数据。可能重复保存。方案:通过事务隔离机制来实现,所以事务引入了transactionId和Epoch原理:同单会话 Consumer端会话 通过msgId自己进行操作 命令 配置文件:监听地址、序列化方法、group-id(消费组)方法:

producer生产:

@Autowired private KafkaTemplate<String, String> kafkaTemplate; @RequestMapping("/send") public String send(String msg) { kafkaTemplate.send("group-id", msg); return "success"; }

consumer消费

单消费组: // 如果是单消费组,这里的group-id就是topicName @KafkaListener(topics = "group-id") public void listen(ConsumerRecord<?, ?> record) throws Exception { System.out.printf("topic = %s, offset = %d, value = %s \n" , record.topic(), record.offset(), record.value()); } 多消费组配置:@KafkaListener(topics = {"${自定义}"},groupId = “xxx”)

Zookeeper 常见功能

分布式的协调组件,功能: 发布/订阅负载均衡命名服务分布式协调/通知集群管理Master选举分布式锁和分布式队列等 崩溃恢复模式(正常时为消息广播模式) 当刚刚启动、Leader服务器宕机、重启、网络故障等导致过半服务器与Leader服务器没有保持正常通信时,所有进程(服务器)进入崩溃恢复模式首先选举产生新的Leader服务器,然后集群中Follower服务器开始与新的Leader服务器进行数据同步,当集群中超过半数机器与该Leader服务器完成数据同步之后,退出恢复模式 Leader选举,过半策略

=3台服务器,投票选举

数据同步,过半策略 直接差异化同步(DIFF同步)先回滚再差异化同步(TRUNC+DIFF同步)仅回滚同步(TRUNC同步)全量同步(SNAP同步) 事务 顺序一致 采用了全局递增的版本Id(ZXID)来标识,zxid记录ZooKeeper状态的改变zxid实际上是一个64位的数字,高32位用来标识leader周期,如果有新的leader产生出来会自增,低32位用来递增计数当新产生(事务)提议的时候,会依据数据库的两阶段过程,首先会向其他的server发出事务执行请求,如果超过半数的机器都能执行并且能够成功,那么就会开始执行 分布式事务、分布式队列 临时节点:每个客户端对某个方法加锁时,在zookeeper上的与该方法对应的指定节点的目录下,生成一个唯一的瞬时有序节点;eg:new ZooKeeper(**).create(**)获取锁:判断有序节点中序号最小的一个释放锁:将瞬时节点删除即可过程:创建临时节点 - 队列中序号最小的获取锁 - 执行 - 关闭锁 - 重复 扩容 水平扩容,全部重启或者顺序重启(不是很好),3.5+会支持动态扩容

数据库、Nosql

Mysql

使用多版本控制协议实现强一致性优化 索引 explain 命令获取语句执行计划 explain extended 会在 explain 的基础上额外提供一些查询优化的信息;show warnings 可以 得到优化后的查询语句,从而看出优化器优化了什么explain partitions 会显示将查询的分区(如果分区的话) 热备、主从、分库分表 配置

Nosql(Redis、MongoDB等)

Nosql完全不适合交易场景,Nosql主要用来做数据分析、ETL(数据抽取、转换以及加载)、报表、数据挖掘、推荐、日志处理等其他非交易场景对比 HBase 实现的语言为Java,依托于 Hadoop 的 HDFS(分布式文件系统)作为最基本存储基础单元。 java编写,需要java环境存储量大、分割简单,但占用内存大api不灵活适用于大数据环境 redis 实现语言为c: 存储数据结构灵活事务保证业务原子性执行速度快适合数据变化快并且容量可预见集群方案在3.0-版本效果不好单线程、支持事务,所以在单个处理和事务处理均可保证原子性 mongdb 实现语言为c++: json格式在服务器端可执行js脚本非事务单个文档大小限制为16M,32位系统上,不支持大于2.5G的数据对内存要求比较大,至少要保证热数据(索引,数据及系统其它开销)都能装进内存适合集群 LevelDBCouchbase(memcache的升级版) 数据备份 redis:主从配置 分布式 非动态 余数算法:通过数据的key进行hash计算,根据数据库数量取余将数据存储到各个数据库上 动态增加 hash槽 一共16384个槽,各个服务器分管一部分新增机器,将数据通过key进行迁移jedis会协调数据的获取 分布式锁 redis锁:setnx,不过这个不是分布式的,是单库的锁;如果需要分布式则建议使用zk的临时节点Redisson(java框架)实现了redis作者出的RedLock算法 分布式部署 修改配置文件

Elasticsearch与Hbase的分析

有es为什么还需要hadoop趋势:相互之间会越来越模糊,现阶段侧重点不同,hadoop是一个生态,es只是能替换其中的一些功能Elasticsearch 优势: ElasticSearch擅长建立索引和搜索索引基于索引查询的快速文本、结构化、统计化查询,以及聚合类数据分析基于json进行查询,开发效率简单且高 劣势: 只能查询索引列,无法搜索和合并未索引的内容;无法运行创建新数据集的复杂分析,所以并不适合做数据分析类操作经上述国外论坛内的讨论,当文档查询结果破万后效率会下降复杂关联查询会降低速度 Hbase(Hadoop) 优势 量大、批处理,复杂计算如果需要专门的数据分析,需要建立团队并使用hadoop 劣势 较es开发复杂,需要人工较多,投入大

Elasticsearch

特点

是一个分布式,高性能、高可用、可伸缩的文本搜索和分析系统Lucene是单机的模式,es解决了分布式问题

场景

全文检索、结构化检索(同义词处理,相关度排名)复杂数据分析近实时数据

日志

logstash

持久化

路由分片查找文档位置

优化

查询的时候,操作系统会将磁盘文件里的数据自动缓存到 filesystem cache里面去,所以cache建议是全部索引数据内容的一半大小所以一定要符合业务,只将需要搜索的字段进行索引,减少索引也就减少了内存占用提高了查询效率数据预热、冷热分离;可以建立一个系统定时对流量较大的索引进行提前刷入内存进行预热复杂数据提前计算,es的关联对象一定要简单或者是已经处理过的数据再插入es分页性能优化:分页也还是要获取之前的数据,所以无论是一次性多取,还是和微博、淘宝一样的下拉等,都无法满足用户自定义页码跳转,建议还是一页页前进;

基础概念

索引(database):含有相同属性的文档集合 分片:每个索引都有多个分片,每个分片是一个lucene索引,减少索引压力备份:拷贝一份分片就完成了分片的备份,用处:分摊搜索压力、容灾启动后自动创建5个分片,1个备份;创建索引的时候指定分片,备份可以后期处理 类型(table):文档必须属于一个类型,索引可以定义1+个类型文档(rows):文档是可以被索引的基本数据单位

API基本格式:http://<ip>:<port>/<索引>/<类型>/<文档id>

json格式可以创建索引,指定分片和备份,并指定索引结构(put方式) put请求:http://\<ip\>:\<port\>/<索引> { "settings":{ "number_of_shards": 3, // 分片 "number_of_replicas": 1 // 备份 }, "mappings":{ // 索引结构 "man":{ // 类型 "properties":{ // 文档 "name":{ "type":"text" }, "country":{ "type": "keyword" }, 插入,根据结构使用json传递即可

Hbase(Hadoop database)

介绍 是一个高可靠性、高性能、面向列、可伸缩的、建立在hdfs上的分布式存储系统是Google Bigtable的开源实现只支持单行事务,可通过hive执行复杂join语句所以一般是配合Hadoop、ZooKeeper、MapReduce进行搭建 特点 主要用来存储非结构化、半松散化数据KV基础存储基于列的模式(其他关系型是基于行)存储大数据,可以支持千万的QPS、PB级别的存储null和空不占用存储空间,表可以设计的非常松散动态列强同步 使用场景 对象存储:1b~100m海量存储(新闻、视频、音频、论坛)时序数据:高并发、海量数据(k线图、监控数据、传感器)推荐画像:用户特征,非常松散时空数据:高并发、海量数据(轨迹、气候数据)CubeDB([kjuːb]):全称是多维立方体,用来实现实时报表,底层数据存储在hbase消息/订单:强同步、海量存储(聊天、订单等)Feeds([fiːd])流:feed是将用户主动订阅的若干消息源组合在一起形成内容聚合器,帮助用户持续地获取最新的订阅源内容;订阅源不再是某个内容,而是生产内容的人/团体。订阅中通常夹杂非订阅内容,比如热门推荐,广告(今日头条、朋友圈、知乎)NewSQL:之上有Phoenix的插件,可以满足二级索引、SQL的需求,对接传统数据需要SQL非事务的需求 语法

RPC

什么是RPC,RPC好处,常用的RPC框架Dubbo 分布式服务框架,以及SOA治理方案 RPC协议底层原理 传输服务:netty(默认)、mina、grizzy序列化:hessian2(默认)、json、fastjson、自定义报文连接描述:单个长连接NIO;异步传输使用场景:1.常规RPC调用 2.传输数据量小 3.提供者少于消费者报文格式:可视化:dobbo admin、各种客户端应用 配置zookeeper,启动dubbo配置指定zk地址、密码、扫描路径、xml配置名、zk组名服务端新建配置:provicer.xml,显式的对外提供接口客户端信息配置:client.xml,同上 SpringCloud 提供了搭建分布式系统及微服务常用的工具以及方案,基于Spring Boot, 使得开发部署极其简单Thrift 可扩展且跨语言的服务的开发 Facebook Thrift是最新一代高性能、跨需要的RPC通信框架,支持多种语言 rmihttphessian

前端

javascriptjqueryvue 脚本引入语法使用

大数据

ElasticSearch见数据库章节Hadoop 分布式系统基础架构,用户可以在不了解分布式底层细节的情况下,开发分布式程序。充分利用集群的威力进行高速运算和存储HDFS 特点 存储非常大的文件采用流式的数据访问方式电脑要求不高 例外 高延时,低延时可以使用hbase大量小文件需要频繁修改 概念 Blocks:文件存储分块Namenode:存储各个节点的元数据、以及文件系统树等Datanode:存储的数据,定期向nomenode汇报 使用 命令行操作(测试、临时操作等,比以下的几个方便很多)java可以直接当做数据库进行访问(太麻烦,要自己实现mapreduce)hive访问(使用spark进一步封装和提高了效率)spark访问(新项目一般使用) 命令 YARN 资源管理和作业调度技术,负责将系统资源分配给在 Hadoop 集群中运行的各种应用程序,并调度要在不同集群节点上执行的任务调度:在整个资源管理框架中,ResourceManager 为 master,NodeManager 是 slave HBASE 见数据库章节HIVE hive -> mapreduce -> hadoop -> hdfshive利用hdfs存储数据,利用mapreduce处理数据HiveOnSpark与SparkSQL SparkSQL 支持多数据源,包括JSON、JDBC、Parquet、MapReduce、文件等组件DataFrame、RDDSpark主推 HiveOnSpark 前期没有很好的适配其他数据源,只支持MapReduce现在使用spark较多,这个就很少用了 为什么要用hive spark没有自己的数据仓库,hive原生支持hdfs(这个不是关键,spark可以用其他的)spark没有自己的meta(管理元数据)库,需要用hive的其实代码里面spark的项目是引用了hive的jar,所以没有替代关系 Spark(快速计算引擎) 特点与优势 封装了mapreduce启用了内存分布数据集,速度更快,适合负载算法api更高级,可以专注开发,不用太关注集群Spark 是一个通用引擎,可用它来完成各种各样的运算,包括 SQL 查询、文本处理、机器学习等 使用 离线 初始化 SparkConf sparkConf = new SparkConf().setMaster(“local[2]”);// 起两个线程sparkConf.setAppName(“Class”); // 当前类名称JavaSparkContext javaSc = new JavaSparkContext(sparkConf);JavaRDD javaRDD = javaSc.textFile(textFilePath); // 文件读取javaSc.stop(); 其他 JavaPairRDD javaPairRDD = javaSc.parallelizePairs(Tuple);JavaRDD javaRDD = javaSc.parallelize(List);…各种类型转换:rdd、map、tuple、list、bean RDD 语法:可以数据转换、json导入解析、file导入导出、hive导入导出、mysql导入导出、cvs导入导出等 JavaRDD javaRDD = javaSc.textFile(textFilePath)JavaRDD javaRDD = javaSc.parallelize(List)…… 操作:过滤、排序、扁平化、分组、抽样等 Dataset(sparksql的封装) 基本过程: SparkContext sc = new SparkContext(sparkConf);SparkSession sparkSession = new SparkSession(sc)Dataset row = sparkSession.read().json(“json text”)Dataset userRow = row.select(“id”);……对row进行数据库类似的操作 其他 rdd、bean、list、json等转JavaRDD 流式 Storm flume

TCP/IP

TCP/IP 传输空空告知协议/因特网互联协议,是一个协议簇的核心,所以如此命名,协议簇还包括FTP、SMTP、ARP、PPP、IEEE 802.x等分层: 应用层:HTTP、SMTP、FTP传输层:TCP、UDP网络层:IP、ARP(地址解析协议,mac寻址)链路层:IEEE 802.x、PPP物理层:网卡 IP,是面向无连接、无状态,是TCP/IP协议的基石 ps:ttl,数据包可经过的最多路由器总数,经过一个路由ttl-1,为0则丢弃数据报并通知主机防止报文继续发送 TCP,每个tcp包都封装在ip包内 特点:面向连接,失败/超时重传,可靠3次握手建立,目的:信息对等、防止超时、防止请求超时导致的脏连接4次挥手断开,多了一个fin信号,接收方处理完所有信息才能通知发送方可以断开 UDP,只是在ip数据包上增加端口等部分信息,是面向无连接的,是不可靠传输HTTPS

JAVA基础

抽象、封装、继承、多态、组合

io

字节流:多处理视频、音频、图片等字符流:多处理带有编码格式的文本装饰器模式

泛型

eg1:public static T max(List list)分析:静态的是标示范型方法eg2:public static <T extends Comparable> T max(List list)分析:如果是排序方法,需要参数继承自Comparable类的子类其他:K - key,V - value,E - element, <? extends T>可以赋值T以及T子类的集合(null可以),元素会向上转型为T,取值会有范型限制 <? super T>可以赋值T以及T父类的集合,元素会范型丢失,例如不记名投票,结束后无法查看投票记录

数据结构

汇总、总结、代码、动图数据结构:栈、队列、链表、树、图(散列、最短路径、拓扑)常用排序算法 稳定性解释:若在排序之前,a[i]在a[j]前面;并且排序之后,a[i]仍然在a[j]前面时间复杂度 O(1),一次就找到,哈希算法就是典型的O(1)时间复杂度O(logn),2为底,eg:当数据增大256倍时,耗时只增大8倍O(n),就代表数据量增大几倍,耗时也增大几倍O(nlogn),eg:当数据增大256倍时,耗时增大256*8=2048倍O(n²)/O(n^2),2为底,数据量增大n倍时,耗时增大n的平方倍 空间复杂度:临时占用存储空间大小的量度推荐 1、基本算法使用插入排序2、快速+稳定+占空间:归并排序3、快速+不稳定+少空间:堆排序4、23之间有个快速排序,简单,不稳定,时间和空间均也介于23之间5、纯数字:基数排序 基本算法,时间换空间 插入排序,稳定,推荐 O(n²),空间:O(1)对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入通过代码分析大数据量比冒泡速度快 冒泡排序,稳定 时间:O(n²),空间:O(1)从前往后依次的比较相邻两个数的大小;如果前者比后者大,则交换它们的位置 选择排序,不稳定 时间:O(n²),空间:O(1)在未排序序列中找到最小(大)元素,存放到排序序列的起始(末尾)位置 希尔排序/缩小增量排序/Shell排序 不稳定,时间:O(n^(1.3—2)),空间:O(1)插入排序的改进版需要定好步长(间隔>1),所以需要对数据非常了解 归并排序,稳定 时间:O(nlogn),空间:O(n)空间换时间使用分治法,递归一分为二,在分组后的数据顺序性较好的情况下使用 快速排序,不稳定 时间:O(nlogn),空间:O(nlogn)选择一个基准数,通过一趟排序将要排序的数据分割成独立的两部分;其中一部分的所有数据都比另外一部分的所有数据都要小 堆排序,不稳定 时间:O(nlogn),空间:O(1)二叉树 基数排序,必须是确定范围的整数,稳定,快速桶排序 算法思想: 分治算法(分组计算后再通过算法合并)动态规划算法(类似递归)贪心算法(最多人满足,eg:先满足最容易满足的人)二分法(折半搜索)搜索算法(eg:导航最近距离)回溯算法(eg:乘阶、ip划分等) 领域算法:大数据算法、分布式算法、加密算法、负载均衡算法、推荐算法等

多线程

锁: 悲观锁:锁表、锁行;乐观锁:增加version字段线程中断 使用线程池ExecutorService的话,shutdownNow是立刻停止,shutdown是执行完现在没执行完的再停止 线程间协作,join(在start后使用join,其他线程会等待)、yield(让出cpu重新竞争)线程池工厂 private static ExecutorService executorService; public static ExecutorService getExecutorService(String groupName) { synchronized (ExecutorFactory.class) { if (executorService == null) { executorService = new ThreadPoolExecutor(4, 8, Long.MAX_VALUE, TimeUnit.NANOSECONDS, new LinkedBlockingQueue<>(1024),

// Executors.defaultThreadFactory(), // 默认工厂 new UserThreadFactory(groupName), // 自定义工厂,可以console线程组和一些上下文参数 new ThreadPoolExecutor.CallerRunsPolicy()); } } return executorService; }

// int corePoolSize, //常驻核心数,0:直接销毁;需要合理分配,太大浪费资源,太小频会繁销毁创建 // int maximumPoolSize, //最大数, >=1 超过会进入缓存队列 // long keepAliveTime, // 连接最大时间,这里使用了最长时间 // TimeUnit unit, // 时间格式,一般使用秒 // BlockingQueue<Runnable> workQueue, // 等待中的任务队列,超过则执行抛弃策略;队列有三种策略,不过阿里云推荐这样,所以有其他需要上网再查 // 该队列为单向链表,使用锁来控制入队和出队的原子性,是一个生产消费模型队列 // ThreadFactory threadFactory, // 创建线程工程,线程池命名是通过给这个工厂增加组命名来实现的 // RejectedExecutionHandler handler // 拒绝策略,超过缓存队列长度以后执行,阿里建议一般跳转固定页面并将数据记数据库or日志后期削峰填谷再处理 //抛弃策略 // ThreadPoolExecutor.AbortPolicy() 抛出java.util.concurrent.RejectedExecutionException异常 // ThreadPoolExecutor.CallerRunsPolicy() 重试添加当前的任务,他会自动重复调用execute()方法 // ThreadPoolExecutor.DiscardOldestPolicy() 抛弃旧的任务 // ThreadPoolExecutor.DiscardPolicy() 抛弃当前的任务 // 不过默认的抛弃策略和线程工厂功能简单,一般不满足使用,实现自己的更合适,实现见 ``` * 使用 ``` while(线程池数量){ Future<Integer> future = executorService.submit(() -> { ...... }) } boolean isDone = false; while (!isDone){ if(future.isDone()) {

// System.out.println(future.get()); isDone = true; } else { System.out.println(false); Thread.sleep(50); } } service.shutdown(); ```

反射

因为效率问题,使用场景不高,一般会在三方或者获取其他项目私有属性的时候使用;或者自己写框架时使用class类:获取类加载器、类名、创建类实例、包名、父类名、接口名、获取注解、所有方法、返回值、类型(匿名、内部、接口实现方法)、构造方法等几乎所有能用到的Field类:成员变量/类的属性Method类:等Constructor类:构造方法使用:Class<?> c = Class.forName(“package path”).method;(eg:newInstance())

动态代理,框架等底层都是通过该方法进行切面编程的:eg:HttpServlet的dopost方法调用

method: private void testInvocation2(){ PersonServer server = new PersonProxy().getPersonProxy(); server.login(); server.submit(); } // 代理类 public class PersonProxy { // 业务接口 private PersonServer server = new PersonServerImp(); public PersonServer getPersonProxy() { // 返回一个代理 return (PersonServer) Proxy.newProxyInstance( server.getClass().getClassLoader() , server.getClass().getInterfaces() , (proxy, method, args) -> { if (method.getName().equals("login")) { // 前置业务 System.out.println("login_begin"); // 主业务执行 Object object = method.invoke(server, args); // 后置业务 System.out.println("login_end"); // 返回执行结果 return object; } else if (method.getName().equals("submit")) { // 其他方法 return method.invoke(server, args); } return null; }); } } // (proxy, method, args) -> {}的原文 new InvocationHandler() { public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { } }

异常

finally 即使发生oom也会执行finally执行顺序:先保存return的值,再执行finally,最后将保存的值return,不再考虑finally改变后的值综上:finally是处理诸如清理资源、释放连接、关闭管道流等,所以不要有赋值、return等操作ps:lock需要写到try内,小心造成finally内的lock.unlock方法在加锁失败后仍旧执行造成报错

测试

类注解 @RunWith(SpringJUnit4ClassRunner.class) @SpringBootTest(classes = xxxApplication.class) 初始化,使用mockMvc,MockMvc实现对Http请求的模拟,可以方便对Controller进行测试,使得测试速度快、不依赖网络环境,而且提供验证的工具,使得请求的验证统一而且很方便 private MockMvc mockMvc; @Autowired private WebApplicationContext webContext; @Before public void before() throws Exception { mockMvc = MockMvcBuilders.webAppContextSetup(webContext).build(); } @After public void after() throws Exception { } 方法 @Test public void testIndexFail() throws Exception { String responseString = mockMvc .perform(get("/api/***") .accept(MediaType.APPLICATION_JSON_UTF8) ) .andExpect(status().isOk()) .andReturn().getResponse().getContentAsString(); assertNotNull(responseString); JSONObject json = JSONObject.fromObject(responseString); assertEquals(json.getString("code").toString(), "1"); assertEquals(json.getString("msg").toString(), TrainConstants.ErrorMsg.PARAMS_ERROR); }

日志

日志门面:门面模式,只提供了接口规范,slf4j、commons-logging日志库:具体实现门面,log4j -> 升级 -> logback、log-jdk日志适配器:因为log4j日志库比slf4j日志接口先出,所以没有使用logback的项目需要增加slf4j-log4j12适配器综述:推荐slf4j + logback模式

JVM

类加载过程 1、bootstrap jvm启动时创建,c/c++实现,加载核心类,eg:object、system、string2、extension classloader平台类加载器,家在扩展的系统类,eg:xml、压缩、加密等3、application classloader应用类加载器,用户可以自定义,用来因为环境的隔离加载类、按需加载、增加加载源、编译加密等4、底层不能越级加载,不能覆盖父类已经加载的类 内存:堆、栈、本地方法、计数寄存器 heap堆,线程共用,存储几乎所有的实例对象,自动gc 新生代,1个eden区,2个survivor区 初始对象占用大于eden区则直接进入老年代eden填满后出发ygc,存活对象进入survivor,如果占用大于survivor则直接进入老年代每次ygc时,将存活的对象存入survivor另一个区,当前区清空,交换使用状态,计数器+1,默认14次后进入老年代如果老年代也放不下,则oom 老年代 perm永久代(摒弃):perm永久代固定大小很难调优,并且fgc的时候会移动类元信息,类加载过多会造成perm的oommetaspace元空间,替换perm区,存储元信息、字段、静态属性、方法、常量等。元空间在本地内存中分配堆设置,-X jvm参数,ms:memory start;mx:memory max -Xms:初始堆大小,初始大小和最大设为一致,避免在gc后调整堆大小时带来的额外压力-Xmx:最大堆大小-XX:NewSize=n:设置年轻代大小,性能考虑不要太小,否则对象直接进入老年代浪费内存-XX:NewRatio=n:设置年轻代和年老代的比值。如:为3,表示年轻代与年老代比值为1:3,年轻代占整个年轻代年老代和的1/4-XX:SurvivorRatio=n:年轻代中Eden区与两个Survivor区的比值。注意Survivor区有两个。eg:3表示 Eden:Survivor = 3:2,说明一个Survivor区占整个年轻代的1/5-XX:MaxTenuringThreshol=n:配置计数器,记录对象从新生代转入老年代的阈值,默认15-XX:PretenureSizeThreshold:设置直接进入老年代的对象大小-XX:MaxPermSize=n:设置持久代大小,在jdk8+设置会提示,现在改为元空间 jvm stack栈,线程私有 只有位于栈顶的帧才是有效的,称为当前栈StackOverflowError栈溢出,通常出现在递归方法中栈存储局部变量、操作栈、动态链接、方法返回地址 native method stacks 本地方法栈,线程私有 不再受jvm控制,甚者可以直接操作cpu的寄存器,出错信息都是黑盒eg:system.currentTimeMillis()native heap OutOfMemory Program Counter Register 程序计数寄存器,线程执行或恢复都要依赖对象实例化过程 1、确认类元数据是否存在,不存在则类加载,进入堆内存2、分配栈内引用变量的内存空间3、设置默认值(不同形式的零值)4、执行方法内的init,并把堆内对象的首地址赋值给引用变量 垃圾回收 System.gc()提醒虚拟机进行垃圾回收,不建议使用判断是否可以回收 判定:如果一个对象与GC Roots之间没有直接或间接的引用关系eg:失去任何引用的对象、或者两个互相环岛状循环引用的对象可回收:类静态属性中、常量、虚拟机栈中、本地方法栈中引用的对象 回收算法 “标记-清除”:基础算法,造成空间碎片,导致分配较大连续空间时容易出发fgc“标记-整理”:改进算法,将存活对象整理到内存空间的一端,解决空间碎片问题“mark-copy”:继续改进算法,将标记和整理空间分为两块,依次激活,解决并行的问题;是主流的解决ygc算法 回收器 jdk8默认回收器查看命令行: java -XX:+PrintCommandLineFlags -version默认: jdk11 默认垃圾收集器G1jdk1.8 默认垃圾收集器Parallel Scavenge(新生代)+Parallel Old(老年代),即:-XX:+UseParallelGC 并行收集器,是独占式的,最大化的提高程序吞吐量,同时缩短程序停顿时间,另外它不能与CMS收集器配合工作idea2017的openjdk默认jvm配置,配置很多,关键点展示 -XX:+UseParNewGC:年轻代并行整理-XX:+UseConcMarkSweepGC:老年代并行整理,一般就使用这个-XX:+UseCMSCompactAtFullCollection:老年代进行压缩整理-XX:+UseCMSInitiatingOccupancyOnly:自定义回收,减少gc-XX:CMSInitiatingOccupancyFraction=70:配合上面的参数,70%以后gc-XX:CMSFullGCsBeforeCompaction=0:每次fgc只要超过70%就进行压缩还有一些减少停顿、gc占运行时间占比、指定线程数量等等的很多配置…… 垃圾回收器详解 CMS回收器:较常用,使用“标记-清除”算法,会产生大量碎片,需要其他配置见上G1回收器:-XX:+UseG1GC,使用“mark-copy”算法,通过jstat查看垃圾回收情况 jstat是jdk提供的查看内存的小工具,命令: jstat -class pid 统计信息 -XX:+PrintGCDetails:java -xx -version 优化 JVM调优工具,Jconsole,jProfile,VisualVM年轻代大小选择 响应时间优先的应用:尽可能设大,直到接近系统的最低响应时间限制(根据实际情况选择)。在此种情况下,年轻代收集发生的频率也是最小的。同时,减少到达年老代的对象。吞吐量优先的应用:尽可能的设置大,可能到达Gbit的程度。因为对响应时间没有要求,垃圾收集可以并行进行,一般适合8CPU以上的应用。 年老代大小选择 响应时间优先的应用:如果堆设置小了,可以会造成内存碎片、高回收频率以及应用暂停而使用传统的标记清除方式;如果堆大了,则需要较长的收集时间。参考: 并发垃圾收集信息持久代并发收集次数传统GC信息花在年轻代和年老代回收上的时间比例减少年轻代和年老代花费的时间,一般会提高应用的效率 吞吐量优先的应用 一般吞吐量优先的应用都有一个很大的年轻代和一个较小的年老代。原因是,这样可以尽可能回收掉大部分短期对象,减少中期的对象,而年老代尽存放长期存活对象。 较小堆引起的碎片问题 MAC优化了停顿,但是碎片需要其他配置,见以上文档描述使用G1的回收方式 oom分析,所有的调优都是为了用户体验(减少卡顿)、减少oom的发生 -XX:+HeapDumpOnOutOfMemoryError:让jvm遇到oom的时候能输入堆内信息 汇总常用工具、框架,例如数据库、文件、映射、地图、多媒体、网络、安全、搜索、序列化、模版等工具汇总最佳工具实践

linux

系统命令 uname [-amnprsv] :显示机器的处理器架构、版本信息、内核等rpmyum installaptcal 2018 :显示2018年的日历表clear :清空命令行ifconfig :显示或设置网卡(查ip等)(类似windows中ipconfig)ping -c 3 www.baidu.com :测试百度与本机的连接情况( -c 3表示测试3次)top :动态实时显示cpu、内存、进程等使用情况(类似windows下的任务管理器)vmstat 2 10 :每隔2秒采集一次服务器状态,采集10次(查看内存、io读写状态、cpu)free -h :查看系统内存及虚拟内存使用情况df -h :显示磁盘的空间使用情况iostat :可查io读写、cpu使用情况(mac)ps aux|grep firefox :获取火狐的进程号(PID)(可查看进程占用cpu、内存百分比及进程触发指令的路径)ps -ef | grep java : <s|l|o|t|m|a>kill -9 进程号 :强制杀死进程systemctl :查看正在运行的服务 权限 chmod [-R] 777文件或目录 :设置权限(chmod a+rwx a=chmod ugo +rwx a=chmod 777 a)chown [-R] admin:root /opt/ :变更文件及目录的拥有者和所属组(-R递归处理所有文件和文件夹,admin为拥有者,root为所属者) 文件 cdpwd 查看当前目录mkdirtouch a.txt :创建文件a.txtrmfind /User/ -name *which 查找文件,eg:which java; which hivemvcpcat [-n] 文件名 :显示文件内容,连行号一起显示cat filename |grep ‘关键字’ [-A10] :查看filename中含有abc所在行后10行less 文件名 :一页一页的显示文件内容 空格、pagedown下一页;pageup上一页“/”向下查询“?”向上查询“n”重复前一个查询;N反向重复前一个查询“q”离开 head [-n] 文件名 :显示文件头n行内容,n指定显示多少行tail [-nf] 文件名:显示文件尾几行内容,n指定显示多少行,f用于实时追踪文件的所有更新,常用于查阅正在改变的日志文件(如tail -f -n 3 a.log 表示开始显示最后3行,并在文件更新时实时追加显示,没有-n默认10行)sed [-nefri] :a新增c替换d删除i插入p打印 sed -n ‘2,$p’ filename :显示第二行到最后一行;sed -n ‘/搜索的关键词/p’ a.txt :显示包括关键词所在行 (A10)、前10行(B10)内容; grep -i ‘HELLO’ . -r -n :在当前目录及子目录下查找文件内容中包含hello的文件并显示文件路径(-i表示忽略大小写) 内容 vim 东西太多 压缩 file 文件名 :查文件类型(可看是用哪一种方式压缩的)tar -zxvf a.tar.gz -C ./test :解压tar.gz到当前目录下的test目录tar -zcvf /opt/c.tar.gz ./a/ :压缩tar.gz(把当前目录下的a目录及目录下所有文件压缩为 /opt/目录下的c.tar.gz,这样tar -zxvf c.tar.gz解压出来带有目录a)tar -jxvf a.tar.bz2 :解压tar.bz2(到当前目录)tar -jcvf c.tar.bz2 ./a/ :压缩tar.bz2(把当前目录下的a目录及目录下所有文件压缩到当前目录下为c.tar.gz2)unzip a.zip :解压zip(到当前目录)unzip -o mdmtest.war -d /opt/mdm :推荐使用unzip解压war包(-o覆盖原有文件,-d指定文件解压后存储的目录)zip -r c.zip ./a/ :压缩zip(把当前目录下的a目录及目录下所有文件压缩到当前目录下为c.zipbzip2 -k file1 : 压缩一个 ‘file1’ 的文件(-k表示保留源文件)(bzip2格式,比gzip好)bzip2 -d -k file1.bz2 : 解压一个叫做 'file1.bz2’的文件gzip file1 : 压缩一个叫做 'file1’的文件(gzip格式)(不能保留源文件)gzip -9 file1 : 最大程度压缩gzip -d file1.gz : 解压缩一个叫做 'file1’的文件 shell脚本

运行 ./xx.sh,如果不用./则会去path里面找路径

变量

基础

与其他语言类似,name=“params”,不能有空格变量以 开 始 , 如 果 是 拼 接 等 使 用 开始,如果是拼接等使用 使{}包裹双引号内部可以有变量,单引号不行,所以拼接等建议使用双引号echo -e 激活转义符(mac不需要)字符串长度:${#变量}

字符串

长度:${#变量}提取:${变量:开始:个数}(从开始+1截取个数)

数组

array_name=(value0 value1 value2 value3)array_name[0]=value0valuen=${array_name[n|@]}

传递参数

echo "执行的文件名:$0"; echo "第一个参数为:$1"; $ ./test.sh 1 2 3 Shell 传递参数实例! 执行的文件名:./test.sh 第一个参数为:1 $@全部参数$*全部参数作为一个参数

命令-关系与逻辑

算数,加减乘除:echo `expr 2 + 2` 注意空格必须要有布尔运算 eg:if [ $a -lt 5 -o $b -gt 100 ] !非-o 或-a 与eg:if [ $one == $two ]; then xxx elif xxx else xxx fi 关系,只支持数字,eg:if [ $a -eq $b ] -eq 相等-ne 不相等-gt 大于-lt 小于-ge 大于等于-le 小于等于 逻辑运算 eg:if [[ $a -lt 100 && $b -gt 100 ]] && || 字符串运算符 = !=-z 是否为0-n 是否不为0 eg:if [ -n “$a” ]$ 是否为空 eg:if [ $a ]

命令-文件测试运算符

-r file 文件是否可读;-w 是否可写-f file 是否是普通文件(非设备、非目录文件);-d 是否是目录-x file 是否可执行-s file 文件不为空;-e 文件存在

命令-其他

read 获取console的输入

eg:read param;echo $param

echo

\n 换行,\c 不换行,\f 换页,\r 回车,\t 水平制表符,\v 垂直制表符-e 转义单引号:原文输出反引号:输出命令结果输出到文件(覆盖):eg:echo “Im’ OK” >xxx/test.sh

printf,同c语言

eg: printf "%-10s %-8s %-4s\n" 姓名 性别 体重kg printf "%-10s %-8s %-4.2f\n" 郭靖 男 66.1234 # %s %c %d %f都是格式替代符;-10:宽度;-4.2f:保留小数等 无论多少个占位符,多少个参数,都按照参数数量进行格式输出;注意:如果是%d,但是参数是字符串,则报错 printf "%s %s\n" "参数一" "参数二" # 参数一 参数二 printf "%s %s %s\n" "参数一" "参数二" # 参数一 参数二 printf "%s\n" "参数一" "参数二" "参数三" # 参数一 # 参数二 # 参数三

test eg:if test $num1 = $num2

测试、调试等使用,可以快速获取表达式问题

流程控制

if:if [ $(ps -ef | grep -c “ssh”) -gt 1 ]; then echo “true”; fifor:for var in item1 item2 … itemN; do command1; command2… done;while:while condition do command done无限循环:while true …… 或者 for (( ; ; ))case: read item case "$item" in 1|z|\*) echo "case 1" ;; *) echo "default" ;; esac breakcontinue

函数,注意参数当n>=10时,需要使用${n}来获取参数

function name () { echo "name函数->$1" #a } name a b c d

输入/重定向

输出 覆盖:command1 > file1;eg:who > test.sh * 追加:command1 >> file1;eg:who >> test.sh 输入 将xxx的内容做cat处理:cat < xxx.xlsx如果希望执行某个命令,但又不希望在屏幕上显示输出结果,那么可以将输出重定向到 /dev/null;/dev/null 是一个特殊的文件,写入到它的内容都会被丢弃

设计模式

spring中的设计模式原则 开闭原则 - 对扩展开放,对修改关闭里氏代换原则 - 任何基类可以出现的地方,子类一定可以出现依赖倒转原则 - 针对接口编程,依赖于抽象而不依赖于具体接口隔离原则 - 使用多个隔离的接口,比使用单个接口要好合成复用原则 - 尽量使用合成/聚合的方式,而不是使用继承 创建型 简单工厂(不属于23种设计模式) Spring 中的 BeanFactory 就是简单工厂模式的体现,根据传入一个唯一的标识来获得 Bean 对象 工厂方法模式(只对结果负责,不要三无产品) 一般情况下,应用程序有自己的工厂对象来创建 Bean.如果将应用程序自己的工厂对象交给 Spring 管 理,那么 Spring 管理的就不是普通的 Bean,而是工厂 Bean 单例模式(保证独一无二) Spring 下默认的 Bean 均为单例 原型模式(拔一根猴毛,吹出千万个) 就是 Java 中的克隆技术,以某个对象为原型。复制出新的对象。显然新的对象具备原 型对象的特点,效率高(避免了重新执行构造过程步骤) 结构型 代理模式(办事要求人,所以找代理) Spring 的 Proxy 模式在 AOP 中有体现,比如 JdkDynamicAopProxy 和 Cglib2AopProxy 模板方法模式(流程标准化,原料自己加) 定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。Template Method 使得子类可以不改变 一个算法的结构即可重定义该算法的某些特定步骤。 TemplateMethod 模式一般是需要继承的。这里想要探讨另一种对 TemplateMethod 的理解。Spring 中的 JdbcTemplate 委派模式(不属于23种设计模式)(活你干,功劳是我的) 这种模式的原理为类 B 和类 A 是两个互相没有任何关系的类,B 具有和 A 一模一样的方法和属性;第三方的代码不需要知道 A 的 存在,也不需要和 A 发生直接的联系,通过 B 就可以直接使用 A 的功能,这样既能够使用到 A 的各种功 能,又能够很好的将 A 保护起来了,一举两得 适配器模式(需要一个转换头) Spring AOP 模块对 BeforeAdvice、AfterAdvice、ThrowsAdvice 三种通知类型的支持实际上是借 助适配器模式来实现的,这样的好处是使得框架允许用户向框架中加入自己想要支持的任何一种通知类 型,上述三种通知类型是 Spring AOP 模块定义的,它们是 AOP 联盟定义的 Advice 的子类型。 装饰器模式(需要包装,但不改变本质) IO流包装、数据源包装 观察者模式(完成时通知我) 定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象 都得到通知并被自动更新。 Spring 中 Observer 模式常用的地方是 Listener 的实现。如 ApplicationListener 行为型 策略模式(我行我素,达到目的就行) 定义一系列的算法,把它们一个个封装起来,并且使它们可相互替换。本模式使得算法可独 立于使用它的客户而变化。 Spring 中在实例化对象的时候用到 Strategy 模式,在 SimpleInstantiationStrategy 有使用
最新回复(0)