前端webstock访问后端netty,可以正常建立连接,但是不能打开,帮帮忙看一下后端代码哪里有问题?

为什么程序需要使用锁?
通俗的说就是多个线程同时对一个资源进行访问时,如果不加锁会造成线程安全问题。
举例:比如有一件商品的库存只有3,但是有5个人进来买,买了一张库存就减1,在他们购买的时候会判断是否还有库存,但是在他们购买的那一刻,库存还剩余2。但是他们都已经点击购买了,过了是否有库存的校验了,所以最后库存被减成负2,显然是不对的,因为库存不能小于0,所以需要加一个锁,在同一时刻只能有一个人进行购买,也就是同一个资源同一个时刻只能有一个线程进行操作。


这层就不粘贴代码了下面实现里面有。

通过结果可以看到,如果不加锁进行并发访问,出现了非常大的漏洞。

我们使用多个线程访问8080这个端口。因为没有加锁,此时肯定会出现并发问题。因此就立马能想到java中的各种锁了,最有名的就是synchronized。所以我们不如对上面的代码进行优化。


 

测试发现,同步锁起作用了,不会出现上述的现象。

我们目前模拟的只是将项目部署在一个服务器上进行并发访问。而实际部署中,面对大量的并发访问,我们采用的是使用Nginx进行反向代理多个服务器,那么会不会出现问题呢?下面模拟测试。

原理:实际的项目部署并不会只部署在一个服务器上,且请求并不会直接发送到项目接口,而是通过Nginx进行反向代理多台服务器,隐藏实际的项目地址。

为了模拟Nginx反向代理多个服务器。我们就把同一个程序开启了三个端口,使Nginx代理三个服务器。

5.1 将项目换个端口号再启动两个分别为8081、8082

我们之前使用synchronized 同步锁只对同一个服务器的并发访问起了作用。而当我们进行Nginx进行反向代理多个服务器时,synchronized 不会对其他服务器进行起作用,就又出现了问题。

使用分布式锁必须要考虑的一些问题。

  • 互斥性:在任意时刻,只能有一个进程持有锁。

  • 防死锁:即使有一个进程在持有锁的期间崩溃而未能主动释放锁,要有其他方式去释放锁从而保证其他进程能获取到锁。

  • 加锁和解锁的必须是同一个进程。

首先,redis是单线程的,这是前提条件。

指定一个 key 作为锁标记,存入 Redis 中,指定一个 唯一的用户标识 作为 value。
当 key 不存在时才能设置值,确保同一时间只有一个客户端进程获得锁,满足 互斥性 特性。
设置一个过期时间,防止因系统异常导致没能删除这个 key,满足 防死锁 特性。
当处理完业务之后需要清除这个 key 来释放锁,清除 key 时需要校验 value 值,需要满足 只有加锁的人才能释放锁 。

在进行数据库的操作之前,先通过redis设置一个key-value,相当于设置了一个标识加了个锁。如果加锁成功,那么可以操作数据库。
如果加锁失败,拒绝操作数据库。
这样的话,当线程A加锁成功,线程B访问接口是,发现加锁失败,就不会去操作数据库了。

但是这样的设计还是存在缺陷的。锁的续期无法实现。
实际项目中,redis设置的key需要设置一个存活时间。假如存活时间是3S,而线程A加锁成功然后去执行程序花了5s时间,那么就会出现程序没有执行完成,其余的线程发现已经没有了锁,也会去操作数据库。这是就会出现问题了。我们通过代码瞅一下。

return "服务器在忙稍后重试。。。。。。。。。。";

可以看到,虽然设置redis分布式锁,但是在高并发访问时还是出现了较大的问题。

Netty框架上,充分的利用了Redis键值数据库提供的一系列优势,在Java实用工具包
中常用接口的基础上,为使用者提供了一系列具有分布式特性的常用工具类。使得原
本作为协调单机多线程并发程序的工具包获得了协调分布式多机多线程并发系统的能
力,大大降低了设计和研发大规模分布式系统的难度。同时结合各富特色的分布式服
务,更进一步简化了分布式环境中程序相互之间的协作。

线程去获取锁,获取成功: 执行lua脚本,保存数据到redis数据库。

线程去获取锁,获取失败: 一直通过while循环尝试获取锁,获取成功后,执行lua脚本,保存数据到redis数据库。

6.2.1.3 看门狗自动延期锁的机制

在一个分布式环境下,假如一个线程获得锁后,突然服务器宕机了,那么在一定时间后这个锁会自动释放,也可以设置锁的有效时间(不设置默认30秒),这样的目的主要是防止死锁的发生。这种情况的出现就会导致redis普通分布式锁出现的问题。
所以这个时候看门狗就出现了,它的作用就是 线程1 业务还没有执行完,锁的时间就过了,线程1 还想持有锁的话,就会启动一个watch dog后台线程,不断的延长锁key的生存时间。其余的线程就进不来了。

传统的HTTP协议是无状态的,每次请求(request)都要由客户端(如 浏览器)主动发起,服务端进行处理后返回response结果,而服务端很难主动向客户端发送数据;这种客户端是主动方,服务端是被动方的传统Web模式 对于信息变化不频繁的Web应用来说造成的麻烦较小,而对于涉及实时信息的Web应用却带来了很大的不便,如带有即时通信、实时数据、订阅推送等功能的应 用。在WebSocket规范提出之前,开发人员若要实现这些实时性较强的功能,经常会使用折衷的解决方法:轮询(polling)和Comet技术。其实后者本质上也是一种轮询,只不过有所改进。
  轮询是最原始的实现实时Web应用的解决方案。轮询技术要求客户端以设定的时间间隔周期性地向服务端发送请求,频繁地查询是否有新的数据改动。明显地,这种方法会导致过多不必要的请求,浪费流量和服务器资源。
  Comet技术又可以分为长轮询和流技术。长轮询改进了上述的轮询技术,减小了无用的请求。它会为某些数据设定过期时间,当数据过期后才会向服务端发送请求;这种机制适合数据的改动不是特别频繁的情况。流技术通常是指客户端使用一个隐藏的窗口与服务端建立一个HTTP长连接,服务端会不断更新连接状态以保持HTTP长连接存活;这样的话,服务端就可以通过这条长连接主动将数据发送给客户端;流技术在大并发环境下,可能会考验到服务端的性能。
  这两种技术都是基于请求-应答模式,都不算是真正意义上的实时技术;它们的每一次请求、应答,都浪费了一定流量在相同的头部信息上,并且开发复杂度也较大。

我要回帖

更多关于 能ping通网关但是不能访问网页 的文章

 

随机推荐