网站后台文章排版,2020网页游戏,在上面网站上可以做统计图,国内优秀wordpress主题前言
京东到家订单中心系统业务中#xff0c;无论是外部商家的订单生产#xff0c;或是内部上下游系统的依赖#xff0c;订单查询的调用量都非常大#xff0c;造成了订单数据读多写少的情况。
我们把订单数据存储在MySQL中#xff0c;但显然只通过DB来支撑大量的查询是不…前言
京东到家订单中心系统业务中无论是外部商家的订单生产或是内部上下游系统的依赖订单查询的调用量都非常大造成了订单数据读多写少的情况。
我们把订单数据存储在MySQL中但显然只通过DB来支撑大量的查询是不可取的。同时对于一些复杂的查询MySQL支持得不够友好所以订单中心系统使用了Elasticsearch来承载订单查询的主要压力。 Elasticsearch作为一款功能强大的分布式搜索引擎支持近实时的存储、搜索数据在京东到家订单系统中发挥着巨大作用目前订单中心ES集群存储数据量达到10亿个文档日均查询量达到5亿。
随着京东到家近几年业务的快速发展订单中心ES架设方案也不断演进发展至今ES集群架设是一套实时互备方案很好地保障了ES集群读写的稳定性下面就给大家介绍一下这个历程以及过程中遇到的一些坑。
一、网络编程基础回顾
1. Socket
Socket本身有“插座”的意思不是Java中特有的概念而是一个语言无关的标准任何可以实现网络编程的编程语言都有Socket。在Linux环境下用于表示进程间网络通信的特殊文件类型其本质为内核借助缓冲区形成的伪文件。既然是文件那么理所当然的我们可以使用文件描述符引用套接字。
与管道类似的Linux系统将其封装成文件的目的是为了统一接口使得读写套接字和读写文件的操作一致。区别是管道主要应用于本地进程间通信而套接字多应用于网络进程间数据的传递。
可以这么理解Socket就是网络上的两个应用程序通过一个双向通信连接实现数据交换的编程接口API。
Socket通信的基本流程具体步骤如下所示:
1服务端通过Listen开启监听等待客户端接入。
2客户端的套接字通过Connect连接服务器端的套接字服务端通过Accept接收客户端连接。在connect-accept过程中操作系统将会进行三次握手。
3客户端和服务端通过write和read发送和接收数据操作系统将会完成TCP数据的确认、重发等步骤。
4通过close关闭连接操作系统会进行四次挥手。
针对Java编程语言java.net包是网络编程的基础类库。其中ServerSocket和Socket是网络编程的基础类型。
SeverSocket是服务端应用类型。Socket是建立连接的类型。当连接建立成功后服务器和客户端都会有一个Socket对象示例可以通过这个Socket对象示例完成会话的所有操作。对于一个完整的网络连接来说Socket是平等的没有服务器客户端分级情况。
2. IO模型介绍
对于一次IO操作数据会先拷贝到内核空间中然后再从内核空间拷贝到用户空间中所以一次read操作会经历两个阶段
1等待数据准备
2数据从内核空间拷贝到用户空间
基于以上两个阶段就产生了五种不同的IO模式。
阻塞IO从进程发起IO操作一直等待上述两个阶段完成此时两阶段一起阻塞。非阻塞IO进程一直询问IO准备好了没有准备好了再发起读取操作这时才把数据从内核空间拷贝到用户空间。第一阶段不阻塞但要轮询第二阶段阻塞。多路复用IO多个连接使用同一个select去询问IO准备好了没有如果有准备好了的就返回有数据准备好了然后对应的连接再发起读取操作把数据从内核空间拷贝到用户空间。两阶段分开阻塞。信号驱动IO进程发起读取操作会立即返回当数据准备好了会以通知的形式告诉进程进程再发起读取操作把数据从内核空间拷贝到用户空间。第一阶段不阻塞第二阶段阻塞。异步IO进程发起读取操作会立即返回等到数据准备好且已经拷贝到用户空间了再通知进程拿数据。两个阶段都不阻塞。
这五种IO模式不难发现存在这两对关系同步和异步、阻塞和非阻塞。那么稍微解释一下
同步和异步
同步 同步就是发起一个调用后被调用者未处理完请求之前调用不返回。异步 异步就是发起一个调用后立刻得到被调用者的回应表示已接收到请求但是被调用者并没有返回结果此时我们可以处理其他的请求被调用者通常依靠事件回调等机制来通知调用者其返回结果。
同步和异步的区别最大在于异步的话调用者不需要等待处理结果被调用者会通过回调等机制来通知调用者其返回结果。
阻塞和非阻塞
阻塞 阻塞就是发起一个请求调用者一直等待请求结果返回也就是当前线程会被挂起无法从事其他任务只有当条件就绪才能继续。非阻塞 非阻塞就是发起一个请求调用者不用一直等着结果返回可以先去干其他事情。
阻塞和非阻塞是针对进程在访问数据的时候根据IO操作的就绪状态来采取的不同方式说白了是一种读取或者写入操作方法的实现方式阻塞方式下读取或者写入函数将一直等待而非阻塞方式下读取或者写入方法会立即返回一个状态值。
如果组合后的同步阻塞(blocking-IO)简称BIO、同步非阻塞(non-blocking-IO)简称NIO和异步非阻塞(asynchronous-non-blocking-IO)简称AIO又代表什么意思呢
BIO (同步阻塞I/O模式): 数据的读取写入必须阻塞在一个线程内等待其完成。这里使用那个经典的烧开水例子这里假设一个烧开水的场景有一排水壶在烧开水BIO的工作模式就是 叫一个线程停留在一个水壶那直到这个水壶烧开才去处理下一个水壶。但是实际上线程在等待水壶烧开的时间段什么都没有做。NIO(同步非阻塞): 同时支持阻塞与非阻塞模式但这里我们以其同步非阻塞I/O模式来说明那么什么叫做同步非阻塞如果还拿烧开水来说NIO的做法是叫一个线程不断的轮询每个水壶的状态看看是否有水壶的状态发生了改变从而进行下一步的操作。AIO(异步非阻塞I/O模型): 异步非阻塞与同步非阻塞的区别在哪里异步非阻塞无需一个线程去轮询所有IO操作的状态改变在相应的状态改变后系统会通知对应的线程来处理。对应到烧开水中就是为每个水壶上面装了一个开关水烧开之后水壶会自动通知我水烧开了。
java 中的 BIO、NIO和AIO理解为是 Java 语言在操作系统层面对这三种 IO 模型的封装。程序员在使用这些 封装API 的时候不需要关心操作系统层面的知识也不需要根据不同操作系统编写不同的代码只需要使用Java的API就可以了。由此为了使读者对这三种模型有个比较具体和递推式的了解并且和本文主题NIO有个清晰的对比下面继续延伸。
Java BIO
BIO编程方式通常是是Java的上古产品自JDK 1.0-JDK1.4就有的东西。编程实现过程为首先在服务端启动一个ServerSocket来监听网络请求客户端启动Socket发起网络请求默认情况下SeverSocket会建立一个线程来处理此请求如果服务端没有线程可用客户端则会阻塞等待或遭到拒绝。服务器实现模式为一个连接一个线程即客户端有连接请求时服务器端就需要启动一个线程进行处理。大致结构如下 如果要让 BIO 通信模型能够同时处理多个客户端请求就必须使用多线程主要原因是 socket.accept()、socket.read()、 socket.write() 涉及的三个主要函数都是同步阻塞的也就是说它在接收到客户端连接请求之后为每个客户端创建一个新的线程进行链路处理处理完成之后通过输出流返回应答给客户端线程销毁。这就是典型的 一请求一应答通信模型 。我们可以设想一下如果这个连接不做任何事情的话就会造成不必要的线程开销不过可以通过线程池机制改善线程池还可以让线程的创建和回收成本相对较低。使用线程池机制改善后的 BIO 模型图如下: BIO方式适用于连接数目比较小且固定的架构这种方式对服务器资源要求比较高并发局限于应用中是JDK1.4以前的唯一选择但程序直观简单易懂。Java BIO编程示例网上很多这里就不进行coding举例了毕竟后面NIO才是重点。
Java NIO
NIONew IO或者No-Blocking IO从JDK1.4 开始引入的非阻塞IO是一种非阻塞 同步的通信模式。这里的No Blocking IO用于区分上面的BIO。
NIO本身想解决 BIO的并发问题通过Reactor模式的事件驱动机制来达到Non Blocking的。当 socket 有流可读或可写入 socket 时操作系统会相应的通知应用程序进行处理应用再将流读取到缓冲区或写入操作系统。
也就是说这个时候已经不是一个连接就 要对应一个处理线程了而是有效的请求对应一个线程当连接没有数据时是没有工作线程来处理的。
当一个连接创建后不需要对应一个线程这个连接会被注册到 多路复用器上面所以所有的连接只需要一个线程就可以搞定当这个线程中的多路复用器 进行轮询的时候发现连接上有请求的话才开启一个线程进行处理也就是一个请求一个线程模式。
NIO提供了与传统BIO模型中的Socket和ServerSocket相对应的SocketChannel和ServerSocketChannel两种不同的套接字通道实现如下图结构所示。这里涉及的Reactor设计模式、多路复用Selector、Buffer等暂时不用管后面会讲到。 NIO 方式适用于连接数目多且连接比较短(轻操作)的架构比如聊天服务器并发局 限于应用中编程复杂JDK1.4 开始支持。同时NIO和普通IO的区别主要可以从存储数据的载体、是否阻塞等来区分 Java AIO
与 NIO 不同当进行读写操作时只须直接调用 API 的 read 或 write 方法即可。这两种方法均为异步的对于读操作而言当有流可读取时操作系统会将可读的流传入 read 方 法的缓冲区并通知应用程序对于写操作而言当操作系统将 write 方法传递的流写入完毕时操作系统主动通知应用程序。即可以理解为read/write 方法都是异步的完成后会主动调用回调函数。在 JDK7 中提供了异步文件通道和异步套接字通道的实现这部分内容被称作 NIO.
AIO 方式使用于连接数目多且连接比较长(重操作)的架构比如相册服务器充分调用 OS 参与并发操作编程比较复杂JDK7 开始支持。
目前来说 AIO 的应用还不是很广泛Netty 之前也尝试使用过 AIO不过又放弃了。
二、NIO核心组件介绍
1. Channel
在NIO中基本所有的IO操作都是从Channel开始的Channel通过Buffer(缓冲区)进行读写操作。
read()表示读取通道中数据到缓冲区write()表示把缓冲区数据写入到通道。 Channel有好多实现类这里有三个最常用
SocketChannel一个客户端发起TCP连接的ChannelServerSocketChannel一个服务端监听新连接的TCP Channel对于每一个新的Client连接都会建立一个对应的SocketChannelFileChannel从文件中读写数据
其中SocketChannel和ServerSocketChannel是网络编程中最常用的一会在最后的示例代码中会有讲解到具体用法。
2. Buffer
概念
Buffer也被成为内存缓冲区本质上就是内存中的一块我们可以将数据写入这块内存之后从这块内存中读取数据。也可以将这块内存封装成NIO Buffer对象并提供一组常用的方法方便我们对该块内存进行读写操作。
Buffer在java.nio中被定义为抽象类 我们可以将Buffer理解为一个数组的封装我们最常用的ByteBuffer对应的数据结构就是byte[]
属性
Buffer中有4个非常重要的属性capacity、limit、position、mark 最后
现在其实从大厂招聘需求可见在招聘要求上有高并发经验优先包括很多朋友之前都是做传统行业或者外包项目一直在小公司技术搞的比较简单没有怎么搞过分布式系统但是现在互联网公司一般都是做分布式系统。
所以说如果你想进大厂想脱离传统行业这些技术知识都是你必备的下面自己手打了一份Java并发体系思维导图希望对你有所帮助。
资料获取方式戳这里免费下载
怎么搞过分布式系统但是现在互联网公司一般都是做分布式系统。
所以说如果你想进大厂想脱离传统行业这些技术知识都是你必备的下面自己手打了一份Java并发体系思维导图希望对你有所帮助。
资料获取方式戳这里免费下载