Java 高并发核心编程 NIO、Netty、Redis、ZooKeeper

第一章 高并发时代的必备技能

1.1 Netty 为何这么火

==火爆的 Kafka 和 RocketMQ 等消息中间件、火热的 ElasticSearch 开源搜索引擎、大数据处理 Hadoop 的 RPC 框架 Avro、分布式通信框架 Dubbo ,都是用了 Netty。==

Netty 之所以受青睐,是因为它提供了异步的、事件驱动的网络应用程序框架和工具。作为一个异步框架, Netty 的所有 IO 操作都是异步非阻塞的,通过 Future-Listener 机制,用户可以方便地主动获取或者通过通知机制获得 IO 操作结果。

Netty 是互联网中间件领域使用最广泛、最核心的网络通信框架,几乎所有 Java 互联网中间件或者大数据中间件的高性能通信与传输均离不开 Netty。

1.2 高并发利器 Redis

==任何高并发的系统不可或缺的就是缓存。Redis 缓存目前已经成为缓存的事实标准。==

1.2.1 什么是 Redis

Redis 是 Remote Dictionary Server (远程字典服务器) 的缩写,最初是作为数据库的工具来使用的,是目前使用广泛、高效的开源缓存。

Redis 使用 C 语言开发,将数据保存在内存中,可以看成是一款纯内存的数据库,所以它的数据存取速度非常快。一些经常被使用并且创建时间较长的内容可以缓存到 Redis 中,而应用程序能以极快的速度存取这些内容。

Redis 的主要应用场景是缓存(数据查询、短连接、新闻内容、商品内容等)、分布式会话(Session)、聊天室的在线好友列表、任务队列(秒杀、抢购、12306等)、应用排行榜、访问统计、数据过期处理(可以精确到毫秒)。

1.2.2 Redis 成为缓存事实标准的原因

Redis 具有以下特点:

  • 速度快,不需要等待磁盘的 IO,而是在内存之间进行数据存储和查询,速度非常快。当然,缓存的数据总量不能太大,因为收到物理内存空间大小的限制。
  • 丰富的数据结构,有 String、List、Hash、Set、SortedSet 五种类型。
  • 单线程,避免了县城切换和锁机制的性能消耗。
  • 可持久化,支持 RDB 和 AOF 两种方式,将内存中的数据写入外部的物理存储设备。
  • 支持发布/订阅。
  • 支持 Lua 脚本。
  • 支持分布式锁。
  • 支持原子操作和事务。Redis 事务是一组命令的集合。一个事务中的命令要么都执行,要么都不执行。
  • 支持主从复制与高可用集群。
  • 支持管道。Redis 管道是指客户端可以将多个命令一次性发送到服务器,然后由服务器一次性返回所有结果。管道技术的优点是,在批量执行命令的应用场景中,可以大大减少网络传输的开销,提高性能。

1.3 分布式利器 ZooKeeper

ZooKeeper 是目前极为重要的分布式协调工具。

1.3.1 什么是 ZooKeeper

一个通用的无单点问题的分布式协调框架。

==ZooKeeper 的核心优势是实现了分布式环境的数据一致性==,简单地说:每时每刻我们访问 ZooKeeper 的树结构时,不同的节点返回的数据都是一致的。也就是说, 对 ZooKeeper 进行数据访问时,无论是什么时间,都不会引起“脏读”、“幻读”、“不可重复读”等问题。

“脏读”、“幻读”、“不可重复读” 是数据库事务的概念,当然, ZooKeeper 也可以被理解为一种简单的分布式数据库。

“脏读”:是指一个事务中访问到了另外一个事务未提交的数据。

“不可重复读”:是指一个事务内根据同一个条件对数据进行多次查询,但是结果却不一致,原因是其他事务对该数据进行了修改。

“幻读”:是指当两个完全相同的查询执行时,第二次查询所返回的结果集和第一次查询所返回的结果集不相同,原因是另外一个事务新增、删除了第一个事务结果集中的数据。

注意: 不可重复读和幻读的区别?

        - 不可重复读:关注的重点在于记录的更新操作,对同样的记录,再次读取后发现返回的数据值不一样了。(数据值不一样)
        - 幻读:关注的重点在于记录新增或者删除操作(数据条数发生了变化),同样的条件第一次和第二次查询出来的记录数不一样。(结果集数目不一样)

可以说, ZooKeeper 提供的是分布式系统中非常底层且必不可少的基本功能,如果开发者自己来实现这些功能且达到高吞吐、低延迟,同时还要保持一致性和可用性,实际上是非常困难的。借助 ZooKeeper 提供的这些功能,开发者就可以轻松地在 ZooKeeper 之上构建自己的各种分布式系统。

1.4 高性能 HTTP 通信技术

1.4.1 十万级以上高并发场景中的高并发 HTTP 通信技术

QPS 在十万级的 Web 应用架构大致如下图所示:

对于十万级流量的系统应用而言,其架构一般可以分为三层:服务层、接入层、客户端层。

服务层:一般执行的是 Java 应用程序,可以细分为传统的单体应用和目前主流的 Spring Cloud 分布式应用。传统的单体 Java 应用执行在 Tomcat 服务器上,目前主流的 Spring Cloud 微服务应用执行在内嵌的 Tomcat 服务器上。

接入层:主要完成鉴权、限流、反向代理和负载均衡等功能。 由于在静态资源、登录验证等简单逻辑的处理性能上 Nginx 和 Tomcat 不可同日而语(一般差别在 10 倍以上),因此接入层基本上都是使用 Nginx + Lua 扩展作为接入服务器。另外,为了保证 Nginx 接入服务器的高可用,会搭建有冗余的接入服务器,然后使用 KeepAlived 中间件进行高可用监控管理并且虚拟出外部 IP,供外部访问。

对于十万级 QPS 流量的 Web 应用,如果流量增长到百万级,可以对接入层 Nginx 进行横向扩展,甚至可以引入 LVS 进行负载均衡。

QPS 在千万级的 Web 应用架构大致如图所示:

对于千万级 QPS 的 Web 应用,除了服务层的独立 Tocmat 或者 Spring Cloud 微服务节点需要进行不断的横向扩展之外,还需要进行一下两个增强:

1)引入 LVS 负载均衡层,进行请求分发和接入层的负载均衡。

2)引入 DNS 服务器的负载均衡,可以在域名下面添加多个 IP,由 DNS 服务器进行多个 IP 之间的负载均衡,甚至可以按照就近原则为用户返回最近的服务器 IP 地址。

Last modification:July 15th, 2021 at 12:38 am
如果觉得我的文章对你有用,请随意赞赏