为了账号安全,请及时绑定邮箱和手机立即绑定
1. 端口

在学习Socket编程之前我们要了解一下概念。端口不是物理设备,而是促进服务器和客户端之间通信的抽象概念。端口是由一个 2 的 16 次幂的整数表示的,所以,一台机器最多可以有65536个端口(0~65535)。端口一共分为三个种类:知名端口:0 ~ 1023(例如:80端口用于http,25端口用于smtp)。注册端口:1024 ~ 49151。动态/私有端口:49152 ~ 65535。

5.1 服务端启动类

public class NettyServer { public static void main(String[] args) { //线程组-主要是监听客户端请求 NioEventLoopGroup bossGroup = new NioEventLoopGroup(); //线程组-主要是处理具体业务 NioEventLoopGroup workerGroup = new NioEventLoopGroup(); //启动类 ServerBootstrap serverBootstrap = new ServerBootstrap(); serverBootstrap //指定线程组 .group(bossGroup, workerGroup) //指定 NIO 模式 .channel(NioServerSocketChannel.class) //双向链表管理 .childHandler(new ChannelInitializer<NioSocketChannel>() { protected void initChannel(NioSocketChannel ch) { //责任链,指定自定义处理业务的 Handler ch.pipeline().addLast(new NettyServerHandler()); } }); //绑定端口号 serverBootstrap.bind(80); }}代码说明:以上都是模板代码,需要变动的是根据不同的业务自定义对应的 Handler,并且在 initChannel () 添加逻辑处理器;根据实际情况指定 bind () 方法的端口号,注意的是端口号不能和其它端口号冲突;这里大家先熟练掌握模板代码的编写,后面章节会讲解 NioEventLoopGroup、Pipeline 等核心组件的原理。

3. 使用 virtual 解决冲突

上面我们说到,不同的项目依赖不同的包很有可能造成项目冲突问题,而 virtual 则正是为了解决这个问题而诞生的:virtualenv 命令可以创建一个隔离的运行环境:每个运行环境中包含有一套组件:Python 解释器、各种第三方包;每个运行环境中包含的组件是私有的、不共享的;因此运行环境之间是隔离的。针对 2.2 小节中项目依赖的问题,使用 virtualenv 的解决方法如下图所示:使用 virtualenv 为项目 A 创建一个隔离环境,隔离环境中包括 python 解释器和 redis-3.5.3。使用 virtualenv 为项目 B 创建一个隔离环境,隔离环境中包括 python 解释器和 redis-3.0.0。如果,需要同时进行两个项目的开发,则开发项目 A 时,进入项目 A 的虚拟环境,开发项目 B 时,进入项目 B 的虚拟环境,也可以同时打开两个终端,分别进行项目 A 和项目 B 的虚拟环境,同时进行两者的项目开发。每一个虚拟环境中的 Python 版本,包版本互不影响,自然完美解决了冲突问题。

3. 端口号

端口号是用 16 bit 无符号整数表示的,取值范围是 0~65535,总共可以分配 65536 个端口号。端口号属于稀缺资源,是由 Internet Assigned Numbers Authority (IANA)统一管理和分配的。端口号当前分配状况:0 ~ 1023此区间内的端口号叫做知名端口号,已经被系统或者是一些知名的服务所占用,比如:端口号用途20 , 21用于 FTP 协议23用于 telnet 协议80用于著名的 HTTP 服务443用于 HTTPS 服务1023 ~ 65535此区间端口号也有很多被知名的应用占有,比如:端口号用途1433用于 SQL Server 服务等等1935用于 RTMP 服务3306用于 MySQL 服务8080作为 HTTP 服务的另外一个端口号

1.2 端口映射访问容器

将宿主机的本地端口,与指定容器的服务端口进行映射绑定,之后访问宿主机端口时,会将请求自动转发到容器的端口上,实现外部对容器内网络服务的访问。创建名为 n0 的 nginx 容器,映射宿主机 8000 端口到它的 80 端口docker run -d -t -p 8000:80 --name n0 nginxTips:指定的宿主机端口必须是未被占用的端口,否则操作会失败,且生成一个无法正常启动的容器 n0, 需要手动删除。使用 docker port n0 查看 n0 的端口映射信息,显示如下:80/tcp -> 0.0.0.0:8000打开浏览器,地址栏输入 http://localhost:8000 或 http:// 宿主机 IP:8000, 都能访问到 n0 的 nginx 服务。如果需要绑定多个容器端口,可以连续使用 -p 参数多次指定docker run -d -t -p 8001:80 -p 8433:443 --name n1 ngin如果不想主动指定宿主机端口,可以使用 -P 参数,宿主机随机使用一个可用端口与容器端口进行映射docker run -d -t -P --name n2 nginx如果只想使用宿主机上特定的网口与容器进行映射docker run -d -t -p 192.168.1.13:8002:80 --name n3 nginxTips:此处 192.168.1.13 指代 宿主机映射网口的 IP 地址,需要根据网口的实际 IP 更改 *。我们执行 docker ps 可能出现如下几个的 nginx 容器:再执行 iptables -t nat -nL 查看下防火墙:比对上面两个的输出,不难发现,这种端口转发方式的本质是通过配置 iptables 规则转发实现的,效率较低,如果容器的服务端口数量过多,需要配置较多的映射,占用大量宿主机端口,也不便于管理。不再使用的容器记得删除掉,释放资源和空间docker rm -f n0 n1 n2 n3

1. 桥接网络模式与端口映射模式

Tips:桥接宿主机网络与 端口映射模式的设定参考 Docker 网络 部分内容。桥接模式,多个宿主机位于同一个局域网,将每一个宿主机上的容器网络桥接到宿主机网络中,容器和宿主机同在一个局域网中互相通信。每台宿主机上的容器都直接从局域网中获取IP地址,容易导致IP地址冲突。端口映射模式,是将容器的服务所运行的端口映射到宿主机的某一个端口,然后其他的容器通过宿主机的对应端口进行访问。只要宿主机间能互相通信,容器之间就能通过宿主机的指定端口进行通信。但是这种方式需要对每一个容器都映射端口,而且宿主机的端口也有限。

4. 通过进程 PID 查找端口号

nginx 软件服务启动之后默认的端口号是 80,可以使用如下命通过 PID 查找到端口号,命令如下:netstat -apn | grep 12471执行结果如下:Tips:如图所示,可以知道进程 PID = 12471 这个进程符合 nginx 启动的端口号。

2.1. 全局样式与局部样式冲突

下面来举个实际例子看看当全局样式与局部样式冲突时,页面是如何显示的。编辑 App.vue 文件,添加全局样式,将页面背景颜色定义为绿色,按钮宽度设置为50%,全局样式将影响到所有页面。实例:page { background-color: green;}button { width:50%; margin-top: 20px;}这里定义的 page 标签, 相当于普通项目中的 body 标签,会影响到所有的页面样式,通常我们会在这里面设置页面的背景颜色、字体样式、大小等。接下来编辑 pages/index/index.vue 文件,添加局部样式,将页面背景颜色定义为红色,局部样式将影响到 index 页面。我们实例中定义的局部样式与全局样式冲突的地方主要是 background-color 背景颜色属性,全局样式中定义的是 green 绿色,局部样式中定义的是 red 红色。实例:page { background-color: red;}button { height:100px;}点击工具栏–运行–运行到内置浏览器,查看效果。局部样式红色背景覆盖了全局样式绿色背景。按钮没有冲突的样式,既显示了全局样式中定义的宽度,又显示了局部样式中定义的高度。

2. ServerBootstrap 流程

ServerBootstrap 的用法基本上都是固定的,一般对于新接触 Netty 的同学来说,会觉得这些模板代码比较多,难以理解。我们主要记住几个核心配置即可。指定线程模型: 通过.group(bossGroup, workerGroup) 给引导类配置两大线程组,这个引导类的线程模型也就定型了。其中 bossGroup 表示监听端口,accept 新连接的线程组;workerGroup 表示处理每一条连接的数据读写的线程组;指定 IO 模型: 通过.channel(NioServerSocketChannel.class) 来指定 NIO 模型。如果指定 IO 模型为 BIO,那么这里配置上 OioServerSocketChannel.class 类型即可,通常都是使用 NIO,因为 Netty 的优势就在于 NIO;指定处理逻辑: 通过 childHandler () 方法,给这个引导类创建一个 ChannelInitializer,这里主要就是定义后续每条连接的数据读写,业务处理逻辑;绑定端口号: 调用 bind (80),端口号自定义,不要和其他应用的端口号有冲突即可。

3. 端口号概念

所谓的端口,就好像是门牌号一样,客户端可以通过 ip 地址找到对应的服务器端,但是服务器端是有很多端口的,每个应用程序对应一个端口号,通过类似门牌号的端口号,客户端才能真正的访问到该服务器。为了对端口进行区分,将每个端口进行了编号,这就是端口号 。

1. 端口号概念

所谓的端口,就好像是门牌号一样,客户端可以通过 ip 地址找到对应的服务器端,但是服务器端是有很多端口的,每个应用程序对应一个端口号,通过类似门牌号的端口号,客户端才能真正的访问到该服务器。为了对端口进行区分,将每个端口进行了编号,这就是端口号 。而 MySQL 服务默认指定的端口号为 3306,这个在之前介绍安装 MySQL 的时候,其中配置 my.ini 文件的内容时候,其中就有端口号配置,内容如下:

3. 小结

本小节介绍了如何在同一台主机操作系统上配置多个 MySQL 实例,这些不同的 MySQL 服务互相独立,分开管理,需要注意的是每个 MySQL 服务需要使用一个唯一的端口号,与其他类似服务之间也是如此,不能和其他类似软件服务之间有端口号冲突,负责会导致 MySQL 服务无法正常运行。

4. 注意事项

实际项目中使用 websocket 需要注意一些问题 :websocket 创建之前需要使用 HTTP 协议进行一次握手请求,服务端正确回复相应的请求之后才能创建 websocket 连接;创建 websocket 时需要进行一些类似 token 之类的登录认证,不然任何客户端都可以向服务器进行 websocket 连接;websocket 是明文传输,敏感的数据需要进行加密处理;由于 websocket 是长连接,当出现异常时连接会断开,服务端的进程也会丢失,所以服务端最好有守护进程进行监控重启;服务器监听的端口最好使用非系统性且不常使用的端口,不然可能会导致端口冲突

3.1 Server 监听端口

首先由服务端初始化 Socket 接口,然后绑定并监听自己的端口号,此时服务端会阻塞式等待客户端连接。

3.2 Client 连接端口

客户端可以在需要发送消息的时候初始化 Socket 接口,设置服务端的 IP 地址和端口号就可以连接到服务器,接着在连接成功之后,双方就完成了连接的建立。

4. 获取当前访问端口

可以使用 Request 对象中的 port() 方法获取当前访问的端口号,代码如下: public function getInfo(Request $request){ halt($request->port()); }执行结果如下图所示:Tips: 所谓的端口,就好像是门牌号一样,客户端可以通过ip地址找到对应的服务器端,但是服务器端是有很多端口的,每个应用程序对应一个端口号,通过类似门牌号的端口号,客户端才能真正的访问到该服务器。为了对端口进行区分,将每个端口进行了编号,这就是端口号 。

1. 缓冲区

我们在编辑文件时候,本质上其实是文件在内存的映像。就是我们说的缓冲区。而文件是需要存储在磁盘上的。所以我们编辑完文件后通过 :w 写入磁盘后才叫文件。buffer 有三种状态:active: 这种状态buffer 显示在当前窗口。hidden: 这种状态buffer是隐藏不显示的。inactive: 这种状态buffer 既不显示也不包含任何东西。

409 Conflict

客户端请求本身没问题,但是服务端对应的资源跟客户端要执行的操作有冲突。比如客户端要修改 版本1的某个资源,但是服务端着个资源只有在 版本2 才存在。

4. Lock 接口相比 synchronized 关键字的优势

我们通过两个个案例分析来了解 Lock 接口的优势所在。案例 1 :在使用 synchronized 关键字的情形下,假如占有锁的线程由于要等待 IO 或者其他原因(比如调用 sleep 方法)被阻塞了,但是又没有释放锁,那么其他线程就只能一直等待,别无他法。这会极大影响程序执行效率。案例 1 分析:该案例体现了 synchronized 的缺陷,当线程被占有时,其他线程会陷入无条件的长期等待。这是非常可怕的,因为系统资源有限,最终可能导致系统崩溃。案例 1 解决:Lock 接口中的 tryLock (long time, TimeUnit unit) 方法或者响应中断 lockInterruptibly () 方法,能够解决这种长期等待的情况。案例 2 :我们知道,当多个线程读写文件时,读操作和写操作会发生冲突现象,写操作和写操作也会发生冲突现象,但是读操作和读操作不会发生冲突现象。但是如果采用 synchronized 关键字实现同步的话,就会导致一个问题,即当多个线程都只是进行读操作时,也只有一个线程可以进行读操作,其他线程只能等待锁的释放而无法进行读操作。案例 2 分析:该案例体现了 synchronized 的缺陷,悲观锁的缺陷。我们说过,如果只是读操作,没有增删改操作的话,多线程环境下无需加锁。但是这种情况下,如果在同一时间多个线程进行读操作,synchronized 会 block 其他的读操作,这是不合理的。案例 2 解决:Lock 接口家族也可以解决这种情况,后续我们会对 ReadWriteLock 接口的一个子类 ReentrantReadWriteLock 进行讲解。总结:Lock 接口实现提供了比使用 synchronized 方法和语句可获得的更广泛的锁定操作,能够解决 synchronized 不能够避免的问题。

1.1 缓冲区列表

我们可以同时"编辑多个文件(缓冲区)",我们可以在这些缓冲区中切换使用。我们可以通过三种命令展示缓冲区列表::files:buffers:ls:buffers 1 %a "main.tf" line 1 2 "jmx_exporter.json" line 0 3 "bind_exporter.json" line 0:ls 1 %a "main.tf" line 1 2 "jmx_exporter.json" line 0 3 "bind_exporter.json" line 0:files 1 %a "main.tf" line 1 2 "jmx_exporter.json" line 0 3 "bind_exporter.json" line 0这里可以看到三个命令结果都一样的。我们具体看下结果展示各个部分的意思。第一列第二列第三列第四列缓冲区序列号指示状态文件名光标位置这里有点难理解的是指示状态:- 只读缓冲区a 活动缓冲区,当前显示在屏幕上的h 隐藏缓冲区% 当前的缓冲区# 交换缓冲区+ 已经更改的缓冲区

1.2 缓冲区列表操作

指令含义:bp[revious]上一个缓冲区:bn[ext]下一个缓冲区:bf[irst]到第一个缓冲区:bl[ast]到最后一个缓冲区:buffer Nubmer/File_name指定缓冲区:ball编辑所有缓冲区:badd add.txt增加一个缓冲区:bdelete add.txt删除一个缓冲区:bufdo %s/pattern/replace/ge | update多buffer查找替换下面我会依次演示上面的操作:1.2.1 移动操作我们先来看下缓冲区如何进行移动操作:1.2.2 增删操作这里我们演示一下如何增加或删除一个缓冲区:

3. RESTful 风格后端接口

前后端分离时,后端接口可不能太随意,目前后端接口编写大多遵循 RESTful 风格。做后端接口的公司这么多,如果大家都定义自己的规范,是不利于公司之间的合作的。如果大家都能遵循一个规范来开发接口,很明显相关人员都能省心不少。RESTful 就是一种非常流行的 HTTP 接口规范,简单明了,使用的人也多,用它准没错。规范的意义,就是提供标准,提高效率。汽车行业标准化程度已经很高了,软件行业还需努力!(图片来源于网络,版权归原作者所有)

1. host 模式

host 模式下启动的容器,网络不再与宿主机隔离,访问容器服务可以直接使用访问宿主机对应的网络端口,且不需要端口转发。网络拓扑图如下:host 拓扑以 host 模式启动 nginx 的容器 h0:docker run -d -t --network host --name h0 nginx启动成功后,在浏览器输入任意的本机地址,都可以打开 nginx 的默认页面,访问宿主机 80 端口就是访问容器的 80 端口,它们是一致的。以 host 模式启动 nginx 的容器 h1:docker run -d -t --network host --name h1 nginx使用 docker ps -a 命令查看所有容器,发现 h1 容器没有运行:使用 docker logs h1 查看容器 h1 的日志,发现,由于宿主机 80 端口已经被 h0 容器的服务占用,使得 h1 无法获取到 此端口,导致无法正常启动。我们在学习过程中,不再使用的容器记得删除掉,释放资源和空间docker rm -f h0 h1

4. emacs 窗口栏介绍

栏目名功能与作用描述File允许你在窗口中打开文件、创建新窗口、关闭窗口、保存缓冲区和打印缓冲区Edit允许你将选择的文本剪切并赋值到剪切板,将剪切板的内容粘贴到光标当前所在位置,以及查找文本和替换文本Options提供许多 emacs 功能设定,如高亮显示、自动换行、光标类型和字体设置Buffers列出当前可用的缓冲区,可以让你在缓冲区域轻松切换Tools提供对 emacs 高级功能的访问,比如命令行界面访问、拼写检查、文件内容比较(称为diff)、发送电子邮件消息、日历以及计算器Help提供 emacs 的在线手册,以获取特定 emacs 功能的帮助

3.安装 MySQL 多实例步骤

前面章节介绍过 Windows 下安装最新版 MySQL,这里我们把下载好的安装包复制两份并分别重新命名为 “mysql3308”、“mysql3309”,如图所示:接下来介绍如何安装启动端口号分别为 3308、3309 的 MySQL 实例,如果想要配置更多 MySQL 实例,也可参考此方法新增多个 MySQL 实例。1. 进入"mysql3308"目录,新建 my.ini" 文件,内容如下:[mysqld]# 设置3308端口port=3308# 设置mysql的安装目录basedir=D:\WWW\mysql\mysql3308# 设置mysql数据库的数据的存放目录datadir=D:\WWW\mysql\mysql3308\data # 允许最大连接数max_connections=200#允许连接失败的次数。防止有人从该主机试图攻击数据库系统max_connect_errors=10# 服务端使用的字符集默认为UTF8character-set-server=utf8# 创建新表时将使用的默认存储引擎default-storage-engine=INNODB# 默认使用“mysql_native_password”插件认证default_authentication_plugin=mysql_native_password[mysql]# 设置mysql客户端默认字符集default-character-set=utf8[client]# 设置mysql客户端连接服务端时默认使用的端口port=3308default-character-set=utf8如下图所示 :2. 以管理员身份打开 cmd 命令,进入 D:WWW\mysql\mysql3308\bin 目录,执行初始化命令,命令如下: 命令 : mysqld --initialize --console初始化成功如下图所示:3. 加载 MySQL 服务,注意之前安装 MySQL 已经加载过 MySQL 服务,为了防止冲突,需要区分,命令如下: 命令 : mysqld install mysql3308加载安装成功如下图所示:4. 此时可以启动 mysql3308 服务了,启动命令如下: 命令 : net start mysql3308启动成功如下图所示:5. 用 3308 端口号登录 MySQL,登录命令如下: 命令 : mysql -uroot -p -P3308登录过程如图所示:登录成功之后如下图所示:6. 至此 安装 3308 端口 MySQL 实例完成,后续参照此方法继续完成 3309 号端口 MySQL 服务即可,每次新增一个实例要保证 my.ini 配置文件端口号配置不冲突即可,安装 3309 端口号实例如下图所示:以上为配置文件 my.ini 内容,下图为 mysql3309 服务启动过程图:

2.4 前端应用部署

前端应用的部署更加简单,我们直接在云服务器上下载 nginx 然后解压。打开网址 http://nginx.org/en/download.html ,点击下图中的链接下载即可。nginx 下载链接下载解压后,将前端页面直接放到 nginx/html 目录下即可。当然如果有很多网页,可以先在该目录下建立子目录便于归类网页。我们建立 shop-front 目录(表示商城系统的前端项目),然后将网页放入其中,效果如下:商城系统前端项目目录内容注意还需要修改 goods.html 中访问的后端 URL 地址,假设云服务器的公网 IP 为 x.x.x.x ,则修改为:实例:$.ajax({ type: "GET", url: "http://x.x.x.x:8080/goods", //后端接口地址 dataType: "json", contentType: "application/json; charset=utf-8", success: function (res) { $.each(res, function (i, v) { row = "<tr>"; row += "<td>" + v.id + "</td>"; row += "<td>" + v.name + "</td>"; row += "<td>" + v.price + "</td>"; row += "<td>" + v.pic + "</td>"; row += "</tr>"; $("#goodsTable").append(row); }); }, error: function (err) { console.log(err); } });此处解释下后端地址 http://x.x.x.x:8080/goods , HTTP 代表协议, x.x.x.x 代表云服务器公网地址, 8080 是我们后端项目的启动端口,由于我们没有在配置文件中设置,所以默认就是 8080 ,最后 goods 是控制器中设定的后端接口路径。双击 nginx.exe 启动 nginx ,由于 nginx 默认启动端口是 80 ,所以此时访问 http://x.x.x.x ,效果如下,说明 nginx 启动成功!nginx 已启动成功

3. 修改监听地址和端口

上面说到要在浏览器中输入 localhost:5000 才能看到运行效果。其中 localhost 代表本地 IP 地址,你也可以把 localhost 改成 127.0.0.1,效果和 localhost 是一样的。那么 5000 代表什么呢?其实 5000 是一个端口号,你可以把端口号理解为是门牌号。我们的电脑会为每一个应用程序划分运行区间,每一个运行区间的标识就是端口号,我们可以通过端口号来访问对应的应用程序,这和你在酒店根据门牌号找到房间是一个道理。默认情况下,Flask 应用程序监听地址 127.0.0.1 和端口 5000。如果你不想让 Flask 程序运行在 5000 端口,也可以通过参数设置可以修改默认的监听地址和端口,比如我们想让 Flask 程序运行在一个比较吉利的端口 8888 上面,可以这样修改代码:from flask import Flaskapp = Flask(__name__)@app.route('/')def hello_world(): return '<b>Hello World</b>'if __name__ == '__main__': app.run(host = '0.0.0.0', port = 8888)设定 app.run 的函数参数 host 为 ‘0.0.0.0’,表示监听每一个可用的网络接口;设定 app.run 的函数参数 port 为 8888,表示监听端口 8888。

4.2 proxy_cache 缓存实验

准备好 proxy_cache 缓存相关的配置,如下:...http { server { listen 8000; location / { default_type text/plain; return 200 '8000, server\n'; } } server { listen 8001; location / { default_type text/plain; return 200 '8001, server\n'; } } server { listen 8002; location / { default_type text/plain; return 200 '8002, server\n'; } } # 定义上游服务器 upstream backends { server 127.0.0.1:8000; server 127.0.0.1:8001; server 127.0.0.1:8002; } # proxy_cache_path 指令 proxy_cache_path /root/test/cache levels=1:2 keys_zone=nginx_cache:10m max_size=10g inactive=60m use_temp_path=off; server { listen 80; location / { proxy_pass http://backends; proxy_cache nginx_cache; # 状态码为200和301的缓存1分钟 proxy_cache_valid 200 301 1m; # 其余的缓存10分钟 proxy_cache_valid any 10m; # response响应的头信息中定义缓存的状态(有没有命中) proxy_cache_key "$host$uri$is_args$args"; expires 1d; proxy_no_cache $cookie_nocache $arg_nocache $arg_comment; proxy_no_cache $http_pragma $http_authorization; # add_header 响应添加缓冲命中结果 add_header Nginx-Cache "$upstream_cache_status"; } }...我们通过 curl 命令向 Nginx 所在主机的 80端 请求,第一次请求转发到8000端口,结果被缓存; 第2-3次请求时由缓存返回结果,所以仍然是8000端口的返回;等待超过1分钟后,缓存失效,请求被转发到8001端口进行处理,返回相应结果;最后再次请求80端口,依旧由缓存命中,返回8001端口的响应结果。参看日志记录的 http 请求。# 第一次请求,转到8000端口响应,然后缓存[shen@shen ~]$ curl http://180.76.152.1138000, server# 接下来请求全部由缓存命中[shen@shen ~]$ curl http://180.76.152.1138000, server[shen@shen ~]$ curl http://180.76.152.1138000, server[shen@shen ~]$ curl http://180.76.152.1138000, server# 缓存失效,转发到8001端口相应,并缓存结果[shen@shen ~]$ curl http://180.76.152.1138001, server# 继续命中缓存[shen@shen ~]$ curl http://180.76.152.1138001, server查看请求的响应结果:[root@server sbin]# tail -f ../logs/access.log127.0.0.1 - - [06/Feb/2020:20:14:15 +0800] "GET / HTTP/1.0" 200 13 "-" "curl/7.29.0" "-""-"103.46.244.69 - - [06/Feb/2020:20:14:15 +0800] "GET / HTTP/1.1" 200 13 "-" "curl/7.29.0" "-""MISS"103.46.244.69 - - [06/Feb/2020:20:14:23 +0800] "GET / HTTP/1.1" 200 13 "-" "curl/7.29.0" "-""HIT"103.46.244.69 - - [06/Feb/2020:20:14:26 +0800] "GET / HTTP/1.1" 200 13 "-" "curl/7.29.0" "-""HIT"127.0.0.1 - - [06/Feb/2020:20:16:10 +0800] "GET / HTTP/1.0" 200 13 "-" "curl/7.29.0" "-""-"103.46.244.69 - - [06/Feb/2020:20:16:10 +0800] "GET / HTTP/1.1" 200 13 "-" "curl/7.29.0" "-""EXPIRED"103.46.244.69 - - [06/Feb/2020:20:16:22 +0800] "GET / HTTP/1.1" 200 13 "-" "curl/7.29.0" "-""HIT"

4.前后端分离模式开发规范

前后端分离模式逐渐成为主流,随之而来的问题也很突出。通常,后端服务开发完成,开发人员会写一份后端接口调用的说明文档。不同公司、不同项目甚至不同开发人员都有各自的喜好,因而开发好的后端服务,也是千奇百怪,前端开发人员为了使用使用后端服务,必须逐个对照说明文档才能知道调用方式。小型项目还好说,大型项目接口繁杂,如果仍然采用千奇百怪的接口调用方式,就会无形中增加开发难度。那么是否有一套接口开发规范,是否有一个见名知意的接口调用方式呢?答案是有的,这就是 RESTful 规范。后续内容,我们将正式开始学习 RESTful。

3. 乐观锁与悲观锁的使用场景

简单的来说 CAS 适用于写比较少的情况下(多读场景,冲突一般较少),synchronized 适用于写比较多的情况下(多写场景,冲突一般较多)。对于资源竞争较少(线程冲突较轻)的情况,使用 synchronized 同步锁进行线程阻塞和唤醒切换以及用户态内核态间的切换操作额外浪费消耗 CPU 资源;而 CAS 基于硬件实现,不需要进入内核,不需要切换线程,操作自旋几率较少,因此可以获得更高的性能;对于资源竞争严重(线程冲突严重)的情况,CAS 自旋的概率会比较大,从而浪费更多的 CPU 资源,效率低于 synchronized。总结:乐观锁适用于写比较少的情况下(多读场景),即冲突真的很少发生的时候,这样可以省去了锁的开销,加大了系统的整个吞吐量。但如果是多写的情况,一般会经常产生冲突,这就会导致上层应用会不断地进行 retry,这样反倒是降低了性能,所以一般多写的场景下用悲观锁就比较合适。

首页上一页1234567下一页尾页
直播
查看课程详情
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号