[自己做个游戏服务器二] 游戏服务器的基石-Netty全解析,有例子,多图解释

本文涉及的产品
云解析 DNS,旗舰版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
云解析DNS,个人版 1个月
简介: Netty的大名我想做java 的基本都知道,因为他实在太出名了,现在很多著名的软件都是使用netty作为通讯基础,今天就聊聊Netty,希望能讲清楚,如果懒得看理论,可以直接拉到后面看Hello world。把代码抄下来,运行一下看看。

Netty的大名我想做java 的基本都知道,因为他实在太出名了,现在很多著名的软件都是使用netty作为通讯基础,今天就聊聊Netty,希望能讲清楚,如果懒得看理论,可以直接拉到后面看Hello world。把代码抄下来,运行一下看看。


1、Netty 是什么


Netty是一个高性能、异步事件驱动的NIO框架,基于JAVA NIO提供的API实现。它提供了对TCP、UDP和文件传输的支持

作为一个异步NIO框架,Netty的所有IO操作都是异步非阻塞的,通过Future-Listener机制,用户可以方便的主动获取或者通过通知机制获得IO操作结果。


作为当前最流行的NIO框架,Netty在互联网领域、大数据分布式计算领域、游戏行业、通信行业等获得了广泛的应用,一些业界著名的开源组件也基于Netty的NIO框架构建。


Netty的官网 :netty.io/


41e87da8f55842d6b881bbb42c0bb8a1~tplv-k3u1fbpfcp-zoom-in-crop-mark_1304_0_0_0.webp.jpg

2、Netty的优点

4861c11a2ce84fc89f8682e407dd200a~tplv-k3u1fbpfcp-zoom-in-crop-mark_1304_0_0_0.webp.jpg

Netty的缺点就不说了,Netty的优点有很多:


统一的 API,支持多种传输类型,阻塞和非阻塞的。


功能强大,内置了多种解码编码器,支持多种协议,比如上图中的右侧黄色区域,通用的文本,二进制协议,google protobuf等。


性能高,对比其他主流的NIO框架,Netty的性能最优。


社区活跃,发现BUG会及时修复,迭代版本周期短,不断加入新的功能。


简单而强大的线程模型。


自带编解码器解决 TCP 粘包/拆包问题。


自带各种协议栈,比如 SSL 。


比直接使用 Java 核心 API 有更高的吞吐量、更低的延迟、更低的资源消耗和更少的内存复制,Zero-Copy Byte buffer。

安全性不错,有完整的 SSL/TLS 以及 StartTLS 支持。


成熟稳定,经历了大型项目的使用和考验,而且很多开源项目都使用到了 Netty, 比如我们经常接触的 Dubbo、RocketMQ ,Elasticsearch等等。


3、核心组件


3.1 Netty的线程模型


Netty的线程模型是比较重要的,理解了Netty的线程模型才能很好地使用Netty,Netty常见的线程模型有三种:


1.单线程模型


单线程模型,是指所有的 I/O 操作都在同一个 NIO 线程上面完成的,此时NIO线程职责包括:接收新建连接请求、读写操作等,在游戏开发中不会使用,也不合理,不展开。


2.Reactor多线程模型


第一种不合理,升级一下,一个接受连接的线程, 所有的 I/O 操作都在同一个 NIO 线程池上面完成,这种线程模型可以满足大部分情况,但是如果在连接的时候需要做一些验证,就会阻塞线程。性能会出问题,服务器


3.Reactor主从多线程模型


服务端用于接收客户端连接的不再是一个单独的 NIO 线程,而是一个独立的 NIO 线程池。Acceptor 接收到客户端 TCP连接请求并处理完成后(可能包含接入认证等),将新创建的 SocketChannel注 册 到 I/O 线 程 池(sub reactor 线 程 池)的某个I/O线程上, 由它负责SocketChannel 的读写和编解码工作。Acceptor 线程池仅仅用于客户端的登录、握手和安全认证,一旦链路建立成功,就将链路注册到后端 subReactor 线程池的 I/O 线程上,由 I/O 线程负责后续的 I/O 操作。


这也是在游戏开发中最常用的线程模型,需要掌握,下面这张图将核心技术都做了展示

246c6159dcf14981a9c3049f90202fcf~tplv-k3u1fbpfcp-zoom-in-crop-mark_1304_0_0_0.webp.jpg

3.2 EventLoopGroup


NioEventLoopGroup 核心实际上就是个线程池,是为了处理IO事件而存在的一个线程池。


一个 EventLoopGroup 包含一个或者多个 EventLoop;一个 EventLoop 在它的生命周期内只和一个 Thread 绑定;所有有 EnventLoop 处理的 I/O 事件都将在它专有的 Thread 上被处理;一个 Channel 在它的生命周期内只注册于一个 EventLoop;每一个 EventLoop 负责处理一个或多个 Channel;


我们实现服务端的时候,一般会初始化两个线程组:


bossGroup :接收连接。


workerGroup :负责具体的处理,交由对应的 Handler 处理


BossEventLoop 只负责处理连接,开销非常小,连接到来,马上将 SocketChannel 转发给 WorkerEventLoopGroup,WorkerEventLoopGroup 会由 next 选择其中一个 EventLoop 来将这 个SocketChannel 注册到其维护的 Selector 并对其后续的 IO 事件进行处理。


注:默认的线程数量 是当前cpu 数量 *2


public abstract class MultithreadEventLoopGroup extends MultithreadEventExecutorGroup implements EventLoopGroup {
   private static final InternalLogger logger = InternalLoggerFactory.getInstance(MultithreadEventLoopGroup.class);
   private static final int DEFAULT_EVENT_LOOP_THREADS = Math.max(1, SystemPropertyUtil.getInt("io.netty.eventLoopThreads", NettyRuntime.availableProcessors() * 2));
   protected MultithreadEventLoopGroup(int nThreads, Executor executor, Object... args) {
       super(nThreads == 0 ? DEFAULT_EVENT_LOOP_THREADS : nThreads, executor, args);
  }
复制代码


3.3 Channel


Channel 表示一个和客户端建立的连接,相当于电话建立了连接,Channel是双向的通道。


通道(Channel)是双向的,可读可写。在 Java NIO 中,Buffer 是一个顶层接口,它的常用子类有:


FileChannel:用于文件读写


DatagramChannel:用于 UDP 数据包收发


ServerSocketChannel:用于服务端 TCP 数据包收发


SocketChannel:用于客户端 TCP 数据包收发


游戏中常用的通道类型有以下:


NioSocketChannel:异步非阻塞的客户端 TCP Socket 连接。


NioServerSocketChannel:异步非阻塞的服务器端 TCP Socket 连接。


常用的就是这两个通道类型,因为是异步非阻塞的。所以是首选。


3.4  option()与childOption()


首先说一下这两个的区别。


option()设置的是服务端用于接收进来的连接,也就是boosGroup线程。


childOption()是提供给父管道接收到的连接,也就是workerGroup线程。


搞清楚了之后,我们看一下常用的一些设置有哪些:


SocketChannel参数,也就是childOption()常用的参数:


SO_RCVBUF Socket参数,TCP数据接收缓冲区大小。TCP_NODELAY TCP参数,立即发送数据,默认值为Ture。


SO_KEEPALIVE Socket参数,连接保活,默认值为False。启用该功能时,TCP会主动探测空闲连接的有效性。


ServerSocketChannel参数,也就是option()常用参数:


SO_BACKLOG Socket参数,服务端接受连接的队列长度,如果队列已满,客户端连接将被拒绝。默认值,Windows为200,其他为128。


3.5  inbound 和 outbound


inbound  表示 消息进入到服务器的路径,可以理解为输入


outBound 表示 消息输出到客户端的路径,可以理解为输出


ChannelPipeline p = ...;
  p.addLast("1", new InboundHandlerA());
  p.addLast("2", new InboundHandlerB());
  p.addLast("3", new OutboundHandlerA());
  p.addLast("4", new OutboundHandlerB());
  p.addLast("5", new InboundOutboundHandlerX());
复制代码


当一个输入事件来了之后,事件处理器的调用顺序为1,2,5


当一个输出事件来了之后,事件处理器的处理顺序为5,4,3。(注意输出事件的处理器发挥作用的顺序与定义的顺序是相反的)

可以理解为对handler 进行压栈操作。


ChannelInboundHandlerAdapter处理器常用的事件有:


注册事件 fireChannelRegistered。


连接建立事件 fireChannelActive。


读事件和读完成事件 fireChannelRead、fireChannelReadComplete。


异常通知事件 fireExceptionCaught。


用户自定义事件 fireUserEventTriggered。


Channel 可写状态变化事件 fireChannelWritabilityChanged。


连接关闭事件 fireChannelInactive。


ChannelOutboundHandler处理器常用的事件有:


端口绑定 bind。


连接服务端 connect。


写事件 write。


刷新时间 flush。


读事件 read。


主动断开连接 disconnect。


关闭 channel 事件 close。


还有一个类似的handler(),主要用于装配parent通道,也就是bossGroup线程。一般情况下,都用不上这个方法。


3.6 ByteBuf


ByteBuff有三种类型:


堆内存缓冲区(HeapByteBuf)


数据存储在堆中,可以认为就是我们常用的内存缓冲区


直接内存缓冲区(DirectByteBuf)


数据存储在内核中。由于数据本身就存储在内核中,因此使用网卡传输数据的时候直接可以传输,不需要多余的拷贝。因此,这也被称为零拷贝。


从硬盘中读取数据使用网卡发送出去,一般步骤如下:


数据从磁盘读取到内核的read buffer数据从内核缓冲区拷贝到用户缓冲区数据从用户缓冲区拷贝到内核的socket buffer

数据从内核的socket buffer拷贝到网卡接口(硬件)的缓冲区使用内存缓冲区只需要两步:


调用transferTo,数据从文件由DMA引擎拷贝到内核read buffer接着DMA从内核read buffer将数据拷贝到网卡接口buffer


6251ed73d1564f7e81bd111c9a122037~tplv-k3u1fbpfcp-zoom-in-crop-mark_1304_0_0_0.webp.jpg

复合缓冲区(CompositeByteBuf)


复合缓冲区可以将多个ByteBuff组合


注:即内核功能模块运行在内核空间,而应用程序运行在用户空间

5eb6c52831674c2aa246f64e14d1448b~tplv-k3u1fbpfcp-zoom-in-crop-mark_1304_0_0_0.webp.jpg

ByteBuf有读readerIndex和写writerIndex两个指针,用来标记“可读”、“可写”、“可丢弃”的字节


调用write*方法写入数据后,写指针将会向后移动


调用read*方法读取数据后,读指针将会向后移动


写入数据或读取数据时会检查是否有足够多的空间可以写入和是否有数据可以读取


写入数据之前,会进行容量检查,当剩余可写的容量小于需要写入的容量时,需要执行扩容操作


扩容时有一个4MB的阈值,需要扩容的容量小于阈值或大于阈值所对应的扩容逻辑不同


clear等修改读写指针的方法,只会更改读写指针位置的值,并不会影响ByteBuf中已有的内容


setZero等修改字节值的方法,只会修改对应字节的值,不会影响读写指针的值以及字节的可读写状态


Netty又为我们提供了两个工具类:Pooled、Unpooled,分类用来分配池化的和未池化的ByteBuf,进一步简化了创建ByteBuf的步骤,只需要调用这两个工具类的静态方法即可。


fa227e18d78b4f4aa6e4b9ac522ff83e~tplv-k3u1fbpfcp-zoom-in-crop-mark_1304_0_0_0.webp.jpg


3.7 使用 Netty 自带的解码器


LineBasedFrameDecoder :


发送端发送数据包的时候,每个数据包之间以换行符作为分隔,LineBasedFrameDecoder 的工作原理是它依次遍历 ByteBuf 中的可读字节,判断是否有换行符,然后进行相应的截取。


DelimiterBasedFrameDecoder :


可以自定义分隔符解码器,LineBasedFrameDecoder 实际上是一种特殊的 DelimiterBasedFrameDecoder 解码器。


FixedLengthFrameDecoder:


固定长度解码器,它能够按照指定的长度对消息进行相应的拆包,每个数据包的长度都是固定的。


LengthFieldBasedFrameDecoder:


这个是后面服务器将要使用的解码器,下期会有实例


3.8 Netty 版本


netty5 中使用了 ForkJoinPool,增加了代码的复杂度,但是对性能的改善却不明显


多个分支的代码同步工作量很大


作者觉得当下还不到发布一个新版本的时候


在发布版本之前,还有更多问题需要调查一下,比如是否应该废弃 exceptionCaught, 是否暴露EventExecutorChooser等等。


当前最新版本:4.1.68.Final


4、Hello World


4.1 官方的demo


官方的demo下载源码就可以在example下看到所有的demo,


gitHub 地址:github.com/netty/netty…

88b76a984fb8432cab04c6a14012ea67~tplv-k3u1fbpfcp-zoom-in-crop-mark_1304_0_0_0.webp.jpg

4.2 idea 建立maven项目


我这里使用了idea,所以下面的截图也是用Idea。


4.2.1 File ->New 进入下面的界面

25e0d81da259466bac84babbb3c09178~tplv-k3u1fbpfcp-zoom-in-crop-mark_1304_0_0_0.webp.jpg

4.2.2  next 如下图填入自己的信息

6782333e7c7d42b9a4a8c60e71ce09d7~tplv-k3u1fbpfcp-zoom-in-crop-mark_1304_0_0_0.webp.jpg

4.2.3 等待一下,知道maven加载项目完成,如下结构

dee71bd2c6584828bd1af80c1d168d53~tplv-k3u1fbpfcp-zoom-in-crop-mark_1304_0_0_0.webp.jpg

4.3 服务端代码


为了尽可能的仅仅展示Netty的代码,去掉那些花里胡哨的技术,只是简单的程序


package com.xiangcai;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
/**
* 服务端代码
* @author 香菜
*/
public class GameServer {
   /**
    * 启动
    */
   public static void start() throws InterruptedException {
       EventLoopGroup boss = new NioEventLoopGroup(1);
       EventLoopGroup worker = new NioEventLoopGroup();
       try {
           ServerBootstrap serverBootstrap = new ServerBootstrap();
           serverBootstrap.group(boss, worker)
                  .channel(NioServerSocketChannel.class)
                   //服务端可连接队列数,对应TCP/IP协议listen函数中backlog参数
                  .option(ChannelOption.SO_BACKLOG, 1024)
                   //设置TCP长连接,一般如果两个小时内没有数据的通信时,TCP会自动发送一个活动探测数据报文
                  .childOption(ChannelOption.SO_KEEPALIVE, true)
                   //将小的数据包包装成更大的帧进行传送,提高网络的负载,即TCP延迟传输
                  .childOption(ChannelOption.TCP_NODELAY, true)
                  .childHandler(new NettyServerHandlerInitializer());
           ChannelFuture channelFuture = serverBootstrap.bind(8088).sync();
           System.out.println("服务器启动了");
           channelFuture.channel().closeFuture().sync();
      } finally {
           // 关闭线程
           boss.shutdownGracefully();
           worker.shutdownGracefully();
      }
  }
   public static void main(String[] args) throws InterruptedException {
       start();
  }
}
复制代码


下面看下Channel的初始化代码:


使用了2个解码器


package com.xiangcai;
import io.netty.channel.Channel;
import io.netty.channel.ChannelInitializer;
import io.netty.handler.codec.LineBasedFrameDecoder;
import io.netty.handler.codec.string.StringDecoder;
/**
* 服务端代码
* @author 香菜
*/
public class NettyServerHandlerInitializer extends ChannelInitializer<Channel> {
   @Override
   protected void initChannel(Channel ch) throws Exception {
       ch.pipeline()
               //基于换行符的解码器
              .addLast(new LineBasedFrameDecoder(1024))
               // 强转字符串
              .addLast(new StringDecoder())
               // 业务处理
              .addLast(new NettyServerHandler());
  }
}
复制代码


下面是业务的代码展示:


这里只是展示了简单的收发消息


package com.xiangcai;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
/**
* 服务端代码
* @author 香菜
*/
public class NettyServerHandler extends ChannelInboundHandlerAdapter {
   @Override
   public void channelActive(ChannelHandlerContext ctx) throws Exception {
       super.channelActive(ctx);
  }
   /**
    * 超时处理 如果5秒没有接受客户端的心跳,就触发; 如果超过两次,则直接关闭;
    */
   @Override
   public void userEventTriggered(ChannelHandlerContext ctx, Object obj) throws Exception {
       if (obj instanceof IdleStateEvent) {
           IdleStateEvent event = (IdleStateEvent) obj;
           if (IdleState.READER_IDLE.equals(event.state())) { // 如果读通道处于空闲状态,说明没有接收到心跳命令
               System.out.println("已经5秒没有接收到客户端的信息了");
          }
      } else {
           super.userEventTriggered(ctx, obj);
      }
  }
   /**
    * 业务逻辑处理
    */
   @Override
   public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
       System.out.println("服务端收到信息:" + msg);
       String respStr = "收到了 " + System.getProperty("line.separator");
       ByteBuf resp = Unpooled.copiedBuffer(respStr.getBytes());
       ctx.writeAndFlush(resp);
  }
   /**
    * 异常处理
    */
   @Override
   public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
       cause.printStackTrace();
       ctx.close();
  }
}
复制代码


4.4 客户端代码


客户端启动代码


package com.xiangcai;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.LineBasedFrameDecoder;
import io.netty.handler.codec.string.StringDecoder;
import org.junit.Test;
/**
* 服务端代码
* @author 香菜
*/
public class TestClient {
   public static void clientStart() {
       EventLoopGroup group = new NioEventLoopGroup();
       try {
           Bootstrap b = new Bootstrap();
           b.group(group)
                  .channel(NioSocketChannel.class)
                  .option(ChannelOption.TCP_NODELAY, true)
                  .handler(new ChannelInitializer<SocketChannel>() {
                       protected void initChannel(SocketChannel ch) throws Exception {
                           ch.pipeline().addLast(new LineBasedFrameDecoder(1024));
                           ch.pipeline().addLast(new StringDecoder());
                           ch.pipeline().addLast(new ClientHandler());
                      };
                  });
           // 发起异步连接操作
           ChannelFuture f = b.connect("127.0.0.1", 8088).sync();
           // 等待客户端连接关闭
           f.channel().closeFuture().sync();
      } catch (InterruptedException e) {
           e.printStackTrace();
      } finally {
           // 优雅退出,释放NIO线程组
           group.shutdownGracefully();
      }
  }
   public static void main(String[] args) {
       clientStart();
  }
}
复制代码


客户端业务处理:


也是简单的收发消息


package com.xiangcai;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import java.nio.charset.StandardCharsets;
/**
* 服务端代码
* @author 香菜
*/
public class ClientHandler extends ChannelInboundHandlerAdapter {
  @Override
  public void channelActive(ChannelHandlerContext ctx) {
      System.out.println("建立连接");
      byte[] bytes = ("连接上了,开始说话" + System.getProperty("line.separator")).getBytes(StandardCharsets.UTF_8);
      ByteBuf message = Unpooled.buffer(bytes.length);
      message.writeBytes(bytes);
      ctx.writeAndFlush(message);
  }
  @Override
  public void channelRead(ChannelHandlerContext ctx, Object msg) {
      String body = (String) msg;
      System.out.println("收到信息 " + body);
  }
  @Override
  public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
      System.out.println("发生异常");
      ctx.close();
  }
}
复制代码

5、总结

现在越来越多的游戏公司使用Java进行开发,Netty是绕不开的网络基础,搞懂Netty 很重要,Netty也很简单,只要记得线程模型,编解码,其他的都是细节问题,在开发的过程中进行学习也不迟,希望这篇文章能帮助你理解,如果你有疑问可以留言给我,一起学习交流。


完整项目源码下载地址:download.csdn.net/download/pe…


最后一张图结尾


f1eb313fb25845ecaad01a9f0dab38af~tplv-k3u1fbpfcp-zoom-in-crop-mark_1304_0_0_0.webp.jpg


写的好累,希望大佬们能点个赞

目录
相关文章
|
3天前
|
机器学习/深度学习 编解码 人工智能
阿里云gpu云服务器租用价格:最新收费标准与活动价格及热门实例解析
随着人工智能、大数据和深度学习等领域的快速发展,GPU服务器的需求日益增长。阿里云的GPU服务器凭借强大的计算能力和灵活的资源配置,成为众多用户的首选。很多用户比较关心gpu云服务器的收费标准与活动价格情况,目前计算型gn6v实例云服务器一周价格为2138.27元/1周起,月付价格为3830.00元/1个月起;计算型gn7i实例云服务器一周价格为1793.30元/1周起,月付价格为3213.99元/1个月起;计算型 gn6i实例云服务器一周价格为942.11元/1周起,月付价格为1694.00元/1个月起。本文为大家整理汇总了gpu云服务器的最新收费标准与活动价格情况,以供参考。
阿里云gpu云服务器租用价格:最新收费标准与活动价格及热门实例解析
|
1月前
|
存储 弹性计算 大数据
阿里云服务器怎么样?云服务器ECS功能、租用费用全解析
阿里云ECS是弹性计算服务,提供安全可靠的云服务器,包括多种实例规格如经济型、通用型、计算型等,适合不同场景。ECS支持VPC专有网络、快照与镜像、多种付费模式。用户可按需选择计算架构、存储类型,享受灵活的网络控制、自动化数据备份和低成本计算资源。适用于Web应用、在线游戏、大数据分析和深度学习等场景。阿里云提供免费试用和优惠价格,服务众多知名企业,如新浪微博。
105 5
|
1月前
|
存储 弹性计算 大数据
阿里云服务器怎么样?全访问解析云服务器ECS功能、租用、优缺点及使用说明
阿里云ECS是弹性计算服务,提供安全可靠的云服务器,包括多种实例规格如经济型、通用型、计算型等,适合不同场景。ECS支持VPC专有网络、快照与镜像、多种付费模式。用户可根据业务需求选择实例、存储类型和网络配置。阿里云服务器适用于Web应用、游戏、大数据和深度学习等场景,提供免费试用和不同优惠套餐。众多知名企业如新浪微博等信赖阿里云服务。更多信息可访问阿里云官方网站。
121 5
|
5天前
|
机器学习/深度学习 弹性计算 人工智能
阿里云第八代云服务器ECSg8i实例深度解析:性能及适用场景参考
目前企业对云服务器的性能、安全性和AI能力的要求日益提高。阿里云推出的第八代云服务器ECS g8i实例,以其卓越的性能、增强的AI能力和全面的安全防护,除了适用于通用互联网应用和在线音视频应用等场景之外,也广泛应用于AI相关应用。本文将深入解析ECS g8i实例的技术特性、产品优势、适用场景及与同类产品的对比,以供参考。
阿里云第八代云服务器ECSg8i实例深度解析:性能及适用场景参考
|
24天前
|
存储 域名解析 运维
阿里云轻量应用服务器82元与298元年解析与选择参考
目前,阿里云推出的两款特惠轻量应用服务器——82元1年的2核2G3M套餐和298元1年的2核4G4M套餐,吸引了众多用户的关注。本文将深入解析这两款套餐的具体配置、优势、应用场景及选购建议,以供参考。
阿里云轻量应用服务器82元与298元年解析与选择参考
|
1月前
|
存储 弹性计算 应用服务中间件
阿里云经济型e与通用算力型u1实例长效特价云服务器解析,性能与性价比的完美平衡
阿里云目前有两款深受个人和普通企业用户喜欢的特价云服务器,ECS 经济型e实例2核2G,3M固定带宽,40G ESSD Entry云盘,仅需99元1年。ECS u1实例2核4G,5M固定带宽,80G ESSD Entry盘,仅需199元1年。新老同享,活动期间新购、续费同价。很多用户关心这两款云服务器性能怎么样?本文将对阿里云2024年推出的特价云服务器进行深度解析,从性能、价格、适用场景等多个维度进行详细探讨,以供选择参考。
阿里云经济型e与通用算力型u1实例长效特价云服务器解析,性能与性价比的完美平衡
|
11天前
|
域名解析 监控 负载均衡
【域名解析DNS专栏】智能DNS解析:自动选择最快服务器的奥秘
在互联网中,智能DNS解析作为一项先进技术,根据用户的网络环境和服务器负载情况,自动挑选最优服务器进行域名解析,显著提升访问速度与体验。其工作原理包括实时监控服务器状态、分析数据以选择最佳路由。通过负载均衡算法、地理位置识别及实时性能测试等策略,确保用户能获得最快的响应。这项技术极大提高了互联网服务的稳定性和效率。
37 5
|
20天前
|
弹性计算 运维 云计算
云服务器 ECS产品使用问题之如何把本地的游戏存档上传到在线游戏服务器
云服务器ECS(Elastic Compute Service)是各大云服务商阿里云提供的一种基础云计算服务,它允许用户租用云端计算资源来部署和运行各种应用程序。以下是一个关于如何使用ECS产品的综合指南。
|
1月前
|
Oracle NoSQL 固态存储
阿里云服务器ESSD Entry云盘与ESSD云盘选择指南:性能与场景解析
在我们选择阿里云服务器的时候,有部分云服务器同时支持ESSD Entry云盘和ESSD云盘,选择不同的云盘,价格也有所差异,有的用户还不清楚他们之间的区别,因此不知道选择哪种更好更能满足自己场景的需求,本文为大家介绍一下阿里云服务器ESSD Entry云盘和ESSD云盘的区别及选择参考。
阿里云服务器ESSD Entry云盘与ESSD云盘选择指南:性能与场景解析

推荐镜像

更多