当前位置: 首页 > news >正文

Hbase

java客户端

导入maven依赖

XML
<dependencies>
    <dependency>
        <groupId>org.apache.zookeeper</groupId>
        <artifactId>zookeeper</artifactId>
        <version>3.4.6</version>
    </dependency>

    <dependency>
        <groupId>org.apache.hbase</groupId>
        <artifactId>hbase-client</artifactId>
        <version>2.2.5</version>
    </dependency>
    <dependency>
        <groupId>org.apache.hadoop</groupId>
        <artifactId>hadoop-client</artifactId>
        <version>3.2.1</version>
    </dependency>
    <dependency>
        <groupId>org.apache.hadoop</groupId>
        <artifactId>hadoop-common</artifactId>
        <version>3.2.1</version>
    </dependency>
    <dependency>
        <groupId>org.apache.hbase</groupId>
        <artifactId>hbase-server</artifactId>
        <version>2.2.5</version>
    </dependency>
    <!--
使用mr程序操作hbase 数据的导入 -->
    <dependency>
        <groupId>org.apache.hbase</groupId>
        <artifactId>hbase-mapreduce</artifactId>
        <version>2.2.5</version>
    </dependency>
    <dependency>
        <groupId>com.google.code.gson</groupId>
        <artifactId>gson</artifactId>
        <version>2.8.5</version>
    </dependency>
    <!-- phoenix 凤凰 用来整合Hbase的工具 -->
    <dependency>
        <groupId>org.apache.phoenix</groupId>
        <artifactId>phoenix-core</artifactId>
        <version>5.0.0-HBase-2.0</version>
    </dependency>
    <dependency>
        <groupId>org.apache.hadoop</groupId>
        <artifactId>hadoop-auth</artifactId>
        <version>3.1.2</version>
    </dependency>
</dependencies>
<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.5.1</version>
            <configuration>
                <source>1.8</source>
                <target>1.8</target>
            </configuration>
        </plugin>

        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-assembly-plugin</artifactId>
            <version>2.6</version>
            <configuration>
                <descriptorRefs>
                    <descriptorRef>jar-with-dependencies</descriptorRef>
                </descriptorRefs>
            </configuration>
            <executions>
                <execution>
                    <id>make-assembly</id>
                    <!-- bind to the packaging phase -->
                    <phase>package</phase>
                    <goals>
                        <goal>single</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>

    </plugins>
</build>

获取hbase的连接,list出所有的表

Java
package com.doit.day01;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.HBaseConfiguration;
import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.client.Admin;
import org.apache.hadoop.hbase.client.Connection;
import org.apache.hadoop.hbase.client.ConnectionFactory;

import java.io.IOException;

/**
 * Hbase
的java客户端连接hbase的时候,只需要连接zookeeper的集群
 * 就可以找到你Hbase集群的位置
 * 核心的对象:
 * Configuration:HbaseConfiguration.create();
 * Connection:ConnectionFactory.createConnection(conf);
 * table:conn.getTable(TableName.valueOf("tb_b")); 对表进行操作 DML
 * Admin:conn.getAdmin();操作Hbase系统DDL,对名称空间等进行操作
 */
public class ConnectionDemo {
    public static void main(String[] args) throws Exception {
        //获取到hbase的配置文件对象
        Configuration conf = HBaseConfiguration.create();
        //针对配置文件设置zk的集群地址
        conf.set("hbase.zookeeper.quorum","linux01:2181,linux02:2181,linux03:2181");
        //创建hbase的连接对象
        Connection conn = ConnectionFactory.createConnection(conf);

        //获取到操作hbase的对象
        Admin admin = conn.getAdmin();

        //调用api获取到所有的表
        TableName[] tableNames = admin.listTableNames();

        //获取到哪个命名空间下的所有的表
        TableName[] doits = admin.listTableNamesByNamespace("doit");


        for (TableName tableName : doits) {
            byte[] name = tableName.getName();
            System.out.println(new String(name));
        }

        conn.close();
    }
}

获取到所有的命名空间

Java
package com.doit.day01;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.HBaseConfiguration;
import org.apache.hadoop.hbase.NamespaceDescriptor;
import org.apache.hadoop.hbase.client.Admin;
import org.apache.hadoop.hbase.client.Connection;
import org.apache.hadoop.hbase.client.ConnectionFactory;

/**
 * Hbase
的java客户端连接hbase的时候,只需要连接zookeeper的集群
 * 就可以找到你Hbase集群的位置
 * 核心的对象:
 * Configuration:HbaseConfiguration.create();
 * Connection:ConnectionFactory.createConnection(conf);
 * Admin:conn.getAdmin();操作Hbase系统DDL,对名称空间等进行操作
 */
public class NameSpaceDemo {
    public static void main(String[] args) throws Exception {
        //获取到hbase的配置文件对象
        Configuration conf = HBaseConfiguration.create();
        //针对配置文件设置zk的集群地址
        conf.set("hbase.zookeeper.quorum","linux01:2181,linux02:2181,linux03:2181");
        //创建hbase的连接对象
        Connection conn = ConnectionFactory.createConnection(conf);

        //获取到操作hbase的对象
        Admin admin = conn.getAdmin();

        //获取到命名空间的描述器
        NamespaceDescriptor[] namespaceDescriptors = admin.listNamespaceDescriptors();

        for (NamespaceDescriptor namespaceDescriptor : namespaceDescriptors) {
            //针对描述器获取到命名空间的名称
            String name = namespaceDescriptor.getName();
            System.out.println(name);
        }

        conn.close();
    }
}

创建一个命名空间

Java
package com.doit.day01;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.HBaseConfiguration;
import org.apache.hadoop.hbase.NamespaceDescriptor;
import org.apache.hadoop.hbase.client.Admin;
import org.apache.hadoop.hbase.client.Connection;
import org.apache.hadoop.hbase.client.ConnectionFactory;
import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos;

import java.util.Properties;

/**
 * Hbase
的java客户端连接hbase的时候,只需要连接zookeeper的集群
 * 就可以找到你Hbase集群的位置
 * 核心的对象:
 * Configuration:HbaseConfiguration.create();
 * Connection:ConnectionFactory.createConnection(conf);
 * Admin:conn.getAdmin();操作Hbase系统DDL,对名称空间等进行操作
 */
public class CreateNameSpaceDemo {
    public static void main(String[] args) throws Exception {
        //获取到hbase的配置文件对象
        Configuration conf = HBaseConfiguration.create();
        //针对配置文件设置zk的集群地址
        conf.set("hbase.zookeeper.quorum","linux01:2181,linux02:2181,linux03:2181");
        //创建hbase的连接对象
        Connection conn = ConnectionFactory.createConnection(conf);

        //获取到操作hbase的对象
        Admin admin = conn.getAdmin();

        //获取到命名空间描述器的构建器
        NamespaceDescriptor.Builder spaceFromJava = NamespaceDescriptor.create("spaceFromJava");
        //当然还可以给命名空间设置属性
        spaceFromJava.addConfiguration("author","robot_jiang");
        spaceFromJava.addConfiguration("desc","this is my first java namespace...");
        //拿着构建器构建命名空间的描述器
        NamespaceDescriptor build = spaceFromJava.build();
        //创建命名空间
        admin.createNamespace(build);

        conn.close();
    }
}

创建带有多列族的表

Java
package com.doit.day01;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.HBaseConfiguration;
import org.apache.hadoop.hbase.NamespaceDescriptor;
import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.client.*;
import org.apache.hadoop.hbase.protobuf.generated.TableProtos;

import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Map;
import java.util.Set;

/**
 * Hbase
的java客户端连接hbase的时候,只需要连接zookeeper的集群
 * 就可以找到你Hbase集群的位置
 * 核心的对象:
 * Configuration:HbaseConfiguration.create();
 * Connection:ConnectionFactory.createConnection(conf);
 * Admin:conn.getAdmin();操作Hbase系统DDL,对名称空间等进行操作
 */
public class CreateTableDemo {
    public static void main(String[] args) throws Exception {
        //获取到hbase的配置文件对象
        Configuration conf = HBaseConfiguration.create();
        //针对配置文件设置zk的集群地址
        conf.set("hbase.zookeeper.quorum","linux01:2181,linux02:2181,linux03:2181");
        //创建hbase的连接对象
        Connection conn = ConnectionFactory.createConnection(conf);

        Admin admin = conn.getAdmin();

        //获取到操作hbase操作表的对象
        TableDescriptorBuilder java = TableDescriptorBuilder.newBuilder(TableName.valueOf("java"));

        //表添加列族需要集合的方式
        ArrayList<ColumnFamilyDescriptor> list = new ArrayList<>();
        //构建一个列族的构造器
        ColumnFamilyDescriptorBuilder col1 = ColumnFamilyDescriptorBuilder.newBuilder("f1".getBytes(StandardCharsets.UTF_8));
        ColumnFamilyDescriptorBuilder col2 = ColumnFamilyDescriptorBuilder.newBuilder("f2".getBytes(StandardCharsets.UTF_8));
        ColumnFamilyDescriptorBuilder col3 = ColumnFamilyDescriptorBuilder.newBuilder("f3".getBytes(StandardCharsets.UTF_8));
        //构建列族
        ColumnFamilyDescriptor build1 = col1.build();
        ColumnFamilyDescriptor build2 = col2.build();
        ColumnFamilyDescriptor build3 = col3.build();
        //将列族添加到集合中去
        list.add(build1);
        list.add(build2);
        list.add(build3);

        //给表设置列族
        java.setColumnFamilies(list);
        //构建表的描述器
        TableDescriptor build = java.build();
        //创建表
        admin.createTable(build);

        conn.close();
    }
}

向表中添加数据

Java
package com.doit.day01;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.HBaseConfiguration;
import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.client.*;

import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;

/**
 *
注意:put数据需要指定往哪个命名空间的哪个表的哪个rowKey的哪个列族的哪个列中put数据,put的值是什么
 */
public class PutDataDemo {
    public static void main(String[] args) throws Exception {
        //获取到hbase的配置文件对象
        Configuration conf = HBaseConfiguration.create();
        //针对配置文件设置zk的集群地址
        conf.set("hbase.zookeeper.quorum","linux01:2181,linux02:2181,linux03:2181");
        //创建hbase的连接对象
        Connection conn = ConnectionFactory.createConnection(conf);

        Admin admin = conn.getAdmin();

        //指定往哪一张表中put数据
        Table java = conn.getTable(TableName.valueOf("java"));
        //创建put对象,设置rowKey
        Put put = new Put("rowkey_001".getBytes(StandardCharsets.UTF_8));
        put.addColumn("f1".getBytes(StandardCharsets.UTF_8),"name".getBytes(StandardCharsets.UTF_8),"xiaotao".getBytes(StandardCharsets.UTF_8));
        put.addColumn("f1".getBytes(StandardCharsets.UTF_8),"age".getBytes(StandardCharsets.UTF_8),"42".getBytes(StandardCharsets.UTF_8));

        Put put1 = new Put("rowkey_002".getBytes(StandardCharsets.UTF_8));
        put1.addColumn("f1".getBytes(StandardCharsets.UTF_8),"name".getBytes(StandardCharsets.UTF_8),"xiaotao".getBytes(StandardCharsets.UTF_8));
        put1.addColumn("f1".getBytes(StandardCharsets.UTF_8),"age".getBytes(StandardCharsets.UTF_8),"42".getBytes(StandardCharsets.UTF_8));

        Put put2 = new Put("rowkey_003".getBytes(StandardCharsets.UTF_8));
        put2.addColumn("f1".getBytes(StandardCharsets.UTF_8),"name".getBytes(StandardCharsets.UTF_8),"xiaotao".getBytes(StandardCharsets.UTF_8));
        put2.addColumn("f1".getBytes(StandardCharsets.UTF_8),"age".getBytes(StandardCharsets.UTF_8),"42".getBytes(StandardCharsets.UTF_8));

        java.put(Arrays.asList(put,put1,put2));

        conn.close();
    }
}

get表中的数据

Java
package com.doit.day01;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.Cell;
import org.apache.hadoop.hbase.CellUtil;
import org.apache.hadoop.hbase.HBaseConfiguration;
import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.client.*;

import java.nio.charset.StandardCharsets;

/**
 *
注意:put数据需要指定往哪个命名空间的哪个表的哪个rowKey的哪个列族的哪个列中put数据,put的值是什么
 */
public class GetDataDemo {
    public static void main(String[] args) throws Exception {
        //获取到hbase的配置文件对象
        Configuration conf = HBaseConfiguration.create();
        //针对配置文件设置zk的集群地址
        conf.set("hbase.zookeeper.quorum","linux01:2181,linux02:2181,linux03:2181");
        //创建hbase的连接对象
        Connection conn = ConnectionFactory.createConnection(conf);

        //指定往哪一张表中put数据
        Table java = conn.getTable(TableName.valueOf("java"));

        Get get = new Get("rowkey_001".getBytes(StandardCharsets.UTF_8));
//        get.addFamily("f1".getBytes(StandardCharsets.UTF_8));
        get.addColumn("f1".getBytes(StandardCharsets.UTF_8),"name".getBytes(StandardCharsets.UTF_8));
        Result result = java.get(get);
        boolean advance = result.advance();
        if(advance){
            Cell current = result.current();
            String family = new String(CellUtil.cloneFamily(current));
            String qualifier = new String(CellUtil.cloneQualifier(current));
            String row = new String(CellUtil.cloneRow(current));
            String value = new String(CellUtil.cloneValue(current));
            System.out.println(row+","+family+","+qualifier+","+value);
        }

        conn.close();
    }
}

scan表中的数据

Java
package com.doit.day01;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.*;
import org.apache.hadoop.hbase.client.*;

import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Iterator;

/**
 *
注意:put数据需要指定往哪个命名空间的哪个表的哪个rowKey的哪个列族的哪个列中put数据,put的值是什么
 */
public class ScanDataDemo {
    public static void main(String[] args) throws Exception {
        //获取到hbase的配置文件对象
        Configuration conf = HBaseConfiguration.create();
        //针对配置文件设置zk的集群地址
        conf.set("hbase.zookeeper.quorum","linux01:2181,linux02:2181,linux03:2181");
        //创建hbase的连接对象
        Connection conn = ConnectionFactory.createConnection(conf);

        //指定往哪一张表中put数据
        Table java = conn.getTable(TableName.valueOf("java"));

        Scan scan = new Scan();
        scan.withStartRow("rowkey_001".getBytes(StandardCharsets.UTF_8));
        scan.withStopRow("rowkey_004".getBytes(StandardCharsets.UTF_8));

        ResultScanner scanner = java.getScanner(scan);
        Iterator<Result> iterator = scanner.iterator();
        while (iterator.hasNext()){
            Result next = iterator.next();
            while (next.advance()){
                Cell current = next.current();
                String family = new String(CellUtil.cloneFamily(current));
                String row = new String(CellUtil.cloneRow(current));
                String qualifier = new String(CellUtil.cloneQualifier(current));
                String value = new String(CellUtil.cloneValue(current));
                System.out.println(row+","+family+","+qualifier+","+value);
            }
        }


        conn.close();
    }
}

删除一行数据

Java
package com.doit.day02;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.HBaseConfiguration;
import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.client.*;

import java.io.IOException;
import java.nio.charset.StandardCharsets;

public class _12_
删除一行数据 {
    public static void main(String[] args) throws IOException {
        Configuration conf = HBaseConfiguration.create();
        conf.set("hbase.zookeeper.quorum","linux01");

        Connection conn = ConnectionFactory.createConnection(conf);

        Table java = conn.getTable(TableName.valueOf("java"));

        Delete delete = new Delete("rowkey_001".getBytes(StandardCharsets.UTF_8));

        java.delete(delete);

    }
}

原理加强

数据存储

行式存储

传统的行式数据库将一个个完整的数据行存储在数据页中

列式存储

列式数据库是将同一个数据列的各个值存放在一起

传统行式数据库的特性如下:
 ①数据是按行存储的。
 ②没有索引的查询使用大量I/O。比如一般的数据库表都会建立索引,通过索引加快查询效率。
 ③建立索引和物化视图需要花费大量的时间和资源。
 ④面对查询需求,数据库必须被大量膨胀才能满足需求。

列式数据库的特性如下:
 ①数据按列存储,即每一列单独存放。
 ②数据即索引。
 ③只访问查询涉及的列,可以大量降低系统I/O
 ④每一列由一个线程来处理,即查询的并发处理性能高。
 ⑤数据类型一致,数据特征相似,可以高效压缩。比如有增量压缩、前缀压缩算法都是基于列存储的类型定制的,所以可以大幅度提高压缩比,有利于存储和网络输出数据带宽的消耗。

列族式存储

列族式存储是一种非关系型数据库存储方式,按列而非行组织数据。它的数据模型是面向列的,即把数据按照列族的方式组织,将属于同一列族的数据存储在一起。每个列族都有一个唯一的标识符,一般通过列族名称来表示。它具有高效的写入和查询性能,能够支持极大规模的数据

  • 如果一个表有多个列族, 每个列族下只有一列, 那么就等同于列式存储。
  • 如果一个表只有一个列族, 该列族下有多个列, 那么就等同于行式存储.

hbase的存储路径:

在conf目录下的hbase-site.xml文件中配置了数据存储的路径在hdfs上

XML
<property>
<name>hbase.rootdir</name>
<value>hdfs://linux01:8020/hbase</value>
</property>

region

Region是HBase数据管理的基本单位,region有一点像关系型数据的分区。
Region中存储这用户的真实数据,而为了管理这些数据,HBase使用了RegionSever来管理region。

region的分配

一个表中可以包含一个或多个Region。

每个Region只能被一个RS(RegionServer)提供服务,RS可以同时服务多个Region,来自不同RS上的Region组合成表格的整体逻辑视图。

regionServer其实是hbase的服务,部署在一台物理服务器上,region有一点像关系型数据的分区,数据存放在region中,当然region下面还有很多结构,确切来说数据存放在memstore和hfile中。我们访问hbase的时候,先去hbase 系统表查找定位这条记录属于哪个region,然后定位到这个region属于哪个服务器,然后就到哪个服务器里面查找对应region中的数据

Memstore Flush流程

flus流程分为三个阶段:

  1. prepare阶段:遍历当前 Region中所有的 MemStore ,将 MemStore 中当前数据集 CellSkpiListSet 做一个快照 snapshot;然后再新建一个 CellSkipListSet。后期写入的数据都会写入新的 CellSkipListSet 中。prepare 阶段需要加一把 updataLock 对写请求阻塞,结束之后会释放该锁。因为此阶段没有任何费时操作,因此锁持有时间很短
  1. flush阶段:遍历所有 MemStore,将 prepare 阶段生成的snapshot 持久化为临时文件,临时文件会统一放到目录.tmp下。这个过程因为涉及到磁盘 IO 操作,因此相对耗时
  1. commit阶段:遍历所有 MemStore,将flush阶段生成的临时文件移动到指定的 ColumnFamily 目录下,针对 HFile生成对应的 StoreFile 和 Reader,把 StoreFile 添加到 HStore 的 storefiles 列表中,最后再清空 prepare 阶段生成的 snapshot快照

Compact 合并机制

hbase中的合并机制分为自动合并和手动合并

自动合并:

  • minor compaction 小合并
  • major compacton 大合并

minor compaction(小合并)

将 Store 中多个 HFile 合并为一个相对较大的 HFile 过程中会选取一些小的、相邻的 StoreFile 将他们合并成一个更大的 StoreFile,对于超过 TTL 的数据、更新的数据、删除的数据仅仅只是做了标记,并没有进行物理删除。一次 minor compaction 过后,storeFile会变得更少并且更大,这种合并的触发频率很高

小合并的触发方式:

memstore flush会产生HFile文件,文件越来越多就需要compact.每次执行完Flush操作之后,都会对当前Store中的文件数进行判断,一旦文件数大于配置3,就会触发compaction。compaction都是以Store为单位进行的,而在Flush触发条件下,整个Region的所有Store都会执行compact

后台线程周期性检查

检查周期可配置:

hbase.server.thread.wakefrequency/默认10000毫秒)*hbase.server.compactchecker.interval.multiplier/默认1000

CompactionChecker大概是2hrs 46mins 40sec 执行一次

XML
<!--表示至少需要三个满足条件的store file时,minor compaction才会启动-->
<property>
        <name>hbase.hstore.compactionThreshold</name>
        <value>3</value>
</property>

<!--表示一次minor compaction中最多选取10个store file-->
<property>
        <name>hbase.hstore.compaction.max</name>
        <value>10</value>
</property>

<!--默认值为128m,
表示文件大小小于该值的store file 一定会加入到minor compaction的store file中
-->
<property>
        <name>hbase.hstore.compaction.min.size</name>
        <value>134217728</value>
</property>

<!--默认值为LONG.MAX_VALUE,表示文件大小大于该值的store file 一定会被minor compaction排除-->
<property>
        <name>hbase.hstore.compaction.max.size</name>
        <value>9223372036854775807</value>
</property>

major compaction(大合并)

合并 Store 中所有的 HFile 为一个 HFile,将所有的 StoreFile 合并成为一个 StoreFile,这个过程中还会清理三类无意义数据:被删除的数据、TTL过期数据、版本号超过设定版本号的数据。合并频率比较低,默认7天执行一次,并且性能消耗非常大,建议生产关闭(设置为0),在应用空间时间手动触发。一般是可以手动控制进行合并,防止出现在业务高峰期。

XML
线程先检查小文件数是否大于配置3,一旦大于就会触发compaction。
大文件周期性合并成Major Compaction
如果不满足,它会接着检查是否满足major compaction条件
如果当前store中hfile的最早更新时间早于某个值mcTime就会触发major compaction
(默认7天触发一次,可配置手动触发)

<!--默认值为7天进行一次大合并,-->
<property>
        <name>hbase.hregion.majorcompaction</name>
        <value>604800000</value>
</property>

手动合并

一般来讲,手动触发compaction通常是为了执行major compaction,一般有这些情况需要手动触发合并是因为很多业务担心自动maior compaction影响读写性能,因此会选择低峰期手动触发也有可能是用户在执行完alter操作之后希望立刻生效,执行手动触发maiorcompaction:

造数据

Shell
truncate 'doit:test'                                
put 'doit:test','001','f1:name','zss'
put 'doit:test','002','f1:name','zss'
put 'doit:test','003','f1:name','zss'
put 'doit:test','004','f1:name','zss'
flush 'doit:test'                   
put 'doit:test','005','f1:name','zss'
put 'doit:test','006','f1:name','zss'
put 'doit:test','007','f1:name','zss'
put 'doit:test','008','f1:name','zss'
flush 'doit:test'                   
put 'doit:test','009','f1:name','zss'
put 'doit:test','010','f1:name','zss'
put 'doit:test','011','f1:name','zss'
put 'doit:test','012','f1:name','zss'
flush 'doit:test'
put 'doit:test','013','f1:name','zss'
put 'doit:test','014','f1:name','zss'
put 'doit:test','015','f1:name','zss'
put 'doit:test','016','f1:name','zss'
flush 'doit:test'
put 'doit:test','017','f1:name','zss'
put 'doit:test','018','f1:name','zss'
put 'doit:test','019','f1:name','zss'
put 'doit:test','020','f1:name','zss'
flush 'doit:test'
put 'doit:test','021','f1:name','zss'
put 'doit:test','022','f1:name','zss'
put 'doit:test','023','f1:name','zss'
put 'doit:test','024','f1:name','zss'
flush 'doit:test'
put 'doit:test','025','f1:name','zss'
put 'doit:test','026','f1:name','zss'
put 'doit:test','027','f1:name','zss'
put 'doit:test','028','f1:name','zss'
flush 'doit:test'
put 'doit:test','021','f1:name','zss'
put 'doit:test','022','f1:name','zss'
put 'doit:test','023','f1:name','zss'
put 'doit:test','024','f1:name','zss'
flush 'doit:test'
put 'doit:test','021','f1:name','zss'
put 'doit:test','022','f1:name','zss'
put 'doit:test','023','f1:name','zss'
put 'doit:test','024','f1:name','zss'
flush 'doit:test'
put 'doit:test','021','f1:name','zss'
put 'doit:test','022','f1:name','zss'
put 'doit:test','023','f1:name','zss'
put 'doit:test','024','f1:name','zss'
flush 'doit:test'

put 'doit:test','021','f1:name','zss'
put 'doit:test','022','f1:name','zss'
put 'doit:test','023','f1:name','zss'
put 'doit:test','024','f1:name','zss'
flush 'doit:test'


每次flush一下都会在底层生成一个小文件

Shell
##使用major_compact命令
major_compact tableName

major_compact 'doit:test'

region的拆分

region中存储的是一张表的数据,当region中的数据条数过多的时候,会直接影响查询效率。当region过大的时候,region会被拆分为两个region,HMaster会将分裂的region分配到不同的regionserver上,这样可以让请求分散到不同的RegionServer上,已达到负载均衡  , 这也是HBase的一个优点

1region的拆分策略

1. ConstantSizeRegionSplitPolicy0.94版本前,HBase region的默认切分策略

region中最大的store大小超过某个阈值(hbase.hregion.max.filesize=10G)之后就会触发切分,一个region等分为2region

但是在生产线上这种切分策略却有相当大的弊端(切分策略对于大表和小表没有明显的区分):

  • 阈值(hbase.hregion.max.filesize)设置较大对大表比较友好,但是小表就有可能不会触发分裂,极端情况下可能就1个,形成热点,这对业务来说并不是什么好事。
  • 如果设置较小则对小表友好,但一个大表就会在整个集群产生大量的region,这对于集群的管理、资源使用、failover来说都不是一件好事。

2. IncreasingToUpperBoundRegionSplitPolicy0.94版本~2.0版本默认切分策略

总体看和ConstantSizeRegionSplitPolicy思路相同,一个region中最大的store大小大于设置阈值就会触发切分。 但是这个阈值并不像ConstantSizeRegionSplitPolicy是一个固定的值,而是会在一定条件下不断调整,调整规则和region所属表在当前regionserver上的region个数有关系.

region split阈值的计算公式是:

  • regioncount:是region所属表在当前regionserver上的region的个数
  • 阈值 = regioncount^3 * 128M * 2,当然阈值并不会无限增长,最大不超过MaxRegionFileSize10G),region中最大的store的大小达到该阈值的时候进行region split

例如:

  • 第一次split阈值 = 1^3 * 256 = 256MB
  • 第二次split阈值 = 2^3 * 256 = 2048MB
  • 第三次split阈值 = 3^3 * 256 = 6912MB
  • 第四次split阈值 = 4^3 * 256 = 16384MB > 10GB,因此取较小的值10GB
  • 后面每次splitsize都是10GB

特点

  • 相比ConstantSizeRegionSplitPolicy,可以自适应大表、小表;
  • 在集群规模比较大的情况下,对大表的表现比较优秀
  • 对小表不友好,小表可能产生大量的小region,分散在各regionserver
  • 小表达不到多次切分条件,导致每个split都很小,所以分散在各个regionServer

3. SteppingSplitPolicy2.0版本默认切分策略

相比 IncreasingToUpperBoundRegionSplitPolicy 简单了一些  region切分的阈值依然和待分裂region所属表在当前regionserver上的region个数有关系

  • 如果region个数等于1,切分阈值为flush size 128M * 2
  • 否则为MaxRegionFileSize

这种切分策略对于大集群中的大表、小表会比 IncreasingToUpperBoundRegionSplitPolicy 更加友好,小表不会再产生大量的小region,而是适可而止。

4. KeyPrefixRegionSplitPolicy

根据rowKey的前缀对数据进行分区,这里是指定rowKey的前多少位作为前缀,比如rowKey都是16位的,指定前5位是前缀,那么前5位相同的rowKey在相同的region

5. DelimitedKeyPrefixRegionSplitPolicy

保证相同前缀的数据在同一个region中,例如rowKey的格式为:userid_eventtype_eventid,指定的delimiter _ ,则split的的时候会确保userid相同的数据在同一个region中。 按照分隔符进行切分,而KeyPrefixRegionSplitPolicy是按照指定位数切分

6. BusyRegionSplitPolicy

按照一定的策略判断Region是不是Busy状态,如果是即进行切分

如果你的系统常常会出现热点Region,而你对性能有很高的追求,那么这种策略可能会比较适合你。它会通过拆分热点Region来缓解热点Region的压力,但是根据热点来拆分Region也会带来很多不确定性因素,因为你也不知道下一个被拆分的Region是哪个

7. DisabledRegionSplitPolicy:不启用自动拆分, 需要指定手动拆分

手动合并拆分egion

手动合并

Shell
hbase(main):025:0> list_regions 'doit:test'
                 SERVER_NAME |                                                          REGION_NAME |  START_KEY |    END_KEY |  SIZE |   REQ |   LOCALITY |
 --------------------------- | -------------------------------------------------------------------- | ---------- | ---------- | ----- | ----- | ---------- |
 linux03,16020,1684200651855 |           doit:test,,1684205468848.920ae3e043ad95890c4f5693cb663bc5. |            | rowkey_010 |     0 |     0 |        0.0 |
 linux01,16020,1684205091382 | doit:test,rowkey_010,1684207066858.5e04eb75e5510ad65a0f3001de3c7aa0. | rowkey_010 | rowkey_015 |     0 |     0 |        0.0 |
 linux02,16020,1684200651886 | doit:test,rowkey_015,1684207066858.ed1b328ca4c485d4fa429922f6c18f0b. | rowkey_015 | rowkey_020 |     0 |     0 |        0.0 |
 linux02,16020,1684200651886 | doit:test,rowkey_020,1684205468848.25d62e8cc2fdaecec87234b8d28f0827. | rowkey_020 | rowkey_030 |     0 |     0 |        0.0 |
 linux03,16020,1684200651855 | doit:test,rowkey_030,1684205468848.2b0468e6643b95159fa6e210fa093e66. | rowkey_030 | rowkey_040 |     0 |     0 |        0.0 |
 linux01,16020,1684205091382 | doit:test,rowkey_040,1684205468848.fb12c09c7c73cfeff0bf79b5dda076cb. | rowkey_040 |            |     0 |     0 |        0.0 |
 6 rows
Took 0.0299 seconds                                                                                                                                                   
hbase(main):026:0> merge_region 'doit:test,,1684205468848.920ae3e043ad95890c4f5693cb663bc5.','doit:test,rowkey_010,1684207066858.5e04eb75e5510ad65a0f3001de3c7aa0.'
Took 1.2638 seconds                                                                                                                                                   
hbase(main):027:0> list_regions 'doit:test'
                 SERVER_NAME |                                                          REGION_NAME |  START_KEY |    END_KEY |  SIZE |   REQ |   LOCALITY |
 --------------------------- | -------------------------------------------------------------------- | ---------- | ---------- | ----- | ----- | ---------- |
 linux03,16020,1684200651855 |           doit:test,,1684207066859.cdc1226d634c0cf16f58832637f485b6. |            | rowkey_015 |     0 |     0 |        0.0 |
 linux02,16020,1684200651886 | doit:test,rowkey_015,1684207066858.ed1b328ca4c485d4fa429922f6c18f0b. | rowkey_015 | rowkey_020 |     0 |     0 |        0.0 |
 linux02,16020,1684200651886 | doit:test,rowkey_020,1684205468848.25d62e8cc2fdaecec87234b8d28f0827. | rowkey_020 | rowkey_030 |     0 |     0 |        0.0 |
 linux03,16020,1684200651855 | doit:test,rowkey_030,1684205468848.2b0468e6643b95159fa6e210fa093e66. | rowkey_030 | rowkey_040 |     0 |     0 |        0.0 |
 linux01,16020,1684205091382 | doit:test,rowkey_040,1684205468848.fb12c09c7c73cfeff0bf79b5dda076cb. | rowkey_040 |            |     0 |     0 |        0.0 |
 5 rows
Took 0.0271 seconds

手动拆分

Shell
hbase(main):029:0> list_regions 'doit:test'
                 SERVER_NAME |                                                          REGION_NAME |  START_KEY |    END_KEY |  SIZE |   REQ |   LOCALITY |
 --------------------------- | -------------------------------------------------------------------- | ---------- | ---------- | ----- | ----- | ---------- |
 linux03,16020,1684200651855 |           doit:test,,1684207066860.8ebf4555c58bd0e5fedae5d4efbe4235. |            | rowkey_030 |     0 |     0 |        0.0 |
 linux03,16020,1684200651855 | doit:test,rowkey_030,1684205468848.2b0468e6643b95159fa6e210fa093e66. | rowkey_030 | rowkey_040 |     0 |     0 |        0.0 |
 linux01,16020,1684205091382 | doit:test,rowkey_040,1684205468848.fb12c09c7c73cfeff0bf79b5dda076cb. | rowkey_040 |            |     0 |     0 |        0.0 |
 3 rows
Took 0.0329 seconds                                                                                                                                                   
hbase(main):030:0> split 'doit:test,,1684207066860.8ebf4555c58bd0e5fedae5d4efbe4235.','rowkey_025'
Took 0.1179 seconds                                                                                                                                                   
hbase(main):031:0> list_regions 'doit:test'
                 SERVER_NAME |                                                          REGION_NAME |  START_KEY |    END_KEY |  SIZE |   REQ |   LOCALITY |
 --------------------------- | -------------------------------------------------------------------- | ---------- | ---------- | ----- | ----- | ---------- |
 linux02,16020,1684200651886 |           doit:test,,1684207502853.af0819bd7f6daa9db2a8f994fb41682d. |            | rowkey_025 |     0 |     0 |        0.0 |
 linux02,16020,1684200651886 | doit:test,rowkey_025,1684207502853.80d7feace447978ffe4a54418a20afd0. | rowkey_025 | rowkey_030 |     0 |     0 |        0.0 |
 linux03,16020,1684200651855 | doit:test,rowkey_030,1684205468848.2b0468e6643b95159fa6e210fa093e66. | rowkey_030 | rowkey_040 |     0 |     0 |        0.0 |
 linux01,16020,1684205091382 | doit:test,rowkey_040,1684205468848.fb12c09c7c73cfeff0bf79b5dda076cb. | rowkey_040 |            |     0 |     0 |        0.0 |
 4 rows
Took 0.0179 seconds                                                                                                                                                    
hbase(main):032:0> split 'doit:test,,1684207502853.af0819bd7f6daa9db2a8f994fb41682d.','rowkey_015'
Took 0.1262 seconds                                                                                                                                                    
hbase(main):033:0> list_regions 'doit:test'
                 SERVER_NAME |                                                          REGION_NAME |  START_KEY |    END_KEY |  SIZE |   REQ |   LOCALITY |
 --------------------------- | -------------------------------------------------------------------- | ---------- | ---------- | ----- | ----- | ---------- |
 linux02,16020,1684200651886 |           doit:test,,1684207546572.0f550ec8fa1af0ab9e73032d224d9f00. |            | rowkey_015 |     0 |     0 |        0.0 |
 linux02,16020,1684200651886 | doit:test,rowkey_015,1684207546572.09a2022c54dfef68866ac73e3f78bc70. | rowkey_015 | rowkey_025 |     0 |     0 |        0.0 |
 linux02,16020,1684200651886 | doit:test,rowkey_025,1684207502853.80d7feace447978ffe4a54418a20afd0. | rowkey_025 | rowkey_030 |     0 |     0 |        0.0 |
 linux03,16020,1684200651855 | doit:test,rowkey_030,1684205468848.2b0468e6643b95159fa6e210fa093e66. | rowkey_030 | rowkey_040 |     0 |     0 |        0.0 |
 linux01,16020,1684205091382 | doit:test,rowkey_040,1684205468848.fb12c09c7c73cfeff0bf79b5dda076cb. | rowkey_040 |            |     0 |     0 |        0.0 |
 5 rows
Took 0.0241 seconds 

bulkLoad实现批量导入

bulkloader 一个用于批量快速导入数据到hbase的工具/方法

用于已经存在一批巨量静态数据的情况!如果不用bulkloader工具,则只能用rpc请求,一条一条地通过rpc提交给regionserver去插入,效率极其低下

相比较于直接写HBase,BulkLoad主要是绕过了写WAL日志这一步,还有写Memstore和Flush到磁盘,从理论上来分析性能会比Put快!

BulkLoad实战示例1importTsv工具

原理:

Importtsvhbase自带的一个 csv文件--HFile文件 的工具,它能将csv文件转成HFile文件,并发送给regionserver。它的本质,是内置的一个将csv文件转成hfile文件的mr程序!

案例演示:

Shell
CSV转HFILE的命令示例如下:
// 001,北戴河,河北省,河北省北戴河昌平区沙河镇赋腾国际创客中心A座4018室
hbase  org.apache.hadoop.hbase.mapreduce.ImportTsv \
-Dimporttsv.separator=, \
-Dimporttsv.columns='HBASE_ROW_KEY,f:city,f:province,x:address'  \
-Dimporttsv.bulk.output=/tsv/output \
user_info \
/tsv/input

ImportTsv命令的参数说明如下:

-Dimporttsv.skip.bad.lines=false - 若遇到无效行则失败

-Dimporttsv.separator=, - 使用特定分隔符,默认是tab也就是\t

-Dimporttsv.timestamp=currentTimeAsLong - 使用导入时的时间戳

-Dimporttsv.mapper.class=my.Mapper - 使用用户自定义Mapper类替换TsvImporterMapper

-Dmapreduce.job.name=jobName - 对导入使用特定mapreduce作业名

-Dcreate.table=no - 避免创建表,注:如设为为no,目标表必须存在于HBase

-Dno.strict=true - 忽略HBase表列族检查。默认为false

-Dimporttsv.bulk.output=/user/yarn/output 作业的输出目录

示例演示:

Plain Text
创建一张表:
hbase(main):005:0> create 'doit:user_info1','f1','f2'
Created table doit:user_info1
Took 1.4252 seconds                                                                                               
=> Hbase::Table - doit:user_info1
hbase(main):006:0>

准备文件:
rowkey_001,zss,18,male,chengxuyuan,beijing
rowkey_002,lss,28,male,jinrongdalao,shanghai
rowkey_003,liuyan,18,female,yanyuan,beijing
rowkey_004,tanyang,38,female,yanyuan,shanghai


上传文件至hdfs上
[root@linux01 data]# hdfs dfs -mkdir -p /tsv/input
[root@linux01 data]# hdfs dfs -put hbase.txt /tsv/input/
[root@linux01 data]#



使用importtsv将测试文件转为hfile
hbase org.apache.hadoop.hbase.mapreduce.ImportTsv \
-Dimporttsv.separator=, \
-Dimporttsv.columns='HBASE_ROW_KEY,f1:name,f1:age,f1:gender,f2:job,f2:address' \
-Dimporttsv.bulk.output=/uu/output \
doit:user_info1 \
/tsv/input/hbase.txt



将hfile注入hbase
hbase org.apache.hadoop.hbase.mapreduce.LoadIncrementalHFiles /uu/output/  doit:user_info1


查看表中的数据
hbase(main):067:0> scan 'doit:user_info1'
ROW                           COLUMN+CELL                                                                          
 rowkey_001                   column=f1:age, timestamp=1684062601474, value=18                                    
 rowkey_001                   column=f1:gender, timestamp=1684062601474, value=male                               
 rowkey_001                   column=f1:name, timestamp=1684062601474, value=zss                                  
 rowkey_001                   column=f2:address, timestamp=1684062601474, value=beijing                           
 rowkey_001                   column=f2:job, timestamp=1684062601474, value=chengxuyuan                           
 rowkey_002                   column=f1:age, timestamp=1684062601474, value=28                                    
 rowkey_002                   column=f1:gender, timestamp=1684062601474, value=male                               
 rowkey_002                   column=f1:name, timestamp=1684062601474, value=lss                                  
 rowkey_002                   column=f2:address, timestamp=1684062601474, value=shanghai                          
 rowkey_002                   column=f2:job, timestamp=1684062601474, value=jinrongdalao                          
 rowkey_003                   column=f1:age, timestamp=1684062601474, value=18                                     
 rowkey_003                   column=f1:gender, timestamp=1684062601474, value=female                             
 rowkey_003                   column=f1:name, timestamp=1684062601474, value=liuyan                               
 rowkey_003                   column=f2:address, timestamp=1684062601474, value=beijing                           
 rowkey_003                   column=f2:job, timestamp=1684062601474, value=yanyuan                               
 rowkey_004                   column=f1:age, timestamp=1684062601474, value=38                                    
 rowkey_004                   column=f1:gender, timestamp=1684062601474, value=female                             
 rowkey_004                   column=f1:name, timestamp=1684062601474, value=tanyang                              
 rowkey_004                   column=f2:address, timestamp=1684062601474, value=shanghai                          
 rowkey_004                   column=f2:job, timestamp=1684062601474, value=yanyuan                                
4 row(s)
Took 0.0587 seconds         

相关文章:

Hbase

java客户端 导入maven依赖 XML<dependencies> <dependency> <groupId>org.apache.zookeeper</groupId> <artifactId>zookeeper</artifactId> <version>3.4.6</version> </dependency>…...

[golang 微服务] 5. 微服务服务发现介绍,安装以及consul的使用,Consul集群

一.服务发现介绍 引入 上一节讲解了使用 gRPC创建微服务,客户端的一个接口可能需要调用 N个服务,而不同服务可能存在 不同的服务器,这时&#xff0c;客户端就必须知道所有服务的 网络位置&#xff08;ipport&#xff09;&#xff0c;来进行连接服务器操作,如下图所示: 以往的做…...

【数据结构】哈希应用

目录 一、位图 1、位图概念 2、位图实现 2.1、位图结构 2.2、比特位置1 2.3、比特位置0 2.4、检测位图中比特位 3、位图例题 3.1、找到只出现一次的整数 3.2、找到两个文件交集 3.3、找到出现次数不超过2次的所有整数 二、布隆过滤器 1、布隆过滤器提出 2、布隆过…...

【 Python 全栈开发 - WEB开发篇 - 31 】where条件查询

文章目录 一、where条件查询1.关系运算符查询2.IN关键字查询3.BETWEEN AND关键字查询4.空值查询5.AND关键字查询6.OR关键字查询7.LIKE关键字查询普通字符串含有%通配的字符串含有_通配的字符串 一、where条件查询 MySQL 的 where 条件查询是指在查询数据时&#xff0c;通过 wh…...

Android系统的Ashmem匿名共享内存子系统分析(5)- 实现共享的原理

声明 其实对于Android系统的Ashmem匿名共享内存系统早就有分析的想法&#xff0c;记得2019年6、7月份Mr.Deng离职期间约定一起对其进行研究的&#xff0c;但因为我个人问题没能实施这个计划&#xff0c;留下些许遗憾…文中参考了很多书籍及博客内容&#xff0c;可能涉及的比较…...

谈一谈冷门的C语言爬虫

C语言可以用来编写爬虫程序&#xff0c;但是相对于其他编程语言&#xff0c;C语言的爬虫开发可能会更加复杂和繁琐。因为C语言本身并没有提供现成的爬虫框架和库&#xff0c;需要自己编写网络请求、HTML解析等功能。 不过&#xff0c;如果你对C语言比较熟悉&#xff0c;也可以…...

基于状态的维护(CBM)如何推动设备效率提高?

基于状态的维护&#xff08;Condition-Based Maintenance&#xff0c;CBM&#xff09;是一种先进的维护策略&#xff0c;通过实时监测和分析设备的状态数据&#xff0c;预测设备故障并采取相应的维护措施。CBM基于数据驱动的方法&#xff0c;能够提高设备的可用性、降低维修成本…...

DC LAB8SDC约束四种时序路径分析

DC LAB 1.启动DC2.读入设计3. 查看所有违例的约束报告3.1 report_constraint -all_violators (alias rc)3.2 view report_constraint -all_violators -verbose -significant_digits 4 (打印详细报告) 4.查看时序报告 report_timing -significant_digits 45. 约束组合逻辑(adr_i…...

学生考试作弊检测系统 yolov8

学生考试作弊检测系统采用yolov8网络模型人工智能技术&#xff0c;学生考试作弊检测系统过在考场中安装监控设备&#xff0c;对学生的作弊行为进行实时监测。当学生出现作弊行为时&#xff0c;学生考试作弊检测系统将自动识别并记录信息。YOLOv8 算法的核心特性和改动可以归结为…...

【基于容器的部署、扩展和管理】 3.2 基于容器的应用程序部署和升级

往期回顾&#xff1a; 第一章&#xff1a;【云原生概念和技术】 第二章&#xff1a;【容器化应用程序设计和开发】 第三章&#xff1a;【3.1 容器编排系统和Kubernetes集群的构建】 3.2 基于容器的应用程序部署和升级 3.2 基于容器的应用程序部署和升级 3.2 基于容器的应用程…...

Jmeter 实现 grpc服务 压测

一、Jmeter安装与配置 网上有很多安装与配置文章&#xff0c;在此不做赘述 二、Jmeter gRPC Request 插件安装 插件下载地址&#xff1a;JMeter Plugins :: JMeter-Plugins.org 将下载文件解压后放到Jmeter安装目录下 /lib/ext 然后在终端输入Jmeter即可打开 Jmeter GUI界面…...

深入源码分析RecyclerView缓存复用原理

文章目录 前言四级缓存 源码分析缓存一级缓存&#xff08;mChangedScrap和mChangedScrap&#xff09;二级缓存&#xff08;mCachedViews&#xff09;三级缓存&#xff08;ViewCacheExtension&#xff09;四级缓存&#xff08;mRecyclerPool&#xff09;缓存池mRecyclerPool结构…...

内网隧道代理技术(一)之内网隧道代理概述

内网隧道代理技术 内网转发 在渗透测试中&#xff0c;当我们获得了外网服务器&#xff08;如web服务器&#xff0c;ftp服务器&#xff0c;mali服务器等等&#xff09;的一定权限后发现这台服务器可以直接或者间接的访问内网。此时渗透测试进入后渗透阶段&#xff0c;一般情况…...

设计图形用户界面的原则

1) 一般性原则&#xff1a;界面要具有一致性、常用操作要有快捷方式、 提供简单的错误处理、对操作人员的重要操作要有信息反馈、操作可 逆、设计良好的联机帮助、合理划分并高效地使用显示屏、保证信息 显示方式与数据输入方式的协调一致 2) 颜色的使用&#xff1a;颜色…...

1:操作系统导论

1.1操作系统的定义 •Anoperatingsystemactsanintermediarybetweenuserofacomputerandthecomputer hardware. ◦ 操作系统充当计算机⽤⼾和计算机硬件之间的中介 •Thepurposeofanoperatingsystemistoprovideanenvironmentinwhichausercanexecute programsinaconvenientandeff…...

什么是微软的 Application Framework?

我是荔园微风&#xff0c;作为一名在IT界整整25年的老兵&#xff0c;今天来看一下什么是微软的 Application Framework&#xff1f; 到底什么是 Application Framework&#xff1f; 还没有真正掌握任何一套Application Framework的使用之前&#xff0c;就来研究这个真的不是很…...

一个关于宏定义的问题,我和ChatGPT、NewBing、Google Bard、文心一言 居然全军覆没?

文章目录 一、问题重述二、AI 解题2.1 ChatGPT2.2 NewBing2.3 Google Bard2.4 文心一言2.5 小结 一、问题重述 今天在问答模块回答了一道问题&#xff0c;要睡觉的时候&#xff0c;又去看了一眼&#xff0c;发现回答错了。 问题描述&#xff1a;下面的z的值是多少。 #define…...

【服务器数据恢复】断电导致RAID无法找到存储设备的数据恢复案例

服务器数据恢复环境&#xff1a; HP EVA存储&#xff0c;6块SAS硬盘组建的raid5磁盘阵列。上层操作系统是WINDOWS SERVER。该存储为公司内部文件服务器使用。 服务器故障&分析&#xff1a; 在遭遇两次意外断电后&#xff0c;设备重启时raid提示“无法找到存储设备”。管理员…...

Windows上不可或缺的5款宝藏软件,工作效率拉满!

职场小白与大牛的区别&#xff1a;小白需要耗费大半天琢磨的事情&#xff0c;而大牛可以只花5分钟就能处理。 “牛人”&#xff0c;即拥有过人之处&#xff0c;专业、经验、技术等等&#xff0c;学会灵活运用高效率的工具也是关键的一点。工具找得好&#xff0c;运用得快&#…...

链表内指定区间反转

题目&#xff1a; 将一个节点数为 size 链表 m 位置到 n 位置之间的区间反转&#xff0c;要求时间复杂度 O(n)&#xff0c;空间复杂度 O(1)。 例如&#xff1a; 给出的链表为 1→2→3→4→5→NULL&#xff0c;m2&#xff0c;n4 返回 1→4→3→2→5→NULL 数据范围&#xff…...

Vue中如何进行地图展示与交互(如百度地图、高德地图)?

Vue中如何进行地图展示与交互 随着移动互联网的普及&#xff0c;地图应用已经成为人们生活中不可或缺的一部分。在Vue.js中&#xff0c;我们可以使用第三方地图库&#xff08;如百度地图、高德地图&#xff09;来实现地图的展示和交互。本文将介绍如何在Vue.js中使用百度地图和…...

uni-app组件概述

1、组件 1.1、组件的含义 组件是视图层的基本组成单元。 组件是一个单独且可复用的功能模块的封装。 组件&#xff0c;包括&#xff1a;以组件名称为标记的开始标签和结束标签、组件内容、组件属性、组件属性值。 <component-name>是开始标签&#xff0c;</compon…...

什么是防火墙?它有什么作用?

作者&#xff1a;Insist-- 个人主页&#xff1a;insist--个人主页 作者会持续更新网络知识和python基础知识&#xff0c;期待你的关注 目录 一、什么是防火墙 二、防火墙的分类 1、软件防火墙 2、硬件防火墙 三、防火墙的作用 1、防止病毒 2、防止访问不安全内容 3、阻…...

基础工程(cubeide串口调试,printf实现,延时函数)

0.基础工程&#xff08;cubeide串口调试&#xff0c;printf实现&#xff0c;延时函数&#xff09; 文章目录 0.基础工程&#xff08;cubeide串口调试&#xff0c;printf实现&#xff0c;延时函数&#xff09;外部时钟源CLOCK(RCC)系统时钟SYS与DEBUG设置UART串口设置cubeide设置…...

大厂设计师都在用的9个灵感工具

每一件伟大的设计作品都离不开设计师灵感的爆发。设计师有很多灵感来源&#xff0c;比如精美的摄影图片、酷炫的网站设计、APP的特色功能、友好的用户体验动画&#xff0c;或者一篇文章。 设计师每天都需要收集灵感&#xff0c;把灵感收集当成日常生活。在这篇文章中&#xff…...

安全实现SpringBoot配置文件自动加解密

需求背景 应用程序开发的时候&#xff0c;往往会存在一些敏感的配置属性 数据库账号、密码第三方服务账号密码内置加密密码其他的敏感配置 对于安全性要求比较高的公司&#xff0c;往往不允许敏感配置以明文的方式出现。 通常做法是对这些敏感配置进行加密&#xff0c;然后在…...

数据结构--队列2--双端队列--java双端队列

介绍 双端队列&#xff0c;和前面学的队列和栈的区别在于双端队列2端都可以进行增删&#xff0c;其他2个都是只能一端可以增/删。 实现 链表 因为2端都需要可以操作所以我们使用双向链表 我们也需要一共头节点 所以节点设置 static class Node<E>{E value;Node<E…...

网络安全:信息收集专总结【社会工程学】

前言 俗话说“渗透的本质也就是信息收集”&#xff0c;信息收集的深度&#xff0c;直接关系到渗透测试的成败&#xff0c;打好信息收集这一基础可以让测试者选择合适和准确的渗透测试攻击方式&#xff0c;缩短渗透测试的时间。 一、思维导图 二、GoogleHacking 1、介绍 利用…...

Linux 命令总结

基本操作 Linux关机,重启 # 关机 shutdown -h now# 重启 shutdown -r now 查看系统,CPU信息 # 查看系统内核信息 uname -a# 查看系统内核版本 cat /proc/version# 查看当前用户环境变量 envcat /proc/cpuinfo# 查看有几个逻辑cpu, 包括cpu型号 cat /proc/cpuinfo | grep na…...

使用腾讯手游助手作为开发测试模拟器的方案---以及部分问题的解决方案

此文主要介绍使用第三方模拟器(这里使用腾讯手游助手)作为开发工具&#xff0c;此模拟器分为两个引擎&#xff0c;一个与其他模拟器一样基于virtualbox的标准引擎&#xff0c;不过优化不太好&#xff0c;一个是他们主推的aow引擎&#xff0c;此引擎。关于aow没有太多的技术资料…...

在线观看视频网站怎么做/营销推广运营

【导读】武大的蒲博士提问&#xff1a;有一个柱状图&#xff0c;拟合了一条曲线&#xff0c;怎样延长拟合曲线到某个点&#xff1f;谭老师没细想说利用Draw工具按照拟合曲线的趋势“画数据”补充几个趋势上的点。现在细想起来&#xff0c;这种方法太Low了。今天谭老师分享一个教…...

宜选网的网站是什么做的/seo排名点击工具

Docker从1.13版本之后采用时间线的方式作为版本号&#xff0c;分为社区版CE和企业版EE 社区版是免费提供给个人开发者和小型团体使用的&#xff0c;企业版会提供额外的收费服务&#xff0c;比如经过官方测试认证过的基础设施、容器、插件等 社区版按照stable和edge两种方式发…...

电子商务网站建设与管理答案/网络营销公司有哪些公司

P1前言在我看来&#xff0c;爬取视频可以分为简单、中等以及困难三种级别。简单级别&#xff1a;网页直接给出了mp4格式的视频链接&#xff0c;所以可以像下载图片一样发个请求就可以轻松获得中等级别&#xff1a;就是网页给出的是ts文件&#xff0c;所有的ts文件会存储在一个m…...

花生棒做网站/如何推广app更高效

老电脑要装什么系统比较好&#xff1f;电脑更新换代速度非常快&#xff0c;现在买的新电脑没几天就变成“老电脑”了&#xff0c;电脑目前已经普及十几年&#xff0c;最开始的老旧电脑硬件配置惨不忍睹&#xff0c;不过在那个年代算很牛逼了&#xff0c;毕竟技术有限。那么老旧…...

php做的网站好么/河南网站优化

题意&#xff1a;给你 n个点 m条边 每条边有些公司支持 问 a点到b点的路径有哪些公司可以支持 这里是一条路径中要每段路上都要有该公司支持 才算合格的一个公司 分析&#xff1a;map[i][j] 等于 i直接到 j 的 公司数,加上i经过中间节点到 j 的 公司数 因为每两个站点间的…...

做网站开发的笔记本配置/平台优化

string &#xff1a;关键字 String &#xff1a;类 可以认为string 是String的别名&#xff0c;在生成的IL中&#xff0c;都是当做String&#xff0c;类似的还有 object 与Object&#xff0c;int 与 Int32 转载于:https://www.cnblogs.com/nzbbody/archive/2012/01/06/2314170.…...