1.什么是高并发
1. 通过英文意思上去脑补
英文为High Concurrency,词义上分析,currency是流通货币的意思,con有一起的意思,
合在一起就是一起抢钱,加上high就是疯狂一起抢钱了。
2. 就如下图那样就是高并发了。
3. 那么我们希望这种事情的发生么?
4. 答案是:我们希望,我们也不希望
5. 我们希望的是我们的网站或者我们的商店能够有这么大的热度达到被抢购的状态。
6. 我们不希望的是如此高并发而导致如下图那样的拥堵,从而导致客户体验度差。
7. 所以高并发是互联网分布式系统架构设计中必须考虑的因素之一。
8. 它指的是通过一定的系统设计保证系统能够同时并行处理很多请求
9. 从而使得减少如下图的那种状况的发生。
2.1. 为什么只谈并发编程而不怎么谈并行编程呢?
1. 通过2.2.的区别分析可以看出,在理想环境下,大家都是王思聪,不考虑成本问题的情况下
2. 明显并行得优于并发的,不管来多少人访问我的网站,我都给你vip待遇,就不会造成拥堵了。
3. 然,现实总归是现实。即然一个人可以多件事情,why not,尽可能的加以利用咯。
4. 所以并发编程就在web编程中变得尤为重要了,但也同时带来了诸多需要考虑的问题。
5. 但也不是说不谈并行编程,并行计算是大数据平台的主角,是分而治之思想的一个主要思想
6. 实际上,我们架构也是 并行+并发 的模式,以达到最高效的解决“拥堵”的问题。
2.2. 并发与并行是什么区别呢?
并发(Concurrency):一个实体在一定时间间隔内干多件事情-->逻辑上的同时执行任务-->单核多线程
并行(parallelism):多个实体在同一时间干多件事情-->物理上的同时执行任务-->多核执行
那么如何提高系统的并发能力
scale up:垂直扩展-->提升单机处理能力(cpu的核数,内存的容量,硬盘的存储容量和访问速度,网络带宽的速度)-->简单暴力也最有效
sacle out:水平扩展-->增加服务器,线性扩充系统系能-->复杂但长远来说更有效
水平扩展的方式
1. 反向代理层的水平扩展:dns轮询
2. 应用服务器层的水平扩展:nginx反向代理
3. 服务层的水平扩展:服务连接池
4. 数据层的水平扩展:缓存数据库,master-slave数据库,范围拆分,hash拆分
5. 线程的水平扩展:多线程--->垂直扩展当然也得用多线程,是一个基本的提升性能的操作
高并发-多线程-传统IO
阻塞:在server.accept(),inputStream.read(bytes)阻塞
所以,得使用线程池来保证多线程的使用
线程池使用案例
#服务端代码
public class OioServer {
public static void main(String[] args) throws Exception {
ExecutorService pool= Executors.newCachedThreadPool();
ServerSocket server=new ServerSocket(6666);
System.out.println("server start");
while (true){
final Socket socket=server.accept();
System.out.println("client in");
pool.execute(new Runnable() {
@Override
public void run(){
handler(socket);
}
});
}
}
public static void handler(Socket socket){
try{
byte[] bytes=new byte[1024];
InputStream inputStream=socket.getInputStream();
while (true){
int read=inputStream.read(bytes);
if(read != -1){
System.out.println(new String(bytes,0,read));
}else{
break;
}
}
} catch (Exception e){
e.printStackTrace();
}finally {
try{
System.out.println("socket close");
}catch (Exception e){
e.printStackTrace();
}
}
}
}
#客户端使用telnet去访问服务端
telnet localhost 6666
高并发-多线程-NIO
#服务端代码
public class NioServer {
private Selector selector;
public void initServer(int port) throws Exception{
ServerSocketChannel serverSocketChannel =ServerSocketChannel.open();
serverSocketChannel.configureBlocking(false);
serverSocketChannel.socket().bind(new InetSocketAddress(port));
this.selector=Selector.open();
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
}
public void listen() throws Exception{
System.out.println("server start");
while (true){
selector.select();
Iterator<?> ite=this.selector.selectedKeys().iterator();
while (ite.hasNext()){
SelectionKey key= (SelectionKey) ite.next();
ite.remove();
handler(key);
}
}
}
public void handler(SelectionKey key) throws Exception{
if(key.isAcceptable()){
handlerAccept(key);
}else if(key.isReadable()){
handleRead(key);
}
}
public void handlerAccept(SelectionKey key) throws Exception{
ServerSocketChannel server=(ServerSocketChannel)key.channel();
SocketChannel channel=server.accept();
channel.configureBlocking(false);
System.out.println("client in");
channel.register(this.selector,SelectionKey.OP_READ);
}
public void handleRead(SelectionKey key) throws Exception{
SocketChannel channel = (SocketChannel) key.channel();
ByteBuffer buffer=ByteBuffer.allocate(20);
channel.read(buffer);
byte[] data=buffer.array();
String msg=new String(data).trim();
System.out.println("server msg:" + msg);
ByteBuffer outbuffer=ByteBuffer.wrap(msg.getBytes());
channel.write(outbuffer);
}
public static void main(String[] args) throws Exception{
NioServer nioServer=new NioServer();
nioServer.initServer(7777);
nioServer.listen();
}
}
#客户端使用telnet去访问服务端
telnet localhost 7777
高并发-多线程-IOvsNIO
NIO IO
ServerSocketChannel ServerSocket #带频道的监听端口 vs 监听端口
SocketChannel Socket #带频道的Socket服务 vs Socket服务
ByteBuffer Stream #缓冲区 vs 数据流
Selector,SelectionKey #选择器 vs 空空如也