架构:
系统一旦多了,技术的重复性就会提高,产生大量的重复代码。所以假设当一个团队A做出一个系统后,需要另一个团队B进行交接分析,团队A就需要写文档去交接,B团队需要再去分析业务,重复开发。所以A团队开发某一部分功能的接口和文档(微服务),其他团队就只需要按照文档进行调用接口,省去了大量操作和时间成本。
其中微服务
就是将项目按照要开发的功能拆分为不同的项目,从而负责不同功能的研发人员就可以在自己的代码项目上进行开发,从而解决了大家无法在开发阶段并行开发的苦恼。到了软件交付阶段,将所有这些开发阶段并行开发的项目集合到一起进行交付。
微服务针对的是对内网开发,get、post请求,ajax…,内网属于子网,没有那么复杂,用http协议太慢,所以内网用的自定义协议,但是有问题,tomcat不能识别,但是由于传输数据也必须很稳定,所以自定义协议是基于TCP协议的,底层也是基于socket实现,所以就需要一套和tomcat相似既能发送协议也能接收协议的工具,就是dubbo和SpringCloud
**常用的微服务框架:**dubbo和SpringCloud
云服务对外网开发的,使用的http协议,springMVC、SpringBoot就是对接外网、公网的
微服务只是个架构理念,dubbo和SpringCloud才是具体技术
微服务也是可能分配多台服务器,每个都是集群,涉及到nginx
集群:多台服务器 做同一个任务
**分布式:**不同的微服务在不同的服务器上,最后组成了一个系统,一个任务分工,由多个服务器一起跑
集群+分布式:一个系统分成五个模块(分布),每几个服务器跑其中一个模块(集群)
**微服务、分布式、集群的区别?**分布式、集群叫技术,提升计算能力,微服务属于架构,提高开发效能的
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-f6KUdPMO-1670228759163)(…/img/image-20220829191001158.png)]
微服务/RPC框架包含的几个模块 dubbo
生产者 提供接口调用 。实现方式和tomcat一样,tomcat主要是识别http协议,生产者需要自己写,因为不是http协议了。tomcat运行serlvet、controller。
生产者也有自己的注解,
其次就是生产者,生产者提供各种服务,并向下和数据库对接,负责系统中的功能提供以及数据持久化。在整个流程中,生产者提供请求处理资源,接收各种各样的请求并对请求进行处理,将处理结果进行妥善的保存后会返回相应的数据,这个数据会发送到消费者处,如果这个请求处理中发生了错误,这个错误也会被发送给消费者。
消费者
内网用的自定义协议,因为没有那么复杂,但是还是基于socket写的,底层是TCP协议,TCP协议传输绝对稳定可靠。在TCP协议的基础上产生了自定义协议,不再使用http协议,自定义协议在内网传输速度更快
首先有关消费者,在微服务概念中,消费者就是问题的制造者,请求的发出者,生产者提供的请求处理资源的消费者,消费者通常和项目的用户对接,用户对消费者进行一个表层调用,消费者会将这个表层调用打包成一次消费请求,这个消费请求会被发送到生产者处被处理,被生产者处理之后会得到一个返回,这个返回会被打包处理成一个合理的信息被展示给用户。
中央管理平台
中央管理平台不仅仅记录消费者,还得记录生产者,记录对应消息,某某消费者比如每分钟调用多少次。当生产者看见消息的时候可以进行操作(比如扩容)
中央管理平台就是一个web系统,需要ZK或者redis进行存储
生产者要在中央管理平台注册,为了使消费者能找到生产者,
消费者信息和调用关系也需要在中央管理平台注册,因为当一个消费者调用的时候把生产者搞崩溃了,别的消费者就无法调用,我们需要准确的知道消费者的信息和调用关系
申请流程:消费者调用的时候需要带上自己的需求量,然后发个生产者,生产者根据调用量(并发量)查看有没有超过总上限,然后去申请服务器去支撑消费者,也就是集群,然后再通过申请
最后是中央控制平台,它可以对生产者和消费者的行为进行监控和管理,并对管理者提供一个向上的操作接口,同时其内部也存在很多用于应急的自动管理措施,包括数据通信,活跃性检测,灾难通知等,这些自动管理措施被称为微服务中的服务治理,我们下面重点研究的就是这些治理行为。
流量监控(访问频率) 其中涉及到负载均衡
消费者申请的时候每分钟申请了某些调用量,但是当调用的时候超过这个申请量就不允许调用了,这就是因为流量控制
权限控制
为了避免有的系统不经过中央管理平台偷偷调用,还得加上权限控制。
服务发现和治理/监控
需要知道哪些生产者和消费者是否正常,需要实时了解生产者、消费者的状态,哪些服务出现了问题,需及时知道
自定义网络协议
第一步:在中央管理平台申请注册生产者(包括介绍功能、部门、起名字等等),然后由自己部门的老大进行通过,每个人都可以注册多个生产者,根据功能模块来的,功能模块的每一个功能都可以作为生产者
每申请下来的一个生产者都会产生自己的唯一身份识别字符串,一般是32位,也可能64位,可以下载粘贴下来的,放到生产者当中
生产者包含jar包和自己的唯一身份识别字符串,引入生产者jar包,里面声明一些方法和注解,开放一些接口供消费者访问,就和SpringMVC一样,启动后jar会去扫描注解
生产者启动后,启动jar包,带着自己的IP地址和身份唯一标识去对中央管理平台进行一个轮询,通知中央管理平台,然后中央管理平台会把已经启动的生产者的IP进行一个记录
第二步:在中央管理平台申请注册消费者,每申请下来的一个消费都会产生自己的唯一身份识别字符串
引入消费者的jar包,从中央管理平台粘贴过来消费者唯一身份识别字符串,
生产者启动后,启动jar包,产生心跳,消费者带着自己的IP地址和身份唯一标识去对中央管理平台进行一个轮询,通知中央管理平台,然后中央管理平台会把已经启动的消费者的IP进行一个记录
第三步:权限控制,消费者调用生产者,为了避免有的系统不经过中央管理平台偷偷调用,还得加上权限控制。
不能私自进行调用,要先向中央管理平台申请,如果直接调用的话,生产者不知道你的调用量,可能承受不住很大的并发压力导致崩溃。
首先要申请中央管理平台,申请的时候带着申请目的和调用量(每分钟不超过多少次),这样才能通知生产者提前准备好多少服务器。
一个消费者可以消费多个生产者,一个生产者也可以供多个消费者调用,而且在中央管理平台上可以看到消费者和生产者互相的调用关系
第四步:流量监控(访问频率) 其中涉及到负载均衡
消费者申请的时候每分钟申请了某些调用量,但是当调用的时候超过这个申请量就不允许调用了,这就是因为流量控制
限流怎么保障消费者调用生产者没分钟不超过一万次
首先流量控制算法是放在消费者的jar包的,因为
服务发现治理就是中央控制平台需要知道哪些生产者和消费者是否正常,需要实时了解生产者、消费者的状态,哪些服务出现了问题,需及时知道
首先有关消费者,在微服务概念中,消费者就是问题的制造者,请求的发出者,生产者提供的请求处理资源的消费者,消费者通常和项目的用户对接,用户对消费者进行一个表层调用,消费者会将这个表层调用打包成一次消费请求,这个消费请求会被发送到生产者处被处理,被生产者处理之后会得到一个返回,这个返回会被打包处理成一个合理的信息被展示给用户。
其次就是生产者,生产者提供各种服务,并向下和数据库对接,负责系统中的功能提供以及数据持久化。在整个流程中,生产者提供请求处理资源,接收各种各样的请求并对请求进行处理,将处理结果进行妥善的保存后会返回相应的数据,这个数据会发送到消费者处,如果这个请求处理中发生了错误,这个错误也会被发送给消费者。
最后是中央控制平台,它可以对生产者和消费者的行为进行监控和管理,并对管理者提供一个向上的操作接口,同时其内部也存在很多用于应急的自动管理措施,包括数据通信,活跃性检测,灾难通知等,这些自动管理措施被称为微服务中的服务治理,我们下面重点研究的就是这些治理行为。
中央管理平台是如何知道哪些消费者或生产者状态的?
通过心跳检测(轮询)——生产者和消费者每过几秒向中央管理平台汇报最新存活时间,在中央管理平台中有定时器会定时检测出哪些生产者或者消费者的服务器的最近存活时间和现在的时间进行一个判断,假设规定一分钟,如果超过一分钟就将其致红,表示该服务器出现故障,工作停止
新的生产者和消费者怎么添加到中央管理平台
新添加生产者或消费者定时向中央管理平台发送心跳,这样中央管理平台就能对新添加的生产消费者进行管理
生产者和消费者都会有特定的jar包,启动程序jar包会被关联调用, jar包中会有中央管理平台的ip地址,然后通过中央管理平台的IP地址向中央管理平台发送自己服务器的IP和生产者的一个标记,中央管理平台自动记录生产者或消费者服务器的IP地址和名字
生产者如何消费消费者
每一个消费者的内部是有一个负载均衡(小nginx)的,能均匀的打到生产者服务器上去
当生产者自己发出心跳通知中央管理平台时,中央管理平台也会通知消费者,新增加了一个生产者,消费者也需要联系上新增加的生产者
每个生产者通知中央管理平台后,中央管理平台再通知消费者,每添加一次就进行一次通知,消耗网络IO,所以.每个消费者后有一个静态的hashmap来作为缓存,存储所连接生产者的ip,这样更加方便。
但是如果有一台生产者宕机了,但是根据设置一分钟后中央管理平台才能接收到生产者宕机,这时可能有上万条请求被忽略了,所以还需要设置消费者对生产者进行一个try catch请求,请求两次不成功就换一台生产者进行消费,然后消费者更新本地缓存中记录的ip地址,同时对中央管理平台进行一个通知,然后中央管理平台再对其他的消费者进行一个通知
心跳检测用什么协议?
首先想到的是长短连接
长连接:
但从HTTP/1.1起,默认使用长连接,用以保持连接特性。使用长连接的HTTP协议,会在响应头有加入这行代码:Connection:keep-alive
在使用长连接的情况下,当一个网页打开完成后,客户端和服务器之间用于传输HTTP数据的 TCP连接不会关闭,如果客户端再次访问这个服务器上的网页,会继续使用这一条已经建立的连接。Keep-Alive不会永久保持连接,它有一个保持时间,可以在不同的服务器软件(如Apache)中设定这个时间。实现长连接要客户端和服务端都支持长连接
但是长连接需要保障服务器需要记录每一条长连接的状态,这是会实时消耗CPU和内存的资源的
所以一般长连接——传输速度快、频繁的
短连接:
浏览器和服务器每进行一次HTTP操作,都建立一次连接,都进行三次握手和四次挥手。传输完后快速释放服务器资源
所以一般短连接——传输速度慢一点,不频繁的
如果客户端浏览器访问的某个HTML或其他类型的 Web页中包含有其他的Web资源,如JavaScript文件、图像文件、CSS文件等;当浏览器每遇到这样一个Web资源,就会建立一个HTTP会话。
如果我们进行心跳检测,两三秒进行一次汇报,没必要去占用服务器资源,使用短连接合适。但是如果0.1秒就发送一次,使用长连接恰当一些。所以用长短连接要看我们的传输速率和频率,所以用起来也不是很合适
因为一个公司的生产者和消费者能达到几万至几十万,20万的生产者消费者,2秒钟请求一次,意味着每秒这十万的并发,所以写定时器的时候用TCP进行一个传输是比较复杂的,就是可以用AJAX进行一个编写定时器,但是http协议传输复杂,速率慢,所以传输速度快的话用UDP协议是可以,但是UDP协议不能保障传输的正确。
我们输入网址,域名进行一个寻址,浏览器向DNS发送请求的时候也是用的UDP
但是微服务的传输一般都在是内网,内网中转的频率比较少,一般大约1毫秒就能完成一次数据的传输。不像外网用http协议需要中转好多设备,一般几十毫秒才能完成一次传输,
所以在内网的情况下干扰少,出错率也是非常低的,不会有影响的,由于是基于UDP的所以就需要用到socket,但是单纯的使用socket是不行,性能上差一些,所以需要NIO,从而进行心跳管理
生产者或者消费者的服务器宕机怎么处理
设计一个通知机制:会通过打电话、发短信、发邮件来进行通知,电话会一直响,短信邮件每隔一段时间发一次,还有微信公众号、小程序
https://mp.weixin.qq.com/s/0EfIUB9E-0Oh_Clwuxswuw
序列化:
对一个Java对象作一下“变换”,变成字节序列,这样一来方便持久化存储到磁盘,避免程序运行结束后对象就从内存里消失,另外变换成字节序列也更便于网络运输和传播
反序列化:
把字节序列回复为原先的java对象,
将硬盘上的数据重新恢复到内存,恢复成java对象列化一个类时,需要实现一个Serializable接口,Serializable接口也仅仅只是做一个标记用。它告诉代码只要是实现了Serializable接口的类都是可以被序列化的!然而真正的序列化动作不需要靠它完成
1、serialVersionUID是序列化前后的唯一标识符
2、默认如果没有人为显式定义过serialVersionUID
,那编译器会为它自动声明一个!
写代码时还是建议,凡是implements Serializable
的类,都最好人为显式地为它声明一个serialVersionUID
明确值
序列化例子:后端controller层return一个对象给前端,前端拿到的是一个json数据,这就是一个序列化和反序列化的过程,后端要转化成字符串返回给前端,前端再转化成json格式
序列化工具 谷歌的gson String x = new Gson.toJson(对象)
gson的内部原理: 序列化和反序列化底层都是反射,拿到内部类的结构后,会去内存进行遍历,然后把值取出来
遍历是如何遍历的呢?内存再给每个类型分配的时候都是有严格边界的,比如int类型四字节,long类型8字节,引用类型也是4字节,引用类型存储着地址4字节,然后顺着地址找到相对应的对象的地址,然后去对象地址里面,内存再给对象里面的属性再去分配空间,int类型4字节,long类型8字节,引用类型存的是地址4字节,然后再沿着对象的地址遍历到下一个对象,然后遍历对象的结构…
new一个对象就申请一片空间,底层c++中malloc函数会去进行一个空间的分配,比如new一个cat对象,里面有int类型、long类型和Person对象(地址4字节),4+8+4=16,一共需要申请16字节的空间。所以**遍历的时候,当gson遍历到一个对象的时候,并不知道这个对象是什么类型,**但是因为是值传递,我们可以找到要遍历的对象的地址,然后对对象头遍历,JVM学过,因为对象的头部存储着这个对象的类型指针,就是类型的指向,我们可以类型指向可以找到我们需要的对象是什么类型的数据,假设是个cat类型的对象,然后我们再去遍历里面都存储着什么类型的数据,然后把值读取出来 ( int类型的的"12",int类型的:“18”,Person{“size”:“12”,“height”:“18”}),然后同时可以算出我们需要分配多大的内存了
(c++中malloc函数,申请空间,*(int*) mal(sizeof(int)10) mal(sizeof(int)*10)表示申请了10个int类型的空间,(int*) 表示转换成int类型的数组)
反射的缺点速度慢。达到了毫秒级的开销,说自己做了几万次for循环测试出来的,
序列化和反序列化利用反射来实现,时间达到毫秒级的开销了,非常慢,和网络IO ,磁盘IO 一个级别了
所以微服务虽然在内网中,他的网络IO不像外网那么慢,但是使用序列化还有反序列化是很浪费时间的,
虽然比外网controller层返回给前端快,但是controller层返回给前端是服务器只支撑自己的前端服务器,慢一些无所谓,但是在微服务中,微服务的生产者要支撑好多的消费者,它必须快速把数据处理完毕去释放内存,所以速度必须非常快才能扛住高访问,所以才需要在序列化和反序列化这里做一些极限的优化
在消费者发送给生产者的过程中,一个类作为传输的类,在启动阶段进行反射,生成模板类,启动阶段只反射一次,然后发送环节就不再需要反射了。然后这个类的引用类型上加上注解规定占据多少字节,然后就相当于生成了一个模板类,然后对原来的类进行替换
怎么进行的替换呢?解决依靠反射解决序列化的问题,我们用反射的原因是不同的类有不同的属性,我们不清楚你有什么属性,但如果不同的类有一个相同的属性,就用不着反射了
不同的类有相同的属性,但是它们的长度不一样
把这个传输的类的所有属性都归纳成只有一个属性,可以用一个byte数组arr,假设那边的所有属性有64字节,声明的byte数组也分配64字节的空间,这64个字节分配着每个属性所占据的空间,比如int占据10字节,long占据20字节,然后之前的get set方法就操作每个属性所占据的字节进行操作,构造方法也是放入每个属性所对应的相对位置。
这样的话我们对这个类进行消费者对生产者的NIO发送,不需要用反射了,因为你传输的类只有一个属性arr,只需要直接调用这个类对象.arr就可以了(byte[] ww = 类对象.arr), 然后NIO发送 发送的类的标记-ww,生产者-方法,这是把传输的类的属性发送给生产者的某个方法。
生产者接收到了先会看看是哪个类的,然后它就可以进行相对应的反序列化的解析了,同样,生产者也是用的非反射的方式被替换掉,用一个byte类型的数组对所有属性进行概括,接收的话,生产者拿到传输的类的一个标记0101,然后通过反射创建对象,然后(对象.arr=ww)直接调用方法
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IrGcn1BJ-1670228759164)(…/img/image-20220927230215212.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ajSG4hSj-1670228759165)(…/img/image-20220928152836248.png)]
dao层 是接口,只有方法没有具体实现,和mybatis比较类似
调用生产者的代码,用动态代理指定调用哪个生产者,传入生产者的接口类的.class文件(通过maven导入的),生成生产者的对象,启动后,然后对象.方法就可以直接调用生产者的方法了,但实际上方法还是在生产者的远程服务器上,实际上的调用是socket发送
消费者的实现原理和和mybatis中的实现原理相似,就比如消费者对接口中方法的调用和mybatis中dao层对接口中方法的调用一样,只不过mybatis是用依赖注入了对象,而消费者是用代理对象进行的对象的生成。
生产者、消费者都有一个的key钥匙,也就是一串字符。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-64G8p1Wt-1670228759165)(…/img/image-20220928094058325.png)]
生产者用一个注解表示它是生产者,注解规定类名就是这个生产者的名字,里面的每个方法都相当于是生产者提供的接口,就和controller层相似,controller层的方法也可以理解成是网络接口。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IJfrHa1i-1670228759166)(…/img/image-20220928094600320.png)]
消费者调用的时候就只需要指定是哪个生产者下面的哪个类就可以了,底层实现是NIO的一个发送,现在方法在生产者那边,消费者只能远程调用,而生产者那边的方法就是自己实现的
消费者调用生产者和tomcat运行servlet相似
生产者定义AAA接口,里面有实现的方法,可以理解成是接口。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0RFKc7Xr-1670228759166)(…/img/image-20220928100450579.png)]
生产者定义类,
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kylZkLDs-1670228759167)(…/img/image-20220928100523513.png)]
生产者定义实现类
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Bsl13ln8-1670228759167)(…/img/image-20220928100740363.png)]
然后把接口和定义的类归为一个项目,打成jar包。然后上传到maven中央仓库然后消费者下载
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oXQK2cOB-1670228759168)(…/img/image-20220928101650944.png)]
消费者下载下来maven坐标,然后调用生产者中的某些方法
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ijRP9ULv-1670228759168)(…/img/image-20220928101815807.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JGDtEvmA-1670228759168)(…/img/image-20220928103640366.png)]
启动阶段:扫描生产者所有类,反射,选择出带注解的实现类,然后生成实例存入hashMap方便匹配
接受阶段: NIO监听端口,获取到序列化数据byte[]&url+方法名----反序列化拿到入参对象—拿url来hashMap里面匹配到生产者实现类的实例以及方法的实例— invoke代理
搭建一台应用服务器,不用来运行程序,而是分配用户的请求,用户的所有请求都会请求到这台服务,由这台服务器来分配给存放程序的服务器。这就是负载均衡。负载均衡通常通过Nginx实现。
nginx可以读取http协议,然后判断是哪个域名下的数据 再转发过去 ,nginx可以达到每秒几百万次的转发量,因为是纯C语言写的,正常情况下,单台nginx服务器可以支撑一个公司了
但有个问题就是如果每个转发的服务器里面都有个数据库,修改一个数据库的信息,另一台的数据库不会改变,所以要给数据库单独整一台服务器
单纯给java加集群达到每秒处理数据量几万次并不能解决问题,最终还是会卡在数据库,因为一个数据库每秒的读取量就那么大,所以我们把访问频率高的数据备份到redis中,所以我们先请求redis,redis查不到再去数据库查到,redis每秒可承受每秒数百次的访问 再看一次 , 数据量太大的时候,redis也承受不住的时候,去优化数据库(把一个表拆成多个表、加索引…百度)会让数据库每秒访问量大大提升,但如果还是解决不了问题
就要分库,把一个数据库的所有表 分给其他数据库,每个库然后再采取分表策略,然后把所有数据库承受的并发量合并
**场景:**河大教务系统选课,医院挂号,持续在线平台(在线聊天)、双十一、营销抢购
但如果一次访问量特别大 超过百万级别,一台nginx承受不住
所以需要多台nginx服务器,首先通过DNS(解析域名)把一个大网站(比如京东)再分成好多个小网站,再去访问多台nginx服务器,每个nginx服务器负责一个小网站
瞬时高压:
双十一抢东西 从0时0分0秒开始高压逐步减缓 并不能持续
只接收不处理对服务器的开销是非常小的,假设我们有10台服务器,最高每秒能处理能处理40W次的数据量,总共有5000W的数据量,所以当我们的服务器处理不了的时候,我们把剩余的访问量单独存储在一台服务器中不处理,然后每次从存储数据量的服务器中一次拿出40W给我们的服务器处理,这样几秒也能处理完
或者我们只需要接收几十万的数据量,然后把剩余的数据量打回,就是货卖完了,不接收了
我们存储数据量的服务器 用MQ消息队列、reids、kafka等等存储数据,这样给我们的服务器发送的时候会快一些
dubbo:自定义协议,处理速度很快,但仅仅提供生产者、消费者功能,其他的很多东西需要自己去配置,比如流量控制、权限控制这些。
springcloud:http协议,全家桶,所有的东西全部配置好了,直接使用,就是因为这些,所以很笨重,处理速度很慢。
底层序列化和反序列化,通过网络的形式传输数据,中间从zk中获取服务的地址。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fHIA7jZL-1670228759169)(C:\Users\86185\AppData\Roaming\Typora\typora-user-images\image-20221126113411953.png)]
dubbo是rpc(远程过程调用)框架的一种典型实现;
节点 | 角色说明 |
---|---|
Provider |
暴露服务的服务提供方 |
Consumer |
调用远程服务的服务消费方 |
Registry |
服务注册与发现的注册中心 |
Monitor |
统计服务的调用次数和调用时间的监控中心 |
Container |
服务运行容器 |
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XxNfkIfy-1670228759169)(…/img/image-20220826162452436.png)]
服务容器负责启动,加载,运行服务提供者。
支付宝,天猫淘宝支付体系
金融支付对网络安全的要求最高,传输的过程中间需要经过很多传输交换设备的,在交换设备的数据是可以被窃听、拦截、篡改的和重复发送的。
安全性高、大幅度牺牲性能的。
但凡是带上协议两个字,不管是http协议还是TCP协议,都是明文的。任何协议都不管加密,它只是保障双方交换的一个传输,所以我们需要在协议的数据部分自行加密
http协议解析是由换行符写切分解析出来的,剩下的每一层协议都是01010101比特流组成,
金融类型的传输肯定用的TCP协议,TCP的数据部分,每8位合成一个byte类型的数据,最终展现在代码上的是一个byte类型的数组,前8或者16位表示它是哪种编码,然后再根据编码去规定一次取多少比特流(根据是2字节还是4字节取8位或者16位),所以在早些的数据传输过程中,根据这些协议是可以解析出来数据的
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qnY3ScMR-1670228759170)(…/img/image-20220930231631191.png)]
1、如果用自定义编码,可以避免数据在中转过程中被解析出来,也算是一种初步的加密,增加破解难度而已,还是能被破解出来的。
就是传输方和接收方都是有编码的,但是javaScript不能这样做,因为javaScript前端代码本身是明文的,所以前后端的传输不能用公开的编码去发
所以一些客户端的组件,比如淘宝支付下载淘宝支付的浏览器组件,浏览器组件有密码和编码,这样的话才能看不见,但是这样的也能探测出来,因为编码相对而言是固定的,比如我是攻击方,攻击方也可以用这些程序,来回发送信息,用抓包工具也可以把编码碰撞出来的。
所以单纯修改编码只是一种简单的加密方式
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-C81gi5wH-1670228759170)(…/img/image-20220928212918984.png)]
2、单纯https证书可以防止监听和篡改,但是没有办法解决拦截和重复发送问题。
但是比如发送方向接收方支付的时候,就可能遇到数据的拷贝,在没有篡改的情况下,会产生重复发送的问题,而接收方是合法接收的。
发送方向接收方发起一个支付的请求,然后接收方生成一个钥匙(和用户身份绑定),然后这个钥匙再返回给接收方,接收方接收到了钥匙之后,和支付的金额一同再进行一个支付的发送请求,进行一个真正的支付
当这个数据如果在传输的过程中被进行拷贝了三份,要进行重复发送,三份数据包陆续到达接收方,接收方那边有线程去接收这个数据包,然后接收方的钥匙再和发送方发送的钥匙进行一个比对,当然,这时候接收方的对象要进行同步加锁,只能同时进行一个比对,比对成功后销毁钥匙,剩余的两个数据包被线程接收后再进行比对,因为没有钥匙,就不会成功了
但如果发送方发送生成钥匙之前的那个请求被拷贝了,接收方一下子生成了好几份钥匙,最终的话,也是只会返回一把钥匙给发送方,剩下的也会被拦截,因为生成的钥匙是和用户id绑定的。
所以防止重复消费就是自己写一个锁,防止生成的钥匙被重复利用
3、无论是公司还是个人,最后都是需要和银行做对接。
比如个人支付到京东,京东账户接收,最终和银行对接。。每一步流程都需要做加密
和银行对接,会有流量控制问题,比如双十一 618活动,都是高并发
瞬间的高并发的交易,并不代表和银行已经做好交易了。而是所有的数据都堆积在了京东平台,需要花费小十几秒才能把数据和银行交易完毕,银行这边也需要做限制,每分钟不允许超过多少次的压力。
如果消息的并发量超过了银行这边流量的上限了怎么办?如果用支付宝支付,就直接和京东平台做对接,如果用银行卡支付的话, 我们个人用手机支付的时候也需要和银行做对接,声明和哪个银行做对接,然后银行也需要和京东平台进行一个对账,而银行的流量上限一般是不够的。
假设所有网购平台有100亿数据,银行消费不了,所以平台暂时会把一部分流量存储起来放到消息队列中,就相当于生产者,然后银行一波一波的进行消费。就会出现排队,把数据放到消息队列中,定时取数据然后发给各大银行。
同步+异步处理
我们个人进行消费的时候感觉支付很快,但实际上平台和银行需要小时级别的对账时间,我们感觉快是同步+异步处理的结果,同步是平台向银行发送,明明还没有对完账,但是平台已经返回交易成功了,这是异步处理。高并发都是同步+异步的,涉及到钱的都是同步的,各种反馈给用户的都是异步处理的。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-drtr5Mgi-1670228759170)(…/img/image-20221001001413040.png)]
同步执行 按理说把这些表的流程走完再去返回给用户支付成功 但是花费时间久 所以
异步支付 所以走完京东账户表,就可能反馈给用户已经支付成功了 如果失败的话,因为京东平台会有记录,去根据记录进行重试,还不行的话就人工处理强行成功
表的执行也可以是异步的,好多模块都可以是异步的,这只是其中一个模块
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-twyAWk1e-1670228759171)(…/img/image-20221001001511793.png)]
上面金融支付整个一个环节中需要保障(要么都成功,要么都失败,其中一个步骤失败,全回滚)的叫做一个事务
为什么能回滚?因为会有快照记录,根据快照进行回滚。快照本质上就是日志,记录好每一步的操作。
费的时候感觉支付很快,但实际上平台和银行需要小时级别的对账时间,我们感觉快是同步+异步处理的结果,同步是平台向银行发送,明明还没有对完账,但是平台已经返回交易成功了,这是异步处理。高并发都是同步+异步的,涉及到钱的都是同步的,各种反馈给用户的都是异步处理的。
[外链图片转存中…(img-drtr5Mgi-1670228759170)]
同步执行 按理说把这些表的流程走完再去返回给用户支付成功 但是花费时间久 所以
异步支付 所以走完京东账户表,就可能反馈给用户已经支付成功了 如果失败的话,因为京东平台会有记录,去根据记录进行重试,还不行的话就人工处理强行成功
表的执行也可以是异步的,好多模块都可以是异步的,这只是其中一个模块
[外链图片转存中…(img-twyAWk1e-1670228759171)]
上面金融支付整个一个环节中需要保障(要么都成功,要么都失败,其中一个步骤失败,全回滚)的叫做一个事务
为什么能回滚?因为会有快照记录,根据快照进行回滚。快照本质上就是日志,记录好每一步的操作。