分类 大观园 下的文章

文章很长,建议收藏起来,慢慢读! 高并发学习社群 - 疯狂创客圈奉献给大家:


经典图书 - 《Netty Zookeeper Redis 高并发实战》 面试必备 + 大厂必备 + 涨薪必备

经典图书 - 《SpringCloud、Nginx高并发核心编程》 面试必备 + 大厂必备 + 涨薪必备

社群资源 - 百度网盘 Java 资源大集合 价值>1000元 随便取

独孤九剑- 高并发 灵魂实验 : 本地 100W连接 高并发实验,瞬间提升 Java内力 ,大大提高水平

文章目录

价值连城:2021春招月薪过5万 面试题 系列

万字长文: 疯狂创客圈 springCloud 高并发系列

2021春招月薪过5万(猛!惊!)面试题之:架构设计篇

场景题

秒杀系统

红包系统

分布式ID

分布式限流

分布式定时任务

微博推送

大文件排序

其他场景题

场景题答题小建议:

分布式微服务架构

问1.什么是分布式系统

分布式系统的目标与要素

分布式系统设计两大思路:中心化和去中心化

分布式与集群的区别是什么?

问2. 如何防止HA集群的脑裂

1. 引言

2如何防止HA集群脑裂

3. 没有fence设备是否安全

4. 主从切换后数据能否保证不丢

5. 如何实现上面的策略

**问3. 微服务架构基本理念和原则,为什么会在团队中使用微服务架构,实行微服务架构过程中碰到的问题及其解决方案。**

关键思路

参考答案:

**问3. RPC 的概念及其包含的核心组件和主流实现技术,如何实现一个自定义的 RPC 框架。**

关键思路

**RPC的由来**

**RPC的实现原理**

**PRC架构组件**

**RPC调用过程**

问4 说说springcloud rpc 的执行流程和原理? 如何对springcloud 微服务进行高并发的性能优化?

分布式事务

问1:什么是分布式事务?

CAP定理

CAP定理的证明

BASE理论

BASE理论的核心思想

BASE理论三要素

1. 基本可用

2. 软状态

3. 最终一致性

负载均衡的算法与实现

1.轮询(Round Robin)

1. 加权轮询(Weighted Round Robbin)

1.4 加权最小连接(Weighted Least Connection)

1.5 随机算法(Random)

实现

2.1 DNS 解析

2.2 修改 MAC 地址

2.3 修改 IP 地址

2.4 HTTP 重定向

2.5 反向代理

分布式锁

数据库分布式锁

Redis 分布式锁

Zookeeper 分布式锁

分布式 Session

1 粘性 Session

2 服务器 Session 复制

3 Session 共享机制

4 Session 持久化到数据库

5 Terracotta 实现 Session 复制

分库与分表

价值连城:2021春招月薪过5万 面试题 系列

搞定下面这些面试题,2021春招月薪过5万(猛!)阿里、京东、美团、头条… 随意挑、横着走!!!

Java基础

1: JVM面试题(史上最强、持续更新、吐血推荐)https://www.cnblogs.com/crazymakercircle/p/14365820.html

2:Java基础面试题(史上最全、持续更新、吐血推荐)https://www.cnblogs.com/crazymakercircle/p/14366081.html

3:死锁面试题(史上最强、持续更新)[https://www.cnblogs.com/crazymakercircle/p/14323919.html]

4:设计模式面试题 (史上最全、持续更新、吐血推荐)https://www.cnblogs.com/crazymakercircle/p/14367101.html

5:架构设计面试题 (史上最全、持续更新、吐血推荐)https://www.cnblogs.com/crazymakercircle/p/14367907.html

还有 10 几篇 篇价值连城 的面试题具体… 请参见【 疯狂创客圈 高并发 总目录 】

万字长文: 疯狂创客圈 springCloud 高并发系列

springCloud 高质量 博文

nacos 实战(史上最全)sentinel (史上最全+入门教程)

springcloud + webflux 高并发实战Webflux(史上最全)

SpringCloud gateway (史上最全)

还有 10 几篇 万字长文 的高质量 博文具体… 请参见【 疯狂创客圈 高并发 总目录 】

2021春招月薪过5万(猛!惊!)面试题之:架构设计篇

场景题

整理了一些常见的架构设计面试题,主要记录关键点,具体细节就不详细叙述了,案例慢慢补充。目前想起以下问题:


秒杀系统

短链接生成

高并发的红包系统

分布式ID生成

分布式限流

分布式定时任务

新浪微博怎么推送微博

大文件有限内存排序

秒杀系统

秒杀系统基本面试被问烂了,网上资料也很多,基本整理了内容如下:


设计难点:并发量大,应用、数据库都承受不了。另外难控制超卖。


设计要点:


将请求尽量拦截在系统上游,html尽量静态化,部署到cdn上面。按钮及时设置为不可用,禁止用户重复提交请求。

设置页面缓存,针对同一个页面和uid一段时间内返回缓存页面。

数据用缓存抗,不直接落到数据库。

读数据的时候不做强一致性教研,写数据的时候再做。

在每台物理机上也缓存商品信息等等变动不大的相关的数据

像商品中的标题和描述这些本身不变的会在秒杀开始之前全量推送到秒杀机器上并一直缓存直到秒杀结束。

像库存这种动态数据会采用被动失效的方式缓存一定时间(一般是数秒),失效后再去Tair缓存拉取最新的数据。

如果允许的话,用异步的模式,等缓存都落库之后再返回结果。

如果允许的话,增加答题教研等验证措施。

其他业务和技术保障措施:


业务隔离。把秒杀做成一种营销活动,卖家要参加秒杀这种营销活动需要单独报名,从技术上来说,卖家报名后对我们来说就是已知热点,当真正开始时我们可以提前做好预热。

系统隔离。系统隔离更多是运行时的隔离,可以通过分组部署的方式和另外 99% 分开。秒杀还申请了单独的域名,目的也是让请求落到不同的集群中。

数据隔离。秒杀所调用的数据大部分都是热数据,比如会启用单独 cache 集群或 MySQL 数据库来放热点数据,目前也是不想0.01%的数据影响另外99.99%。

另外需要复习缓存穿透、雪崩等等问题,主要的流量都落在了缓存数据库上,需要针对缓存数据库的高可用作保障。


短链接生成


这个应该是比较公认的方案了:


分布式ID生成器产生ID

ID转62进制字符串

记录数据库,根据业务要求确定过期时间,可以保留部分永久链接

主要难点在于分布式ID生成。鉴于短链一般没有严格递增的需求,可以使用预先分发一个号段,然后生成的方式。


看了下新浪微博的短链接,8位,理论上可以保存超过200万亿对关系,具体怎么存储的还有待研究。


红包系统

红包系统其实很像秒杀系统,只不过同一个秒杀的总量不大,但是全局的并发量非常大,比如春晚可能几百万人同时抢红包。


主要技术难点也类似,主要在数据库,减库存的时候会抢锁。另外由于业务需求不同,没办法异步,也不能超卖,事务更加严格。


不能采用的方式:


乐观锁:手慢会失败,DB 面临更大压力,所以不能采用。

直接用缓存顶,涉及到钱,一旦缓存挂掉就完了。

建议的方式:


接入层垂直切分,根据红包ID,发红包、抢红包、拆红包、查详情详情等等都在同一台机器上处理,互不影响,分而治之。

请求进行排队,到数据库的时候是串行的,就不涉及抢锁的问题了。

为了防止队列太长过载导致队列被降级,直接打到数据库上,所以数据库前面再加上一个缓存,用CAS自增控制并发,太高的并发直接返回失败。

红包冷热数据分离,按时间分表。

分布式ID

分布式ID生成大概也算老生常谈的问题了,主要关键在于是否需要严格递增,严格递增的话效率必然大降。


不需要递增的话比较简单:


一种方式是预先分片,比如十台机器,每台先分一千个ID,一号机从0开始,二号从1000开始等等。缺点是大致上可以被人看出来业务量。

另一种方式是类似雪花算法,每个机器有个id,然后基于时间算一个id,再加上一个递增id。比如如下美团的方案。缺点是机器的时间戳不能回拨,回拨的话会出现问题。



如果要求严格递增,我没找到现成的很好的方案,大概只能单机生成,不能分布式了,然后都去单机上取号。效率的话,类似Redis的数据库大概能到每秒十几二十几万的速度。


分布式限流

常见的限流方法:


固定窗口计数器:按照时间段划分窗口,有一次请求就+1,最为简单的算法,但这个算法有时会让通过请求量允许为限制的两倍。

滑动窗口计数器:通过将窗口再细分,并且按照时间“滑动”来解决突破限制的问题,但是时间区间的精度越高,算法所需的空间容量就越大。

漏桶:请求类似水滴,先放到桶里,服务的提供方则按照固定的速率从桶里面取出请求并执行。缺陷也很明显,当短时间内有大量的突发请求时,即便此时服务器没有任何负载,每个请求也都得在队列中等待一段时间才能被响应。

令牌桶:往桶里面发放令牌,每个请求过来之后拿走一个令牌,然后只处理有令牌的请求。令牌桶满了则多余的令牌会直接丢弃。令牌桶算法既能够将所有的请求平均分布到时间区间内,又能接受服务器能够承受范围内的突发请求,因此是目前使用较为广泛的一种限流算法。

Google 的开源项目 guava 提供了 RateLimiter 类,实现了单点的令牌桶限流。


分布式环境下,可以考虑用 Redis+Lua 脚本实现令牌桶。


如果请求量太大了,Redis 也撑不住怎么办?我觉得可以类似于分布式 ID 的处理方式,Redis 前面在增加预处理,比如每台及其预先申请一部分令牌,只有令牌用完之后才去 Redis。如果还是太大,是否可以垂直切分?按照流量的来源,比如地理位置、IP 之类的再拆开。


分布式定时任务

任务轮询或任务轮询+抢占排队方案


每个服务器首次启动时加入队列;

每次任务运行首先判断自己是否是当前可运行任务,如果是便运行;

如果不是当前运行的任务,检查自己是否在队列中,如果在,便退出,如果不在队列中,进入队列。

微博推送

主要难点:关系复杂,数据量大。一个人可以关注非常多的用户,一个大 V 也有可能有几千万的粉丝。


先介绍最基本的方案:


推模式:推模式就是,用户A关注了用户 B,用户 B 每发送一个动态,后台遍历用户B的粉丝,往他们粉丝的 feed 里面推送一条动态。

拉模式:推模式相反,拉模式则是,用户每次刷新 feed 第一页,都去遍历关注的人,把最新的动态拉取回来。

一般采用推拉结合的方式,用户发送状态之后,先推送给粉丝里面在线的用户,然后不在线的那部分等到上线的时候再来拉取。


另外冷热数据分离,用户关系在缓存里面可以设置一个过期时间,比如七天。七天没上线的可能就很少用这个 APP。


大文件排序

对于远高于内存的文件排序。


外归并排序:


对文件分割,然后分别排序

排好序的文件依次读取一个缓冲区的大小,然后进行排序,输出到输出缓冲区,然后保存到结果文件。

如果是数字,可以用位图排序,但是要求比较苛刻:


数字不重复

知道最大值

相对密集,因为没出现的数字也会占用空间

比较适合电话号之类的。


其他场景题

1、情景题:如果一个外卖配送单子要发布,现在有200个骑手都想要接这一单,如何保证只有一个骑手接到单子?


这个可以用redis的lpush rpop来实现。


2、场景题:美团首页每天会从10000个商家里面推荐50个商家置顶,每个商家有一个权值,你如何来推荐?第二天怎么更新推荐的商家?


这个可以用堆排,第二天更新推荐的可以在要更新之前的时候在redis做计算操作,然后放数据库做个同步就行了。


3、场景题:微信抢红包问题

悲观锁,乐观锁,存储过程放在mysql数据库中。

4、场景题:1000个任务,分给10个人做,你怎么分配,先在纸上写个最简单的版本,然后优化。

全局队列,把1000任务放在一个队列里面,然后每个人都是取,完成任务。

分为10个队列,每个人分别到自己对应的队列中去取务。

5、场景题:保证发送消息的有序性,消息处理的有序性。


给消息加一个header,识别一下header的syn就行


6、如何把一个文件快速下发到100w个服务器


边下发,边复制


7、给每个组分配不同的IP段,怎么设计一种结构使的快速得知IP是哪个组的?


8、10亿个数,找出最大的10个。

建议一个大小为10的小根堆。

9、有几台机器存储着几亿淘宝搜索日志,你只有一台2g的电脑,怎么选出搜索热度最高的十个搜索关键词?


分bucket,每个bucket找出频次最高的10个,总体用分治算法做。


10、分布式集群中如何保证线程安全?


分布式锁,意在让分布式多线程的环境针对一个共享资源一次性只会有一个线程获取到锁里的资源。分布式锁的实现一般就是redis和zk居多。redis设置一下expire time就行。


11、10万个数,输出从小到大?

先划分成多个小文件,送进内存排序,然后再采用多路归并排序。

12、有十万个单词,找出重复次数最高十个?


map<String,Integer> 字符串,频次,然后堆排。


场景题答题小建议:

架构设计题目远不止这些,我觉得主要从以下几个方面准备:


先了解常用算法,针对解决各种问题能用哪些算法,比如大文件排序用外排序,大量数据中的命中判断用位图/布隆过滤器等等。

注意扩展性、多考虑极端情况,多问自己几个为什么。比如说起单机的限流算法想想分布式的怎么做。

实在不知道怎么弄的叙述自己的思考过程,着重展示自己考虑周全、思维缜密。

比如之前一个同事面阿里被问整个机房网络挂了/断电了之类的极端问题,相信很多人不可能真的遇到这种情况,而且可用性一般也到不了这个级别。如果是我的话,我会着重考虑数据一致性、数据恢复、脏数据处理之类的问题,是否有其他机房提供服务,如果有的话涉及到网络分区,是不是可以引申谈谈 zab、raft 算法,另外原本两个或者三个机房提供服务,现在瞬间少了一个,其他机房的负载瞬间上升,怎么做削峰、降级,这就有回到我们会的问题上了。另外等到网络恢复了,怎么恢复服务?之前处理到一半的数据怎么处理?这些引申开来都有太多可以聊。


分布式微服务架构

问1.什么是分布式系统

分布式系统的目标与要素

分布式系统的目标是提升系统的整体性能和吞吐量另外还要尽量保证分布式系统的容错性(假如增加10台服务器才达到单机运行效果2倍左右的性能,那么这个分布式系统就根本没有存在的意义)。


即使采用了分布式系统,我们也要尽力运用并发编程、高性能网络框架等等手段提升单机上的程序性能。


分布式系统设计两大思路:中心化和去中心化



中心化设计


两个角色: 中心化的设计思想很简单,分布式集群中的节点机器按照角色分工,大体上分为两种角色: “领导” 和 “干活的”

角色职责: “领导”通常负责分发任务并监督“干活的”,发现谁太闲了,就想发设法地给其安排新任务,确保没有一个“干活的”能够偷懒,如果“领导”发现某个“干活的”因为劳累过度而病倒了,则是不会考虑先尝试“医治”他的,而是一脚踢出去,然后把他的任务分给其他人。其中微服务架构 Kubernetes 就恰好采用了这一设计思路。

中心化设计的问题

中心化的设计存在的最大问题是“领导”的安危问题,如果“领导”出了问题,则群龙无首,整个集群就奔溃了。但我们难以同时安排两个“领导”以避免单点问题。

中心化设计还存在另外一个潜在的问题,既“领导”的能力问题:可以领导10个人高效工作并不意味着可以领导100个人高效工作,所以如果系统设计和实现得不好,问题就会卡在“领导”身上。

领导安危问题的解决办法: 大多数中心化系统都采用了主备两个“领导”的设计方案,可以是热备或者冷备,也可以是自动切换或者手动切换,而且越来越多的新系统都开始具备自动选举切换“领导”的能力,以提升系统的可用性。

去中心化设计


众生地位平等: 在去中心化的设计里,通常没有“领导”和“干活的”这两种角色的区分,大家的角色都是一样的,地位是平等的,全球互联网就是一个典型的去中心化的分布式系统,联网的任意节点设备宕机,都只会影响很小范围的功能。

“去中心化”不是不要中心,而是由节点来自由选择中心。 (集群的成员会自发的举行“会议”选举新的“领导”主持工作。最典型的案例就是ZooKeeper及Go语言实现的Etcd)

去中心化设计的问题: 去中心化设计里最难解决的一个问题是 “脑裂”问题 ,这种情况的发生概率很低,但影响很大。脑裂指一个集群由于网络的故障,被分为至少两个彼此无法通信的单独集群,此时如果两个集群都各自工作,则可能会产生严重的数据冲突和错误。一般的设计思路是,当集群判断发生了脑裂问题时,规模较小的集群就“自杀”或者拒绝服务。

分布式与集群的区别是什么?

分布式: 一个业务分拆多个子业务,部署在不同的服务器上

集群: 同一个业务,部署在多个服务器上。比如之前做电商网站搭的redis集群以及solr集群都是属于将redis服务器提供的缓存服务以及solr服务器提供的搜索服务部署在多个服务器上以提高系统性能、并发量解决海量存储问题。

问2. 如何防止HA集群的脑裂

1. 引言

脑裂(split-brain),指在一个高可用(HA)系统中,当联系着的两个节点断开联系时,本来为一个整体的系统,分裂为两个独立节点,这时两个节点开始争抢共享资源,结果会导致系统混乱,数据损坏。


对于无状态服务的HA,无所谓脑裂不脑裂;但对有状态服务(比如MySQL)的HA,必须要严格防止脑裂。(但有些生产环境下的系统按照无状态服务HA的那一套去配置有状态服务,结果可想而知…)


2如何防止HA集群脑裂

一般采用2个方法


仲裁

当两个节点出现分歧时,由第3方的仲裁者决定听谁的。这个仲裁者,可能是一个锁服务,一个共享盘或者其它什么东西。

fencing

当不能确定某个节点的状态时,通过fencing把对方干掉,确保共享资源被完全释放,前提是必须要有可靠的fence设备。

理想的情况下,以上两者一个都不能少。但是,如果节点没有使用共享资源,比如基于主从复制的数据库HA,我们也可以安全的省掉fence设备,只保留仲裁。而且很多时候我们的环境里也没有可用的fence设备,比如在云主机里。


所以,单纯的双节点,无论如何也防止不了脑裂。


3. 没有fence设备是否安全

以PostgreSQL或MySQL的数据复制为例来说明这个问题。


客户端路由有几种方式,基于VIP,基于Proxy,基于DNS或者干脆客户端维护一个服务端地址列表自己判断主从。不管采用哪种方式,主从切换的时候都要更新路由。


基于VIP的路由有一些变数,如果本该死掉的节点没有摘掉自己身上的VIP,那么它随时可能出来捣乱(即使新主已经通过arping更新了所有主机上的arp缓存,如果某个主机的arp过期,发一个arp查询,那么就会发生ip冲突)。所以可以认为VIP也是一种特殊的共享资源,必需把它从故障节点上摘掉。至于怎么摘,最简单的办法就是故障节点发现自己失联后自己摘,如果它还活着的话(如果它死了,也就不用摘了)。如果负责摘vip的进程无法工作怎么办?这时候就可以用上本来不太靠谱的软fence设备了(比如ssh)。

也要考虑Proxy的高可用

至于基于服务端地址列表的方法,客户端需要通过后台服务判断主从(比如PostgreSQL/MySQL会话是否处于只读模式)。这时,如果出现2个主,客户端就会错乱。为防止这个问题,原主节点发现自己失联后要自己把服务停掉,这和前面摘vip的道理是一样的。


4. 主从切换后数据能否保证不丢

主从切换后数据会不会丢和脑裂可以认为是2个不同的问题。还以PostgreSQL或MySQL的数据复制为例来说明。

对PostgreSQL,如果配置成同步流复制,可以做到不管路由是否正确,都不会丢数据。因为路由到错误节点的客户端根本写不进任何数据,它会一直等待从节点的反馈,而它以为的从节点,现在已经是主子了,当然不会理它。当然如果老是这样也不好,但它给集群监视软件纠正路由错误提供了充足的时间。

如果本来就是配置的异步复制,那就是说已经做好丢数据的准备了。这时候,主从切换时丢点数据也没啥大不了,但要控制自动切换的次数。比如控制已经被failover掉的原主不允许自动上线,否则如果因为网络抖动导致故障切换,那么主从就会不停的来回切,不停的丢数据,破坏数据的一致性。


5. 如何实现上面的策略

你可以自己完全从头开始实现一套符合上述逻辑的脚本。但我更倾向于基于成熟的集群软件去搭建,比如Pacemaker+Corosync+合适的资源Agent。Keepalived我是极不推荐的,它就不适合用于有状态服务的HA,即使你把仲裁,fence那些东西都加到方案里,总觉得别扭。


使用Pacemaker+Corosync的方案也有一些注意事项

1)了解资源Agent的功能和原理

了解资源Agent的功能和原理,才能知道它适用的场景。比如pgsql的资源Agent是比较完善的,支持同步和异步流复制,并且可以在两者之前自动切换,并且可以保证同步复制下数据不会丢失。但目前MySQL的资源Agent就很弱了,没有使用GTID又没有日志补偿,很容易丢数据,还是不要用的好,继续用MHA吧(但是,部署MHA时务必要防范脑裂)。


2)确保法定票数(quorum)

quorum可以认为是Pacemkaer自带的仲裁机制,集群的所有节点中的多数选出一个协调者,集群的所有指令都由这个协调者发出,可以完美的杜绝脑裂问题。为了使这套机制有效运转,集群中至少有3个节点,并且把no-quorum-policy设置成stop,这也是默认值。(很多教程为了方便演示,都把no-quorum-policy设置成ignore,生产环境如果也这么搞,又没有其它仲裁机制,是很危险的!)

但是,如果只有2个节点该怎么办?

一是拉一个机子借用一下凑足3个节点,再设置location限制,不让资源分配到那个节点上。

二是把多个不满足quorum小集群拉到一起,组成一个大的集群,同样适用location限制控制资源的分配的位置。


但是如果你有很多双节点集群,找不到那么多用于凑数的节点,又不想把这些双节点集群拉到一起凑成一个大的集群(比如觉得不方便管理)。那么可以考虑第三种方法。

第三种方法是配置一个抢占资源,以及服务和这个抢占资源的colocation约束,谁抢到抢占资源谁提供服务。这个抢占资源可以是某个锁服务,比如基于zookeeper包装一个,或者干脆自己从头做一个,就像下面这个例子。http://my.oschina.net/hanhanztj/blog/515065(这个例子是基于http协议的短连接,更细致的做法是使用长连接心跳检测,这样服务端可以及时检出连接断开而释放锁)但是,一定要同时确保这个抢占资源的高可用,可以把提供抢占资源的服务做成lingyig高可用的,也可以简单点,部署3个服务,双节点上个部署一个,第三个部署在另外一个专门的仲裁节点上,至少获取3个锁中的2个才视为取得了锁。这个仲裁节点可以为很多集群提供仲裁服务(因为一个机器只能部署一个Pacemaker实例,否则可以用部署了N个Pacemaker实例的仲裁节点做同样的事情。)。但是,如非迫不得已,尽量还是采用前面的方法,即满足Pacemaker法定票数,这种方法更简单,可靠


问3. 微服务架构基本理念和原则,为什么会在团队中使用微服务架构,实行微服务架构过程中碰到的问题及其解决方案。

关键思路

对于微服务架构而言,服务建模、服务拆分和服务集成是基本的设计理念,而 RPC、RESTful、API 网关、分布式配置中心等基础组件以及服务可用性和数据最终一致性等关键要素也是重点内容。至于引入微服务架构的原因和碰到的困难,团队业务发展特点和组织架构、微服务粒度和边界等都是回答该问题的切入点。为了实现微服务架构,我们可以引入 Spring Cloud 等相对完善的技术实现体系,也可以使用 Dubbo 作为我们的基础微服务架构。


参考答案:

一体化架构的问题


或者说是微服务架构所解决的问题。


1.难以扩展


一体化架构应用只能通过在负载均衡器后面放置整个应用程序的多个实例来进行水平扩展。如果应用中的特定服务需要扩展,则没有简单的选项。我们需要完整地扩展应用程序,这显然会造成不必要的资源浪费。


相比之下,基于微服务的应用程序允许我们根据需要独立扩展单个服务。在上图中,如果需要缩放服务B,则可以有10个实例,同时保持其他实例,并可以根据需要随时更改。


2.交付时间长


一体化架构在单个应用的任何部分/层中进行的任何更改都需要构建和部署整个应用程序。个人开发人员还需要下载整个应用程序代码来修复和测试,而不仅仅是受影响的模块,这就影响到了持续部署的效率。


而在微服务架构中,如果仅在一百个微服务中的一个中需要改变,则仅构建和部署改变的微服务,没有必要部署一切。我们甚至可以在短时间内多次部署。


3.应用复杂性


过去,随着应用规模的增长(功能、功能等),团队也会相应扩张,应用很快就就会变得复杂和交织在一起。随着不同的团队不断修改代码,维护模块化结构慢慢变得越来越困难,并慢慢导致像意大利面一样交织的代码。这不仅会影响代码质量,还会影响整个组织。


在基于微服务的应用中,每个团队都在单独的微服务上工作,代码会有序很多。


4.没有明确的所有权


在一体化应用中,看起来独立的团队实际上并不是独立的。它们同时在相同的代码库上工作,严重依赖于彼此。


在基于微服务的应用中,独立团队处理单独的微服务。一个团队将拥有一个完整的微服务。工作的明确所有权明确控制服务的一切,包括开发、部署和监控。


5.故障级联


如果没有正确设计,一体化交媾应用的一部分失败可能会级联并导致整个系统崩溃。


在基于微服务的架构的情况下,我们可以使用断路器来避免这种故障。


6.Dev和Ops之间的墙


开发团队通常会进行开发、测试,一旦部署,就会将维护和支持的所有权交给运维团队,应用此时与开发团队无关了,而运维团队需要努力在生产环境中支持一体化架构应用。


在基于微服务的应用中,团队的组织理解为“构建它、运行它”,开发团队继续在生产中拥有该应用。


7.陷入某种技术/语言


使用一体化架构,意味着被某种已实现的技术/语言锁定。如果需要更改技术/语言,则必须重写整个应用程序。


使用微服务,每个服务可以根据需求和业务以不同的技术或语言实现。任何改变服务技术/语言的决定都只需要重写该特定服务,因为所有微服务都是相互独立的。


8.支持微服务的正确工具/技术的可用性


几年前,我们还没有适当的工具和技术来支持微服务。但自从Docker容器和云基础设施(特别是PaaS)向大众提供服务以来,微服务正在大规模采用,因为它们提供了我们所需的“自由”,而无需进行传统的配置程序。


小结


简单来说,使用微服务架构会获得以下好处:


独立开发部署服务

速度和敏捷性

更高的代码质量

获得围绕业务功能创建/组织的代码

提高生产力

更容易扩展

自由(在某种程度上)选择实施技术/语言

问3. RPC 的概念及其包含的核心组件和主流实现技术,如何实现一个自定义的 RPC 框架。

关键思路

该面试题相对容易回答,RPC 是分布式系统的基础,从思路上我们应该理解它是由网络通信、序列化、传输协议、服务调用等组件所构成。同时,对业界主流 RPC 的实现技术也要有足够的了解,如 Alibaba Dubbo、Google gRPC、Facebook Thrift 等。


RPC的由来

随着互联网的发展,网站应用的规模不断扩大,常规的垂直应用架构已无法应对,分布式服务架构以及流动计算架构势在必行,亟需一个治理系统确保架构有条不紊的演进。


单一应用架构

当网站流量很小时,只需一个应用,将所有功能都部署在一起,以减少部署节点和成本。

此时,用于简化增删改查工作量的 数据访问框架(ORM) 是关键。

垂直应用架构

当访问量逐渐增大,单一应用增加机器带来的加速度越来越小,将应用拆成互不相干的几个应用,以提升效率。

此时,用于加速前端页面开发的 Web框架(MVC) 是关键。

分布式服务架构

当垂直应用越来越多,应用之间交互不可避免,将核心业务抽取出来,作为独立的服务,逐渐形成稳定的服务中心,使前端应用能更快速的响应多变的市场需求。

此时,用于提高业务复用及整合的 分布式服务框架(RPC),提供统一的服务是关键。

例如:各个团队的服务提供方就不要各自实现一套序列化、反序列化、网络框架、连接池、收发线程、超时处理、状态机等“业务之外”的重复技术劳动,造成整体的低效。


所以,统一RPC框架来解决提供统一的服务。


以下我将分别从如下四个方面详解RPC。




RPC的实现原理



也就是说两台服务器A,B,一个应用部署在A服务器上,想要调用B服务器上应用提供的函数/方法,由于不在一个内存空间,不能直接调用,需要通过网络来表达调用的语义和传达调用的数据。


比如说,A服务器想调用B服务器上的一个方法:


Employee getEmployeeByName(String fullName)


整个调用过程,主要经历如下几个步骤:


1、建立通信


首先要解决通讯的问题:即A机器想要调用B机器,首先得建立起通信连接。


主要是通过在客户端和服务器之间建立TCP连接,远程过程调用的所有交换的数据都在这个连接里传输。连接可以是按需连接,调用结束后就断掉,也可以是长连接,多个远程过程调用共享同一个连接。


2、服务寻址


要解决寻址的问题,也就是说,A服务器上的应用怎么告诉底层的RPC框架,如何连接到B服务器(如主机或IP地址)以及特定的端口,方法的名称名称是什么。


通常情况下我们需要提供B机器(主机名或IP地址)以及特定的端口,然后指定调用的方法或者函数的名称以及入参出参等信息,这样才能完成服务的一个调用。


可靠的寻址方式(主要是提供服务的发现)是RPC的实现基石,比如可以采用redis或者zookeeper来注册服务等等。




从服务提供者的角度看:当提供者服务启动时,需要自动向注册中心注册服务;

当提供者服务停止时,需要向注册中心注销服务;

提供者需要定时向注册中心发送心跳,一段时间未收到来自提供者的心跳后,认为提供者已经停止服务,从注册中心上摘取掉对应的服务。

从调用者的角度看:调用者启动时订阅注册中心的消息并从注册中心获取提供者的地址;

当有提供者上线或者下线时,注册中心会告知到调用者;

调用者下线时,取消订阅。

3、网络传输


3.1、序列化


当A机器上的应用发起一个RPC调用时,调用方法和其入参等信息需要通过底层的网络协议如TCP传输到B机器,由于网络协议是基于二进制的,所有我们传输的参数数据都需要先进行序列化(Serialize)或者编组(marshal)成二进制的形式才能在网络中进行传输。然后通过寻址操作和网络传输将序列化或者编组之后的二进制数据发送给B机器。


3.2、反序列化


当B机器接收到A机器的应用发来的请求之后,又需要对接收到的参数等信息进行反序列化操作(序列化的逆操作),即将二进制信息恢复为内存中的表达方式,然后再找到对应的方法(寻址的一部分)进行本地调用(一般是通过生成代理Proxy去调用,

通常会有JDK动态代理、CGLIB动态代理、Javassist生成字节码技术等),之后得到调用的返回值。


4、服务调用


B机器进行本地调用(通过代理Proxy)之后得到了返回值,此时还需要再把返回值发送回A机器,同样也需要经过序列化操作,然后再经过网络传输将二进制数据发送回A机器,而当A机器接收到这些返回值之后,则再次进行反序列化操作,恢复为内存中的表达方式,最后再交给A机器上的应用进行相关处理(一般是业务逻辑处理操作)。


通常,经过以上四个步骤之后,一次完整的RPC调用算是完成了。


PRC架构组件

一个基本的RPC架构里面应该至少包含以下4个组件:


1、客户端(Client):服务调用方(服务消费者)


2、客户端存根(Client Stub):存放服务端地址信息,将客户端的请求参数数据信息打包成网络消息,再通过网络传输发送给服务端


3、服务端存根(Server Stub):接收客户端发送过来的请求消息并进行解包,然后再调用本地服务进行处理


4、服务端(Server):服务的真正提供者


RPC调用过程



1、服务消费者(client客户端)通过本地调用的方式调用服务


2、客户端存根(client stub)接收到调用请求后负责将方法、入参等信息序列化(组装)成能够进行网络传输的消息体


3、客户端存根(client stub)找到远程的服务地址,并且将消息通过网络发送给服务端


4、服务端存根(server stub)收到消息后进行解码(反序列化操作)


5、服务端存根(server stub)根据解码结果调用本地的服务进行相关处理


6、本地服务执行具体业务逻辑并将处理结果返回给服务端存根(server stub)


7、服务端存根(server stub)将返回结果重新打包成消息(序列化)并通过网络发送至消费方


8、客户端存根(client stub)接收到消息,并进行解码(反序列化)


9、服务消费方得到最终结果


问4 说说springcloud rpc 的执行流程和原理? 如何对springcloud 微服务进行高并发的性能优化?

请参考 《springcloud nginx 高并发核心编程》一书


分布式事务

问1:什么是分布式事务?

指事务的每个操作步骤都位于不同的节点上,需要保证事务的 AICD 特性。


产生原因

数据库分库分表;


SOA 架构,比如一个电商网站将订单业务和库存业务分离出来放到不同的节点上。


应用场景

下单:减少库存同时更新订单状态。库存和订单不在不同一个数据库,因此涉及分布式事务。


支付:买家账户扣款同时卖家账户入账。买家和卖家账户信息不在同一个数据库,因此涉及分布式事务。


解决方案

3.1 两阶段提交协议


两阶段提交协议可以很好得解决分布式事务问题,它可以使用 XA 来实现,XA 它包含两个部分:事务管理器和本地资源管理器。其中本地资源管理器往往由数据库实现,比如 Oracle、DB2 这些商业数据库都实现了 XA 接口,而事务管理器作为全局的协调者,负责各个本地资源的提交和回滚。


3.2 消息中间件


消息中间件也可称作消息系统 (MQ),它本质上是一个暂存转发消息的一个中间件。在分布式应用当中,我们可以把一个业务操作转换成一个消息,比如支付宝的余额转如余额宝操作,支付宝系统执行减少余额操作之后向消息系统发一个消息,余额宝系统订阅这条消息然后进行增加账户金额操作。


3.2.1 消息处理模型


点对点




.


发布/订阅




.


3.2.2 消息的可靠性


消息的发送端的可靠性:发送端完成操作后一定能将消息成功发送到消息系统。


消息的接收端的可靠性:接收端仅且能够从消息中间件成功消费一次消息。


发送端的可靠性


在本地数据建一张消息表,将消息数据与业务数据保存在同一数据库实例里,这样就可以利用本地数据库的事务机制。事务提交成功后,将消息表中的消息转移到消息中间件,若转移消息成功则删除消息表中的数据,否则继续重传。


接收端的可靠性


保证接收端处理消息的业务逻辑具有幂等性:只要具有幂等性,那么消费多少次消息,最后处理的结果都是一样的。


保证消息具有唯一编号,并使用一张日志表来记录已经消费的消息编号。


CAP定理



在理论计算机科学中,CAP定理(CAP theorem),又被称作布鲁尔定理(Brewer’s theorem),它指出对于一个分布式计算系统来说,不可能同时满足以下三点:


选项描述

Consistency(一致性)指数据在多个副本之间能够保持一致的特性(严格的一致性)

Availability(可用性)指系统提供的服务必须一直处于可用的状态,每次请求都能获取到非错的响应(不保证获取的数据为最新数据)

Partition tolerance(分区容错性)分布式系统在遇到任何网络分区故障的时候,仍然能够对外提供满足一致性和可用性的服务,除非整个网络环境都发生了故障

Spring Cloud在CAP法则上主要满足的是A和P法则,Dubbo和Zookeeper在CAP法则主要满足的是C和P法则


CAP仅适用于原子读写的NOSQL场景中,并不适合数据库系统。现在的分布式系统具有更多特性比如扩展性、可用性等等,在进行系统设计和开发时,我们不应该仅仅局限在CAP问题上。


注意:不是所谓的3选2(不要被网上大多数文章误导了)


现实生活中,大部分人解释这一定律时,常常简单的表述为:“一致性、可用性、分区容忍性三者你只能同时达到其中两个,不可能同时达到”。实际上这是一个非常具有误导性质的说法,而且在CAP理论诞生12年之后,CAP之父也在2012年重写了之前的论文。


当发生网络分区的时候,如果我们要继续服务,那么强一致性和可用性只能2选1。也就是说当网络分区之后P是前提,决定了P之后才有C和A的选择。也就是说分区容错性(Partition tolerance)我们是必须要实现的。


CAP定理的证明

关于CAP这三个特性我们就介绍完了,接下来我们试着证明一下为什么CAP不能同时满足。




为了简化证明的过程,我们假设整个集群里只有两个N1和N2两个节点,如下图:


N1和N2当中各自有一个应用程序AB和数据库,当系统满足一致性的时候,我们认为N1和N2数据库中的数据保持一致。在满足可用性的时候,我们认为无论用户访问N1还是N2,都可以获得正确的结果,在满足分区容错性的时候,我们认为无论N1还是N2宕机或者是两者的通信中断,都不影响系统的运行。


我们假设一种极端情况,假设某个时刻N1和N2之间的网络通信突然中断了。如果系统满足分区容错性,那么显然可以支持这种异常。问题是在此前提下,一致性和可用性是否可以做到不受影响呢?


我们做个假象实验,如下图,突然某一时刻N1和N2之间的关联断开:




有用户向N1发送了请求更改了数据,将数据库从V0更新成了V1。由于网络断开,所以N2数据库依然是V0,如果这个时候有一个请求发给了N2,但是N2并没有办法可以直接给出最新的结果V1,这个时候该怎么办呢?


这个时候无法两种方法,一种是将错就错,将错误的V0数据返回给用户。第二种是阻塞等待,等待网络通信恢复,N2中的数据更新之后再返回给用户。显然前者牺牲了一致性,后者牺牲了可用性。


这个例子虽然简单,但是说明的内容却很重要。在分布式系统当中,CAP三个特性我们是无法同时满足的,必然要舍弃一个。三者舍弃一个,显然排列组合一共有三种可能。


BASE理论

BASE理论由eBay架构师Dan Pritchett提出,在2008年上被分表为论文,并且eBay给出了他们在实践中总结的基于BASE理论的一套新的分布式事务解决方案。


BASE 是 Basically Available(基本可用) 、Soft-state(软状态) 和 Eventually Consistent(最终一致性) 三个短语的缩写。BASE理论是对CAP中一致性和可用性权衡的结果,其来源于对大规模互联网系统分布式实践的总结,是基于CAP定理逐步演化而来的,它大大降低了我们对系统的要求。


BASE理论的核心思想

即使无法做到强一致性,但每个应用都可以根据自身业务特点,采用适当的方式来使系统达到最终一致性。也就是牺牲数据的一致性来满足系统的高可用性,系统中一部分数据不可用或者不一致时,仍需要保持系统整体“主要可用”。


针对数据库领域,BASE思想的主要实现是对业务数据进行拆分,让不同的数据分布在不同的机器上,以提升系统的可用性,当前主要有以下两种做法:


按功能划分数据库

分片(如开源的Mycat、Amoeba等)。

由于拆分后会涉及分布式事务问题,所以eBay在该BASE论文中提到了如何用最终一致性的思路来实现高性能的分布式事务。


BASE理论三要素



1. 基本可用

基本可用是指分布式系统在出现不可预知故障的时候,允许损失部分可用性。但是,这绝不等价于系统不可用。


比如:


响应时间上的损失:正常情况下,一个在线搜索引擎需要在0.5秒之内返回给用户相应的查询结果,但由于出现故障,查询结果的响应时间增加了1~2秒

系统功能上的损失:正常情况下,在一个电子商务网站上进行购物的时候,消费者几乎能够顺利完成每一笔订单,但是在一些节日大促购物高峰的时候,由于消费者的购物行为激增,为了保护购物系统的稳定性,部分消费者可能会被引导到一个降级页面

2. 软状态

软状态指允许系统中的数据存在中间状态,并认为该中间状态的存在不会影响系统的整体可用性,即允许系统在不同节点的数据副本之间进行数据同步的过程存在延时


3. 最终一致性

最终一致性强调的是系统中所有的数据副本,在经过一段时间的同步后,最终能够达到一个一致的状态。因此,最终一致性的本质是需要系统保证最终数据能够达到一致,而不需要实时保证系统数据的强一致性。


负载均衡的算法与实现

1.轮询(Round Robin)

轮询算法把每个请求轮流发送到每个服务器上。下图中,一共有 6 个客户端产生了 6 个请求,这 6 个请求按 (1, 2, 3, 4, 5, 6) 的顺序发送。最后,(1, 3, 5) 的请求会被发送到服务器 1,(2, 4, 6) 的请求会被发送到服务器 2。




.


该算法比较适合每个服务器的性能差不多的场景,如果有性能存在差异的情况下,那么性能较差的服务器可能无法承担多大的负载。下图中,服务器 2 的性能比服务器 1 差,那么服务器 2 可能无法承担多大的负载。




.


1. 加权轮询(Weighted Round Robbin)

加权轮询是在轮询的基础上,根据服务器的性能差异,为服务器赋予一定的权值。例如下图中,服务器 1 被赋予的权值为 5,服务器 2 被赋予的权值为 1,那么 (1, 2, 3, 4, 5) 请求会被发送到服务器 1,(6) 请求会被发送到服务器 2。




.


1.3 最少连接(least Connections)


由于每个请求的连接时间不一样,使用轮询或者加权轮询算法的话,可能会让一台服务器当前连接数多大,而另一台服务器的连接多小,造成负载不均衡。例如下图中,(1, 3, 5) 请求会被发送到服务器 1,但是 (1, 3) 很快就断开连接,此时只有 (5) 请求连接服务器 1;(2, 4, 6) 请求被发送到服务器 2,它们的连接都还没有断开,继续运行时,服务器 2 会承担多大的负载。




.


最少连接算法就是将请求发送给当前最少连接数的服务器上。例如下图中,服务器 1 当前连接数最小,那么请求 6 就会被发送到服务器 1 上。




.


1.4 加权最小连接(Weighted Least Connection)

在最小连接的基础上,根据服务器的性能为每台服务器分配权重,然后根据权重计算出每台服务器能处理的连接数。




.


1.5 随机算法(Random)

把请求随机发送到服务器上。和轮询算法类似,该算法比较适合服务器性能差不多的场景。




.


实现

2.1 DNS 解析

使用 DNS 作为负载均衡器,会根据负载情况返回不同服务器的 IP 地址。大型网站基本使用了这种方式最为第一级负载均衡手段,然后在内部在第二级负载均衡。




.


2.2 修改 MAC 地址

使用 LVS(Linux Virtual Server)这种链路层负载均衡器,根据负载情况修改请求的 MAC 地址。




.


2.3 修改 IP 地址

在网络层修改请求的目的 IP 地址。




.


2.4 HTTP 重定向

HTTP 重定向负载均衡服务器收到 HTTP 请求之后会返回服务器的地址,并将该地址写入 HTTP 重定向响应中返回给浏览器,浏览器收到后再次发送请求。




.


2.5 反向代理

正向代理:发生在客户端,是由用户主动发起的。比如翻墙,客户端通过主动访问代理服务器,让代理服务器获得需要的外网数据,然后转发回客户端。


反向代理:发生在服务器端,用户不知道发生了代理。




.


分布式锁

Java 提供了两种内置的锁的实现,一种是由 JVM 实现的 synchronized 和 JDK 提供的 Lock,当你的应用是单机或者说单进程应用时,可以使用 synchronized 或 Lock 来实现锁。当应用涉及到多机、多进程共同完成时,那么这时候就需要一个全局锁来实现多个进程之间的同步。


使用场景

例如一个应用有手机 APP 端和 Web 端,如果在两个客户端同时进行一项操作时,那么就会导致这项操作重复进行。


实现方式

数据库分布式锁

基于 MySQL 锁表


该实现方式完全依靠数据库唯一索引来实现。当想要获得锁时,就向数据库中插入一条记录,释放锁时就删除这条记录。如果记录具有唯一索引,就不会同时插入同一条记录。这种方式存在以下几个问题:


锁没有失效时间,解锁失败会导致死锁,其他线程无法再获得锁。


只能是非阻塞锁,插入失败直接就报错了,无法重试。


不可重入,同一线程在没有释放锁之前无法再获得锁。


采用乐观锁增加版本号


根据版本号来判断更新之前有没有其他线程更新过,如果被更新过,则获取锁失败。


Redis 分布式锁

基于 SETNX、EXPIRE


使用 SETNX(set if not exist)命令插入一个键值对时,如果 Key 已经存在,那么会返回 False,否则插入成功并返回 True。因此客户端在尝试获得锁时,先使用 SETNX 向 Redis 中插入一个记录,如果返回 True 表示获得锁,返回 False 表示已经有客户端占用锁。


EXPIRE 可以为一个键值对设置一个过期时间,从而避免了死锁的发生。


RedLock 算法


ReadLock 算法使用了多个 Redis 实例来实现分布式锁,这是为了保证在发生单点故障时还可用。


尝试从 N 个相互独立 Redis 实例获取锁,如果一个实例不可用,应该尽快尝试下一个。


计算获取锁消耗的时间,只有当这个时间小于锁的过期时间,并且从大多数(N/2+1)实例上获取了锁,那么就认为锁获取成功了。


如果锁获取失败,会到每个实例上释放锁。


Zookeeper 分布式锁

Zookeeper 是一个为分布式应用提供一致性服务的软件,例如配置管理、分布式协同以及命名的中心化等,这些都是分布式系统中非常底层而且是必不可少的基本功能,但是如果自己实现这些功能而且要达到高吞吐、低延迟同时还要保持一致性和可用性,实际上非常困难。


抽象模型


Zookeeper 提供了一种树形结构级的命名空间,/app1/p_1 节点表示它的父节点为 /app1。




.


节点类型


永久节点:不会因为会话结束或者超时而消失;


临时节点:如果会话结束或者超时就会消失;


有序节点:会在节点名的后面加一个数字后缀,并且是有序的,例如生成的有序节点为 /lock/node-0000000000,它的下一个有序节点则为 /lock/node-0000000001,依次类推。


监听器


为一个节点注册监听器,在节点状态发生改变时,会给客户端发送消息。


分布式锁实现


创建一个锁目录 /lock。


在 /lock 下创建临时的且有序的子节点,第一个客户端对应的子节点为 /lock/lock-0000000000,第二个为 /lock/lock-0000000001,以此类推。


客户端获取 /lock 下的子节点列表,判断自己创建的子节点是否为当前子节点列表中序号最小的子节点,如果是则认为获得锁,否则监听自己的前一个子节点,获得子节点的变更通知后重复此步骤直至获得锁;


执行业务代码,完成后,删除对应的子节点。


会话超时


如果一个已经获得锁的会话超时了,因为创建的是临时节点,因此该会话对应的临时节点会被删除,其它会话就可以获得锁了。可以看到,Zookeeper 分布式锁不会出现数据库分布式锁的死锁问题。


羊群效应


在步骤二,一个节点未获得锁,需要监听监听自己的前一个子节点,这是因为如果监听所有的子节点,那么任意一个子节点状态改变,其它所有子节点都会收到通知,而我们只希望它的下一个子节点收到通知。


分布式 Session

如果不做任何处理的话,用户将出现频繁登录的现象,比如集群中存在 A、B 两台服务器,用户在第一次访问网站时,Nginx 通过其负载均衡机制将用户请求转发到 A 服务器,这时 A 服务器就会给用户创建一个 Session。当用户第二次发送请求时,Nginx 将其负载均衡到 B 服务器,而这时候 B 服务器并不存在 Session,所以就会将用户踢到登录页面。这将大大降低用户体验度,导致用户的流失,这种情况是项目绝不应该出现的。


1 粘性 Session

原理


粘性 Session 是指将用户锁定到某一个服务器上,比如上面说的例子,用户第一次请求时,负载均衡器将用户的请求转发到了 A 服务器上,如果负载均衡器设置了粘性 Session 的话,那么用户以后的每次请求都会转发到 A 服务器上,相当于把用户和 A 服务器粘到了一块,这就是粘性 Session 机制。


优点


简单,不需要对 Session 做任何处理。


缺点


缺乏容错性,如果当前访问的服务器发生故障,用户被转移到第二个服务器上时,他的 Session 信息都将失效。


适用场景


发生故障对客户产生的影响较小;


服务器发生故障是低概率事件。


2 服务器 Session 复制

原理


任何一个服务器上的 Session 发生改变,该节点会把这个 Session 的所有内容序列化,然后广播给所有其它节点,不管其他服务器需不需要 Session,以此来保证 Session 同步。


优点


可容错,各个服务器间 Session 能够实时响应。


缺点


会对网络负荷造成一定压力,如果 Session 量大的话可能会造成网络堵塞,拖慢服务器性能。


实现方式


设置 Tomcat 的 server.xml 开启 tomcat 集群功能。


在应用里增加信息:通知应用当前处于集群环境中,支持分布式,即在 web.xml 中添加 选项。


3 Session 共享机制

使用分布式缓存方案比如 Memcached、Redis,但是要求 Memcached 或 Redis 必须是集群。


使用 Session 共享也分两种机制,两种情况如下:


3.1 粘性 Session 共享机制


和粘性 Session 一样,一个用户的 Session 会绑定到一个 Tomcat 上。Memcached 只是起到备份作用。




.


3.2 非粘性 Session 共享机制


原理


Tomcat 本身不存储 Session,而是存入 Memcached 中。Memcached 集群构建主从复制架构。




.


优点


可容错,Session 实时响应。


实现方式


用开源的 msm 插件解决 Tomcat 之间的 Session 共享:Memcached_Session_Manager(MSM)


4 Session 持久化到数据库

原理


拿出一个数据库,专门用来存储 Session 信息。保证 Session 的持久化。


优点


服务器出现问题,Session 不会丢失


缺点


如果网站的访问量很大,把 Session 存储到数据库中,会对数据库造成很大压力,还需要增加额外的开销维护数据库。


5 Terracotta 实现 Session 复制

原理


Terracotta 的基本原理是对于集群间共享的数据,当在一个节点发生变化的时候,Terracotta 只把变化的部分发送给 Terracotta 服务器,然后由服务器把它转发给真正需要这个数据的节点。它是服务器 Session 复制的优化。




.


优点


这样对网络的压力就非常小,各个节点也不必浪费 CPU 时间和内存进行大量的序列化操作。把这种集群间数据共享的机制应用在 Session 同步上,既避免了对数据库的依赖,又能达到负载均衡和灾难恢复的效果。


分库与分表

分库与分表带来的分布式困境与应对之策




.


事务问题

使用分布式事务。


查询问题

使用汇总表。


ID 唯一性

使用全局唯一 ID:GUID;


为每个分片指定一个 ID 范围

————————————————

版权声明:本文为CSDN博主「架构师-尼恩」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。

原文链接:https://blog.csdn.net/crazymakercircle/article/details/113618397


整理中....未整理完


大家好,本人面试基本 “笔试死”、问"基础死"、"Java常识死"那一类型的....面试的过程中也从曾经被“鄙视”过,被否定过,但是这些并不能否定我们的一个价值,笔试或者基础成为面试环节中的重要一环,为什么不整理一下,好好准备呢?


我们要正确认识"笔试"的意图:即使做不好也没关系,在之后的面试当中表现好也是有 机会的 。(我面试时从来没有做完过一套题,只是选择其中1-2道认真作答,然后手机百度试卷上其他不会的知识点但是不会再作答,只是掌握不会的知识点,不建议和我学哈)


这几天面试了众多公司,涉及BAT,涉及金融、电子商务、传统行业、互联网行业等,职位涉及Java高级工程师、架构师、技术经理等,特此整理一份比较全的面试题,供大家参考。(整理周期一周:截止2018年9月15日完)


一般在程序员的垂直招聘网站投递即可,比如脉脉、BOSS直聘、拉勾等等。智联招聘啥的,不太适合咱们程序员,你懂的。另外,由于自己不是大牛,所以如果有猎头勾搭的话,尽量不去理会。所以尽量还是自己投简历比较靠谱,或者是内推


 


分类面试笔试题  传送门


1、Java面试题以及答案精选(架构师面试题)-Spring专题


2、Java面试题以及答案精选(架构师面试题)-数据库专题


3、Java面试题以及答案精选(架构师面试题)-基础题1


基础题


100、hashset和hashmap的区别与联系



101. 类有哪基本特性?各特性的优点? 

解答:类具有抽象、封装性、继承性和多态性。 


抽象:抽象就是忽略一个主题中与当前目标无关的那些方面,以便更充分地注意与当前目标有关的方面。抽象并不打算了解全部问题,而只是选择其中的一部分,暂时不用部分细节。抽象包括两个方面,一是过程抽象,二是数据抽象

封装性:类的封装性为类的成员提供公有、缺省、保护和私有等多级访问权限,目的是隐藏类中的私

有变量和类中方法的实现细节。 

继承性:类的继承性提供从已存在的类创建新类的机制,继承(inheritance)使一个新类自动拥有

被继承类(父类)的全部可继承的成员。 

多态性:类的多态性提供类中方法执行的多样性,多态性有两种表现形式:重载和覆盖。


102 .jsp 有哪些内置对象?作用分别是什么?(至少三个) 

解答: 

1)request 表示 HttpServletRequest 对象。它包含了有关浏览器请求的信息,并且提供了几个用于

获取 cookie, header 和 session 数据的有用的方法。 

2)response 表示 HttpServletResponse 对象,并提供了几个用于设置送回 浏览器的响应的方法(如

cookies,头信息等) 。 

3) out 对象是 javax.jsp.JspWriter 的一个实例, 并提供了几个方法使你能用于向浏览器回送输出结

果。 

4) pageContext 表示一个 javax.servlet.jsp.PageContext 对象。 它是用于方便存取各种范围的名字

空间、servlet 相关的对象的 API,并且包装了通用的 servlet 相关功能的方法。 

5)session 表示一个请求的 javax.servlet.http.HttpSession 对象。Session 可以存贮用户的状态

信息。 

6)application 表示一个 javax.servle.ServletContext 对象。这有助于查找有关 servlet 引擎和

servlet 环境的信息。 

7)config 表示一个 javax.servlet.ServletConfig 对象。该对象用于存取 servlet 实例的初始化参

数。 

8)page 表示从该页面产生的一个 servlet 实例。


103.说一说Servlet的生命周期?


答: Servlet生命周期分为三个阶段:


  1,初始化阶段  调用init()方法


  2,响应客户请求阶段  调用service()方法-àdoGet/doPost()


  3,终止阶段  调用destroy()方法


104.方法重载和方法重写的概念和区别(面试过程中别问到过)


方法重写(override):即方法覆盖。指的是父子类中方法的关系。父类A中有方法method1,在子类中想要使用method1这个方法签名而又要实现与父类method1方法不同的功能,这个时候就要用到方法重写。即子类使用父类的方法签名,但子类方法体与父类不同,实现的功能不同。(实现了父类方法内部逻辑,即覆盖,方法名称和参数保持一致)


方法重载(overload):同一个类中方法之间的关系。这里要弄清楚如何区别是两个方法签名是否同一个方法的签名。方法签名的区分规则:方法签名的区分是以方法的参数类型、排序与个数为标准的。如果两个方法签名有相同的参数类型、参数排序和参数个数,那么这两个方法使用的同一个签名。在同一个类中两个方法使用同一个方法签名会报错。而方法重载就是两个方法使用了相同的方法名而方法的参数不一致。(方法名称一致,但是参数类型和个数不一样)


105.线程的基本概念、线程的基本状态以及状态之间的关系


 


106.运行时异常与一般异常有何异同


异常表示程序运行过程中可能出现的非正常状态,运行时异常表示虚拟机的通常操作中可能遇到的异常,是一种常见运行错误。java编译器要求方法必须声明抛出可能发生的非运行时异常,但是并不要求必须声明抛出未被捕获的运行时异常。


107 说出ArrayList,Vector, LinkedList的存储性能和特性


ArrayList和Vector都是使用数组方式存储数据,此数组元素数大于实际存储的数据以便增加和插入元素,它们都允许直接按序号索引元素,但是插入元素要涉及数组元素移动等内存操作,所以索引数据快而插入数据慢,Vector由于使用了synchronized方法(线程安全),通常性能上较ArrayList差,而LinkedList使用双向链表实现存储,按序号索引数据需要进行前向或后向遍历,但是插入数据时只需要记录本项的前后项即可,所以插入速度较快。


108.说出Servlet的生命周期,并说出Servlet和CGI的区别。


Servlet被服务器实例化后,容器运行其init方法,请求到达时运行其service方法,service方法自动派遣运行与请求对应的doXXX方法(doGet,doPost)等,当服务器决定将实例销毁的时候调用其destroy方法。


与cgi的区别在于servlet处于服务器进程中,它通过多线程方式运行其service方法,一个实例可以服务于多个请求,并且其实例一般不会销毁,而CGI对每个请求都产生新的进程,服务完成后就销毁,所以效率上低于servlet。


 


提升篇:


200.


sql使用建议及优化方法


https://blog.csdn.net/u010223407/article/details/50736810 


 


内存溢出常见情况和和处理方式?


 


解答:导致OutOfMemoryError异常的常见原因有以下几种:


内存中加载的数据量过于庞大,如一次从数据库取出过多数据;

集合类中有对对象的引用,使用完后未清空,使得JVM不能回收;

代码中存在死循环或循环产生过多重复的对象实体;

使用的第三方软件中的BUG;

启动参数内存值设定的过小;

此错误常见的错误提示:


tomcat:java.lang.OutOfMemoryError: PermGen space

tomcat:java.lang.OutOfMemoryError: Java heap space

weblogic:Root cause of ServletException java.lang.OutOfMemoryError

resin:java.lang.OutOfMemoryError

java:java.lang.OutOfMemoryError

解决java.lang.OutOfMemoryError的方法有如下几种:


增加jvm的内存大小。方法有: 1)在执行某个class文件时候,可以使用java -Xmx256M aa.class来设置运行aa.class时jvm所允许占用的最大内存为256M。 2)对tomcat容器,可以在启动时对jvm设置内存限度

 优化程序,释放垃圾。

主要包括避免死循环,应该及时释放种资源:内存, 数据库的各种连接,防止一次载入太多的数据。导致java.lang.OutOfMemoryError的根本原因是程序不健壮。因此,从根本上解决Java内存溢出的唯一方法就是修改程序,及时地释放没用的对象,释放内存空间。 遇到该错误的时候要仔细检查程序,嘿嘿,遇多一次这种问题之后,以后写程序就会小心多了


Java代码导致OutOfMemoryError错误的解决:


需要重点排查以下几点:


检查代码中是否有死循环或递归调用。

检查是否有大循环重复产生新对象实体。

检查对数据库查询中,是否有一次获得全部数据的查询。一般来说,如果一次取十万条记录到内存,就可能引起内存溢出。这个问题比较隐蔽,在上线前,数据库中数据较少,不容易出问题,上线后,数据库中数据多了,一次查询就有可能引起内存溢出。因此对于数据库查询尽量采用分页的方式查询。

检查List、MAP等集合对象是否有使用完后,未清除的问题。List、MAP等集合对象会始终存有对对象的引用,使得这些对象不能被GC回收。

参考文章:http://outofmemory.cn/c/java-outOfMemoryError  


 


经常面试一些候选人,整理了下我面试使用的题目,陆陆续续整理出来的题目很多,所以每次会抽一部分来问。答案会在后面的文章中逐渐发布出来。 

基础题目


Java线程的状态 

进程和线程的区别,进程间如何通讯,线程间如何通讯 

HashMap的数据结构是什么?如何实现的。和HashTable,ConcurrentHashMap的区别 

Cookie和Session的区别 

索引有什么用?如何建索引? 

ArrayList是如何实现的,ArrayList和LinkedList的区别?ArrayList如何实现扩容。 

equals方法实现 

面向对象 

线程状态,BLOCKED和WAITING有什么区别 

JVM如何加载字节码文件 

JVM GC,GC算法。 

什么情况会出现Full GC,什么情况会出现yong GC。 

JVM内存模型 

Java运行时数据区 

事务的实现原理 

技术深度


有没有看过JDK源码,看过的类实现原理是什么。 

HTTP协议 

TCP协议 

一致性Hash算法 

JVM如何加载字节码文件 

类加载器如何卸载字节码 

IO和NIO的区别,NIO优点 

Java线程池的实现原理,keepAliveTime等参数的作用。 

HTTP连接池实现原理 

数据库连接池实现原理 

数据库的实现原理 

技术框架


看过哪些开源框架的源码 

为什么要用Redis,Redis有哪些优缺点?Redis如何实现扩容? 

Netty是如何使用线程池的,为什么这么使用 

为什么要使用Spring,Spring的优缺点有哪些 

Spring的IOC容器初始化流程 

Spring的IOC容器实现原理,为什么可以通过byName和ByType找到Bean 

Spring AOP实现原理 

消息中间件是如何实现的,技术难点有哪些 

系统架构


如何搭建一个高可用系统 

哪些设计模式可以增加系统的可扩展性 

介绍设计模式,如模板模式,命令模式,策略模式,适配器模式、桥接模式、装饰模式,观察者模式,状态模式,访问者模式。 

抽象能力,怎么提高研发效率。 

什么是高内聚低耦合,请举例子如何实现 

什么情况用接口,什么情况用消息 

如果AB两个系统互相依赖,如何解除依赖 

如何写一篇设计文档,目录是什么 

什么场景应该拆分系统,什么场景应该合并系统 

系统和模块的区别,分别在什么场景下使用 

分布式系统


分布式事务,两阶段提交。 

如何实现分布式锁 

如何实现分布式Session 

如何保证消息的一致性 

负载均衡 

正向代理(客户端代理)和反向代理(服务器端代理) 

CDN实现原理 

怎么提升系统的QPS和吞吐量 

实战能力


有没有处理过线上问题?出现内存泄露,CPU利用率标高,应用无响应时如何处理的。 

开发中有没有遇到什么技术问题?如何解决的 

如果有几十亿的白名单,每天白天需要高并发查询,晚上需要更新一次,如何设计这个功能。 

新浪微博是如何实现把微博推给订阅者 

Google是如何在一秒内把搜索结果返回给用户的。 

12306网站的订票系统如何实现,如何保证不会票不被超卖。 

如何实现一个秒杀系统,保证只有几位用户能买到某件商品。 

软能力


如何学习一项新技术,比如如何学习Java的,重点学习什么 

有关注哪些新的技术 

工作任务非常多非常杂时如何处理 

项目出现延迟如何处理 

和同事的设计思路不一样怎么处理 

如何保证开发质量 

职业规划是什么?短期,长期目标是什么 

团队的规划是什么 

能介绍下从工作到现在自己的成长在那里


 


一、


Java


基础(非


Jave


程序员可略过)


1. HashTable



HashMap


的区别


2. String和StringBuffer的区别


3.final,finally,finalize


的区别


4. static,final,const


的区别


二、基础知识


派生子进程的系统凋用是什么?


如何使某进程使用某个固定的


cpu?


进程、线程、协程的区别是什么?


简単解释什么是死锁?


进程间通信有几种方法?


简述tcp/udp的逐别


简述tcp三次握手


 


架构题


300:说明反转控制(IOC)和面向方向编程(AOP)在 spring 中的应用 

解答:Spring 核心容器(Core)提供 Spring 框架的基本功能。核心容器的主要组件是 BeanFactory,

它是工厂模式的实现。BeanFactory 使用控制反转(Ioc)模式将应用程序的配置和依赖性规范与实际

的应用代码程序分开。Spring 的声明式事务基于 AOP 实现,却并不需要程序开发者成为 AOP 专家,亦

可轻易使用 Spring 的声明式事务管理。 


 


301:HashMap和Hashtable的区别.以及HashMap底层实现原理,线程安全新增一个类是XXX


这个道题被许多公司问到过,希望大家重视起来,熟练的掌握。(未整理完)


HashMap是Hashtable的轻量级实现(非线程安全的实现),他们都实现了Map接口。主要区别在于HashMap允许空(null)键值(key),由于非线程安全,效率上高于Hashtable,


HashMap允许将null作为一个entry的key或者value,Hashtable不允许。HashMap把Hashtable的contains方法去掉了,改成containsValue和containsKey,因为contains方法容易让人产生误解。


Hashtable继承自Dictionary类, 而HashMap是Java1.2引进的Map interface的一个实现。


最大的不同是,Hashtable的方法是synchronize的,而HashMap不是,在多个线程访问Hashtable时,不需要自己为它的方法实现同步,而HashMap就必须为之提供同步


 


302.abstract class 和 interface 有什么区别


 


303.Arraylist,Vector,LinkedList的存储性能和特性


ArrayList和Vector都是使用数组方式存储数据,此数组元素数大于实际存储的数据以便增加和插入元素,它们都允许直接按序号索引元素,但是插入元素要涉及数组元素移动等内存操作,所以索引数据快而插入数据慢。


Vector由于用了synchronized方法(线程安全),通常性能上较ArrayList差,而LinkedList使用双向链表实现存储,序号索引数据需要进行前向或后台遍历,但是插入数据时只需要记录本项的前后项即可,所以插入速度较快


304 .JVM相关(重点!架构师必问)


 


305.并发包&并发变成&多线程&线程池(高开&架构师必须会)


 


306.AOP &IOC&事务&Spring源码


IoC就是Inversion of Control,控制反转。在Java开发中,IoC意味着将你设计好的类交给系统去控制,而不是在你的类内部控制。这称为控制反转。


 Spring AOP面向方面编程原理:AOP概念(1)AOP(Aspect Oriented Programming),也就是面向方面编程的技术。AOP基于IoC基础,是对OOP的有益补充。


AOP将应用系统分为两部分,核心业务逻辑(Core business concerns)及横向的通用逻辑,也就是所谓的方面Crosscutting enterprise concerns,例如,所有大中型应用都要涉及到的持久化管理(Persistent)、事务管理(Transaction Management)、安全管理(Security)、日志管理(Logging)和调试管理(Debugging)等。


AOP正在成为软件开发的下一个光环。使用AOP,你可以将处理aspect的代码注入主程序,通常主程序的主要目的并不在于处理这些aspect。AOP可以防止代码混乱。


Spring framework是很有前途的AOP技术。作为一种非侵略性的、轻型的AOP framework,你无需使用预编译器或其他的元标签,便可以在Java程序中使用它。这意味着开发团队里只需一人要对付AOP framework,其他人还是像往常一样编程。

 



spring提供的事务管理可以分为两类:编程式的和声明式的。编程式的,比较灵活,但是代码量大,存在重复的代码比较多;声明式的比编程式的更灵活。


围绕Poxy的动态代理 能够自动的提交和回滚事务

org.springframework.transaction.interceptor.TransactionProxyFactoryBean


PROPAGATION_REQUIRED--支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。 


PROPAGATION_SUPPORTS--支持当前事务,如果当前没有事务,就以非事务方式执行。 


PROPAGATION_MANDATORY--支持当前事务,如果当前没有事务,就抛出异常。 


PROPAGATION_REQUIRES_NEW--新建事务,如果当前存在事务,把当前事务挂起。 


PROPAGATION_NOT_SUPPORTED--以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。 


PROPAGATION_NEVER--以非事务方式执行,如果当前存在事务,则抛出异常。 


PROPAGATION_NESTED--如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则进行与PROPAGATION_REQUIRED类似的操作。


307.注解方式,注解相关


 


308.分布式事务(架构师必考)


最终一致性


309.dubbo相关


10层


 


310.solr&es


变慢原因:solr 建立索引 IO阻塞


 


311 CAP&base


 


312.设计模式


单例,工厂,观察者,等等


 


313.排序常用方法(sort,compareXXX)


 


 


 


JAVA架构师的水准:

既然java架构师,首先你要是一个高级java攻城尸,熟练使用各种框架,并知道它们实现的原理。jvm虚拟机原理、调优,懂得jvm能让你写出性能更好的代码;池技术,什么对象池,连接池,线程池…:;java反射技术,写框架必备的技术,但是有严重的性能问题,替代方案java字节码技术;nio,没什么好说的,值得注意的是”直接内存”的特点,使用场景;java多线程同步异步;java各种集合对象的实现原理,了解这些可以让你在解决问题时选择合适的数据结构,高效的解决问题,比如hashmap的实现原理,好多五年以上经验的人都弄不清楚,还有为什扩容时有性能问题?不弄清楚这些原理,就写不出高效的代码,还会认为自己做的很对;总之一句话越基础的东西越重要,很多人认为自己会用它们写代码了,其实仅仅是知道如何调用api而已,离会用还差的远。 

熟练使用各种数据结构和算法,数组、哈希、链表、排序树…,一句话要么是时间换空间要么是空间换时间,这里展开可以说一大堆,需要有一定的应用经验,用于解决各种性能或业务上的问题;有时间再补充。 

熟练使用linux操作系统,必备,没什么好说的 。 

熟悉tcp协议,创建连接三次握手和断开连接四次握手的整个过程,不了解的话,无法对高并发网络应用做优化; 熟悉http协议,尤其是http头,我发现好多工作五年以上的都弄不清session和cookie的生命周期以及它们之间的关联。 

系统集群、负载均衡、反向代理、动静分离,网站静态化 。 

分布式存储系统nfs,fastdfs,tfs,Hadoop了解他们的优缺点,适用场景 。 

分布式缓存技术memcached,redis,提高系统性能必备,一句话,把硬盘上的内容放到内存里来提速,顺便提个算法一致性hash 。 

工具nginx必备技能超级好用,高性能,基本不会挂掉的服务器,功能多多,解决各种问题。 

数据库的设计能力,mysql必备,最基础的数据库工具,免费好用,对它基本的参数优化,慢查询日志分析,主从复制的配置,至少要成为半个mysql dba。其他nosql数据库如mongodb。 

还有队列中间件。如消息推送,可以先把消息写入数据库,推送放队列服务器上,由推送服务器去队列获取处理,这样就可以将消息放数据库和队列里后直接给用户反馈,推送过程则由推送服务器和队列服务器完成,好处异步处理、缓解服务器压力,解藕系统。 

以上纯粹是常用的技术,还有很多自己慢慢去摸索吧;因为要知道的东西很多,所以要成为一名合格的架构师,必须要有强大的自学能力,没有人会手把手的教给你所有的东西。 

想成为架构师不是懂了一大堆技术就可以了,这些是解决问题的基础、是工具,不懂这些怎么去提解决方案呢?这是成为架构师的必要条件。 

架构师还要针对业务特点、系统的性能要求提出能解决问题成本最低的设计方案才合格,人家一个几百人用户的系统,访问量不大,数据量小,你给人家上集群、上分布式存储、上高端服务器,为了架构而架构,这是最扯淡的,架构师的作用就是第一满足业务需求,第二最低的硬件网络成本和技术维护成本。 

架构师还要根据业务发展阶段,提前预见发展到下一个阶段系统架构的解决方案,并且设计当前架构时将架构的升级扩展考虑进去,做到易于升级;否则等系统瓶颈来了,出问题了再去出方案,或现有架构无法扩展直接扔掉重做,或扩展麻烦问题一大堆,这会对企业造成损失。


面试题:


1.HttpservletResponse的sendError方法的作用

2.什么情况下使用URL重写

3.doGet和doPost在什么时候调用?区别?

4.response对象的作用

5.jsp中import指令的作用


1.    网络通讯中,端口有什么含义。端口的取值范围?

2.    jsp是如何被容器调用和执行的?

3.    编写一个servlet的步骤。

4.    为什么要为servlet配置URL映射

5.    谈谈servlet的生命周期


21.    说出3个常见协议的默认端口。

22.    socket是什么,它有什么作用?

23.    TCP/IP通讯的基本步骤是什么?

24.    UDP通讯的基本步骤是什么?

25.    JDBC访问数据库的基本步骤是什么(手写)?

26.    说说preparedStatement和Statement的区别

27.    说说事务的概念,在JDBC编程中处理事务的步骤。

28.    数据库连接池的原理。为什么要使用连接池。

29.    servlet和jsp有什么关系?

30.    编写一个servlet的步骤。

 


1.    css和div 开发的优势?

优点:1)div+css,这个布局中,div承载的是内容,而css承载的是样式。内容和样式的分离。

2)搜索引擎亲和力(快速找到需要的数据,而不是像在table中一层层的查找) 重构页面的方便性(换皮肤如blog)

   缺点:开发效率低

2.    谈谈页面间的参数传递有哪些方式 ?

通过请求作用域request,session,通过内部转发携带参数,在jsp页面中使用<jsp:forward /> <jsp:param />

3.    hidden表单域有什么作用?

    用来记录一些用户不需要关心,但你程序需要关心的东西比如某条数据的主键值. 

暂时隐藏某个表单字段可以让你的表单变的简洁

4.    jsp有哪些内置对象?

Page,request,session,application,exception,config,pageContext,out,

5.    request的作用有哪些?

获取客户端传递的参数值

获取客户端请求头信息

获取会话

获取转发对象

获取servletContext对象

6.    session有什么作用。

Session对象类似于一个容器,可以存放任何对象,以供不同页面间共享数据

Session是记录客户端的状态信息,它是针对http协议的无状态连接的特性而提供的解决方案。

7.     application有什么作用。

取得保存的一些全局性的对象信息。

8.    在jsp中怎样操作page作用域

特定于 JSP 的一个类型,代表当前的 JSP 页面。pageContext.setAttribute();

9.    jsp有哪些动作?作用分别是什么?

<jsp:include /> <jsp:forward /> <jsp:usebean /> <jsp:setProperty /> <jsp:getProperty />

<jsp:param /> 

10.    java servlet api中forward() 与redirect()的区别?

1.    forward客户端请求服务器一次,redirect请求服务器两次

2.    forward由request对象发出,而redirect由response对象发起

3.      对于页面跳转来说,forward请求在URL地址栏会显示SERVLET的地址,而redirect显示的是重定向后页面的地址

4。     由于redirect()是2次请求,因此不能使用request作用域来保存信息

 


1.    class.forname的作用?为什么要用?

2.    在oracle大数据量下的分页解决方法?

3.    mySQl的分页是怎么实现的?

4.    cookie被禁止后怎样使用session?

5.    项目开发经历了哪几个阶段?

6.    谈谈项目的体系统架构:(客户层,表示层)web层,业务层,数据层?

7.    J2EE规范中的组件技术在项目中用到了哪些?

8.    TCP/IP通讯和UDP通迅的区别?

9.    浏览器和WEB服务器是用什么协议通迅的?

10.    网络通讯中,端口有什么含义。端口的取值范围?

————————————————

版权声明:本文为CSDN博主「十年呵护」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。

原文链接:https://blog.csdn.net/zzhuan_1/article/details/82532065


背景:

为了让bat文件执行不会有黑窗口停留,所以再脚本中加入了一下内容


@echo off

:: 这里控制脚本的后台执行

if "%1" == "h" goto begin

mshta vbscript:createobject("wscript.shell").run("%~nx0 h",0)(window.close)&&exit

问题在 `run("%~nx0 h",0)` 上面,window定时任务时,执行的命令是`C:\selenium\uts-cmd.bat`,执行后再脚本内容`%~nx0`参数的值是`uts-cmd.bat`,所以`mshta vbscript:createobject("wscript.shell").run("%~nx0 h",0)(window.close)&&exit`执行会报错,提示找不到文件,因为这个命令默认的路径是`C:\Windows\System32`


解决:

1.直接再脚本里把文件的脚本写成绝对路径(这种方式不够灵活,因为在不同的机器上会有不同的路径,可以看个人需求,set path)


2.在设置定时时指定路径(就是一个 -d参数),如下图:




 总结:

路径问题很容易被发现,需要去研究具体的代码步骤,下设计脚本的时候,可能没有注意到对应的路径规则,没有关系,出现问题要记得根据错误提示去review。


 

————————————————

版权声明:本文为CSDN博主「jwensh」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。

原文链接:https://blog.csdn.net/u013948858/article/details/84664794


本人笔记本2011年,网卡有时会自动断开连接,于是有了以下批处理。


@echo off

setlocal ENABLEDELAYEDEXPANSION

set "netName=WIFINAME"

 

:loop

   >nul ping baidu.com -n 1

   if !errorlevel! equ 0  (

      echo [%time%]   ping is OK.

   )

   if !errorlevel! equ 1  (

      echo [%time%]   ping is Error.

      >nul netsh wlan disconnect name=%netName%

      >nul netsh wlan connect name=%netName%

   )

   >nul ping 127.0.0.1 -n 5

   goto loop

 

 


————————————————

版权声明:本文为CSDN博主「end1n9」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。

原文链接:https://blog.csdn.net/end1n9/article/details/105337884


                                                                      Windows 自动连接wifi脚本

一、简述


          记-使用bat脚本实现自动连接wifi(wifi是已经连接过的)。


          使用场景1:需要连接设备的wifi热点进行调试设备并获取设备的相关信息,设备是会定时重启的,此时需要自动连接上设备的wifi,但发现系统自带的自动连接热点功能不靠谱,所以需要使用bat批处理脚本进行定时检测是否已经连接上wifi并自动重连设备wifi。


          使用场景2:测试仪器wifi热点的稳定行,wifi连接和断开wifi测试。


          使用场景3:需要保持PC上位机与设备的wifi连接


         注1:该脚本使用前提是已经连接过WiFi,即电脑已经保存了要连接的热点的相关信息(包括密码,没有连接过的需要自己添加配置文件)


         注2:有的系统需要以管理员权限执行该脚本,此时日志默认保存目录不是当前路径,可以直接指定set log_file=D:\wifi.log


测试脚本打包:外链:https://wwa.lanzoui.com/b0c9qo3vg 密码:8lq8


二、测试脚本


@echo off

rem @file:auto_connect_wifi.bat

rem @author:Genven_Liang

rem @date:2021.02.05

rem @note:for auto connect wifi

 

rem 要连接的wifi名称

set wifi_name=mywifi

set log_file=wifi.log

set try_cnt=1

 

rem 如果有参数1,就将参数1指定为wifi名称

if [%1] == [] (echo default_wifi>nul) || (

set wifi_name=%1

)

 

echo [%date% %time%] Start connect wifi:%wifi_name% >>%log_file%

 

rem 主循环

:mainloop

(netsh WLAN show interfaces | findStr %wifi_name% >nul && ( 

echo already connected.

)) || (

set /a try_cnt+=1

echo [%date% %time%] try to connect...[%try_cnt%]

echo [%date% %time%] try to connect...[%try_cnt%] >>%log_file%

netsh wlan connect ssid=%wifi_name% name=%wifi_name% >>%log_file%

)

 

choice /t 5 /d y /n >nul

 

goto mainloop

三、测试效果




四、总结


4.1 @echo off 表示关闭回显,即不显示执行的命令本身,只显示执行命令的输出信息。


4.2 rem 开头的是注释


4.3 %date%表示当前日期,%time%表示当前时间




4.4 获取附近wifi信息:netsh wlan show networks mode=bssid




4.5 获取当前连接的wifi名称:netsh WLAN show interfaces




可以使用findStr进一步提取信息


4.6 连接指定wifi:netsh wlan connect ssid=mywifi name=mywifi   (需要是已经连接过的,如果没有连接过的,需要添加一份xml配置)




4.7 断开当前WiFi:netsh wlan disconnect




4.8 简单实现5秒延时:choice /t 5 /d y /n >nul


还可以使用timeout /t 3 /nobreak


还可以使用ping -n 5 www.xxx.com




4.9 查看已连接的wifi:netsh wlan show profiles




4.10 查看mywifi的相关信息:netsh wlan show profile name=mywifi key=clear




=============== 以下回复 aiya_maya123 =============


连接未连接过的wifi,添加xml配置:


1、查看已经连接的wifi

netsh wlan show profiles

 

2、导出wifi名称为mywifi的配置文件(随便自己找个连接过的wifi就行了), 保存路径是C:\Users\Liang\Desktop,文件名格式为"Wlan-wifi名字"; key=clear表示密码用明文输出,用于下个步骤修改

netsh wlan export profile name="mywifi" folder=C:\Users\Liang\Desktop interface="Wlan" key=clear

 

3、修改配置文件,修改配置文件名为Wlan-mywifi2.xml

字符串转十六进制:打开浏览器按F12(或右键--检查)进入开发者模式,输入以下代码并按回车就得到十六进制的结果

function stringtoHex(str) {

    var hexStr = "";

    for (var i = 0; i < str.length; i++) {

        if ("" == hexStr)

            hexStr = str.charCodeAt(i).toString(16);

        else

            hexStr += str.charCodeAt(i).toString(16);

    }

    return hexStr.toUpperCase();

};

console.log(stringtoHex("mywifi2"));//mywifi2就是要连接的wifi名称

 

4、将添加wifi配置文件

netsh wlan add profile filename="C:\Users\Liang\Desktop\Wlan-mywifi2.xml"

 

5、查看配置是否添加成功

netsh wlan show profiles | findStr mywifi2

 

6、连接wifi(记得先开启热点mywifi2)

netsh wlan connect ssid=mywifi2 name=mywifi2

 

附:删除配置

netsh wlan delete profile filename="mywifi2"

Wlan-mywifi2.xml文件:外链:https://wwa.lanzoui.com/b0c9qo3vg 密码:8lq8


<?xml version="1.0"?>

<WLANProfile xmlns="http://www.microsoft.com/networking/WLAN/profile/v1">

<name>mywifi2</name>

<SSIDConfig>

<SSID>

<hex>6D797769666932</hex>

<name>mywifi2</name>

</SSID>

</SSIDConfig>

<connectionType>ESS</connectionType>

<connectionMode>manual</connectionMode>

<MSM>

<security>

<authEncryption>

<authentication>WPA2PSK</authentication>

<encryption>AES</encryption>

<useOneX>false</useOneX>

</authEncryption>

<sharedKey>

<keyType>passPhrase</keyType>

<protected>false</protected>

<keyMaterial>87654321</keyMaterial>

</sharedKey>

</security>

</MSM>

<MacRandomization xmlns="http://www.microsoft.com/networking/WLAN/profile/v3">

<enableRandomization>false</enableRandomization>

<randomizationSeed>740396315</randomizationSeed>

</MacRandomization>

</WLANProfile>




 


结果: (测试环境win10 64bit系统笔记本电脑)






 附:删除配置

netsh wlan delete profile filename="mywifi2"




字符串转十六进制(也可以直接在线搜索字符串转十六进制,也可以使用相关的软件winhex,ultraedit、等等......)



————————————————

版权声明:本文为CSDN博主「Genven_Liang」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。

原文链接:https://blog.csdn.net/nanfeibuyi/article/details/113703264