从网络到分布式 从单机到微服务

在这里插入图片描述

第一大部分:计算机网络+TCP/IP 
-=======================================
osi七层参考模型 
tcpip五层模型 分层解耦 各干各的 提供好标准
应用层 传输层 网络层 链路层 物理层
tcpdump 网络抓包软件

tcpdump -nn -i enp0s3 port 80
curl www.baidu.com
就会打印
三次握手 发送数据 打印数据 四次分手 四个过程

提示:一个连接可以看成是一个文件描述符📃
------------------------
1.与百度建立一个tcp连接 用数字9 来代表这个文件描述符📃
即完成tcp的三次握手
exec 9<> /dev/tcp/www.baidu.com/80

2.然后基于http协议发一段文本给到百度
echo -e "get /http/1.0\n" >& 9
重定向发送给文件描述符9 

3.百度收到你请求首页的意图,然后返回首页给你
cat <& 9

看看:
cd /proc/$$/fd


程序员一般都是忙活在应用层,但是先要传输层先建立连接,建立连接之后才能发东西,
建立连接服务端等待客户端发送数据的这个时候处于 阻塞状态

------------------------
传输控制层:
tcp协议:面向 连接的 可靠的 传输协议
 三次握手
 数据传输 
 四次分手

应用层要发数据,需要传输层要先tcp三次握手建立连接:
1.client先发送一个想与server建立连接的sync包
2.server收到请求包之后,会给client返回sync➕ack,像client表明自己收到请求
3.client最后再给server发送一个ack包


话说回来:为啥要三次握手,因为并非物理连接,要在公用的介质上进行通信,
三次握手双方才能为对方建立资源为对方服务。

Docs攻击:大量肉机往一台服务器发送sync的包,服务端正常返回确认,客户端不发送最后确认。
服务端就会一直等待。这样大量等待会导致资源浪费比较大。这时真正想要建立连接的机器就挤不进去了

解决:负载均衡+黑名单技术

TCP三次握手
客户端:sync1 包想要建立连接
服务端:回复sync2 + ack(sync1+1)
客户端:ack=1


四次分手:
客户端:sync1+ack1
服务端:ack2(sync1+1)
服务端:sync2(ack1)+ack2(sync+1)
客户端:ack3(sync2+1)
 
-----------
30min重点

什么叫做socket:套接字
本质 ip port +  ip port 保证客户端唯一性
ssh 两个标签页 ,就可以看见
netstat -tanp
每个连接相互不影响,保证了客户端唯一性

一台主机端口号大约最多 65535 个


四次分手:
由于客户端端口号是有限的,你不用了要立刻释放掉,给其他客户端使用。关闭连接。

1.client会先给server发一个fin+ack数据包,表明想断开连接
2.server先回一个 ack表明自己收到了client的意图

3.server 这个时候如果也想断开,也会给client发送一个 fin+ack 数据包,(这里如果不发,客户端是不能断开连接,即:释放资源)
4.client收到server发的fin,会回一个ack数据包。

至此,连接断开,各自释放资源。

小结:
三次握手建立好连接,双方各自建立资源为对方服务,只有建立成功连接才能开始发送数据。
四次分手就是双方都确认把建立的资源都销毁掉。
应用层想要发送数据,必须先要建立tcp连接,如何才能建立连接呢?要从上往下走网络层 链路层 一直到物理层。才能把数据包发出去


~~~分割线~~~
网络层 
应该知道的东西包含以下:
ip地址 :网络号➕主机号
通过子网掩码来划分ip的网络号和主机号
点分十进制=每个位都是一子节=8个二进制位=0~255
子网掩码与ip地址按位与 :全1则1,其余为0  ==> 得到网络号

网络这一层使用 路由表 来解决通信问题
route -n
路由表:主要通过记录 下一跳 来完成互联网的通信


下一跳机制:最短匹配原则
目标地址ip与路由表每行的掩码做与运算,结果和路由表前面比对,看是否对上。

ps:你家里的路由器很大可能存的是你的电脑ip加上网关(下一跳)即可。然后路由器本身路由表会将网关跳到运营商ip。
️同一局域网内数据传输不需要走网关

ip数据包的目标地址放的是 目标服务器的地址



~~~分割线~~
链路层
arp -a
存放物理mac地址与ip地址的映射关系

️在数据包传输的时候,目标服务器地址一直未变,一直变化的是mac地址(通过网络层的路由表找到下一跳ip地址,这个ip地址是在链路层和物理mac地址绑定的)

每跳一下,数据包里面的mac地址就会改变一次


-=======================================
第二大部分:io(socket代出: bio nio epoll ... )
-=======================================
第二部分:如何衔接到io的?
===io bio nio select poll epoll=
前置知识:
kernel:连接软件程序和物理硬件
向上提供api,向下兼容硬件
os=kernel➕应用程序


电脑:
按下电源按钮 
1.bios程序会被先加载入内存(出现的第一个程序)
2.bios里面最基本的是一个引导程序,(出现的第二个程序)
假如我们从磁盘引导,磁盘的第一个位置有一个叫做mbr的分区表

引导程序可以识别磁盘的文件格式 ,fat fat32 ntfs等。

3.识别之后,找到kernel程序。加载入内存(出现的第三个程序)
然后kernel接管os,进入保护模式。

kernel这段地址空间叫做:系统空间
其余内存地址空间叫做:用户空间

我们开发的应用程序是加载到用户空间的:
通过系统调用 system call 从用户空间切换到系统空间


yum install man man-pages
帮助程序里面有8类文档,比如
2类代表系统调用
man 2  socket //查看socket的系统调用
linux用数字来代表一个对象
️man 2 bind 可以好好研究


以tomcat 运行为例:
启动一个绑定在8080端口的server。
类似于socket就会阻塞accept在那里,等待客户端连接。
此时有一个连接连接上了,然后会调用read 阻塞在那里,等待用户发送数据过来。

注意这个时候,新的客户端是进不来的。

️然后就出现了 多线程模型
每一个连接开辟一个新的线程去阻塞等待自己的数据。即,BIO。阻塞时期。

弊端:
每连接对应每线程
这样会导致线程过多 ,导致切换开销大,资源耗费大
默认一个线程1mb。

考究一台服务器性能:看在用户空间还是系统空间花费的时间多


️内核发生了演进,提供nonblock机制
出现了nio 非阻塞io
不用开辟新的子线程

只用一个主线程
他自己不断轮询,
先轮询是否有新的连接,
没有返回-1,有的话进入下一步。
开始加入不断轮询kernel的read方法的队列里面去。
即:假如此时已经有了5000个连接,那么就会不停循环发生5000个连接的read系统调用,尽管很大部分连接根本没有数据。此时,还有新的连接不断加入进来。

如果程序知道哪些文件描述符,即连接 。有在发送数据。

️内核又发生了新的演进,增加了多路复用select系统调用:允许✅程序监控多个连接

本质:减少全局系统调用,发起一次,由内核对连接状态进行判断。这个判断开销远远小于连接的read调用

接着上面例子:我们可以把上面nio弊端中的 5000个连接产生的5000次连接。封装为一个连接。即仅发生一次系统调用,由内核去判断全部5000个连接哪些有数据。
遍历得到有数据的连接,返回相应信息,再有对应的连接自己发起read系统调用获取数据


️上面所有的类型:都需要client主动去拉取数据,即都是同步模型

️ epoll

上面select模型还是有弊端:
1.每次循环♻️要调用一次全量select(参数需要传递所有的连接)
2.内核判断连接是否有数据,这个也是很费时的,太多啦因为是O(n)复杂度

中断

由事件驱动机制来避免内核kernel主动去判断连接是否有数据

man epoll
man epoll_create
man epoll_ctl
man epoll_wait

本质:
事件驱动,每个fd(连接)在其生命周期内,只需通过epoll_ctl 传递一次,

每循环调用的其实是epoll_wait。因为内核通过中断机制,那些到达的数据被动的放入了另一个空间,epoll_wait只需要遍历出空间里面的有数据的连接

这样cpu都基本工作在有意义的事情上了。




-=======================================
第三大部分:直接内存映射 零拷贝 分布式理论基础
-=======================================
---------1----------------------------------------------------------
内存两部分:内核空间 用户空间
内核空间:kernel
用户空间:程序

正常情况下:
程序要想读磁盘上的文件,需要先调用内核,内核把磁盘文件读取到内核内存中,
程序内存再把内核内存上读取得文件拷贝

想哟要加速文件读取怎么办?
直接内存映射:mmap
1.内核和程序可以同时访问的一块内存空间
2.这个内存空间还可以直接和某一磁盘块做映射

可以做到减少从内核拷贝到程序这一过程;

 
Kafka消息队列: 进程跑在Jvm之上
Producer
Consumer
数据可以持久化到磁盘,
一般来说,数据存储在磁盘都是很慢的,但是Kafka对外宣称很快?

Kafka程序  内核  磁盘  

segment段文件:文件固定大小分段
Kafka顺序写磁盘


生产者:mmap技术解决很快写数据到磁盘
Kafka Producer 要把数据发送给Kafka,
1.通过网卡,首先到达内核,内核再拷贝给Kafka,【网卡->内核->Kafka进程】
2.Kafka对这个生产的数据要先进行处理,加一些标记信息
3.然后在持久化到磁盘中去,是不用从 Kafka进程->内核->磁盘 这个流程的
而是直接 【Kafka进程->磁盘文件】,这里就是直接使用的直接内存映射技术



消费者:
Kafka Consumer 通过Socket网络连接到Kafka进程
通过网卡,首先到达内核,
1.如果是最新被Kafka进程处理好的,还没来得及存到磁盘的,直接读mmap上被处理好的即可
2.sendfile  零拷贝
如果请求的是已经持久化到磁盘上的文件:
请求连到内核,再到Kafka进程解析你的请求,解析之后:开始读文件
	1.没有零拷贝技术:
	先调用kernel read方法读数据到自己进程中
	再调用kernel write方法将读到的数据通过kernel写出去到网卡

	数据流向:
	磁盘->内核->Kafka进程->内核->网卡出去  


	2.如何优化?为啥能优化
	本质还是因为读取的数据 不需要被读到Kafka进程处理,可以直接吐出去
	具体就是Kafka进程直接调用内核的 sendfile方法 ,将需要的数据吐出去即可

	数据流向:
	磁盘->内核->网卡出去  
	
零拷贝:是不用把数据从内核拷贝到Kafka进程中;


直接内存映射:mmap
1.内核和程序可以同时访问的一块内存空间
2.这个内存空间还可以直接和某一磁盘块做映射

----------2---------------------------------------------------------
秒杀系统
并发量一定会很大,本质:多个线程抢的是资源
可能发生:超卖

考虑的问题:不能降低用户体验

思路:
削峰限流
多级缓存

有些场景是处理是同步的,有些是异步的

----
可以做啥?
动静分离:静态资源cdn   动态数据发送到数据中心的
预热:先提前把请求某些数据提前活动,提前缓存到用户手机里


第一个隔离:隔离恶意请求,判断用户请求是否恶意
抢购状态:新 、等待付款、已付款(等待付款成功)
	对于不同的抢购状态,应该走不同处理
	
这个状态是可以存储在Redis的
------------3--------------------------------------------------------------------
高并发中对MySQL中的库存减的操作
MySQL其实是串行化:挨个执行,多个并发降为单个串行

改进,使用Redis:
基于内存
KV
V有多种数据类型:每种类型还有自己的本地方法直接处理数据
单线程 -> 串行化执行的
多并发给到Redis处理

这里为啥单线程不会阻塞:
Redis底层用到了epoll,不需要轮询 哪些连接有数据,
而是数据到了,产生一个事件,直接处理就可以



------------4-------------------------------------------------------------------
集群分布式主题 
cap paxos  zookeeper   

cap:
c:一致性
a:可用性
p:分区

zookeeper:分布式协调服务,自带高可靠光环

Redis 可以做啥?
	分布式锁:不推荐
	缓存
	排行榜
Redis本质就是单机单线程小程序

Redis持久化:
	rdb 窗口大小
	aof三个级别
	开启aof会降低性能,因为本质是减少磁盘io才快

Redis主从复制+哨兵 :
	这里主从复制有两种同步方式:
		1.同步阻塞:主节点同步给从节点,阻塞等待从节点返回OK
			在一致性里面叫做 强一致性
		  从节点解决的是 可用性,即高可用
	      假如从节点挂掉了,如果采用的是同步阻塞,从节点这时也
		  间接的破坏了主节点的可用性
			
		  这里Redis是可以调整为强一致性
		
		2.不用等待从节点反馈
			弱一致性
	
	
3.最终一致性
	可能具备延迟


使用Redis做分布式锁:
	1.可以使用一个实现了paxos协议的框架来帮忙
	2.自己代码实现过半机制判定


zk本质还是各个节点之间能够通信,能够主动确认自己是否该活着

不过半选举容易出现脑裂:不同客户端都可以组合出结果
结果过半通过:

zookeeper:有一个leader ,即只发送给一台
leader挂掉了,变成无主集群,zk能快速恢复,200ms能恢复出来,接近高可用

如何选举这么快的?
1.zxid 事务ID
2.myid,即话语权
这是一种谦让制

zk从无主投票 过半选举均是符合paxos 协议,其实zk是基于paxos协议实现了一个
自己的叫做zab协议


布式锁 
etcd(需要一定功底) k8s etcd
zk
redis 

---
小结:
1/2部分网址:https://www.bilibili.com/video/BV1CQ4y1K7K4?p=2
3部分网址:https://www.bilibili.com/video/BV1y7411h7XG?spm_id_from=333.1007.top_right_bar_window_view_later.content.click
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java高并发高性能分布式框架从无到有微服务架构设计 Java高并发高性能分布式框架从无到有微服务架构设计 微服务架构模式(Microservice Architect Pattern)。近两年在服务的疯狂增长与云计算技术的进步,让微服务架构受到重点关注 微服务架构是一种架构模式,它提倡将单一应用程序划分成一组小的服务,服务之间互 相协调、互相配合,为用户提供最终价值。每个服务运行在其独立的进程中,服务与服 务间采用轻量级的通信机制互相沟通(通常是基于HTTP的RESTful API)。每个服务都围绕着具体业务进行构建,并且能够被独立地部署到生产环境、类生 产环境等。另外,应尽量避免统一的、集中式的服务管理机制,对具体的一个服务而言 ,应根据业务上下文,选择合适的语言、工具对其进行构建。微服务架构优势 首先简单介绍了微服务(Microservices)的内涵及优势,微服务架构的本质,是用一些 功能比较明确、业务比较精练的服务去解决更大、更实际的问题。微服务架构将服务拆 分,分别采用相对独立的服务对各方面进行管理,彼此之间使用统一的接口来进行交流 ,架构变得复杂,优势也很明显: 复杂度可控:在将应用分解的同时,规避了原本复杂度无止境的积累。每一个微服务专 注于单一功能,并通过定义良好的接口清晰表述服务边界。由于体积小、复杂度低,每 个微服务可由一个小规模开发团队完全掌控,易于保持高可维护性和开发效率。什么 即当堆内存不足时,可以强制回收这部分内存释放堆内存空间。一般使用堆缓存存储较 热的数据。有Guava Cache: 缓存和ConcurrentMap是非常相像的,但是它们也不完全一样。最根本的区别就是,Con currentMap会持有所有添加的对象,直到被显示的移除。而缓存为了限制其内存的使用 ,通常都会配置成可以自动的将对象移除。在某些情况下即使不自动移除对象也是非常 有用的,如LoadingCache它会自动加载缓存对象。Ehcache 3.x:是一种广泛使用的开源Java分布式缓存。主要面向通用缓存,Java EE和轻量级容器。它具有内存和磁盘存储,缓存加载器,缓存扩展,缓存异常处理程序,一 个gzip缓存servlet过滤器,支持REST和SOAP api等特点。MapDB: mapdb是一个内嵌的纯java的数据库,提供了并发的HashMap、TreeMap、Queue,可以基 于堆外或者磁盘来存储数据高并发-应用缓存堆外缓存 即缓存数据存储在堆外内存,可以减少GC暂停时间(堆对象转移到堆外,GC扫描和移动 的对象变少),但是,读取数据时需要序列化/反序列化,因此会比堆缓存要慢很多。有 Ehcache 3.x、MapDB实现磁盘缓存 即缓存数据存储在磁道上,在JVM重启时数据还存在的,而堆缓存/堆外缓存数据会丢失 ,需要重新加载。有Ehcache 3.x、MapDB实现分布式缓存 进程内缓存和磁盘缓存,在多JVM实例的情况下,会存在两个问题: 1、单机容量问题; 2、数据一致性问题(多台JVM实例的缓存数据不一致怎么办?),这个问题不用纠结, 既然数据允许缓存,则表示允许一定时间内的不一致,因此可以设置缓存数据的过期时 间来定期更新数据; 3、缓存不命中时,需要回源到DB/服务请求多变问题:每个实例在缓存不命中的情况下 都会回源到DB加载数据,因此多实例后DB整体的访问量变多了解决办法是可以使用如一 致性哈希分片算法。因此,这些情况可以考虑使用分布式缓存来解决。 可以使用ehcache –clustered(配合 Terracotta server) 实现JAVA进程间分布式缓存。最好的办法是使用redis实现分布式缓存。高并发- HTTP缓存浏览器缓存是指当我们使用浏览器访问一些网站页面或者http服务时,根据服 务端返回的缓存设置响应头将响应内容缓存到浏览器,下次可以直接使用缓存内容或者 仅需要去服务端验证内容是否过期即可。这样的好处可以减少浏览器和服务端之间来回 传输的数据量,节省带宽提升性能。 解决办法:内容不需要动态(计算、渲染等)速度更快,内容越接近于用户速度越快。 像apache traffic server、squid、varnish、nginx等技术都可以来进行内容缓存。还有CDN就是用来加速 用户访问的:即用户首先访问到全国各地的CDN节点(使用如ATS、Squid实现),如果C DN没命中,会回源到中央nginx集群,该集群如果没有命中缓存(该集群的缓存不是必须 的,要根据实际命中情况等决定),最后回源到后端应用集群。高并发- 多级缓存(分布式缓存)高并发- 池化在应用系统开发过程中,我们经常会用到池化技术,如对象池、连接池、线程池等 ,通过池化来减少一些消耗,以提升性能。 对象池通过复用对象

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值