文件同步

1.功能描述

能够配置监控多个目录下文件变化;slave节点同步master节点的文件;新节点上线或者感知到master变化,slave节点要主动向master节点进行一次全量同步(rsyn实际传输也只是变化的部分);master节点启动inotify监控,感知到文件变化,将变化消息通过mqtt topic通知到slave节点;slave节点收到文件变化消息,发起向master节点的一次同步连接

2.依赖模块

njet.conf:

helper broker  modules/njt_helper_broker_module.so conf/mqtt.conf; 
helper rsync modules/njt_helper_rsync_module.so conf/rsync.conf;

njet_ctrl.conf:

load_module modules/njt_http_ctrl_request_forward_module.so;

3.指令说明

rsync.conf 样例 :

{
    "log_file": "logs/rsync.log",   #指定日志输出文件
    
    #可配置rsync 日志级别
    "log_level": "info",   #日志级别(如 debug、info、warn、error),控制日志详细程度 默认为 info
    
    #监控目录列表(不支持文件),必须为绝对路径
    "watch_dirs": [
        {
             "ignore_files": [
                "1.txt",          #排除所有1.txt文件
                "tmp1/tmp11",     #排除tmp1/tmp11目录 
                "tmp1/*.doc",     #排除tmp1/下所有.doc结尾的文件
                "tmp1/abc.*"      #排除tmp1/下所有abc.开始的文件
            ],
       
            "identifier": "dir_name1",     #监控目录标识,用于标识不同集群节点目录对应关系
            "prefix": "/a/b",          #必须是dir路径开始的前缀路径
            "dir": "/a/b/c"            #必须是绝对路径
        },
        
        {
            "identifier": "dir_name2",     #监控目录标识,用于标识不同集群节点目录对应关系
            "prefix": "/e",          #必须是dir路径开始的前缀路径
            "dir": "/e/f/g"          #必须是绝对路径
        }
    ]
}
字段层级 字段名 是否必须 作用/为什么要配 如果不配会怎样
全局 log_file 指定 rsync 日志写到哪里 启动报错:找不到日志路径
全局 log_level 控制日志详细程度(debug/info/warn/error) 缺省 info,可运行但无法按需调级别
顶层 watch_dirs 声明需要监控/同步的目录列表 没任务可做
单条目录 dir 被监控的绝对路径 找不到目录,直接失败
单条目录 prefix 去掉公共前缀,生成 rsync 的相对路径 路径层级错乱,远端收到错误路径
单条目录 identifier 集群内统一标识,用于多节点目录映射 节点间无法匹配同一逻辑目录,同步失败或重复
单条目录 ignore_files 排除文件/目录的 glob 规则(–exclude) 不排除任何文件,全部同步

支持文件忽略配置(不参与同步)

  • 能够配置全局过滤(文件或者目录,后缀匹配模式,比如过滤b.txt, 则所有路径(包含子目录)以b.txt结尾的都会被过滤掉)
  • 过滤支持简单的前缀通配符过滤(比如*.txt, 则过滤所有以.txt类型的文件)
  • 过滤支持简单的后缀通配符过滤(比如abc.*, 则过滤所有abc.开头的文件)
  • 符合过滤规则的文件不会进行同步,也不会被删除

4.配置样例

具体配置如下:

njet.conf 样例(master 和backup 节点相同配置):

helper broker  modules/njt_helper_broker_module.so conf/mqtt.conf;  #注意:此处配置需要加上conf/mqtt.conf,因为rpm 和deb 包安装时是不带这个conf/mqtt.conf的
helper ctrl modules/njt_helper_ctrl_module.so  conf/njet_ctrl.conf;
helper rsync modules/njt_helper_rsync_module.so conf/rsync.conf;

load_module modules/njt_http_split_clients_2_module.so;
load_module modules/njt_agent_dynlog_module.so;
load_module modules/njt_http_dyn_bwlist_module.so;
load_module modules/njt_dyn_ssl_module.so;
load_module modules/njt_http_vtsc_module.so;
load_module modules/njt_http_location_module.so;
load_module modules/njt_range_module.so;
load_module modules/njt_http_dyn_range_module.so;

cluster_name njet;
node_name node156;


worker_processes auto;   


error_log  logs/error.log info;

#pid        logs/nginx.pid;


events {
    worker_connections  1024;
}


http {
    include mime.types;
    access_log off;
    server {
        listen       8100;
        location / {
           root html;
        }
    }
}

stream {
        server {
                listen 238.255.253.251:5557 udp;
                gossip zone=test:1m heartbeat_timeout=100ms nodeclean_timeout=1s local_ip=192.168.40.156 sync_port=8873 ctrl_port=8811 bridge_port=1884;
        }
}

        

              

njet_ctrl.conf(master 和backup 节点相同配置):

load_module modules/njt_http_sendmsg_module.so;
load_module modules/njt_ctrl_config_api_module.so; 
load_module modules/njt_helper_health_check_module.so;
load_module modules/njt_http_upstream_api_module.so; 
load_module modules/njt_http_location_api_module.so;
load_module modules/njt_doc_module.so;
load_module modules/njt_http_ctrl_request_forward_module.so;

error_log logs/error_ctrl.log error;

events {
    worker_connections  1024;
}

http {
    dyn_kv_conf conf/ctrl_kv.conf;
    include mime.types;
    access_log off;
    server {
        listen       8811;

        location / {
            return 200 "njet control panel\n";
        }
       
        location /api {
            dyn_module_api;  
        } 
        
        location /doc {
            doc_api;
        }
        
         location / {
            root /home/limin/test_bridge/html;
            index upload.html;
       }
        
        location /cluster_forward {
          internal;
          proxy_connect_timeout 1s;
          proxy_read_timeout 2s;
          proxy_send_timeout 2s;
          proxy_pass http://${cluster_master_ip}:${cluster_master_ctrl_port}$request_uri;
       }
    }
}

Location 的名称 /cluster_forward 目前在代码中做subrequest 时hardcode 了, 不能改成其它名称。

变量 说明 作用域
cluster_master_ip 集群主节点IP HTTP
cluster_master_ctrl_port 集群主节点控制面监听端口 HTTP

该配置的作用:用户在从节点上请求修改配置,从节点将原样转发到集群主节点,然后主节点处理请求并同步变更到所有从节点

conf/ctrl_kv.conf (master 和backup 节点相同配置):

topic /gossip/#

rsync.conf(master 和backup 节点相同配置,identifier相同,prefix和dir 可以不相同,这样可以实现多个节点的不同目录实现监控):

{
  
   "log_level": "debug",

    "log_file": "logs/rsync.log",
     "watch_dirs": [
        {
            "identifier": "rsync1",
            "prefix": "/home/limin/test_bridge",
            "dir": "/home/limin/test_bridge/apigw_data"
        },
       {
            "identifier": "rsync2",
            "prefix": "/home/limin/test_bridge",
            "dir": "/home/limin/test_bridge/watch_dir"
         },
         {
            "identifier": "rsync3",
            "prefix": "/home/limin/test_bridge/data/",
            "dir": "/home/limin/test_bridge/data/file_upload"
        },
        {
            "ignore_files": [
                "4.txt",
                "tmp4/tmp3/tmp4/tmp5/tmp6/*.doc",
                "tmp4/tmp22/tmp33/tmp44/tmp55/tmp66/*.doc",
                "tmp4/abc.*",
                "tmp4/tmp44"
            ],
            "identifier": "rsync1",
            "prefix": "/home/limin/test_bridge",
            "dir": "/home/limin/test_bridge/tmp4"
        }
       
 ]
}                    

master节点mqtt配置(明文配置)

#全局log配置
log_dest file logs/mosquitto.log
log_type debug
log_type information
log_type error
log_type warning
log_type notice
#全局其他配置
autosave_interval 1
autosave_on_changes true
persistence true

allow_anonymous true  #允许匿名访问,后面的unix socket listen需要
persistence_location /home/limin/test_bridge/data/   #持久化数据路径



listener 0 /home/limin/test_bridge/data/mosquitto.sock    
#ip 地址 server
listener 1884 192.168.40.156

#master节点也要配置bridge(固定的名字bridge-backup),inactive一定设置,初始启动的时候实际不进行连接
connection bridge-backup inactive
address 192.168.40.156:1884  #配置bridge ip,此处配置为本节点ip即可,初始化配置使用
topic /dyn/# both 0
topic /ins/# both 0

backup节点mqtt配置(明文配置):

log_dest file logs/mosquitto.log
log_type debug
log_type information
log_type error
log_type warning
log_type notice

autosave_interval 1
autosave_on_changes true
persistence true

allow_anonymous true
persistence_location /home/limin/test_bridge/data/


listener 0 /home/limin/test_bridge/data/mosquitto.sock

listener 1884 192.168.40.145


connection bridge-backup  inactive
address 192.168.40.145:1884
topic /dyn/# both 0
topic /ins/# both 0

master节点mqtt配置(ssl证书):

#全局log配置
log_dest file logs/mosquitto.log
log_type debug
log_type information
log_type error
log_type warning
log_type notice

#全局其他配置
autosave_interval 1
autosave_on_changes true
persistence true

allow_anonymous true        #允许匿名访问,后面的unix socket listen需要
persistence_location /root/bug/njet1.0/data/    #持久化数据路径

#下面是unix socket 的指令组
listener 0 /root/bug/njet1.0/data/mosquitto.sock

#下面是ip 端口配置组,以及配置证书
listener 1883 192.168.40.158
cafile /root/bug/njet1.0/cert/mqtt_ca.crt
certfile /root/bug/njet1.0/cert/mqtt_server.crt    #服务端证书
keyfile /root/bug/njet1.0/cert/mqtt_server.key
require_certificate true           #listener级别配置
use_identity_as_username true      #listener级别配置

#下面是bridge 桥接配置组以及桥接使用的配置证书(固定的名字bridge-backup)
#master节点也要配置bridge,inactive一定设置,初始启动的时候实际不进行连接
connection bridge-backup inactive
address 192.168.40.158:1883     #ip也配置为初始得master节点ip即可
topic /dyn/# both 0
topic /ins/# both 0
bridge_insecure true
bridge_cafile /root/bug/njet1.0/cert/mqtt_ca.crt
bridge_certfile /root/bug/njet1.0/cert/mqtt_client.crt   #客户端证书
bridge_keyfile /root/bug/njet1.0/cert/mqtt_client.key

backup节点mqtt配置(ssl证书):

#全局log配置
log_dest file logs/mosquitto.log
log_type debug
log_type information
log_type error
log_type warning
log_type notice

#全局配置
autosave_interval 1
autosave_on_changes true
persistence true

allow_anonymous true       #允许匿名访问,后面的unix socket listen需要
persistence_location /root/bug/njet1.0/data/     #持久化数据路径

#下面是unix socket
listener 0 /root/bug/njet1.0/data/mosquitto.sock

#下面是ip 端口配置组,以及配置证书
listener 1883 192.168.40.156
cafile /root/bug/njet1.0/cert/mqtt_ca.crt
certfile /root/bug/njet1.0/cert/mqtt_server.crt  #服务端证书
keyfile /root/bug/njet1.0/cert/mqtt_server.key
require_certificate true      #listener级别配置
use_identity_as_username true  #listener级别配置

#下面是bridge 桥接配置组以及桥接使用的配置证书(固定的名字bridge-backup)
connection bridge-backup  inactive
address 192.168.40.158:1883
topic /dyn/# both 0
topic /ins/# both 0
bridge_insecure true
bridge_cafile /root/bug/njet1.0/cert/mqtt_ca.crt
bridge_certfile /root/bug/njet1.0/cert/mqtt_client.crt  #客户端证书
bridge_keyfile /root/bug/njet1.0/cert/mqtt_client.key

5.调用样例

5.1 查看连接状态:

按顺序分别启动158,156和145 节点的njet,158 作为主节点,156和145 作为backup 节点,所以156 和145 连接158的1884端口

在156机器上查看连接状态

[root@CDN156 njet]#  sudo netstat -anpl|grep 1884     
tcp        0      0 192.168.40.156:1884     0.0.0.0:*               LISTEN      2031/njet: copilot  
tcp        0      0 192.168.40.156:46008    192.168.40.158:1884     ESTABLISHED 2031/njet: copilot  

在145机器上查看连接状态

limin@ldap:~/test_bridge$ sudo netstat -anpl|grep 1884 
tcp        0      0 192.168.40.145:1884     0.0.0.0:*               LISTEN      14232/njet: copilot 
tcp     2385      0 192.168.40.145:56040    192.168.40.158:1884     ESTABLISHED 14232/njet: copilot

在158机器上查看连接状态

[njet@k8s-master158 test_bridge]$ sudo netstat -anpl|grep 1884
tcp        0      0 192.168.40.158:1884     0.0.0.0:*               LISTEN      15545/njet: copilot 
tcp        0      0 192.168.40.158:1884     192.168.40.156:46008    ESTABLISHED 15545/njet: copilot 
tcp        0      0 192.168.40.158:1884     192.168.40.145:56844    ESTABLISHED 15545/njet: copilot 

5.2 文件同步

158 作为主节点,156和145 作为backup 节点

在备节点156上传文件:

[limin@CDN156 test_bridge]$ curl -F "file=@/usr/local/njet/conf/njet.conf" http://192.168.40.156:8081/api/v1/upload
{"code":200,"file":"a02aa67e47b73c80ac60b4bc6e5c2a7c.dat"}

请求先转发到主节点158 上,在主节点的data 目录下有上传的文件

158:

njet@k8s-master158 test_bridge]$ ll data/file_upload
总用量 40
-rw-------. 1 njet njet    1203 7月   2 15:05 a02aa67e47b73c80ac60b4bc6e5c2a7c.dat

请求由主节点同步到备节点156和145 上,在备节点的data 目录下同样有上传的文件:

156:

[limin@CDN156 test_bridge]$ ll data/file_upload
总用量 52
-rw------- 1 limin limin    1203 7月   2 15:05 a02aa67e47b73c80ac60b4bc6e5c2a7c.dat

145:

limin@ldap:~/test_bridge$ ll data/file_upload
-rw-------  1 limin limin    1203 Jul  2 15:05 a02aa67e47b73c80ac60b4bc6e5c2a7c.dat

5.3 忽略文件同步

主节点:

[limin@CDN156 test_bridge]$ tree tmp4
tmp4
├── 4.txt     #符合规则 4.txt
├── abc.jpg    #符合规则 tmp4/abc.*  
├── abc.png    #符合规则 tmp4/abc.*  
├── a.jpg
├── a.png
├── tmp22
│   └── tmp33
│       └── tmp44
│           └── tmp55
│               └── tmp66
│                   ├── 1.doc   #符合规则 tmp4/tmp22/tmp33/tmp44/tmp55/tmp66/*.doc
│                   ├── 2.doc   #符合规则 tmp4/tmp22/tmp33/tmp44/tmp55/tmp66/*.doc
│                   ├── 3.doc   #符合规则 tmp4/tmp22/tmp33/tmp44/tmp55/tmp66/*.doc
│                   ├── 4.doc   #符合规则 tmp4/tmp22/tmp33/tmp44/tmp55/tmp66/*.doc
│                   ├── 4.txt  #符合规则4.txt
│                   ├── 5.doc  #符合规则 tmp4/tmp22/tmp33/tmp44/tmp55/tmp66/*.doc
│                   └── 5.txt  
│── tmp3   
│   └── tmp4
│       └── tmp5
│           └── tmp6
│               ├── 1.doc   #符合规则  tmp4/tmp3/tmp4/tmp5/tmp6/*.doc
│               ├── 2.doc   #符合规则  tmp4/tmp3/tmp4/tmp5/tmp6/*.doc
│               ├── 3.doc   #符合规则  tmp4/tmp3/tmp4/tmp5/tmp6/*.doc
│               └── 4.txt   #符合规则4.txt
└── tmp44   #符合规则 tmp4/tmp44
    ├── 1.txt
    └── 4.txt

从节点145:

limin@ldap:~/test_bridge$ tree tmp4
tmp4
├── a.jpg
├── a.png
├── tmp22
│   └── tmp33
│       └── tmp44
│           └── tmp55
│               └── tmp66
│                   └── 5.txt
└── tmp3
    └── tmp4
        └── tmp5
            └── tmp6

从节点158:

[njet@k8s-master158 test_bridge]$ tree tmp4
tmp4
├── a.jpg
├── a.png
├── tmp22
│   └── tmp33
│       └── tmp44
│           └── tmp55
│               └── tmp66
│                   └── 5.txt
└── tmp3
    └── tmp4
        └── tmp5
            └── tmp6

Slave 节点添加master 节点不存在的文件,重新启动同步后,该文件由于不在master中存在,会自动删除掉:

limin@ldap:~/test_bridge$ mkdir tmp4/156.txt
limin@ldap:~/test_bridge$ tree tmp4
tmp4
├── 156.txt
├── a.jpg
├── a.png
├── tmp22
│   └── tmp33
│       └── tmp44
│           └── tmp55
│               └── tmp66
│                   └── 5.txt
└── tmp3
    └── tmp4
        └── tmp5
            └── tmp6

Slave 节点重启后:

limin@ldap:~/test_bridge$ tree tmp4
tmp4
├── a.jpg
├── a.png
├── tmp22
│   └── tmp33
│       └── tmp44
│           └── tmp55
│               └── tmp66
│                   └── 5.txt
└── tmp3
    └── tmp4
        └── tmp5
            └── tmp6

添加符合规则的文件,tmp1/1.txt, 重新启动同步后,由于符合过滤规则,该文件不会被同步,也不会被删除

vim tmp4/4.txt

添加后,从节点:

limin@ldap:~/test_bridge$ tree tmp4     
tmp4
├── 4.txt
├── a.jpg
├── a.png
├── tmp22
│   └── tmp33
│       └── tmp44
│           └── tmp55
│               └── tmp66
│                   └── 5.txt
└── tmp3
    └── tmp4
        └── tmp5
            └── tmp6

Slave 节点重启后,由于符合过滤规则,该文件不会被同步,也不会被删除:

limin@ldap:~/test_bridge$ tree tmp4
tmp4
├── 4.txt  #仍然存在
├── a.jpg
├── a.png
├── tmp22
│   └── tmp33
│       └── tmp44
│           └── tmp55
│               └── tmp66
│                   └── 5.txt
└── tmp3
    └── tmp4
        └── tmp5
            └── tmp6