分布式微服务

1.springcloud

1.微服务架构模式:
	微服务架构从SOA架构演变过来,比SOA架构上粒度更加精细,让专业的人做专业的事情,目的是为了提高效率,每个服务与服务之间互不影响,每个服务必须独立部署(独立数据库,独立redis),微服务架构更加提现轻量级,采用restful风格提供API,也就是Http协议+JSON格式进行存储,更加轻巧,更加适合互联网敏捷开发,快速迭代产品
2.eureka集群:
	eureka搭建集群原理使用相互注册原理,形成一组相互注册的注册中心,从而实现数据相互的同步,达到高可用
	eureka自我保护机制:
		为了防止eurekaClient与eurekaServer网络不通的情况下,eurekaServer端不会将eurekaClient端剔除。eurekaclient正常情况下,会每隔一段时间向eurekaServer端发送心跳包,证明该服务正常运行中
3.ribbon :
	ribbon和Nginx负载均衡区别:ribbon本地负载: Ribbon是从eureka注册中心服务器端上获取服务注册信息列表,	缓存到本地,让后在本地实现轮训负载均衡策略。既在客户端实现负载均衡。
	Nginx适合于服务器端实现负载均衡 比如TomcatRibbon适合与在微服务中RPC远程调用实现本地服务负载均衡,	比如DubboSpringCloud中都是采用本地负载均衡。

3.feign

1.:Feign客户端是一个web声明式http远程调用工具,提供了接口和注解方式进行调用。

4.Hystrix

1:服务雪崩效应:默认情况下Tomcat只有一个线程池去处理客户端发送的所有服务请求,这样的话在高并发情况下,如果客户端所有的请求堆积到同一个服务接口上,就会产生tomcat的所有线程去处理该服务接口,可能会导致其他服务接口服务访问
2.Hystrix服务保护:
断路器,
服务降级:在高并发情况下防止用户一直等待,使用服务降级方式(返回一个友好的提示给	客户端)
服务熔断,在高并发情况下,如果请求达到一定的极限(可以自己设置阈值),自动开启保护服务功能,使用服务降级方式返回一个友好提示,和服务降级一起使用
服务隔离机制,每个服务接口都有自己独立的线程池,每个线程池互不影响,
服务雪崩效应

5.config

1:在微服务当中使用同一个服务器管理所有服务配置文件信息,能够实现后台可管理,当服务器正在运行的时候,如果配置文件需要发生改变,可以实现不需要重启服务器实时更改配置文信息
2.原理:提交配置文件到配置中心服务器上持久存储,项目configServer服务器

6.网关

1.开放接口:其他机构合作伙伴进行调用(必须在外网访问) 微信公众号开发需要通过appid+appsocet生成AccessToken进行通讯,对接支付开发,微信开放,接受一些接口权限OAuth2.0协议方式
2.内部接口:一般只能在局域网进行访问,服务与服务之间关系都在同一个微服务系统中,	目的保证安全问题
3.设计一套公司项目接口,如何设计
	接口权限(开放接口|内部接口),考虑幂等性,安全性(Https,防止篡改数据(验证签名),使用网关拦截接口实现黑名单和白名单,接口使用http协议+json格式restful(目的跨平台)考虑高并发对接服务实现保护,服务降级,熔断,隔离,统一使用Api接口文档 Swagger
4.网关作用:可以拦截客户端所有请求,对该请求进行权限开工至,负载均衡,日志管理,接口调用监控等
5.过滤器和网关区别:
	过滤器适合于单个Tomcat服务器进行拦截请求,网关是拦截整个微服务所有请求
6.Nginx与zuul区别
	相同点:1.Zuul和Nginx都可以实现负载均衡,反向代理,过滤请求,实现网关效果
	不同点:Nginx采用C语言编写,Zuul采用java语言编写,在效率上Nginx性能更好
	Zuul负载均衡实现:采用ribbon+eureka实现本地负载均衡,Nginx负载均衡实现:采	用服务器端实现负载均衡,NginxZuul功能更加强大,Nginx适合于服务器端负载均	衡,Zuul适合微服务中网关负载均衡,在项目中最好建议Nginx+Zuul实现网关,通过	Nginx实现反向代理,Zuul对微服务实现网关拦截
7.Zuul网关集群
	使用Nginx反向代理,负载均衡到每一台网关服务器,实现集群

7.dubbo

1.原理:当生产者启动的时候,会将自己的服务信息注册到注册中心上,会将当前服务中接口class完整路径做为key,value为实际dubbo协议调用地址以临时加持久节点方式存放在Zookeeper,消费者在启动的时候采用订阅的方式获取服务接口地址,Zookeeper上当有节点发生变化时(新增,删除,修改),Zookeeper会以事件通知方式通知给消费者,
消费者在获取地址之后,然后采用本地的RPC远程调用技术,监控中心会记录服务之间的调用记录
2.dubbo和springcloud区别
	相同点:都可以实现rpc远程调用框架,都可以实现服务治理与发现
	不同点:从框架架构层面dubbo内部实现功能没有springcloud更加 强大,		springcloud是一整套微服务解决方案,dubbo目前迭代速度没有springcloud更新快,springboot2.0后整合springcloud更加完美

8.springcloud stream

Stream 消息驱动可以简化开发人员对消息中间件的使用复杂度,整合了常用MQ框架,让开发人员不需要具体的知道MQ底层实现,只需要关注核心业务逻辑

9.springsecurity


10.springmvc执行过程

1.当从客户端发送了一个request的请求时,会被我们在web.xml文件中配置的DispatcherServlet进行拦截,如果配置的是/,则会拦截所有,然后DispatchServlet会请求HandlerMapping处理器映射器,根据xml配置或注解进行查找Controller,然后通过HandlerAdapter处理器适配器查找每一个controller类中的处理url请求的方法,		a.如果没有找到对应的映射,然后会再去看是否配置了<mvc:default-servlet-handler/>静态资源处理器,如果没有则直接抛出异常页面显示404,配置了则会去找静态资源。同样的找到则正常运行,找不到则404.
	b.如果找到了对应的映射,会调用一系列的拦截器的方法,进行参数绑定,数据验证等,接着执行请求的方法,调用一系列的业务逻辑,获取到处理请求后需要的数据,根据方法的不同返回类型,都会把逻辑视图和处理请求的数据封装到ModelAndView对象中,然后把该对象返回给DispatcherServlet,然后DispatchServlet会去请求视图解析器进行视图解析,以前缀+逻辑视图+后缀形成一个真正的物理视图,然后又向DispatcherServlet返回View对象,(包括了请求数据以及视图路径),然后DispatcherServlet去视图进行渲染,进模型数据填充到request域中,并根据路径做转发或重定向的操作

2.在SSM整合时会出现spring的IOC容器和springmvc的IOC容器,容器扫描的包有重合的部分, 就会导致有的 bean 会被创建 2 次。针对这种情况的解决方法:
	a. 使 Spring 的 IOC 容器扫描的包和 SpringMVC 的 IOC 容器扫描的包没有重合的部分. (往往在项目的实际开发中都是分模块开发的,不同的模块会有不同的包路径。实现起来很麻烦)
	b. 使用 exclude-filter 和 include-filter 子节点来规定只能扫描的注解
<!--springmvc.xml  让springmvcIOC容器只扫描@Controller@ControllerAdvice-->
<context:component-scan base-package="com.znsd.ssm" use-default-filters="false">
  <context:include-filter type="annotation" 
                          expression="org.springframework.stereotype.Controller"/>
  <context:include-filter type="annotation"                         expression="org.springframework.web.bind.annotation.ControllerAdvice"/>
</context:component-scan>
	<!--applicationContext.xml 让spring的IOC容器不扫描@Controller@ControllerAdvice-->
	<context:component-scan base-package="com.znsd.ssm">
		<context:exclude-filter type="annotation" 
			expression="org.springframework.stereotype.Controller"/>
		<context:exclude-filter type="annotation" 
			expression="org.springframework.web.bind.annotation.ControllerAdvice"/>
	</context:component-scan>
3.俩个容器之间的关系:
	Spring IOC 容器和springmvc IOC容器之间为父子关系,SpringMVC的IOC容器中的bean可以来引用 Spring IOC 容器中的 bean.  反之则不行

4.springmvc执行过程:
	第一步:发起请求到前端控制器(DispatcherServlet)
    第二步:前端控制器请求HandlerMapping查找Handler
        可以根据xml配置、注解进行查找
    第三步:处理器映射器HandlerMapping向前端控制器返回Handler
    第四步:前端控制器调用处理器适配器去执行Handler
    第五步:处理器适配器去执行Handler
    第六步:Handler执行完成给适配器返回ModelAndView
    第七步:处理器适配器向前端控制器返回ModelAndView
        ModelAndView是springmvc框架的一个底层对象,包括 Model和view
    第八步:前端控制器请求视图解析器去进行视图解析
        根据逻辑视图名解析成真正的视图(jsp)
    第九步:视图解析器向前端控制器返回View
    第十步:前端控制器进行视图渲染
        视图渲染将模型数据(ModelAndView对象中)填充到request域
    第十一步:前端控制器向用户响应结果 
    
mvc框架做了哪些事情
	1):将url映射到java类或java类的方法
	2):封装用户提交的数据
	3):处理请求-调用相关的业务代码-封装响应的数据
	4):将响应的数据进行渲染,jsp,html等
为什么要学习springmvc?
	性能较struts2好,简单便捷易学,能和spring无缝集成,使用约定大于配置,能够进行简单的junit测试,支持	Restful风格
	
1.框架机制方面:
	Struts2采用FilterStrutsPrepareAndExecuteFilter)实现,SpringMVCDispatcherServlet)则采用		Servlet实现,Filter是一种特殊的ServletFilter在容器启动之后即初始化;服务停止以后坠毁,晚于ServletServlet在是在调用时初始化,先于Filter调用;服务停止后坠毁。
2.拦截机制方面:
	Struts2是类级别的拦截,一个类对应一个request上下文,因此数据都是绑定到了类中的成员变量中,使得类中所有		的方法都共享数据,正因此struts2是线程不安全的,针对这种情况,struts2的action必须是多实例对象。		SpringMVC是方法级别的拦截,一个方法对应一个request上下文,其传递过来的数据绑定到了方法的形参上,只在本		方法内有效,因此是线程安全的,可以进行Action的单实例开发,而方法同时又跟一个url对应,所以说从架构本身上	SpringMVC就容易实现restful风格的url,而struts2的架构实现起来要费劲,因为Struts2Action的一个方法可以		对应一个url,而其类属性却被所有方法共享,这也就无法用注解或其他方式标识其所属方法了
3.配置方面:
	springMVC和Spring是无缝集成,使用约定大于配置,且每次请求只对应一个Action实例,struts2每次请求都是对	应一个全新的action,因此也决定了springMVC开发效率和性能要比Struts2更高
4.集成方面:
	SpringMVC集成了Ajax,使用非常方便,只需一个注解@ResponseBody就可以实现,然后直接返回响应文本即可,而		Struts2拦截器集成了Ajax,在Action中处理时须要安装插件或者自己写代码集成进去,使用起来也相对不方便。	
	

11 Spring

IOC(Inversion of Control):其思想是反转资源获取的方向. 传统的资源查找方式要求组件向容器发起请求查找资源. 作为回应, 容器适时的返回资源. 而应用了 IOC 之后, 则是容器主动地将资源推送给它所管理的组件, 组件所要做的仅是选择一种合适的方式来接受资源. 这种行为也被称为查找的被动形式

最主要是完成了完成对象的创建和依赖的管理注入,通俗点讲,将对象的创建权交给spring,我们需要new对象,则由spring帮我们创建,然后供我们使用

```tex
比如有一个类,在类里面有方法(不是静态的方法),调用类里面的方法,需要创建类的对象,使用对象调用方法,创建类对象的过程,需要new出来对象,当该类发生变化时,相应通过new出来的对象需要修改源代码,使得程序有很大的依赖性,耦合度极高

- spring把对象的创建不是通过new方式实现,而是交给spring配置创建类对象,这种叫IOC控制反转,实现了程序的解耦
```

**1.IOC的底层原理**

```tex
1 ioc底层原理使用技术
(1)xml配置文件
(2)dom4j解析xml
(3)工厂设计模式
(4)反射
1.如果有一个类要调用类中的方法,我们需要创建该类的对象,都是通过new的方式创建对象,这样功能能够完成,但是耦合度太多了,不利于业务的扩展,然后为了解决这种情况。后来使用工厂模式来解耦,使用工厂beanFactory来创建对象,当要创建对象时,可以直接调用工厂类中的静态方法来实现,但是这样又使得工厂和类又有了耦合度,在我们的程序代码中的原则是“高内聚低耦合”,然则IOC把对象的创建配置到了xml配置文件中,我们只需要把要创建的对象的全类名配置进去,IOC容器使用dom4j技术解析xml文件,可以得到我们要创建对象的全类名,然后使用工厂设计模式,利用反射技术可以创建该类的对象,因此我们只需要在类中使用IOC的工厂来得到对象,从而把对象的创建都配置到了xml文件中,大大的降低了代码的耦合度
```

**2.IOC的入门案例**
AOP(Aspect Oriented Programming):面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术,采用横向抽取机制,取代了传统的纵向继承体系,扩展功能不需要修改源代码

比如:有一个类,类中有很多个方法,当根据业务的需求时,需要在每个方法执行的前后加入日志信息,这时候就需要修改类中的每个方法。在方法的前后加入业务代码。这样每次都要修改源代码。且每个方法都有相同的代码,可重用性太低,耦合度太高,而传统的纵向继承体系就可以解决,可以抽取一个父类,让这些要扩展功能的类去继承这个父类,在扩展类中调用父类的方法,就可以解决了,但是不是最优的方案,因为子类和父类耦合在了一起,如果父类的名字改了,那么每一个子类都需要修改源代码,并且要扩展的功能太多,需要子类一直去继承父类,如果随着业务的改变中间的哪一个扩展需要撤销,这样就得去修改它的继承体系,代码更改难道很大。耦合度还是高。然而AOP采用的是横向抽取机制,很优雅的解决了这类问题,aop的底层使用了反射中的动态代理的方式实现的,我们只需要创建一个接口。让需要扩展功能的类去实现该接口,然而动态代理就是创建接口实现类的代理对象,我们把要扩展功能的代码写在代理对象中,就可以实现在方法的前后做事情

Enhancer enhancer = new Enhancer();
Object o = enhancer.create();

AspectJ是一个面向切面的框架,它扩展了Java语言。AspectJ定义了AOP语法,所以它有一个专门的编译器用来生成遵守Java字节编码规范的Class文件。

在编译Java代码时,也称为编译时增强。(静态织入)		AspectJ

在运行时动态修改类,生成新类,也称为运行时增强。(动态织入)	Spring AOP
使用静态织入的方式性能要高于动态织入,但是动态织入更加方便。

2.网络安全架构

1.网络安全架构

1.Web 安全常见攻击手段
	XSS SQL注入 防盗链 CSRF 上传漏洞
	XSS其实就是使用JavaScript脚本语言攻击:采用过滤器对特殊字符转义
	防盗链:防止其他网站盗用自己网站的图片,视频等资源,限制资源只能在某个域名来源上才能访问
	原理:判断http请求头Referer域中的记录来源的值,如果和当前访问的域名不一致的情况下,说明该图片可能被其他服务器盗用
	CSRF攻击:防止伪造Token模拟请求,保证数据唯一性,不允许重复提交
	原理:在调用API接口的时候,需要传递令牌,改API接口获取到令牌之后,执行当前业务逻辑然后删除该令牌
	忘记密码漏洞:
		找回验证码最好不要全是数字,建议验证码+字符,如果五次以上还是错误,出现图形验证码,配置防止DDOS,限流,限制IP访问,黑名单白名单
	上传文件漏洞格式化服务器硬盘:在上传接口中,没有限制上传文件格式,如果黑客上传木马文件(可执行程序),可能会导致服务器崩溃
	防御方法:在上传图片的时候,一定要使用判断文件流的方式确定知道它一定是一张图片,不要判断后缀方式,2.静态资源与动态资源分开服务器执行,	
4.网站安全漏洞扫描与抓包

2.互联网API接口安全设计

1.需求:现在A公司与B公司进行合作,B公司需要调用A公司开放的外网接口获取数据,
	如何保证外网开放接口的安全性。
2.常用解决办法:
	2.1 使用加签名方式,防止篡改数据
	2.2 使用Https加密传输
	2.3 搭建OAuth2.0认证授权
	2.4 使用令牌方式
	2.5 搭建API网关实现黑名单和白名单
3.使用令牌方式搭建搭建API开放平台
	原理:为每个合作机构创建对应的appid、app_secret,生成对应的access_token(有效期2小时),在调用外网开放接口的时候,必须传递有效的access_token。
	App_Name       表示机构名称
    App_ID          应用id
    App_Secret      应用密钥  (可更改) 
    Is_flag           是否可用 (是否对某个机构开放)
    access_token  上一次access_token

3.OAuth2.0联合登陆

1.OAuth: OAuth(开放授权)是一个开放标准,允许用户授权第三方网站访问他们存	储在另外的服务提供者上的信息,而不需要将用户名和密码提供给第三方网站或分	享他们数据的所有内容。
2.原理:
	a.在微信开放平台申请对应的appid信息
	b.生成登陆授权链接跳转到微信开放平台
	c.用户确认登陆后,跳转到回调地址(配置域名权限)
	d.获取授权码Code,使用授权码获取对应的access_token
	e.使用access_token + oppenid获取用户相关信息
3.联合登陆中实现第二次不需要账号和密码登陆
	1.条用获取用户的openid
	2.使用用户的openid去数据库表查询是否有对应的openid
	3.如果有对应的openid,直接生成对应用户令牌
	4.如果没有则需要关联账号
1.QQ联合登陆实现思路:
	准备工作:
	资料:腾讯开放平台网址: https://connect.qq.com/index.html
		 腾讯开放平台文档: http://wiki.connect.qq.com/
	APP ID:101462456
	APP Key4488033be77331e7cdcaed8ceadc10d5
	1.生成QQ联合登陆授权链接:传入文档必须得几个参数
	https://graph.qq.com/oauth2.0/authorize?response_type=code&client_id=101462456&redirect_uri=http://shop.mayikt.com/qqLoginBack&state=1
	2.(腾讯)用户选择账号后,使用重定向方式跳转回调地址
		http://shop.mayikt.com/qqLoginBack (包含传递一个code参数)
	3.code作用:授权码
		使用code参数获取accessToken,使用accessToken获取用户信息(openid、头像、QQ年龄之类)
       通过该链接获取accessToken: https://graph.qq.com/oauth2.0/token?grant_type=authorization_code&client_id=101462456&client_secret=4488033be77331e7cdcaed8ceadc10d5&
code=B51B72DBA72A4F4D2EEA994BABFA283C&redirect_uri=http://shop.mayikt.com/qqLoginBack
	4.获取openid:
    	https://graph.qq.com/oauth2.0/me?access_token=469C321ABA9BC7A2629D4484BA0C52E8
	5.通过openid获取用户信息
		https://graph.qq.com/user/get_user_info?access_token=469C321ABA9BC7A2629D4484BA0C52E8&
oauth_consumer_key=101462456&openid=4130A96EDE4187C8FD6BB055CC542B40

2.代码实现思路:
	1.	编写授权链接接口
	2.	编写授权回调接口
		### 获取到授权码
		### 使用授权码获取accessToken
		### 使用accessToken获取用户openid 
	3.	使用openid查询数据库user信息表中是否有关联
		SELECT * FROM meite_user where QQ_OPENID='4130A96EDE4187C8FD6BB055CC542B40';
		### 如果使用openid能够查询用户信息,说明用户已经绑定成功,自动实现登陆
		如果使用openid没有查询到用户信息的话,说明用户没有绑定账信息,跳转到关联账号页面
		关联成功账号之后,将openid修改为对应的账号信息。
		
3.将sdk打入maven仓库
	mvn install:install-file -Dfile="D:\devEnvironment\qqConnect_Server_SDK_java_v2.0\Sdk4J.jar" -DgroupId=com.tengxun -DartifactId=sdk4j -Dversion=1.0 -Dpackaging=jar

4.信息加密

1.URl特殊字符转码
2.对称加密与非对称加密
	对称加密:DES:加密和解密都是同一个秘钥
	非对称加密:RSA:公钥和私钥,使用第三方工具生成非对称秘钥对,公钥加密,私		钥解密,移动APP客户端保存公钥,APP使用公钥加密,服务器端保存私钥,使用		私钥解密
4.移动APP接口安全加密设计
5.基于令牌方式实现接口参数安全传输
6.验签单向加密MD5(加盐)

5.HTTPS协议

1.HTTPS(Hyper Text Transfer Protocol over Secure Socket Layer),简单	来讲就是加了安全的HTTP,即HTTP+SSL;我们知道HTTP通讯时,如果客户端C请求	服务器S,那么可以通过网络抓包的形式来获取信息,甚至可以模拟服务器S端,来	骗取与C端的通讯信息;这对互联网应用在安全领域的推广非常不利;HTTPS解决了		这个问题。
证书的作用:返回一些加密信息,颁发者机构,加密算法,验证证书有效期
https加密流程
	客户端发送https请求到服务器端,服务器返回证书,公钥给客户端
	1.验证证书是否有效,2.有效则会随机生成一个随机数,3.使用公钥加密随机数 发给服务器端,4.服务器端用私钥解密5.服务器使用该随机数作为秘钥传递给客户端,客户端与服务器端使用该随机数对称加密
	
HttpsHttp区别
1)HTTPS的服务器需要到CA申请证书,以证明自己服务器的用途;
2)HTTP信息是明文传输,HTTPS信息是密文传输;
3)HTTP与HTTPS的端口不同,一个是80端口,一个是443端口;
可以说HTTP与HTTPS是完全不同的连接方式,HTTPS集合了加密传输,身份认证,更加的安全。
在微信小程序里面都限制只能有https协议、搜索引擎排名都对https优先收录

3.分布式解决方案

1.分布式协调工具:Zookeeper(有头一致数据数)

1.Zookeeper是一个分布式协调工具(Java语言编写开源框架),是一个基于观察者模式设计的分布式服务管理框架,它负 责存储和管理大家都关心的数据,然 后接受观察者的注 册,一旦这些数据的状态发生变化,Zookeeper
就 将负责通知已经在Zookeeper上注册的那些观察者做出相应的反应
	> 一个领导者(Leader),多个跟随者(Follower)组成的集群
	> 集群中只要有半数以上节点存活,Zookeeper集群就能正常服务
	> 全局数据一致:每个Server保存一份相同的数据副本,Client无论连接到哪个Server,数据都是一致的。
	> 数据更新原子性,一次数据更新要么成功,要么失败。
	> 实时性,在一定时间范围内,Client能读到最新数据。
2.应用场景:
	1.注册中心
	2.分布式配置中心(SpringCloud config,appllo)动态管理配置文件
	3.消息中间件 事件通知(类似于发布订阅功能)
	4.Zookeeper解决分布式事务 (全局协调者)
	5.分布式锁
	6.消息中间件集群管理
3.Zookeeper数据结构:
	a.由一个一个的Node节点组成的数据数状结构,每一个节点都是数据存储
	b.节点类型:临时节点(与当前链接会话保持一致,如果断开链接,自动删除),持久节点(创建的持久节点持久化		在硬盘上)
	c.节点事件通知:对该节点发生修改,删除,添加都会有事件通知
4.Zookeeper集群:
	a.原理:

2.分布式锁

1.产生原因:在分布式(集群)环境下,每台JVM不能实现同步,在分布式场景下使用时间戳生成订单号可能会重复
2.分布式锁解决方案:
	a.基于Redis实现分布式锁,redission
	b.基于Zookeeper(推荐),使用临时节点释放锁
	c.数据库实现分布式锁(不推荐,效率特慢)
3.zookeeper实现分布式锁原理:
	Zookeeper节点(临时节点和持久节点区别:临时是在当前连接会话有效,断开删除,持久永久保存在硬盘上)
	多个jvm同时在Zookeeper上创建同一个相同的节点(/lock),因为zk要求创建的节点要求唯一性,那么同时只有一个线程能创建/lock节点,该节点为临时节点并且带有序号,当多个客户端创建节点时判断自己是不是当前节点下最小的节点:是,获取到锁;不是,对前一个节点进行监听,当业务执行完毕时会断开和zk的连接,删除临时节点,即会释怀分布式锁,然后其他客户端,会重复刚的操作,判断序号拿锁,如果程序一直不处理万完,会导致死锁,可以设置超时时间
4.redis实现分布式锁与Zookeeper分布式锁的区别
	在集群环境下,保证只允许有一个jvm进行执行
	实现思路,Zookeeper是在多个客户端(jvm),会在Zookeeper上创建同一个临时节点,因为节点命名路径保证唯一,不允许重复,谁能先创建就谁先获取锁,Zookeeper使用直接关闭临时节点session会话连接,这时候Zookeeper会删除该临时节点,这时候其他客户端使用事件监听,如果该临时节点被删除,重新进入到获取锁步骤,针对于死锁,Zookeeper使用会话有效期解决死锁
	redis:在多个客户端(jvm),会在redis使用setnx命令创建相同的一个key,因为redis的key保证唯一,不允许出现重复,只要谁先成功,谁获取锁,redis在释放锁的时候,为了确保锁的一致性问题,再删除redis的key时候,需要判断同一个锁的ID才可以删除,redis通过对key设置有效期解决死锁
	从性能上说:因为redis是nosql数据库,相对比来说redis比Zookeeper性能要好
	可靠性:从可靠性来说Zookeeper可靠性比redis更好,因为redis有效期不是很好控制,可能会产生延迟,Zookeeper临时节点特性,先天可控性好

3解决跨域问题

1.跨域:在当前域名请求网站中,默认不允许通过ajax请求发送其他域名。属于浏览器安全问题,请求是可以访问的,只是获取不到结果
2.跨域解决方案:
	1.使用jsonp解决跨域问题(不推荐,因为只能支持get请求,不支持post请求)
	2.使用httpClient进行转发(不推荐,因为效率非常低,会发送俩次请求)
	3.设置响应头允许跨域(可以推荐)
	4.使用Nginx搭建API接口网关(强烈推荐)以项目区分反向代理到真实服务器地址
	5.使用Zuul微服务搭建API接口网关(强烈推荐)

4.分布式定时Job

1.如何保证分布式Job幂等问题
	a.使用Zookeeper实现分布式锁(效率不高)
	b.在配置文件中加上启动定时jbo开关
	c.启动的时候使用数据库唯一标识(不推荐)
	d.使用分布式任务调度平台(推荐)
2.XXL-job
	支持job集群(保证幂等问题),Job负载均衡轮训机制
	支持job补偿,如果job执行失败的话,会自动实现重试机制,如果多次失败,可发送邮件通知运维人员
	支持job日志记录
	动态配置定时规则
3.xxl-job原理:
	执行器:定时Job实际执行的服务地址
	任务表达式:配置定时任务规则,路由策略,允许模式等
	定时任务在执行的时候,先在任务调度中心进行出发,在由任务调度中心使用JobHandler访问对应执行器地址,			查找对应的class信息,在使用反射机制执行execute

5.分布式配置中心

1.作用:将配置文件注册到配置中心平台上,可以使用分布式配置中心实时更新配置文件,统一管理,不需要重新打包发布
2.Appllo配置中心:
	Apollo(阿波罗)是携程框架部门研发的分布式配置中心,能够集中化管理应用不		同环境、不同集群的配置,配置修改后能够实时推送到应用端,并且具备规范的权	限、流程治理等特性,适用于微服务配置管理场景
3.原理:
	应用端项目启动时会连接Appllo配置中心地址,项目进行扫包获取当前包下的类

6.分布式事务解决方案

1.产生原因:服务与服务之间通讯采用RPC远程调用技术,但是每个服务中都有自己独立的数据源,即自己独立的本地事务。两个服务相互通讯的时候,两个本地事务互不影响,从而出现分布式事务产生的原因。
2.LCN分布式事务原理:
	LCN客户端(发起方和参与方都必须要注册到事务协调者中)建议一个长连接
	订单服务(发起方)调用库存服务(参与方)之前会向TxManager事务协调者创建一个事务的分组id。订单服务(发起方)调用库存服务(参与方)的时候,会在请求头中存放该事务的分组id,给库存服务,如果库存服务获取到请求头中有对应的事务分组id,库存服务业务逻辑代码执行完毕时,会采用假关闭,不会提交该事务,在发起方执行成功后,会使用对应的事务分组id,通知给TxManager事务协调者,然后事务协调者在根据事务分组id,通知给所有的参与方提交事务(如事务协调者超时未通知参与者 提交事务,默认五秒会回滚事务)
3.使用rabbitMQ解决分布式事物:
	1.使用mq的重试和补偿机制,异步的实现事物的最终一致性,当生产者推送消息到mq时,当消费者消费失败时,mq会有重试机制,重新消费,这时候又要解决mq消息队列的幂等性问题,也就是消息重复消费的问题,可以采用全局唯一id
	2.原理:如果生产者发送消息到MQ失败:使用生产者重试机制进行重试,如果消费者消费消息失败了,消费者是不用回滚的,只需要消费者手动ack自动应答机制,做补偿重试,在做补偿重试时,要注意幂等性问题,防止重复消费
	如果生产者发送消息成功,消费者也消费成功,但是最后生产者程序失败了,订单回滚,却消费了消息,导致数据不一致:通过补单队列去数据库中查询该订单是否创建,如果没有创建,则进行重试,创建订单

4.zookeeper

1.分布式协调工具:Zookeeper

1.Zookeeper是一个分布式协调工具(Java语言编写开源框架)
2.应用场景:
	1.注册中心
	2.分布式配置中心(SpringCloud config,appllo)动态管理配置文件
	3.消息中间件 事件通知(类似于发布订阅功能)
	4.Zookeeper解决分布式事务 (全局协调者)
	5.分布式锁
	6.消息中间件集群管理
3.Zookeeper数据结构:
	a.由一个一个的Node节点组成的数据数状结构,每一个节点都是数据存储
	b.节点类型:临时节点(与当前链接会话保持一致,如果断开链接,自动删除),持久节点(创建的持久节点持久化		在硬盘上)
	c.节点事件通知:对该节点发生修改,删除,添加都会有事件通知
4.Zookeeper集群选举机制:
	多个服务器在启动的时候,会在Zookeeper上创建相同的临时节点,谁如果能够先创建成功,谁就为主节点,其他为从节点,如果主节点master宕机之后,会话连接即会失效,其他服务器使用事件监听到节点被删除后,会在剩余运行的服务器中,重新选举主节点

2.分布式锁

1.产生原因:在分布式(集群)环境下,每台JVM不能实现同步,在分布式场景下使用时间戳生成订单号可能会重复
2.分布式锁解决方案:
	a.基于Redis实现分布式锁,redission
	b.基于Zookeeper(推荐),使用临时节点释放锁
	c.数据库实现分布式锁(不推荐,效率特慢)
3.zookeeper实现分布式锁原理:
	Zookeeper节点(临时节点和持久节点区别:临时是在当前连接会话有效,断开删除,持久永久保存在硬盘上)
	多个jvm同时在Zookeeper上创建同一个相同的节点(/lock),因为zk要求创建的节点要求唯一性,那么同时只有一个线程能创建/lock节点,该节点为临时节点,当业务执行完毕时会断开和zk的连接,临时节点消失,即会释怀分布式锁,如果程序一直不处理万完,会导致死锁,可以设置超时时间
4.redis实现分布式锁与Zookeeper分布式锁的区别
	在集群环境下,保证只允许有一个jvm进行执行
	实现思路,Zookeeper是在多个客户端(jvm),会在Zookeeper上创建同一个临时节点,因为节点命名路径保证唯一,不允许重复,谁能先创建就谁先获取锁,Zookeeper使用直接关闭临时节点session会话连接,这时候Zookeeper会删除该临时节点,这时候其他客户端使用事件监听,如果该临时节点被删除,重新进入到获取锁步骤,针对于死锁,Zookeeper使用会话有效期解决死锁
	redis:在多个客户端(jvm),会在redis使用setnx命令创建相同的一个key,因为redis的key保证唯一,不允许出现重复,只要谁先成功,谁获取锁,redis在释放锁的时候,为了确保锁的一致性问题,再删除redis的key时候,需要判断同一个锁的ID才可以删除,redis通过对key设置有效期解决死锁
	从性能上说:因为redis是nosql数据库,相对比来说redis比Zookeeper性能要好
	可靠性:从可靠性来说Zookeeper可靠性比redis更好,因为redis有效期不是很好控制,可能会产生延迟,Zookeeper临时节点特性,先天可控性好

3.分布式Session一致性问题

session存放在服务器端,浏览器关闭了Session不会马上失效,而是会有一个失效时间
请求和响应过程:
	服务器端接受到客户端请求,会创建一个session,使用响应头返回sessionid给客户端,浏览器获取到sessionid		后,保存在本地cookie中,当第二次请求时,客户端读取到本地sessionid,存放在请求头中,服务器端从请求头中		获取到对应的sessionid,然后到本地session内存中查询,如果一致则为同一次用户会话
	
分布式session:
	分布式session问题:
		因为session存放在服务器端,在分布式中请求不同的系统,sessionid找不到对应的session信息
		分布式任务调度平台,(服务器集群之后如何保证定时任务唯一性)幂等性
		分布式锁问题(基于zookeeper使用临时节点+时间通知解决,springcloud对redison中提供很多分布式方案)
		分布式日志手机问题(使用分布式日志手机系统ELK)
		分布式事物问题(rpc远程通讯服务与服务之间实现事物管理)
		分布式配置中心
	分布式Session解决方案
		方案1:可以使用cookie替代Session(不靠谱。不安全)
		方案2: 使用nginx(反向代理)ip绑定 同一个ip只能在指定的同一太机器访问(不推荐,没有负载均衡)
		方案3: 使用数据库 (效率不高)
		方案4: tomcat内置支持session同步(不推荐)服务多的时候回降低系统的性能并且同步会延迟
		方案5: 使用spring-session框架 相当于把我们的session缓存到redis中
		方案6: 使用token替代session功能

4.网站跨域问题

1.跨域问题:在当前域名请求网站中,默认不允许通过ajax请求发送其他域名。

5.消息中间件

Message Queue 消息中间件,利用高效可靠的消息传递机制进行平台无关的数据交流,是分布式系统中不可或缺的一个组件,对于消息中间件,常用的角色大致就有producer,consumer,
MQ的应用场景:
1.异步消息处理:比如说要写一个发送短信的注册功能,发送了短信之后才把注册信息写人到数据库中,这样耗费时间会比较长,客户会有一个等待的过程,而使用MQ,则只需要用户注册消息后,将消息写入到数据库中,并不直接发送短信,而是将消息写入到MQ消息队列中,让短信服务去监听消息队列,当MQ中有消息时就把消息读取出来做进一步操作,这个过程就是异步操作,大大减少了请求的时间,客户就不需要长时间等待
2.应用解耦
	用户下单后,将订单保存到数据库之后,还要通知库存系统减少库存信息,这时候就要让订单系统去调用库存系统,然后使俩个系统耦合在了一起,当库存系统减少库存是失败就会导致下单失败,这样就会丢失订单,如果引入MQ之后订单系统下完单之后不需要直接通知库存系统,而是将消息写人消息队列中,让库存系统去订阅消息,就实现了系统之间的解耦
3.流量削锋
	应用场景:秒杀,或抢购活动中,一时之间访问量暴增,会导致系统承受不了压力也挂掉,使用MQ就能解决这类问题
	当用户高并发的访问时,假如有十万个请求过来了,只能有一百个人抢到产品,使用队列消息,就只将前100个消息写人消息队列中,而其他的消息给出提示,请求超时,或者产品已售罄,然后根据消息队列中的100个请求,处理相应的业务逻辑
常见的MQ消息中间件产品有ActiveMQ,RabbitMQ,RocketMQ,Kafka等,

1.ActivityMQ

1.消息中间件是分布式系统中重要组件,主要解决应用解耦,异步消息,流量削锋,实现高可用,高性能,可伸缩和最终一致性
2.activitymq:是一个java平台中面向消息中间件的API

2.RabbitMQ

1.点对点模式:一对一模式,一个生产者投递消息给队列,只能允许有一个消费者进行消费
2.消费者在消费消息的时候,如果消费者业务逻辑出现异常,可以使用消息重试机制,如果是代码bug问题,应该采用日志记录+定时job检查进行人工补偿
3.如何解决消费者消息重复消费(幂等性)
	使用全局MessageID判断消费方使用同一个,解决幂等性。
4.在定义业务队列的时候,可以考虑指定一个死信交换机,并绑定一个死信队列,当消息变成死信时,该消息就会被发送到该死信队列上,这样就方便我们查看消息失败的原因了
5.rabbitmq解决分布式事务问题:
	原理:如果生产者发送消息到MQ失败:使用生产者重试机制进行重试,如果消费者消费消息失败了,消费者是不用回滚的,只需要消费者手动ack自动应答机制,做补偿重试,在做补偿重试时,要注意幂等性问题,防止重复消费
	如果生产者发送消息成功,消费者也消费成功,但是最后生产者程序失败了,订单回滚,却消费了消息,导致数据不一致:通过补单队列去数据库中查询该订单是否创建,如果没有创建,则进行重试,创建订单

6.缓存

1.redis

1.应用场景:
	1.令牌生成(临时有效期)
	2.短信验证码(临时有效)
	3.缓存热点数据(经常查询,不经常修改)
	4.分布式锁(使用ZK或者是Redis实现分布式锁)
	5.发布订阅(使用Redis实现消息中间件,不推荐)
	6.网站计数器(因为Redis是单线程,在高并发下,记录全局count唯一性)
2.主从复制
	将服务器分为主服务和从服务器,主的服务可以允许做读写操作,从服务器只允许做读的操作
3.
4.redis穿透问题:
	客户端随机生成不同的key,Redis中没有查询该数据,数据库中也没有该数据,这样的话可能会频繁的产生jdbc链接
	解决方案:网关判断客户端传入对应的key规则,如果不符合数据库查询的规则,直接返回空
redis的出现是为了解决一些问题的存在,在现如今大数据时代背景下,用户的并发访问量非常大,会给数据库带来极大的压力,这时候就需要用缓存技术(非关系型数据库)挡在数据库的前面,高效的性能问题,在非关系型数据库中现如今最常用的就是redis了,redis是一个高性能的key-value分布式内存数据库,基于内存运行并支持持久化的NoSQL数据库,提供了最常用的五种数据类型的存储,比如最常用的hash String ,list ,set ,zset
经常使用的命令:讲一波...,redis支持数据的持久化,可以将内存中的数据保存在磁盘中,重启的时候可以再次加载进行使用,在redis 中持久化的方式有俩种,一个是RDB,和AOF,RDB是redis默认的一种持久化方式:它是在指,定的时间间隔内将内存中的数据集快照写入磁盘,当要恢复时直接从快照文件中读到内存中,而AOF是以日志的形式来记录每个写操作,将redis执行过的所有指令记录下来(不包括读的),重启的时候就根据日志文件中的内容将写的指令从前到后执行一次恢复到内存中,这俩种方式各有优缺点:RDB快照保存数据极快,还原数据也极快,但是在一定间隔时间做数据的备份,如果redis宕机了就回丢失最后一次快照后所操作的数据,而且在快照fork的时候,内存中的数据被克隆一份,就会需要2倍大小的内存空间,而AOF的持久化方式在数据的安全性来说相对高些,它可以设置每秒或者每次修改就写入到AOF日志文件中,但同时频繁的进行IO写入,而且AOF的文件体积通常都会比RDB要大很多,恢复的速度比RDB要慢很多
通常在保证redis的高可用时一般都会使用redis的集群,并且在每个redis的节点中采用主从复制的方式保证数据的完整性和一致性,建议在Slave上持久化RDB文件,而且只要15分钟备份一次就够了
主从复制:主机数据更新后根据配置和策略自动同步到Slave从机上,Master以写为主,Slave以读为主,通常采用一主二从的方式配置主从复制,如果主机挂了,我们可以让从机变主机,继续保证程序的高可用

7.多线程

1.并发编程

1.线程安全问题
	当多个线程同时共享,同一个全局变量或静态变量,做写的操作时,可能会发生数据冲突问题,也就是线程安全问题。	但是做读操作是不会发生数据冲突问题。
2.线程安全解决办法
	1.内置锁(synchronized):保证线程原子性,当线程进入方法的时候,自动获取锁,一旦该线程获取锁后,其他线		程就会等待,只有当该线程执行完毕之后,释放掉锁之后,其他线程才有机会拿到锁进行执行
	使用方法:同步方法或者同步代码块
3.多线程特性
	原子性、
	可见性、:当多个线程访问同一个变量时,一个线程修改了这个变量的值,其他线程能够立即看得到修改的值。
		Volatile:可见性也就是说一旦某个线程修改了该被volatile修饰的变量,它会保证修改的值会立即被更新到主 存,当有其他线程需要读取时,可以立即获取修改之后的值。
在Java中为了加快程序的运行效率,对一些变量的操作通常是在该线程的寄存器或是CPU缓存上进行的,之后才会同步到主存中,而加了volatile修饰符的变量则是直接读写主存。
Volatile 保证了线程间共享变量的及时可见性,但不能保证原子性

VolatileSynchronized区别
	(1)从而我们可以看出volatile虽然具有可见性但是并不能保证原子性。
	(2)性能方面,synchronized关键字是防止多个线程同时执行一段代码,就会影响程序执行效率,而volatile关键	字在某些情况下性能要优于synchronized。
	但是要注意volatile关键字是无法替代synchronized关键字的,因为volatile关键字无法保证操作的原子性。
	1.Synchronized保证内存可见性和操作的原子性
	2.volatile只保证内存可见性
	3.valatile不需要加锁,比synchronized更轻量级,并不会阻塞线程
	4.volatile标记的变量不会被编译器优化,而synchronized标记的变量会被编译器优化(如重排序优化)

	有序性、

2.线程池

线程池是预先创建线程的一种技术,线程池在还没有任务到来之前,创建一定数量的线程,放入到空闲队列中,然后对这些资源进行复用,每个工作线程都可以被重复利用,可执行多个任务。减少频繁的创建和销毁消耗资源,耗时间因为有的线程执行的时间比创建和销毁一个线程的时间还短那么线程池的作用就体现出来了.

1.线程池的好处:
	第一:降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗。
	第二:提高响应速度。当任务到达时,任务可以不需要等到线程创建就能立即执行。
	第三:提高线程的可管理性。线程是稀缺资源,如果无限制地创建,不仅会消耗系统资源
2.线程池的创建方式
	Java通过Executors(jdk1.5并发包)提供四种线程池,分别为:
	newCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,	则新建线程。
	newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
	newScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行。
	newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照		指定顺序(FIFO, LIFO, 优先级)执行。
3.线程池原理:
	corePoolSize:核心线程数-> 实际运用线程数
	maximumPoolSize:最大线程数->线程池最多创建的线程个数
	首先当用户提交线程给线程池,会判断是否大于核心线程数,如果小于核心线程数,则创建线程,执行任务,如果大于核心线程数,在继续判断缓存队列是否已满,如果没有满缓存到队列中创建线程,如果满了判断是否大于最大线程数,如果大于,则会拒绝队列,不大于则会创建线程
4.合理配置线程池:CPU密集,IO密集

3.java锁机制


4.Java内存模型

多线程的三大特性:
	1.原子性:独一无二,一致性,保证线程安全问题
	2.可见性:java内存模型
	3.有序性:join,wait,nodify(多线程之间通讯)
java内存模型:决定了一个线程与另一个线程是否可见,
	java内存模型主要分为:主内存(主要存放共享的全局变量) 私有本地内存(本地线程私有变量),当在多个线程去共享数据进行访问时,共享数据存在主内存中,而每个线程都有自己的副本,当一个线程对数据进行操作时,只刷新本地副本数据,并没有刷新主内存数据,因为线程之间默认是不可见得,因此另一个线程访问时,数据就不一致了

5.java内存结构

方法区:类的信息,常量,静态,永久区 
堆内存:使用new的对象
栈:基本数据类型

6.CGLIB与JDK动态代理区别

jdk动态代理是由Java内部的反射机制来实现的,cglib动态代理底层则是借助asm来实现的。总的来说,反射机制在生成类的过程中比较高效,而asm在生成类之后的相关执行过程中比较高效(可以通过将asm生成的类进行缓存,这样解决asm生成类过程低效问题)。还有一点必须注意:jdk动态代理的应用前提,必须是目标类基于统一的接口。如果没有上述前提,jdk动态代理不能应用。

7.JVM

堆内存划分:新生代和老年代
	新生代:刚出生不久的对象,存放在新生代里面,存放不是经常使用的对象
	老年代:存放比较活跃对象,存放经常被引用对象
	垃圾回收机制回收再新生代比较频繁,老年代回收次数计较少

8 .Nginx

1.Nginx

1.应用场景:
	http服务器:使用Nginx做静态服务器,图片服务器
	虚拟主机配置:将一台服务器,拆分多个网站部署
	反向代理(负载均衡):使用反向代理隐藏真实ip地址,减少单台服务器压力,故障转移(重试机制,幂等问题,健康检查)
	安全配置
	使用Nginx搭建API接口网关,解决网站跨越
	使用Nginx实现网站动静分离
	使用Nginx实现防止DDOS(安全控制) 防盗链
2.负载均衡
	四层负载均衡器(基于传输层,也叫做基于TCP协议实现负载均衡,LVS(软负载),和F5硬件负载,在Nginx1.9之后支持四层负载均衡)
	七层负载均衡(基于应用层也叫做基于HTTP协议实现负载均衡)
作用:目的是为了解决高并发,负载均衡拦截到所有请求,在采用负载均衡算法分配到不同真实的服务上

2.CDN

1:CDN分发:减少服务器传输速度,让用户到最近的服务器上访问,当客户端访问时,首先会将域名转发到到CDN云服务器地址,如果云服务器上有缓存静态资源,直接判断访问ip离哪一台CDN云服务器最近,然后将资源响应到客户端,如果没有缓存静态资源,则会请求真是服务器
2.应用场景:可以缓存静态资源IMG,CSSm,JS视屏,视频网站,直播网站对CDN要求特别高

9.MYSQL

1.MySQL

1.主从复制:MySQL的主从复制是本身自带的功能,主要是借助binlog日志文件里面的sql命令实现的主从复制,在master端执行了一条sql 命令,那么salve端同样会执行一遍,从而实现主从复制,从库生产俩个线程,一个I/O线程,一个Sql线程,I/O线程去请求主库的binlog,并将得到的binlog日志写到relay log文件中,主库会生成一个log dump线程用来给从库的i/o线程传binlog
2.mycat读写分离:
	把对数据库的读和写操作分开,对应不同的数据库服务器,主数据库提供写操作,从数据库提供读操作,这样能有效减轻单台数据库的压力,主数据库进行写操作后,数据及时同步到读数据库,尽可能保证读,写数据库的数据一致性
3.mycat原理:
	会拦截客户端的所有的jdbc连接,根据sql语句判断转发到不同的数据库执行

2.索引

1:如果向MySQL发送一条sql查询语句,如果没有建立索引,那么数据库会全表扫描,效率低
2.hash结构索引:通过字段的值计算hash值,定位数据非常快,不支持范围查询
3.平衡二叉树:会取一个中间值,左边为左子树,右边为右子数,查询效率还可以,支持范围查询,但是回旋查询效率低
4.B树:查询效率比平衡二叉树效率要高,因为B树的节点中有多个元素,从而减少树的高度,提高查询效率
5.B+树:相比B树,新增叶子节点,和非叶子节点关系,叶子节点包含了key和value,非叶子节点只包含了key,所有相邻的叶子节点包含非叶子节点,使用链表结合,有一定顺序
6.索引失效:
	索引无法存储null

你可能感兴趣的:(分布式微服务)