(三)nio通道之Channel的类型、通道的创建和通道的Scatter(分散)和Gather(聚集)

本文介绍了Java NIO中通道的概念及其分类,包括文件通道和套接字通道,并详细讲解了如何创建和使用这些通道。此外,还探讨了通道的单向与双向特性以及分散读取和聚集写入的操作。

一、通道的分类:

通道(Channel)是访问I/O服务的导管。I/O广义上可分为两大类:File I/O和Stream I/O。相应的会有两大类型的通道,它们分别是文件(file)通道和套接字(socket)通道。

主要的文件通道有:

    FileChannel:用于读取、写入、映射和操作文件的通道。

主要的套接字通道有:

    SocketChannel:通过 TCP 读写网络中的数据。

    ServerSocketChannel :可以监听新进来的 TCP 连接,对每一个新进来的连接都会创建一个 SocketChannel。

    DatagramChannel:通过 UDP 读写网络中的数据通道。

其中前两个为TCP的套接字通道,后一个为UDP套接字通道。

-------------------------------------------------------------------------

二、通道的创建:

通道可以以多种方式创建。Socket 通道有可以直接创建新 socket 通道的工厂方法。但是一个FileChannel 对象却只能通过在一个打开的 RandomAccessFile、FileInputStream 或 FileOutputStream对象上调用 getChannel( )方法来获取。不能直接创建一个 FileChannel 对象。

如:

    SocketChannel sc = SocketChannel.open( );

    DatagramChannel dc = DatagramChannel.open( );

    FileChannel fc = RandomAccessFile raf = new RandomAccessFile ("somefile", "r").getChannel( );

    FileChannel fc = new FileInputStream(path).getChannel();

在java.net 的 socket 类也有新的 getChannel( )方法。这些方法虽然能返回一个相应的 socket 通道对象,但它们却并非新通道的来源。

----------------------------------------------------------------------

三、使用通道:


通道可以是单向的,也可以是双向的。一个channel类可以实现ReadableByteChannel接口定义read()方法,而另一个channel类也可以实现WritableByteChannel接口定义的write()方法。实现这两个接口其中之一的类都是单向的,只能在一个方向上进行传输数据。如果一个类同时实现了这两个接口,那么它是双向的,可以双向进行传输数据。如上图所示:ByteChannel是一个实现了WritableByteChannel和ReadableByteChannel的接口,该ByteChannel的实现类可以进行双向传输数据。

实例:

public class ChannelCopy {
public static void main(String[] args) throws Exception {
ReadableByteChannel src = Channels.newChannel(System.in);
WritableByteChannel dest = Channels.newChannel(System.out);
channelCopy1(src, dest);
src.close();
dest.close();
}
private static void channelCopy1(ReadableByteChannel src, WritableByteChannel dest) throws IOException {
ByteBuffer buffer = ByteBuffer.allocate(16 * 1024);
while ((src.read(buffer)) != -1) {
buffer.flip();
dest.write(buffer);
buffer.compact();
}
buffer.flip();
while (buffer.hasRemaining()) {
dest.write(buffer);
}
}

}

-------------------------------------------------------------

四、Scatter(分散)和Gather(聚集):

Scatter(分散)和Gather(聚集)是指在多个缓冲区中实现一个简单的I/O操作。

对于一个write操作而言,数据是从几个缓冲区按顺序抽取(成为gatter)并沿着通道发送的。缓冲
区本身并不需要具备这种 gather 的能力(通常它们也没有此能力)。该 gather 过程的效果就好比全

部缓冲区的内容被连结起来,并在发送数据前存放到一个大的缓冲区中。


对于 read 操作而言,从通道读取的数据会按顺序被散布(称为 scatter)到多个缓冲区,将每个缓冲区填满直至通道中的数据或者缓冲区的最大空间被消耗完。


1、分散读取(Scattering Reads):是指从 Channel 中读取的数据“分散”到多个 Buffer 中。

注意:按照缓冲区的顺序,从 Channel 中读取的数据依次将 Buffer 填满。


2、聚集写入(Gathering Writes)是指将多个 Buffer 中的数据“聚集”到 Channel。

注意:按照缓冲区的顺序,写入 position 和 limit 之间的数据到 Channel 。


3、将数据从源通道传输他 到其他  Channel  中 :


4、将数据从源通道传输他 到其他  Channel  中:












### 查询性能优化方法 ClickHouse作为一个高性能的OLAP数据库,其查询性能在很大程度上取决于数据的组织方式、查询的编写方式以及集群的配置。为了充分发挥ClickHouse的性能优势,可以从以下几个方面进行优化: #### 数据分区策略 合理的数据分区策略可以显著提升查询性能。ClickHouse支持多种分区方式,包括按时间、按范围、按哈希等。例如,按时间分区适用于时间序列数据,能够加速基于时间范围的查询。选择合适的分区策略后,查询引擎只需扫描相关的数据分区,而不是全表扫描,从而减少I/O开销并加快查询速度[^4]。 #### 索引策略 ClickHouse支持多种索引类型,如主键索引、二级索引(如`Set`、`BloomFilter`)等。通过在常用查询字段上建立合适的索引,可以大幅减少需要扫描的数据量。例如,在经常用于过滤或分组的字段上建立主键索引,可以显著提升查询效率。此外,定期维护索引以确保其有效性也是优化的一部分[^4]。 #### 分布式查询优化 在分布式环境下,合理使用`GLOBAL JOIN`和`GLOBAL IN`可以减少集群内部的数据传输次数。例如,在进行分布式表的`JOIN`操作时,使用`GLOBAL JOIN`可以让驱动表在各个节点上执行本地查询,从而避免多次跨节点数据传输。假设b表有N个分片,不使用`GLOBAL`时需要执行N²次查询,而使用`GLOBAL`后仅需执行N次查询即可,显著降低了网络开销[^5]。 #### 提前过滤 在编写查询语句时,尽量在`WHERE`子句中提前进行过滤,减少中间结果集的大小。这样可以减少后续操作的数据量,提高整体查询效率。例如,使用`WHERE`条件在数据读取阶段就进行筛选,而不是在后续的聚合或排序阶段才进行过滤,可以有效降低内存和CPU的使用。 #### 集群水平扩展 ClickHouse支持水平扩展,可以通过添加更多的服务器来提升系统的容量和性能。在执行复杂查询时,ClickHouse能够利用集群中所有可用的CPU核心和磁盘资源,即使是单个查询也可以并行处理,从而加快响应速度。这种特性使得ClickHouse能够高效处理大规模数据集[^3]。 #### 查询语句优化 避免不必要的列查询,尽量使用`SELECT`指定所需的列,而不是使用`SELECT *`。减少返回的数据量可以降低网络传输和内存消耗。此外,避免在`WHERE`子句中使用复杂的表达式或函数,尽量将过滤条件简化为可以直接利用索引的形式。 #### 存储引擎选择 根据业务需求选择合适的存储引擎(如MergeTree系列、Log、TinyLog等)。MergeTree系列存储引擎支持分区、索引和数据压缩,适合大规模数据的OLAP场景;而Log类存储引擎则更适合小规模数据的快速写入和读取场景。 #### 系统参数调优 ClickHouse提供了丰富的配置参数,可以根据硬件资源和业务需求进行调整。例如,调整`max_threads`控制并行查询的线程数,或者调整`max_memory_usage`限制单个查询的内存使用量,以避免内存不足导致的性能下降。 #### 定期维护 定期对表进行`OPTIMIZE`操作,合并分区中的小数据块,减少存储碎片,提升查询效率。此外,监控表的大小、分区情况和查询性能,及时发现并解决潜在的性能瓶颈。 ### 示例代码 以下是一个使用`GLOBAL JOIN`的示例,展示如何在分布式环境中优化查询性能: ```sql -- 使用 GLOBAL JOIN 优化分布式表的关联查询 SELECT a.id, a.name, b.score FROM a GLOBAL JOIN b ON a.id = b.id; -- 使用 GLOBAL IN 优化查询中的分布式表过滤 SELECT a.id, a.name FROM a WHERE a.id GLOBAL IN (SELECT id FROM b); ``` 上述查询通过`GLOBAL`关键字确保查询在各个节点上本地执行,减少了跨节点的数据传输次数,从而提升查询性能。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值