精华内容
下载资源
问答
  • nRF Connect

    热门讨论 2017-06-06 16:53:32
    android BLE4.0调试工具
  • EasyConnect Mac OX 客户端

    2018-11-06 12:02:07
    EasyConnect Mac OX 客户端,支持新版本,支持证书、用户密码登录
  • hillstone secure connect Mac版

    热门讨论 2018-02-02 09:18:10
    山石网科,Hillstone secure connect, 苹果电脑桌面版
  • Connect命令参考手册

    热门讨论 2014-09-03 21:47:22
    要想深层次使用stk,connect指令是必不可少的。stk帮助文档里有connect指令详细使用说明,但都是英文,看起来很不方便。去年翻译了一部分,大概翻译了一半,还有很多没有翻译。现在没有精力搞这个了,把word版本提供...
  • 深信服EasyConnect客户端PC端

    千次下载 热门讨论 2015-11-03 19:33:28
    深信服EasyConnect SSL 客户端PC端下载
  • Connect By

    千次阅读 2019-01-12 17:13:57
    Oracle Connect By Prior用法: 1、connect by中的条件就表示了父子之间的连接关系,比如 connect by id=prior pid。 2、prior,表示在一表上,prior所在列pid的某一值A的记录行的父亲是列id上值等于列pid上值A的...

    Oracle Connect By Prior用法:

    1、connect by中的条件就表示了父子之间的连接关系,比如 connect by id=prior pid。
    2、prior,表示在一表上,prior所在列pid的某一值A的记录行的父亲是列id上值等于列pid上值A的记录行。
    3、LEVEL伪列表示树的深度(或叫高度)。

    一、oracle中的select语句可以用START WITH…CONNECT BYPRIOR子句实现递归查询(或叫树状查询),connect by 是结构化查询中用到的,

    其基本语法是:

     select ... from <TableName>
    
      where <Conditional-1>
    
      start with <Conditional-2>
    
      connect by <Conditional-3>;
    
      <Conditional-1>:过滤条件,用于对返回的所有记录进行过滤。
    
      <Conditional-2>:该限定条件,表示查询结果以谁作为起始根结点的。当然可以放宽该限定条件,以取得多个根结点,实际就是多棵树。
    
      <Conditional-3>:连接条件,即表示不同节点间以该连接条件构成一个父子关系
    

    或:

      [ START WITH condition ] CONNECT BY [ NOCYCLE  ] condition
    

    其中 connect by 与 start with 语句摆放的先后顺序不影响查询的结果,[where 条件1]可以不需要,若是出现则要放在 connect by 与 start with 语句之前,否则出错。

    [where 条件1]、[条件2]、[条件3]各自作用的范围都不相同:*

    [where 条件1]

    是在根据“connect by [条件2] start with [条件3]”选择出来的记录中进行过滤,是针对单条记录的过滤, 不会考虑树的结构(最后的过滤);

    [ connect by 条件2]

    指定构造树的条件,以及对树分支的过滤条件,在这里执行的过滤会把符合条件的记录及其下的所有子节点都过滤掉;

    [ start with 条件3]

    限定作为搜索起始点的条件,如果是自上而下的搜索则是限定作为根节点的条件,如果是自下而上的搜索则是限定作为叶子节点的条件;

    要根据connect by 从上到下还是从下到上,来确定起始节点,可能是叶节点,也可能是父节点,这些开始节点可以是多个,并且包含这些节点。

    oracle 11g r2貌似不支持从下到上的遍历??
    oracle 10g支持从下到上的遍历??

    二、层级查询语句(hierarchical query)中,where子句先被执行,再执行CONNECT BY子句以及其附属子句。

    LEVEL 伪列表示树的深度(或叫高度)。

    使用LEVEL伪列:

    在具有树结构的表中,每一行数据都是树结构中的一个节点,由于节点所处的层次位置不同,所以每行记录都可以有一个层号。层号根据节点与根节点的距离确定。不论从哪个节点开始,该起始根节点的层号始终为1,根节点的子节点为2, 依此类推。

    1、这里说的节点指的是层级查询语句(hierarchical query)中from子句里的表的每一数据行。

    2、层级查询语句(hierarchical query)中,CONNECT BY子句是必选的,而START WITH子句是可选的,START WITH子句是用来修饰CONNECT BY子句的。
    3、prior关键字放在CONNECT BY子句中。其中用PRIOR表示上一条记录,比如 CONNECT BY PRIOR id = parent_id就是说上一条记录的id 是本条记录的parent_id,即本记录的父亲是上一条记录。

    例如,

    connect by parent_id =prior id
    表示的是一数据行中列名为parent_id的列上的值为该行的父节点的编号值,而

    父节点的编号值都是来源于表中列名为id的列上的各个值。
    总之,prior放在connect by子句连接条件里的哪一边,哪一边就是父节点的编号值的来源,而connect by子句连接条件里等号另一边就是记录一数据行其对应的父节点的编号值。

    4、START WITH 子句为可选项,用来标识哪个节点作为查找树型结构的根节点。若该子句被省略,则表示所有满足查询条件(即where子句里的条件)的行作为根节点。具体例子见下文二大点里的注释。

    START WITH: 不但可以指定一个根节点,还可以指定多个根节点。

    “START WITH 子句被省略,则表示所有满足查询条件(即where子句里的条件)的行作为根节点”这个特性可以用来证明”层级查询语句(hierarchical query)中,where子句先被执行,再执行CONNECT BY子句以及其附属子句“。
    5、START WITH 子句和CONNECT BY子句是两个相互独立的子句,即并没有规定START WITH 子句出现的列就是要为CONNECT BY子句里那个带有关键字prior的列,START WITH 子句出现的列可以来自表里的任何列,也就是说START WITH 子句出现的列可以没有在START WITH 子句里出现,因为START WITH 子句的作用就是根据START WITH 子句的限定条件来筛选出哪些数据行作为根节点而已。例子,

    select * from t2 start with id = 1 connect by prior id= root_id;
    select *  from t2 start with root_id = 0 connect by prior id = root_id;
    

    6、层级查询语句(hierarchical query),
    Oracle采用了自上而下的深度优先的算法。

    下面以一个具体例子来说明层级查询语句(hierarchical query)connect by 用法。

    现在有一个表t2,

    表t2的表结构如下:

    create table t2(
    
      root_id number,
    
      id number,
    
      name varchar(5),
    
      description varchar(10)
    
      );
    
      insert into t2(root_id,id,name,description)values(0,1,'a','aaa');
    
      insert into t2(root_id,id,name,description)values(1,2,'a1','aaa1');
    
      insert into t2(root_id,id,name,description)values(1,3,'a2','aaa2');
    
      insert into t2(root_id,id,name,description)values(0,4,'b','bbb');
    
      insert into t2(root_id,id,name,description)values(4,5,'b1','bbb1');
    
      insert into t2(root_id,id,name,description)values(4,6,'b2','bbb2');
    

    获取完整树:

    select * from t2 start withroot_id = 0connect by prior id = root_id;
    

    注释:

    简单说来是将一个树状结构存储在一张表里,比如一个表中存在两个字段: root_id,id。那么通过表示每一条记录的父记录是谁,就可以形成一个树状结构。
    用上述语法的查询可以取得这棵树的所有记录。

    上述SQL语句具体执行过程分析:

    1) 首先,执行的是该select语句中的start with子句部分,具体地说,就是执行该select语句的服务器进程先从表t2中找出所有 root_id字段的值为 0的数据行。在上述例子中,就是name字段分别为a和b的两条数据行,它们两构成了上图中树的第一层。

    2)接着,执行的是该select语句中的connect by子句部分,具体地说,就是执行该select语句的服务器进程先从表t2剩下的数据行(即除去了已经被选中的那些数据行)中找出所有root_ id字段的值等于在上图的树中位于其上一层中各个数据行的id字段的值的数据行。在上述例子中,上图中树的第一层里name字段为a的数据行的id字段值为1,所以服务器进程就从表t2剩下的数据行(即出去了上图中树的第一层里的那两条数据行)中找出所有root_ id字段的值等于1的数据行,即name字段分别为a1和a2的两条数据行;上图中树的第一层里name字段为b的数据行的id字段值为4,所以服务器进程就从表t2剩下的数据行(即出去了上图中树的第一层里的那两条数据行以及前面刚被选中的两条数据行)中找出所有root_ id字段的值等于4的数据行,即name字段分别为b1和b2的两条数据行。于是,name字段分别为a1和a2,b1和b2的四条数据行,构成了上图中树的第二层。

    3)再接着,服务器进程还是要重复执行该select语句中的connect by子句部分,直到表中不存在符合prior id = root_id这个条件的数据行为止。

    此时,服务器进程发现表t2中剩余的数据行为空了。

    这样,该select语句整个过程就执行完毕了。如果表t2中还是有剩余的数据行的,则服务器进程重复执行2)步骤。

    注释:

    在 层次查询(或叫递归查询)中,connect by子句的条件里的表达式必须要有prior运算符 放在一个字段的前面来表示该字段是父数据行((即树结构图中位于子数据行所在层的直接上一层里的数据行))的该字段。例如,

    … PRIOR expr = expr

    or

    … expr = PRIOR expr

    也就是说,当connect by子句的条件里出现的字段是普通字段,不是伪列字段rownum或是level时,connect by子句的条件里的表达式必须要有prior运算符 放在一个字段的前面;当connect by子句的条件里出现的是伪列字段rownum或是level时,connect by子句的条件里的表达式不用出现prior运算符。

    还有一点要说明的是,start with子句不是一个独立的子句,即start with子句是一个不能单独出现在SQL语句的子句,必须在SQL语句中出现了connect by子句后,才能出现。换句话说,start with子句是来配合connect by子句的。例如,

    SQL> select * from t2 start with id = 1;

    select * from t2 start withid = 1

              *
    

    第 1 行出现错误:

    ORA-01788: 此查询块中要求 CONNECT BY 子句

    附加:其他依赖于CONNECT BY 子句的伪列,如level、CONNECT_BY_ISCYCLE等也会有相同的提示,若是独立出现的话。

    当connect by子句没有带start with子句时,例如,select * from t2 connect by prior id = root_id,则因为带prior的id字段是父数据行的字段,所以执行该select语句的服务器进程先从表t2中找出所有 id字段值非空的数据行(差不多就是表t2的所有数据行),它们构成了树结构的第一层。接着,执行该select语句的服务器进程从表t2中找出所有root_ id字段的值等于在树结构的第一层中各个数据行的id字段值的数据行,它们构成了树结构的第二层。再接着,服务器进程从表t2中找出所有root_ id字段的值等于在树结构的第二层中各个数据行的id字段值的数据行。就这样,一直重复执行connect by prior id = root_id这一个子句,直到表中不存在符合prior id = root_id这个条件的数据行为止。

    下面是该SQL语句的执行结果:

     select t2.*,level from t2 connect by prior id = root_id;
    

    LEVEL ID ROOT_ID NAME DESCRIPTIO


    1 1 0 a aaa

    1 2 1 a1 aaa1

    1 3 1 a2 aaa2

    1 4 0 b bbb

    1 5 4 b1 bbb1

    1 6 4 b2 bbb2

    2 2 1 a1 aaa1

    2 3 1 a2 aaa2

    2 5 4 b1 bbb1

    2 6 4 b2 bbb2

    注释:

    ID表示树状结构图中各个节点的编号值。

    LEVEL伪列表示树的深度(或叫高度)。

    当connect by子句带有start with子句时,例如,select * from t2 start with root_id = 0 connect by prior id = root_id,则执行该select语句的服务器进程首先执行的是该select语句中的start with子句部分。start with子句部分的功能就是让服务器进程根据start with子句里的字段找到树结构的第一层里所有的数据行。找完第一层的数据行后,服务器进程执行的操作和connect by子句没带有start with子句时的操作就是一样的了,也是重复执行connect by prior id = root_id这一个子句,直到表中不存在符合prior id = root_id这个条件的数据行为止。

    select * from t2 start with root_id = 0 connect by prior id = root_id;
    

    LEVEL ID ROOT_ID NAME DESCRIPTIO


    1 1 0 a aaa

    1 4 0 b bbb

    1 5 4 b1 bbb1

    1 6 4 b2 bbb2

    2 2 1 a1 aaa1

    2 3 1 a2 aaa2

    虽然这个SQL语句中start with子句里的字段和connect by子句里的带prior的字段不一样,但是不会相互影响的。

    2)在connect by 子句里出现的两个字段都是同一个表里的两个字段。

    3) “执行该select语句的服务器进程先从表t2剩下的数据行(即除去了已经被选中的那些数据行)中查找数据行“这样的表述是不正确的。其实,每次服务器进程都是从表t2中的所有的数据行上查找的。例如,

     select t2.*,level from t2 connect by prior id = root_id;
    

    ROOT_ID ID NAME DESCRIPTIO LEVEL


        0          1 a     aaa                 1
    
        1          2 a1    aaa1                1
    
        1          3 a2    aaa2                1
    
        0          4 b     bbb                 1
    
        4          5 b1    bbb1                1
    
        4          6 b2    bbb2                1
    
        1         2 a1    aaa1                2
    
        1          3 a2    aaa2                2
    
        4          5 b1    bbb1                2
    
        4          6 b2    bbb2                2
    

    从上面的例子可以看出,处于树结构第二层(level=2)的数据行也在处于树结构第一层(level=1)中出现。这就说明了,每次服务器进程都是从表t2中的所有的数据行上查找的。

    4)当表中有重复行时,这些重复行不会合并在一起,而是单独算的。例如,

     insert into t2(root_id,id,name,description)values(4,6,'b2','bbb2');
    
    
    
    
    select t22.*,level from t2  connect by prior id = root_id order bylevel,i
    
    d;
    

    ROOT_ID ID NAME DESCRIPTIO LEVEL


         0          1 a     aaa                 1
    
         1          2 a1    aaa1                1
    
         1          3 a2    aaa2                1
    
         0          4 b     bbb                 1
    
         4          5 b1    bbb1                1
    
         4          6 b2    bbb2                1
    
        4          6 b2    bbb2                1
    
         1         2 a1    aaa1                2
    
         1          3 a2    aaa2                2
    
         4          5 b1    bbb1                2
    
         4          6 b2    bbb2                2
    
        4          6 b2    bbb2                2
    

    二、获取特定子树:

    select * from t2 start with id = 1 connect by prior id= root_id;
    
    select * from t2 start with id = 4 connect by prior id = root_id;
    

    如果connect by prior中的prior被省略,则查询将不进行深层递归。如:

    select * from t2 start with root_id = 0 connect by id = root_id;//此时 start with子句还是有被执行的
    
    select * from t2 start with id = 1 connect by id = root_id;
    

    注释:

    上述两个例子如果connect by prior中的关键字prior被省略,且在connect by 里的字段不是伪列rownum或是伪列level(伪列level只有在SQL语句中出现了connect by 子句时才有的),那么connect by子句会被忽略不被执行的(此时 start with子句还是有被执行的)。

    附加 Oracle “CONNECT BY” 使用

    Oracle “CONNECT BY”是层次查询子句,一般用于树状或者层次结果集的查询。其语法是:

    [ START WITH condition ]

    CONNECT BY [ NOCYCLE ] condition

    说明:

    1. START WITH:告诉系统以哪个节点作为根结点开始查找并构造结果集,该节点即为返回记录中的最高节点。

    2. 当分层查询中存在上下层互为父子节点的情况时,会返回ORA-01436错误。此时,需要在connect by后面加上NOCYCLE关键字。同时,可用connect_by_iscycle伪列定位出存在互为父子循环的具体节点。 connect_by_iscycle必须要跟关键字NOCYCLE结合起来使用,也就说,connect_by_iscycle伪列是一个不能单独出现在SQL语句的伪列,必须在SQL语句中出现了关键字NOCYCLE后,才能出现。例如,

      select connect_by_iscycle from t2 start with root_id = 0 connect byNOCYCLE prior id = root_id;

    接下来,用一些示例来说明“CONNECT BY”的用法。

    [例1] 创建一个部门表,这个表有三个字段,分别对应部门ID,部门名称,以及上级部门ID

    – Create table

    create table DEP(
    
    DEPID number(10)notnull,
    
    DEPNAME varchar2(256),
    
    UPPERDEPID number(10)
    
    );
    

    初始化数据

     INSERTINTODEP(DEPID,  DEPNAME, UPPERDEPID)VALUES(0, '总经办',null);
    
     INSERTINTODEP(DEPID,  DEPNAME, UPPERDEPID)VALUES(1, '开发部', 0);
    
     INSERTINTODEP(DEPID,  DEPNAME, UPPERDEPID)VALUES(2, '测试部', 0);
    
     INSERTINTODEP(DEPID,  DEPNAME, UPPERDEPID)VALUES(3, 'Sever开发部', 1);
    
     INSERTINTODEP(DEPID,  DEPNAME, UPPERDEPID)VALUES(4, 'Client开发部', 1);
    
    
     INSERTINTODEP(DEPID,  DEPNAME, UPPERDEPID)VALUES(5, 'TA测试部', 2);
    
     INSERTINTODEP(DEPID,  DEPNAME, UPPERDEPID)VALUES(6, '项目测试部', 2);
    
    
    
    SELECT*FROM DEP;
    

    DEPID DEPNAME UPPERDEPID


    0 General Deparment

    1 Development 0

    2 QA 0

    3 Server Development 1

    4 Client Development 1

    5 TA 2

    6 Porject QA 2

    7 rowsselected

    根据“CONNECT BY”来实现树状查询结果

    SELEC TRPAD(' ',  2*(LEVEL-1),'-') || DEPNAME "DEPNAME",
    
    CONNECT_BY_ROOT  DEPNAME"ROOT",
    
    CONNECT_BY_ISLEAF  "ISLEAF",
    
    LEVEL ,
    
    SYS_CONNECT_BY_PATH(DEPNAME,'/')"PATH"
    
    FROM DEP
    
    START WITHUPPERDEPIDIS NULL
    
    CONNECT BY PRIOR DEPID = UPPERDEPID;
    

    DEPNAME ROOT ISLEAF LEVELPATH


    General Deparment General Deparment 0 1 /General Deparment

    -Development General Deparment 0 2 /General Deparment/Development

    —Server Development General Deparment 1 3 /General Deparment/Development/Server Development

    —Client Development General Deparment 1 3 /General Deparment/Development/Client Development

    -QA General Deparment 0 2 /General Deparment/QA

    —TA General Deparment 1 3 /General Deparment/QA/TA

    —Porject QA General Deparment 1 3 /General Deparment/QA/Porject QA
    说明:

    1. CONNECT_BY_ROOT (伪列)返回当前节点的最顶端节点
    2. CONNECT_BY_ISLEAF (伪列)判断是否为叶子节点,如果这个节点下面有子节点,则不为叶子节点
    3. LEVEL 伪列表示树的深度(或叫高度)
    4. SYS_CONNECT_BY_PATH函数显示详细路径,并用“/”分隔

    CONNECT BY的应用例子

    [例2]

    通过CONNECT BY用于十六进度转换为十进制

    CREATE OR REPLACE FUNCTION f_hex_to_dec(p_str  IN VARCHAR2) RETURN VARCHAR2 IS
    
    ----------------------------------------------------------------------------------------------------------------------
    
    -- 对象名称: f_hex_to_dec
    
    -- 对象描述: 十六进制转换十进制
    
    -- 输入参数: p_str 十六进制字符串
    
    -- 返回结果: 十进制字符串
    
    -- 测试用例: SELECT f_hex_to_dec('78A')  FROM dual;
    
    ----------------------------------------------------------------------------------------------------------------------
    
    v_return VARCHAR2(4000);
    
    BEGIN
    
    SELECT SUM(DATA) INTO v_return
    
    FROM (SELECT (CASE upper(substr(p_str,  rownum, 1))
    
    WHEN 'A' THEN '10'
    
    WHEN 'B' THEN '11'
    
    WHEN 'C' THEN '12'
    
    WHEN 'D' THEN '13'
    
    WHEN 'E' THEN '14'
    
    WHEN 'F' THEN '15'
    
    ELSE substr(p_str, rownum, 1)
    
    END) * power(16, length(p_str)  - rownum) DATA
    
    FROM dual
    
    CONNECT BY rownum  <= length(p_str));
    
    RETURN v_return;
    
    EXCEPTION
    
    WHEN OTHERS THEN
    
    RETURN NULL;
    
    END;
    

    说明:

    1. CONNECT BY rownum <= length(p_str))对输入的字符串进行逐个遍历

    2. 通过CASE语句,来解析十六进制中的A-F对应的10进制值

    [例3]通过CONNECT BY生成序列

     SELECT ROWNUM FROM DUAL  CONNECT BY ROWNUM  <= 10;
    

    ROWNUM


    1
    2
    3
    4
    5
    6
    7
    8
    9
    10

    展开全文
  • EasyConnect安装使用教程

    万次阅读 多人点赞 2021-02-26 11:09:31
    easyconnect电脑版是一款为企业提供的移动信息化办公软件,这款软件可以让公司经常出差的人员能在公司范围外使用公司的内网系统和相关应用。软件支持移动和pc平台,不管是在电脑上还是手机上使用都非常方便,easy...

    easyconnect电脑版是一款为企业提供的移动信息化办公软件,这款软件可以让公司经常出差的人员能在公司范围外使用公司的内网系统和相关应用。软件支持移动和pc平台,不管是在电脑上还是手机上使用都非常方便,easyconnect电脑版便捷性和安全性使企业可以随时随地准确获得信息,进行决策。

    公司员工可以借助这个工具使用外网连接到公司内网。

    下载地址:https://download.csdn.net/download/weixin_41937552/15480073

    目录

     

    安装方法:

    使用教程


    安装方法:

    下载安装包解压后,双击.exe文件就可以安装软件。

    耐心等待easyconnect安装完就可以了,点击完成。

    可能需要下载必要的组件。直接下载安装即可

    使用教程

    双击easyconnect打开软件,主界面如下图所示,输入服务器地址,这个地址一般是公司或校园的vpn地址,点击“连接”即可。界面显示正在初始化,等待一段时间后,即可进入帐号登录界面。

    输入用户名以及密码,勾选记住密码,点击箭头处的“登录”即可。

    这样我们就成功登录到内网,浏览器会自动跳转到相应的内网界面。如果需要退出easyconnect,找到右下角的软件图标,单击鼠标右键,点击“退出”即可。

     

    好啦,本期的内容就分享到这里,我们下期见!

        好书不厌百回读,熟读自知其中意。让学习成为习惯,用知识改变命运,让博客见证成长,用行动证明努力。
        如果我的博客对你有帮助、如果你喜欢我的博客内容,请 “点赞” “评论” “收藏” 一键三连哦!
        听说 👉 点赞 👈 的人运气不会太差,每一天都会元气满满呦!^ _ ^ ❤️ ❤️ ❤️
        码字不易,大家的支持就是我坚持下去的动力。点赞后不要忘了👉 关注 👈我哦!
        更多精彩内容请前往 孙叫兽的博客

    微信公众号【电商程序员】,分享改变自己的项目。

    如果以上内容有任何错误或者不准确的地方,欢迎在下面 👇 留个言。或者你有更好的想法,欢迎一起交流学习~~~
     

     

    展开全文
  • Kafka Connect简介

    万次阅读 2019-06-25 18:44:59
    Kafka Connect简介  Kafka是一个使用越来越广的消息系统,尤其是在大数据开发中(实时数据处理和分析)。为何集成其他系统和解耦应用,经常使用Producer来发送消息到Broker,并使用Consumer来消费Broker中的消息...

    一. Kafka Connect简介

      Kafka是一个使用越来越广的消息系统,尤其是在大数据开发中(实时数据处理和分析)。为何集成其他系统和解耦应用,经常使用Producer来发送消息到Broker,并使用Consumer来消费Broker中的消息。Kafka Connect是到0.9版本才提供的并极大的简化了其他系统与Kafka的集成。Kafka Connect运用用户快速定义并实现各种Connector(File,Jdbc,Hdfs等),这些功能让大批量数据导入/导出Kafka很方便。

                 

    如图中所示,左侧的Sources负责从其他异构系统中读取数据并导入到Kafka中;右侧的Sinks是把Kafka中的数据写入到其他的系统中。

    二. 各种Kafka Connector

      Kafka Connector很多,包括开源和商业版本的。如下列表中是常用的开源Connector

    ConnectorsReferences
    JdbcSourceSink
    Elastic SearchSink1Sink2Sink3
    CassandraSource1Source 2Sink1Sink2 
    MongoDBSource
    HBaseSink
    SyslogSource
    MQTT (Source)Source
    Twitter (Source)SourceSink
    S3Sink1Sink2
     

      商业版的可以通过Confluent.io获得

    三. 示例

    3.1 FileConnector Demo

     本例演示如何使用Kafka Connect把Source(test.txt)转为流数据再写入到Destination(test.sink.txt)中。如下图所示:

              

          本例使用到了两个Connector:

    • FileStreamSource:从test.txt中读取并发布到Broker中
    • FileStreamSink:从Broker中读取数据并写入到test.sink.txt文件中

      其中的Source使用到的配置文件是${KAFKA_HOME}/config/connect-file-source.properties

    name=local-file-source
    connector.class=FileStreamSource
    tasks.max=1
    file=test.txt
    topic=connect-test

      其中的Sink使用到的配置文件是${KAFKA_HOME}/config/connect-file-sink.properties

    name=local-file-sink
    connector.class=FileStreamSink
    tasks.max=1
    file=test.sink.txt
    topics=connect-test

      Broker使用到的配置文件是${KAFKA_HOME}/config/connect-standalone.properties

    复制代码

    bootstrap.servers=localhost:9092key.converter=org.apache.kafka.connect.json.JsonConverter
    value.converter=org.apache.kafka.connect.json.JsonConverter
    key.converter.schemas.enable=true
    value.converter.schemas.enable=trueinternal.key.converter=org.apache.kafka.connect.json.JsonConverter
    internal.value.converter=org.apache.kafka.connect.json.JsonConverter
    internal.key.converter.schemas.enable=false
    internal.value.converter.schemas.enable=false
    offset.storage.file.filename=/tmp/connect.offsets
    offset.flush.interval.ms=10000
    

    复制代码

     

    3.2 运行Demo

      需要熟悉Kafka的一些命令行,参考本系列之前的文章Apache Kafka系列(二) 命令行工具(CLI)

     3.2.1 启动Kafka Broker

    [root@localhost bin]# cd /opt/kafka_2.11-0.11.0.0/
    [root@localhost kafka_2.11-0.11.0.0]# ls
    bin  config  libs  LICENSE  logs  NOTICE  site-docs
    [root@localhost kafka_2.11-0.11.0.0]# ./bin/zookeeper-server-start.sh ./config/zookeeper.properties &
    [root@localhost kafka_2.11-0.11.0.0]# ./bin/kafka-server-start.sh ./config/server.properties &

    3.2.2 启动Source Connector和Sink Connector

    [root@localhost kafka_2.11-0.11.0.0]# ./bin/connect-standalone.sh config/connect-standalone.properties config/connect-file-source.properties config/connect-file-sink.properties 

    3.3.3 打开console-consumer

    ./kafka-console-consumer.sh --zookeeper localhost:2181 --from-beginning --topic connect-test

    3.3.4 写入到test.txt文件中,并观察3.3.3中的变化

    [root@Server4 kafka_2.12-0.11.0.0]# echo 'firest line' >> test.txt
    [root@Server4 kafka_2.12-0.11.0.0]# echo 'second line' >> test.txt
    3.3.3中打开的窗口输出如下
    {"schema":{"type":"string","optional":false},"payload":"firest line"}
    {"schema":{"type":"string","optional":false},"payload":"second line"}

    3.3.5 查看test.sink.txt

    [root@Server4 kafka_2.12-0.11.0.0]# cat test.sink.txt 
    firest line
    second line

     本例仅仅演示了Kafka自带的File Connector,后续文章会完成JndiConnector,HdfsConnector,并且会使用CDC(Changed Data Capture)集成Kafka来完成一个ETL的例子

     

    四. kafka 0.9 connect JDBC测试

    kafka 0.9的connect功能,测试过程如下:

    1.创建容器(本次采用docker容器构建kafka环境)

    docker run -p 10924:9092 -p 21814:2181 --name confluent -i -t -d java /bin/bash

    2.将confluent安装程序拷贝进容器;

    docker cp  confluent.zip confluent:/root

    3.进入到confluent容器

    docker exec -it confluent /bin/bash

    4.解压confluent压缩包

    unzip confluent.zip

    5.启动kafka

    /root/confluent/bin/zookeeper-server-start  /root/confluent/etc/kafka/zookeeper.properties  & > zookeeper.log

    /root/confluent/bin/kafka-server-start  /root/confluent/etc/kafka/server.properties & > server.log

    /root/confluent/bin/schema-registry-start  /root/confluent/etc/schema-registry/schema-registry.properties & > schema.log

    6.测试kafka 是否正常

    开两个docker窗口,一个跑producer,一个跑consumer,

    /root/confluent/bin/kafka-avro-console-producer --broker-list localhost:9092 --topic test --property value.schema='{"type":"record","name":"myrecord","fields":[{"name":"f1","type":"string"}]}'

     

    /root/confluent/bin/kafka-avro-console-consumer --topic test  --zookeeper localhost:2181 --from-beginning

    在producer端依次输入以下记录,确认consumer能正确显示;

    {"f1": "value1"}

    {"f1": "value2"}

    {"f1": "value3"}

    以上为安装kafka过程,接下来开始测试jdbc接口;

    测试之前,需要获取mysql JDBC的驱动并将获放在kafka环境对应的jre/lib文件夹里

    测试jdbc connect

    1.创建配置文件quickstart-mysql.properties,内容如下: 

    name=test-mysql-jdbc-autoincrement
    connector.class=io.confluent.connect.jdbc.JdbcSourceConnector
    tasks.max=1
    connection.url=jdbc:mysql://192.168.99.100:33061/test1?user=root&password=welcome1
    mode=incrementing
    incrementing.column.name=id
    topic.prefix=test-mysql-jdbc-

    注:mysql是我在另一个容器里运行的,jdbc:mysql://192.168.99.100:33061/test1?user=root&password=welcome1是连接容器里的mysql的连接串

    2.执行./bin/connect-standalone etc/schema-registry/connect-avro-standalone.properties etc/kafka-connect-jdbc/quickstart-mysql.properties

    3.执行./bin/kafka-avro-console-consumer --new-consumer --bootstrap-server 192.168.99.100:10924 --topic test-mysql-jdbc-accounts --from-beginning

    然后在数据库里增加一条记录

    然后就会在consumer端显示新增记录

     

    五. 配置连接器

     

    Connector的配置是简单的key-value映射。对于独立模式,这些都是在属性文件中定义,并通过在命令行上的Connect处理。在分布式模式,JSON负载connector的创建(或修改)请求。大多数配置都是依赖的connector,有几个常见的选项:

    • name - 连接器唯一的名称,不能重复。
    • connector.calss - 连接器的Java类。
    • tasks.max - 连接器创建任务的最大数。
    • connector.class配置支持多种格式:全名或连接器类的别名。比如连接器是org.apache.kafka.connect.file.FileStreamSinkConnector,你可以指定全名,也可以使用FileStreamSinkFileStreamSinkConnector。Sink connector也有一个额外的选项来控制它们的输入:
    • topics - 作为连接器的输入的topic列表。

    对于其他的选项,你可以查看连接器的文档。

    六、rest api

    kafka connect的目的是作为一个服务运行,默认情况下,此服务运行于端口8083。它支持rest管理,用来获取 Kafka Connect 状态,管理 Kafka Connect 配置,Kafka Connect 集群内部通信,常用命令如下:

    GET /connectors 返回一个活动的connect列表
    POST /connectors 创建一个新的connect;请求体是一个JSON对象包含一个名称字段和连接器配置参数

    GET /connectors/{name} 获取有关特定连接器的信息
    GET /connectors/{name}/config 获得特定连接器的配置参数
    PUT /connectors/{name}/config 更新特定连接器的配置参数
    GET /connectors/{name}/tasks 获得正在运行的一个连接器的任务的列表

    DELETE /connectors/{name} 删除一个连接器,停止所有任务,并删除它的配置

    GET /connectors 返回一个活动的connect列表

    POST /connectors 创建一个新的connect;请求体是一个JSON对象包含一个名称字段和连接器配置参数

    GET /connectors/{name} 获取有关特定连接器的信息
    GET /connectors/{name}/config 获得特定连接器的配置参数
    PUT /connectors/{name}/config 更新特定连接器的配置参数
    GET /connectors/{name}/tasks 获得正在运行的一个连接器的任务的列表

    DELETE /connectors/{name} 删除一个连接器,停止所有任务,并删除它的配置

    curl -s <Kafka Connect Worker URL>:8083/ | jq   获取 Connect Worker 信息

    curl -s <Kafka Connect Worker URL>:8083/connector-plugins | jq 列出 Connect Worker 上所有 Connector

    curl -s <Kafka Connect Worker URL>:8083/connectors/<Connector名字>/tasks | jq 获取 Connector 上 Task 以及相关配置的信息

    curl -s <Kafka Connect Worker URL>:8083/connectors/<Connector名字>/status | jq 获取 Connector 状态信息

    curl -s <Kafka Connect Worker URL>:8083/connectors/<Connector名字>/config | jq 获取 Connector 配置信息

    curl -s -X PUT <Kafka Connect Worker URL>:8083/connectors/<Connector名字>/pause 暂停 Connector

    curl -s -X PUT <Kafka Connect Worker URL>:8083/connectors/<Connector名字>/resume 重启 Connector

    curl -s -X DELETE <Kafka Connect Worker URL>:8083/connectors/<Connector名字> 删除 Connector

    创建新 Connector (以FileStreamSourceConnector举例)

     
    1. curl -s -X POST -H "Content-Type: application/json" --data

    2. '{"name": "<Connector名字>",

    3. "config":

    4. {"connector.class":"org.apache.kafka.connect.file.FileStreamSourceConnector",

    5. "key.converter.schemas.enable":"true",

    6. "file":"demo-file.txt",

    7. "tasks.max":"1",

    8. "value.converter.schemas.enable":"true",

    9. "name":"file-stream-demo-distributed",

    10. "topic":"demo-distributed",

    11. "value.converter":"org.apache.kafka.connect.json.JsonConverter",

    12. "key.converter":"org.apache.kafka.connect.json.JsonConverter"}

    13. }'

    14. http://<Kafka Connect Worker URL>:8083/connectors | jq

     

    更新 Connector配置 (以FileStreamSourceConnector举例)

     
    1. curl -s -X PUT -H "Content-Type: application/json" --data

    2. '{"connector.class":"org.apache.kafka.connect.file.FileStreamSourceConnector",

    3. "key.converter.schemas.enable":"true",

    4. "file":"demo-file.txt",

    5. "tasks.max":"2",

    6. "value.converter.schemas.enable":"true",

    7. "name":"file-stream-demo-distributed",

    8. "topic":"demo-2-distributed",

    9. "value.converter":"org.apache.kafka.connect.json.JsonConverter",

    10. "key.converter":"org.apache.kafka.connect.json.JsonConverter"}'

    11. <Kafka Connect Worker URL>:8083/connectors/file-stream-demo-distributed/config | jq

    七、kafka connect + debezium,解析binlog至kafka

    在已知kafka connect和debezium作用,会使用kafka的基础上,学会使用debezium来读取binlog,并通过kafka connect将读取的内容放入kafka topic中。 

    基于kafka0.10.0和Debezium0.6,mysql5.6

    kafka connect

    • Kafka Connect是一种用于Kafka和其他数据系统之间进行数据传输的工具。
    • 仅关注数据的复制,并且不处理其他任务
    • Kafka connect有两个概念,一个source,另一个是sink。source是把数据从一个系统拷贝到kafka里,sink是从kafka拷贝到另一个系统里。
    • 可使用插件,获取不同系统的数据。例如通过Debezium插件解析mysql的日志,获取数据。
    • 支持集群,可以通过REST API管理Kafka Connect。
    • 对数据的传输进行管理和监控。

    Debezium

    • Debezium是一个分布式平台,可将现有数据库转换为事件流,因此应用程序可以立即查看并立即响应数据库中每一行的更改。
    • Debezium建立在Apache Kafka之上,并提供用于监视特定数据库管理系统的Kafka Connect兼容连接器。
    • 本教程使用Debezium监控binlog。

    准备操作

    • mysql需开启binlog
     
    1. [mysqld]

    2. log-bin=mysql-bin #添加这一行就ok

    3. binlog-format=ROW #选择row模式

    4. server_id=1 #配置mysql replaction需要定义,不能和canal的slaveId重复

    • mysql需创建一个有mysql slave相关权限的账号,若mysql不在本机,则需要远程权限,防火墙放行。
     
    1. //mysql slave相关权限

    2. CREATE USER canal IDENTIFIED BY 'debezium';

    3. GRANT SELECT, REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'debezium'@'%';

    4. -- GRANT ALL PRIVILEGES ON *.* TO 'debezium'@'%' ;

    5. FLUSH PRIVILEGES;

    • 操作概述
    • 安装并启动kafka
    • 安装并启动mysql
    • 下载Debezium的mysql连接器http://debezium.io/docs/install/并解压
    • 安装debezium,即将解压目录写入classpath变量,例如:export classpath=/root/debezium-connector-mysql/* 
      只在当前shell有效
    • 参考http://debezium.io/docs/connectors/mysql/的配置文件示例,写好配置文件。
    • 以独立模式启动kafka connect,此时debezium会对数据库中的每一个表创建一个topic,消费相应的topic,即可获取binlog解析信息。
     
    1. //启动kafka connect

    2. bin/connect-standalone.sh config/connect-standalone.properties mysql.properties

    3. //查看topic列表

    4. bin/kafka-topics.sh --list --zookeeper localhost:2181

    5. //消费该主题

    6. bin/kafka-console-consumer.sh --bootstrap-server localhost:9092 --topic test --from-beginning

    • 配置文件
     
    1. //mysql.properties

    2. name=inventory-connector

    3. connector.class=io.debezium.connector.mysql.MySqlConnector

    4. database.hostname=192.168.99.100

    5. database.port=3306

    6. database.user=debezium

    7. database.password=dbz

    8. database.server.id=184054

    9. database.server.name=fullfillment

    10. database.whitelist=inventory

    11. database.history.kafka.bootstrap.servers=192.168.30.30:9092

    12. database.history.kafka.topic=dbhistory.fullfillment

    13. include.schema.changes=true

    • 索引

    debezium官网 http://debezium.io/ 

    kafka文档 http://kafka.apache.org/0100/documentation.html

     

    八、Kafka Connect的优点

    1.对开发者提供了统一的实现接口
    2.开发,部署和管理都非常方便,统一 
    3.使用分布式模式进行水平扩展,毫无压力
    4.在分布式模式下可以通过Rest Api提交和管理Connectors
    5.对offset自动管理,只需要很简单的配置,而不像Consumer中需要开发者处理
    6.流式/批式处理的支持

    九、第三方资源

    这是已经得到支持的组件,不需要做额外的开发: https://www.confluent.io/product/connectors/
    括号中的Source表示将数据从其他系统导入Kafka,Sink表示将数据从Kafka导出到其他系统。
    其他的我没看,但是JDBC的实现比较的坑爹,是通过primary key(如id)和时间戳(如updateTime)字段,

    来判断数据是否更新,这样的话应用范围非常受局限。

     

    十、Connector Development Guide

     

    在kafka与其他系统间复制数据需要创建kafka connect,他们将数复制到kafka或者从kafka复制到其他系统

    连接器有两种形式:sourceconnectors将另一个系统数据导入kafka,sinkconnectors将数据导出到另一个系统

    连接器不执行任何数据复制:它们的描述复制的数据,并且负责将工作分配给多个task

    task分为sourcetask与sinktask

    每个task从kafka复制数据,connect会保证record与schema的一致性完成任务分配,通常record与schema的映射是明显的,每一个文件对应一个流,流中的每一条记录利用schema解析并且保存对应的offset,另外一种情况是我们需要自己完成这种映射,比如数据库,表的offset不是很明确(没有自增id),一种可能的选择是利用时间(timestamp)来完成增量查询。

    Streams and Records


    每一个stream是包含key value对的记录的序列,key value可以是原始类型,可以支持复杂结构,除了array,object,嵌套等。数据转换是框架来完成的,record中包含stream id与offset,用于定时offset提交,帮助当处理失败时恢复避免重复处理。

    Dynamic Connectors

    所有的job不是静态的,它需要监听外部系统的变化,比如数据库表的增加删除,当一个新table创建时,它必须发现并且更新配置由框架来分配给该表一个task去处理,当通知发布后框架会更新对应的task.

    Developing a Simple Connector

    例子很简单
    在standalone模式下实现 SourceConnector/SourceTask 读取文件并且发布record给SinkConnector/SinkTask 由sink写入文件

    Connector Example

    我们将实现SourceConnector,SinkConnector实现与它非常类似,它包括两个私有字段存放配置信息(读取的文件名与topic名称)
    public class FileStreamSourceConnector extends SourceConnector {
        private String filename;
        private String topic;
    getTaskClass()方法定义实现执行处理的task
    @Override
    public Class getTaskClass() {
        return FileStreamSourceTask.class;
    }
    下面定义FileStreamSourceTask,它包括两个生命周期方法start,stop
    @Override
    public void start(Map<String, String> props) {
        // The complete version includes error handling as well.
        filename = props.get(FILE_CONFIG);
        topic = props.get(TOPIC_CONFIG);
    }
    @Override
    public void stop() {
        // Nothing to do since no background monitoring is required.
    }
    最后是真正核心的方法getTaskConfigs()在这里我们仅处理一个文件,所以我们虽然定义了max task(在配置文件里)但是只会返回一个包含一条entry的list
    @Override
    public List<Map<String, String>> getTaskConfigs(int maxTasks) {
        ArrayList>Map<String, String>> configs = new ArrayList<>();
        // Only one input stream makes sense.
        Map<String, String> config = new Map<>();
        if (filename != null)
            config.put(FILE_CONFIG, filename);
        config.put(TOPIC_CONFIG, topic);
        configs.add(config);
        return configs;
    }
    即使有多个任务,这种方法的执行通常很简单。它只是要确定输入任务的数量,这可能需要拉取数据从远程服务,然后分摊。请注意,这个简单的例子不包括动态输入。在下一节中看到讨论如何触发任务的配置更新。

    Task Example - Source Task

    实现task,我们使用伪代码描述核心代码
    public class FileStreamSourceTask extends SourceTask<Object, Object> {
        String filename;
        InputStream stream;
        String topic;
        public void start(Map<String, String> props) {
            filename = props.get(FileStreamSourceConnector.FILE_CONFIG);
            stream = openOrThrowError(filename);
            topic = props.get(FileStreamSourceConnector.TOPIC_CONFIG);
        }
        @Override
        public synchronized void stop() {
            stream.close()
        }
    start方法读取之前的offset,并且处理新的数据,stop方法停止stream,下面实现poll方法
    @Override
    public List<SourceRecord> poll() throws InterruptedException {
        try {
            ArrayList<SourceRecord> records = new ArrayList<>();
            while (streamValid(stream) && records.isEmpty()) {
                LineAndOffset line = readToNextLine(stream);
                if (line != null) {
                    Map sourcePartition = Collections.singletonMap("filename", filename);
                    Map sourceOffset = Collections.singletonMap("position", streamOffset);
                    records.add(new SourceRecord(sourcePartition, sourceOffset, topic, Schema.STRING_SCHEMA, line));
                } else {
                    Thread.sleep(1);
                }
            }
            return records;
        } catch (IOException e) {
            // Underlying stream was killed, probably as a result of calling stop. Allow to return
            // null, and driving thread will handle any shutdown if necessary.
        }
        return null;
    }
    该方法重复执行读取操作,跟踪file offset,并且利用上述信息创建SourceRecord,它需要四个字段:source partition,source offset,topic name,output value(包括value及value的schema)

    Sink Tasks

    之前描述了sourcetask实现,sinktask与它完全不同,因为前者是拉取数据,后者是推送数据
    public abstract class SinkTask implements Task {
    public void initialize(SinkTaskContext context) { ... }
    public abstract void put(Collection<SinkRecord> records);
    public abstract void flush(Map<TopicPartition, Long> offsets);
    put方法是最重要的方法,接收sinkrecords,执行任何需要的转换,并将其存储在目标系统。此方法不需要确保数据已被完全写入目标系统,然后返回。事实上首先放入缓冲,因此,批量数据可以被一次发送,减少对下游存储的压力。sourcerecords中保存的信息与sourcesink中的相同。flush提交offset,它接受任务从故障中恢复,没有数据丢失。该方法将数据推送至目标系统,并且block直到写入已被确认。的offsets参数通常可以忽略不计,但在某些情况保存偏移信息到目标系统确保一次交货。例如,一个HDFS连接器可以确保flush()操作自动提交数据和偏移到HDFS中的位置。

    Resuming from Previous Offsets

    kafka connect是为了bulk 数据拷贝工作,它拷贝整个db而不是拷贝某个表,这样会使用connnect的input或者output随时改变,source connector需要监听source系统的改变,当改变时通知框架(通过ConnectorContext对象)
    举例
    if (inputsChanged())
        this.context.requestTaskReconfiguration();
    当接收到通知框架会即时的更新配置,并且在更新前确保优雅完成当前任务
    如果一个额外的线程来执行此监控,该线程必须存在于连接器中。该线程不会影响connector。然而,其他变化也会影响task,最常见的是输入流失败在输入系统中,例如如果一个表被从数据库中删除。这时连接器需要进行更改,任务将需要处理这种异常。sinkconnectors只能处理流的加入,可以分配新的数据到task(例如,一个新的数据库表)。框架会处理任何kafka输入的改变,例如当组输入topic的变化因为一个正则表达式的订阅。sinktasks应该期待新的输入流,可能需要在下游系统创造新的资源,如数据库中的一个新的表。在这些情况下,可能会出现输入流之间的冲突(同时创建新资源),其他时候,一般不需要特殊的代码处理一系列动态流  

    Dynamic Input/Output Streams

    FileStream连接器是很好的例子,因为他们很简单的,每一行是一个字符串。实际连接器都需要具有更复杂的数据格式。要创建更复杂的数据,你需要使用kafka connector数据接口:Schema,Struct
    Schema schema = SchemaBuilder.struct().name(NAME)
                        .field("name", Schema.STRING_SCHEMA)
                        .field("age", Schema.INT_SCHEMA)
                        .field("admin", new SchemaBuilder.boolean().defaultValue(false).build())
                        .build();
    Struct struct = new Struct(schema)
                               .put("name", "Barbara Liskov")
                               .put("age", 75)
                               .build();
    如果上游数据与schema数据格式不一致应该在sinktask中抛出异常

    展开全文
  • nike+connect for mac

    2014-07-26 18:31:05
    nike+有时候上不去,需要连接fuelband的可以下载,mac专用
  • kafka connect

    万次阅读 2018-05-16 14:18:43
    Kafka Connect简介 Kafka是一个使用越来越广的消息系统,尤其是在大数据开发中(实时数据处理和分析)。为何集成其他系统和解耦应用,经常使用Producer来发送消息到Broker,并使用Consumer来消费Broker中的消息。...

    一. Kafka Connect简介

      Kafka是一个使用越来越广的消息系统,尤其是在大数据开发中(实时数据处理和分析)。为何集成其他系统和解耦应用,经常使用Producer来发送消息到Broker,并使用Consumer来消费Broker中的消息。Kafka Connect是到0.9版本才提供的并极大的简化了其他系统与Kafka的集成。Kafka Connect运用用户快速定义并实现各种Connector(File,Jdbc,Hdfs等),这些功能让大批量数据导入/导出Kafka很方便。

                 

    如图中所示,左侧的Sources负责从其他异构系统中读取数据并导入到Kafka中;右侧的Sinks是把Kafka中的数据写入到其他的系统中。

    二. 各种Kafka Connector

      Kafka Connector很多,包括开源和商业版本的。如下列表中是常用的开源Connector

    ConnectorsReferences
    JdbcSource, Sink
    Elastic SearchSink1, Sink2, Sink3
    CassandraSource1, Source 2, Sink1, Sink2 
    MongoDBSource
    HBaseSink
    SyslogSource
    MQTT (Source)Source
    Twitter (Source)Source, Sink
    S3Sink1, Sink2

      商业版的可以通过Confluent.io获得

    三. 示例

    3.1 FileConnector Demo

     本例演示如何使用Kafka Connect把Source(test.txt)转为流数据再写入到Destination(test.sink.txt)中。如下图所示:

              

          本例使用到了两个Connector:

    • FileStreamSource:从test.txt中读取并发布到Broker中
    • FileStreamSink:从Broker中读取数据并写入到test.sink.txt文件中

      其中的Source使用到的配置文件是${KAFKA_HOME}/config/connect-file-source.properties

    name=local-file-source
    connector.class=FileStreamSource
    tasks.max=1
    file=test.txt
    topic=connect-test

      其中的Sink使用到的配置文件是${KAFKA_HOME}/config/connect-file-sink.properties

    name=local-file-sink
    connector.class=FileStreamSink
    tasks.max=1
    file=test.sink.txt
    topics=connect-test

      Broker使用到的配置文件是${KAFKA_HOME}/config/connect-standalone.properties

    复制代码
    bootstrap.servers=localhost:9092key.converter=org.apache.kafka.connect.json.JsonConverter
    value.converter=org.apache.kafka.connect.json.JsonConverter
    key.converter.schemas.enable=true
    value.converter.schemas.enable=trueinternal.key.converter=org.apache.kafka.connect.json.JsonConverter
    internal.value.converter=org.apache.kafka.connect.json.JsonConverter
    internal.key.converter.schemas.enable=false
    internal.value.converter.schemas.enable=false
    offset.storage.file.filename=/tmp/connect.offsets
    offset.flush.interval.ms=10000
    复制代码

     

    3.2 运行Demo

      需要熟悉Kafka的一些命令行,参考本系列之前的文章Apache Kafka系列(二) 命令行工具(CLI)

     3.2.1 启动Kafka Broker

    [root@localhost bin]# cd /opt/kafka_2.11-0.11.0.0/
    [root@localhost kafka_2.11-0.11.0.0]# ls
    bin  config  libs  LICENSE  logs  NOTICE  site-docs
    [root@localhost kafka_2.11-0.11.0.0]# ./bin/zookeeper-server-start.sh ./config/zookeeper.properties &
    [root@localhost kafka_2.11-0.11.0.0]# ./bin/kafka-server-start.sh ./config/server.properties &

    3.2.2 启动Source Connector和Sink Connector

    [root@localhost kafka_2.11-0.11.0.0]# ./bin/connect-standalone.sh config/connect-standalone.properties config/connect-file-source.properties config/connect-file-sink.properties 

    3.3.3 打开console-consumer

    ./kafka-console-consumer.sh --zookeeper localhost:2181 --from-beginning --topic connect-test

    3.3.4 写入到test.txt文件中,并观察3.3.3中的变化

    [root@Server4 kafka_2.12-0.11.0.0]# echo 'firest line' >> test.txt
    [root@Server4 kafka_2.12-0.11.0.0]# echo 'second line' >> test.txt
    3.3.3中打开的窗口输出如下
    {"schema":{"type":"string","optional":false},"payload":"firest line"}
    {"schema":{"type":"string","optional":false},"payload":"second line"}

    3.3.5 查看test.sink.txt

    [root@Server4 kafka_2.12-0.11.0.0]# cat test.sink.txt 
    firest line
    second line

     本例仅仅演示了Kafka自带的File Connector,后续文章会完成JndiConnector,HdfsConnector,并且会使用CDC(Changed Data Capture)集成Kafka来完成一个ETL的例子

    四. kafka 0.9 connect JDBC测试

    kafka 0.9的connect功能,测试过程如下:

    1.创建容器(本次采用docker容器构建kafka环境)

    docker run -p 10924:9092 -p 21814:2181 --name confluent -i -t -d java /bin/bash

    2.将confluent安装程序拷贝进容器;
    docker cp  confluent.zip confluent:/root
    3.进入到confluent容器
    docker exec -it confluent /bin/bash
    4.解压confluent压缩包
    unzip confluent.zip
    5.启动kafka
    /root/confluent/bin/zookeeper-server-start  /root/confluent/etc/kafka/zookeeper.properties  & > zookeeper.log
    /root/confluent/bin/kafka-server-start  /root/confluent/etc/kafka/server.properties & > server.log
    /root/confluent/bin/schema-registry-start  /root/confluent/etc/schema-registry/schema-registry.properties & > schema.log

    6.测试kafka 是否正常

    开两个docker窗口,一个跑producer,一个跑consumer,

    /root/confluent/bin/kafka-avro-console-producer --broker-list localhost:9092 --topic test --property value.schema='{"type":"record","name":"myrecord","fields":[{"name":"f1","type":"string"}]}'

    /root/confluent/bin/kafka-avro-console-consumer --topic test  --zookeeper localhost:2181 --from-beginning
    在producer端依次输入以下记录,确认consumer能正确显示;
    {"f1""value1"}
    {"f1""value2"}
    {"f1""value3"}
    以上为安装kafka过程,接下来开始测试jdbc接口;
    测试之前,需要获取mysql JDBC的驱动并将获放在kafka环境对应的jre/lib文件夹里
    测试jdbc connect
    1.创建配置文件quickstart-mysql.properties,内容如下:  
    name=test-mysql-jdbc-autoincrement
    connector.class=io.confluent.connect.jdbc.JdbcSourceConnector
    tasks.max=1
    connection.url=jdbc:mysql://192.168.99.100:33061/test1?user=root&password=welcome1
    mode=incrementing
    incrementing.column.name=id
    topic.prefix=test-mysql-jdbc-
    注:mysql是我在另一个容器里运行的,jdbc:mysql://192.168.99.100:33061/test1?user=root&password=welcome1是连接容器里的mysql的连接串
    2.执行./bin/connect-standalone etc/schema-registry/connect-avro-standalone.properties etc/kafka-connect-jdbc/quickstart-mysql.properties
    3.执行./bin/kafka-avro-console-consumer --new-consumer --bootstrap-server 192.168.99.100:10924 --topic test-mysql-jdbc-accounts --from-beginning
    然后在数据库里增加一条记录
    然后就会在consumer端显示新增记录

    五. 配置连接器

    Connector的配置是简单的key-value映射。对于独立模式,这些都是在属性文件中定义,并通过在命令行上的Connect处理。在分布式模式,JSON负载connector的创建(或修改)请求。大多数配置都是依赖的connector,有几个常见的选项:

    • name - 连接器唯一的名称,不能重复。
    • connector.calss - 连接器的Java类。
    • tasks.max - 连接器创建任务的最大数。
    • connector.class配置支持多种格式:全名或连接器类的别名。比如连接器是org.apache.kafka.connect.file.FileStreamSinkConnector,你可以指定全名,也可以使用FileStreamSinkFileStreamSinkConnector。Sink connector也有一个额外的选项来控制它们的输入:
    • topics - 作为连接器的输入的topic列表。

    对于其他的选项,你可以查看连接器的文档。

    六、rest api

    kafka connect的目的是作为一个服务运行,默认情况下,此服务运行于端口8083。它支持rest管理,用来获取 Kafka Connect 状态,管理 Kafka Connect 配置,Kafka Connect 集群内部通信,常用命令如下:

    GET /connectors 返回一个活动的connect列表
    POST /connectors 创建一个新的connect;请求体是一个JSON对象包含一个名称字段和连接器配置参数

    GET /connectors/{name} 获取有关特定连接器的信息
    GET /connectors/{name}/config 获得特定连接器的配置参数
    PUT /connectors/{name}/config 更新特定连接器的配置参数
    GET /connectors/{name}/tasks 获得正在运行的一个连接器的任务的列表

    DELETE /connectors/{name} 删除一个连接器,停止所有任务,并删除它的配置

    GET /connectors 返回一个活动的connect列表

    POST /connectors 创建一个新的connect;请求体是一个JSON对象包含一个名称字段和连接器配置参数

    GET /connectors/{name} 获取有关特定连接器的信息
    GET /connectors/{name}/config 获得特定连接器的配置参数
    PUT /connectors/{name}/config 更新特定连接器的配置参数
    GET /connectors/{name}/tasks 获得正在运行的一个连接器的任务的列表

    DELETE /connectors/{name} 删除一个连接器,停止所有任务,并删除它的配置

    curl -s <Kafka Connect Worker URL>:8083/ | jq   获取 Connect Worker 信息

    curl -s <Kafka Connect Worker URL>:8083/connector-plugins | jq 列出 Connect Worker 上所有 Connector

    curl -s <Kafka Connect Worker URL>:8083/connectors/<Connector名字>/tasks | jq 获取 Connector 上 Task 以及相关配置的信息

    curl -s <Kafka Connect Worker URL>:8083/connectors/<Connector名字>/status | jq 获取 Connector 状态信息

    curl -s <Kafka Connect Worker URL>:8083/connectors/<Connector名字>/config | jq 获取 Connector 配置信息

    curl -s -X PUT <Kafka Connect Worker URL>:8083/connectors/<Connector名字>/pause 暂停 Connector

    curl -s -X PUT <Kafka Connect Worker URL>:8083/connectors/<Connector名字>/resume 重启 Connector

    curl -s -X DELETE <Kafka Connect Worker URL>:8083/connectors/<Connector名字> 删除 Connector

    创建新 Connector (以FileStreamSourceConnector举例)

    curl -s -X POST -H "Content-Type: application/json" --data 
     '{"name": "<Connector名字>", 
       "config":
        {"connector.class":"org.apache.kafka.connect.file.FileStreamSourceConnector",
        "key.converter.schemas.enable":"true",
        "file":"demo-file.txt",
        "tasks.max":"1",
        "value.converter.schemas.enable":"true",
        "name":"file-stream-demo-distributed",
        "topic":"demo-distributed",
        "value.converter":"org.apache.kafka.connect.json.JsonConverter",
        "key.converter":"org.apache.kafka.connect.json.JsonConverter"}
     }' 
    http://<Kafka Connect Worker URL>:8083/connectors | jq
    


    更新 Connector配置 (以FileStreamSourceConnector举例)

    curl -s -X PUT -H "Content-Type: application/json" --data 
    '{"connector.class":"org.apache.kafka.connect.file.FileStreamSourceConnector",
    "key.converter.schemas.enable":"true",
    "file":"demo-file.txt",
    "tasks.max":"2",
    "value.converter.schemas.enable":"true",
    "name":"file-stream-demo-distributed",
    "topic":"demo-2-distributed",
    "value.converter":"org.apache.kafka.connect.json.JsonConverter",
    "key.converter":"org.apache.kafka.connect.json.JsonConverter"}' 
    <Kafka Connect Worker URL>:8083/connectors/file-stream-demo-distributed/config | jq
    

    七、kafka connect + debezium,解析binlog至kafka

    在已知kafka connect和debezium作用,会使用kafka的基础上,学会使用debezium来读取binlog,并通过kafka connect将读取的内容放入kafka topic中。 

    基于kafka0.10.0和Debezium0.6,mysql5.6

    kafka connect

    • Kafka Connect是一种用于Kafka和其他数据系统之间进行数据传输的工具。
    • 仅关注数据的复制,并且不处理其他任务
    • Kafka connect有两个概念,一个source,另一个是sink。source是把数据从一个系统拷贝到kafka里,sink是从kafka拷贝到另一个系统里。
    • 可使用插件,获取不同系统的数据。例如通过Debezium插件解析mysql的日志,获取数据。
    • 支持集群,可以通过REST API管理Kafka Connect。
    • 对数据的传输进行管理和监控。

    Debezium

    • Debezium是一个分布式平台,可将现有数据库转换为事件流,因此应用程序可以立即查看并立即响应数据库中每一行的更改。
    • Debezium建立在Apache Kafka之上,并提供用于监视特定数据库管理系统的Kafka Connect兼容连接器。
    • 本教程使用Debezium监控binlog。

    准备操作

    • mysql需开启binlog
    [mysqld]
    log-bin=mysql-bin #添加这一行就ok
    binlog-format=ROW #选择row模式
    server_id=1 #配置mysql replaction需要定义,不能和canal的slaveId重复
    • mysql需创建一个有mysql slave相关权限的账号,若mysql不在本机,则需要远程权限,防火墙放行。
    //mysql slave相关权限
    CREATE USER canal IDENTIFIED BY 'debezium';  
    GRANT SELECT, REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'debezium'@'%';
    -- GRANT ALL PRIVILEGES ON *.* TO 'debezium'@'%' ;
    FLUSH PRIVILEGES;
    • 操作概述
    • 安装并启动kafka
    • 安装并启动mysql
    • 下载Debezium的mysql连接器http://debezium.io/docs/install/并解压
    • 安装debezium,即将解压目录写入classpath变量,例如:export classpath=/root/debezium-connector-mysql/* 
      只在当前shell有效
    • 参考http://debezium.io/docs/connectors/mysql/的配置文件示例,写好配置文件。
    • 以独立模式启动kafka connect,此时debezium会对数据库中的每一个表创建一个topic,消费相应的topic,即可获取binlog解析信息。
    //启动kafka connect
    bin/connect-standalone.sh config/connect-standalone.properties mysql.properties
    //查看topic列表
    bin/kafka-topics.sh --list --zookeeper localhost:2181
    //消费该主题
    bin/kafka-console-consumer.sh --bootstrap-server localhost:9092 --topic test --from-beginning
    • 配置文件
        //mysql.properties
        name=inventory-connector
        connector.class=io.debezium.connector.mysql.MySqlConnector
        database.hostname=192.168.99.100
        database.port=3306
        database.user=debezium
        database.password=dbz
        database.server.id=184054
        database.server.name=fullfillment
        database.whitelist=inventory
        database.history.kafka.bootstrap.servers=192.168.30.30:9092
        database.history.kafka.topic=dbhistory.fullfillment
        include.schema.changes=true
    • 索引

    debezium官网 http://debezium.io/ 

    kafka文档 http://kafka.apache.org/0100/documentation.html

    八、Kafka Connect的优点

    1.对开发者提供了统一的实现接口
    2.开发,部署和管理都非常方便,统一 
    3.使用分布式模式进行水平扩展,毫无压力
    4.在分布式模式下可以通过Rest Api提交和管理Connectors
    5.对offset自动管理,只需要很简单的配置,而不像Consumer中需要开发者处理
    6.流式/批式处理的支持

    九、第三方资源

    这是已经得到支持的组件,不需要做额外的开发: https://www.confluent.io/product/connectors/
    括号中的Source表示将数据从其他系统导入Kafka,Sink表示将数据从Kafka导出到其他系统。
    其他的我没看,但是JDBC的实现比较的坑爹,是通过primary key(如id)和时间戳(如updateTime)字段,

    来判断数据是否更新,这样的话应用范围非常受局限。

    十、Connector Development Guide

    在kafka与其他系统间复制数据需要创建kafka connect,他们将数复制到kafka或者从kafka复制到其他系统
    连接器有两种形式:sourceconnectors将另一个系统数据导入kafka,sinkconnectors将数据导出到另一个系统
    连接器不执行任何数据复制:它们的描述复制的数据,并且负责将工作分配给多个task
    task分为sourcetask与sinktask

    每个task从kafka复制数据,connect会保证record与schema的一致性完成任务分配,通常record与schema的映射是明显的,每一个文件对应一个流,流中的每一条记录利用schema解析并且保存对应的offset,另外一种情况是我们需要自己完成这种映射,比如数据库,表的offset不是很明确(没有自增id),一种可能的选择是利用时间(timestamp)来完成增量查询。

    Streams and Records

    每一个stream是包含key value对的记录的序列,key value可以是原始类型,可以支持复杂结构,除了array,object,嵌套等。数据转换是框架来完成的,record中包含stream id与offset,用于定时offset提交,帮助当处理失败时恢复避免重复处理。
    Dynamic Connectors
    所有的job不是静态的,它需要监听外部系统的变化,比如数据库表的增加删除,当一个新table创建时,它必须发现并且更新配置由框架来分配给该表一个task去处理,当通知发布后框架会更新对应的task.

    Developing a Simple Connector

    例子很简单
    在standalone模式下实现 SourceConnector/SourceTask 读取文件并且发布record给SinkConnector/SinkTask 由sink写入文件
    Connector Example
    我们将实现SourceConnector,SinkConnector实现与它非常类似,它包括两个私有字段存放配置信息(读取的文件名与topic名称)
    public class FileStreamSourceConnector extends SourceConnector {
        private String filename;
        private String topic;
    getTaskClass()方法定义实现执行处理的task
    @Override
    public Class getTaskClass() {
        return FileStreamSourceTask.class;
    }
    下面定义FileStreamSourceTask,它包括两个生命周期方法start,stop
    @Override
    public void start(Map<String, String> props) {
        // The complete version includes error handling as well.
        filename = props.get(FILE_CONFIG);
        topic = props.get(TOPIC_CONFIG);
    }
    @Override
    public void stop() {
        // Nothing to do since no background monitoring is required.
    }
    最后是真正核心的方法getTaskConfigs()在这里我们仅处理一个文件,所以我们虽然定义了max task(在配置文件里)但是只会返回一个包含一条entry的list
    @Override
    public List<Map<String, String>> getTaskConfigs(int maxTasks) {
        ArrayList>Map<String, String>> configs = new ArrayList<>();
        // Only one input stream makes sense.
        Map<String, String> config = new Map<>();
        if (filename != null)
            config.put(FILE_CONFIG, filename);
        config.put(TOPIC_CONFIG, topic);
        configs.add(config);
        return configs;
    }
    即使有多个任务,这种方法的执行通常很简单。它只是要确定输入任务的数量,这可能需要拉取数据从远程服务,然后分摊。请注意,这个简单的例子不包括动态输入。在下一节中看到讨论如何触发任务的配置更新。
    Task Example - Source Task
    实现task,我们使用伪代码描述核心代码
    public class FileStreamSourceTask extends SourceTask<Object, Object> {
        String filename;
        InputStream stream;
        String topic;
        public void start(Map<String, String> props) {
            filename = props.get(FileStreamSourceConnector.FILE_CONFIG);
            stream = openOrThrowError(filename);
            topic = props.get(FileStreamSourceConnector.TOPIC_CONFIG);
        }
        @Override
        public synchronized void stop() {
            stream.close()
        }
    start方法读取之前的offset,并且处理新的数据,stop方法停止stream,下面实现poll方法
    @Override
    public List<SourceRecord> poll() throws InterruptedException {
        try {
            ArrayList<SourceRecord> records = new ArrayList<>();
            while (streamValid(stream) && records.isEmpty()) {
                LineAndOffset line = readToNextLine(stream);
                if (line != null) {
                    Map sourcePartition = Collections.singletonMap("filename", filename);
                    Map sourceOffset = Collections.singletonMap("position", streamOffset);
                    records.add(new SourceRecord(sourcePartition, sourceOffset, topic, Schema.STRING_SCHEMA, line));
                } else {
                    Thread.sleep(1);
                }
            }
            return records;
        } catch (IOException e) {
            // Underlying stream was killed, probably as a result of calling stop. Allow to return
            // null, and driving thread will handle any shutdown if necessary.
        }
        return null;
    }
    该方法重复执行读取操作,跟踪file offset,并且利用上述信息创建SourceRecord,它需要四个字段:source partition,source offset,topic name,output value(包括value及value的schema)
    Sink Tasks
    之前描述了sourcetask实现,sinktask与它完全不同,因为前者是拉取数据,后者是推送数据
    public abstract class SinkTask implements Task {
    public void initialize(SinkTaskContext context) { ... }
    public abstract void put(Collection<SinkRecord> records);
    public abstract void flush(Map<TopicPartition, Long> offsets);
    put方法是最重要的方法,接收sinkrecords,执行任何需要的转换,并将其存储在目标系统。此方法不需要确保数据已被完全写入目标系统,然后返回。事实上首先放入缓冲,因此,批量数据可以被一次发送,减少对下游存储的压力。sourcerecords中保存的信息与sourcesink中的相同。flush提交offset,它接受任务从故障中恢复,没有数据丢失。该方法将数据推送至目标系统,并且block直到写入已被确认。的offsets参数通常可以忽略不计,但在某些情况保存偏移信息到目标系统确保一次交货。例如,一个HDFS连接器可以确保flush()操作自动提交数据和偏移到HDFS中的位置。
    Resuming from Previous Offsets
    kafka connect是为了bulk 数据拷贝工作,它拷贝整个db而不是拷贝某个表,这样会使用connnect的input或者output随时改变,source connector需要监听source系统的改变,当改变时通知框架(通过ConnectorContext对象)
    举例
    if (inputsChanged())
        this.context.requestTaskReconfiguration();
    当接收到通知框架会即时的更新配置,并且在更新前确保优雅完成当前任务
    如果一个额外的线程来执行此监控,该线程必须存在于连接器中。该线程不会影响connector。然而,其他变化也会影响task,最常见的是输入流失败在输入系统中,例如如果一个表被从数据库中删除。这时连接器需要进行更改,任务将需要处理这种异常。sinkconnectors只能处理流的加入,可以分配新的数据到task(例如,一个新的数据库表)。框架会处理任何kafka输入的改变,例如当组输入topic的变化因为一个正则表达式的订阅。sinktasks应该期待新的输入流,可能需要在下游系统创造新的资源,如数据库中的一个新的表。在这些情况下,可能会出现输入流之间的冲突(同时创建新资源),其他时候,一般不需要特殊的代码处理一系列动态流   

    Dynamic Input/Output Streams

    FileStream连接器是很好的例子,因为他们很简单的,每一行是一个字符串。实际连接器都需要具有更复杂的数据格式。要创建更复杂的数据,你需要使用kafka connector数据接口:Schema,Struct
    Schema schema = SchemaBuilder.struct().name(NAME)
                        .field("name", Schema.STRING_SCHEMA)
                        .field("age", Schema.INT_SCHEMA)
                        .field("admin", new SchemaBuilder.boolean().defaultValue(false).build())
                        .build();
    Struct struct = new Struct(schema)
                               .put("name", "Barbara Liskov")
                               .put("age", 75)
                               .build();
    如果上游数据与schema数据格式不一致应该在sinktask中抛出异常

    参考

    Kafka Documentation

    http://kafka.apache.org/documentation/#connect

    https://www.confluent.io/product/connectors/

    展开全文
  • Socket Connect问题

    千次阅读 2018-11-15 09:42:54
    Socket Connect问题 https://www.cnblogs.com/Adoryn/p/5876104.html   一、非阻塞Connect对于Select时应注意的问题二、linux客户端socket非阻塞connect编程   一、非阻塞Connect对于Select时应注意的问题 ...
  • SSO的通用标准OpenID Connect

    万次阅读 2020-12-15 21:20:15
    OpenID Connect简称为OIDC,已成为Internet上单点登录和身份管理的通用标准。 它在OAuth2上构建了一个身份层,是一个基于OAuth2协议的身份认证标准协议。 OAuth2实际上只做了授权,而OpenID Connect在授权的基础上...
  • 在刚开始使用Dva的时候,写好models,通过connect进行仓库与组件的链接的时候怎么不是很理解,翻译官方文档也没有明确的解释。 提示:以下是本篇文章正文内容,下面案例可供参考 一、connect的用来干什么 connect...
  • juniper-networks-network-connect

    热门讨论 2013-05-26 00:45:56
    juniper-networks-network-connect.
  • 这几天看sql看到了有关connect by和level的关键字用法,以前都用mysql也没用过这个关键字,感觉挺有用的,就学了下,整理一下学习过程。 首先,connect by和level都是为了快速的查询层级关系的关键字,在代理关系中...
  • 解决 Connection refused: connect error

    万次阅读 2019-07-11 16:06:01
    Connection refused: connect error 异常如下: * What went wrong: Could not resolve all files for configuration ':utils:debugCompileClasspath'. > Could not download design.aar ...
  • oracle connect by 递归查询用法

    万次阅读 2018-04-04 14:42:50
    connect by [condition] :与一般的条件一样作用于当前列,但是在满足条件后,会以全部列作为下一层级递归(没有其他条件的话)。 prior : 表示上一层级的标识符。经常用来对下一层级的数据进行限制。不可以接伪列...
  • connect 连接超时

    千次阅读 2017-11-20 11:01:24
    在使用TCP的connect连接服务器时,在默认情况下系统使用的是阻塞式socket,如果服务器当前不可用,则connect会等待知道超时时间到达,而这个超时时间是系统内核规定的,并不能使用setSocketOpt来设置,这个函数只能...
  • kafka connect简介以及部署

    万次阅读 2019-07-30 09:39:28
    1、什么是kafka connect? 根据官方介绍,Kafka Connect是一种用于在Kafka和其他系统之间可扩展的、可靠的流式传输数据的工具。它使得能够快速定义将大量数据集合移入和移出Kafka的连接器变得简单。 Kafka Connect...
  • oracle connect by用法篇

    万次阅读 2018-11-13 14:04:45
      1、基本语法 select * from table [start with condition1] connect by [prior] id=parentid 一般用来查找存在父子关系的数据,也就是树形结构的数据;其返还的数据也能够明确的区分出每一...
  • Centos/Ubuntu 连接EasyConnect失败的解决办法 背景 最近心血来潮要学好linux,索性就直接笔记本上安装了Centos 8,在上面进行办公,但是连接内网是通过深信服的EasyConnect VPN。在连接过程中遇到了一点问题,并在...
  • mysql_connect函数解释

    千次阅读 2019-05-22 21:55:35
    mysql_connect — 打开一个到 MySQL 服务器的连接 Warning 本扩展自 PHP 5.5.0 起已废弃,并在自 PHP 7.0.0 开始被移除。应使用 MySQLi 或 PDO_MySQL 扩展来替换之。参见 MySQL:选择 API 指南以及相关 FAQ 来获取...
  • 由于代理变更,android studio 会有一系列报错,其中一个是 Connect to 127.0.0.1:xxxxxx [/127.0.0.1] failed: Connection refused 网上答案大都太片面了,无法完全解决问题,这里列举出四个可能的原因,希望对大家...
  • WiFi Easy Connect

    千次阅读 2020-03-02 09:44:50
    Wi-Fi Easy Connect是Wi-Fi Alliance一系列计划之中的一个,为支持简便的网络及客户端设备配置提供了新的机制,可提供更好的用户体验、更高的安全性并支持IoT设备的配置。 基本原理 Wi-Fi Easy Connect允许住宅或...
  • mysql8 实现connect by语法

    万次阅读 2019-07-30 17:46:12
    mysql8 已只吃connect by语法
  • Emulator: emulator: ERROR: AdbHostServer.cpp:102: Unable to connect to adb daemon on port: 5037 网上找了很多,各种提示要我配置adb的环境变量,杀死占用5037端口的线程…… 毛用没得…… 解决方案:允许...
  • EasyConnect 自定义路由表

    千次阅读 2020-07-02 23:48:42
    2020/07/02 如今有很多学校、企业选用 EasyConnect 套端作为远程... 在我使用 EasyConnect 远程访问学校校园网时,尴尬的问题来了:EasyConnect 默认做全局代理,而我只是想用 EasyConnect 访问知网或校园网资源...
  • react-redux的connect用法详解

    千次阅读 2021-01-02 11:17:03
    一、UI组件和容器组件 React-Redux 将所有组件分成两大类:UI 组件和容器组件。 UI 组件:只负责 UI 的呈现,不带有任何业务逻辑,没有状态state值的使用,所以的参数是通过this.props获取。...connect的意
  • connect之前先来回顾一下redux的基本用法, 见下面的例子: import { createStore } from 'redux'; function counter(state = 0, action) { switch (action.type) { case 'INCREMENT': return state + 1; ...
  • ubuntu 20.04 下安装easyconnect

    千次阅读 2021-03-01 15:33:56
    下载easyconnect客户端 wget http://download.sangfor.com.cn/download/product/sslvpn/pkg/linux_01/EasyConnect_x64.deb 安装easyconnect $ sudo dpkg -i EasyConnect_x64.deb 打开easyconnect,Harfbuzz ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,302,619
精华内容 521,047
关键字:

connect