sensitive-word-admin v1.3.0 发布 如何支持敏感词控台分布式部署?

拓展阅读

sensitive-word-admin v1.3.0 发布 如何支持分布式部署?

sensitive-word-admin 敏感词控台 v1.2.0 版本开源

sensitive-word 基于 DFA 算法实现的高性能敏感词工具介绍

更多技术交流

view

业务背景

如果我们的敏感词部署之后,不会变化,那么其实不用考虑这个问题。

但是实际业务,敏感词总是随着时间不断变化的,所以我们需要支持敏感词的动态修改。

整体设计

pull vs push

以数据库存储自定义场景为例,如果页面修改了敏感词信息,那么如何通知到部署的多台敏感词客户端呢?

一般通知方式有两大类:

1)push 推送方式

修改时同时通知敏感词发生了变化,每个敏感词客户端接收到通知后,重新初始化敏感词信息。

优点是实时性比较高,缺点是需要引入额外的通知机制,需要通知的服务比较多时,也比较麻烦。

推送方式

2)pull 拉取方式

修改后,直接落库数据库,每一个敏感词客户端自己定时拉取变更的信息。

这种方式有点是非常简单,缺点是存在一定的延迟性。

定时拉取

考虑到我们的场景可以允许分钟级的延迟,所以这里先实现定时拉取方式。

如何知道敏感词是否发生了变化?

定时拉取的方式比较简单,但是每一次拉取的话,如何知道是否需要重新初始化呢?

虽然每次的初始化的耗时还好,但是考虑到变更不是很频繁,所以有没有办法定时拉取时知道有没有变化呢?

回顾一下上一篇文章,我们设计的 word 表

create table word
(id int unsigned auto_increment comment '应用自增主键' primary key,word varchar(128) not null comment '单词',type varchar(8) not null comment '类型',status char(1) not null default 'S' comment '状态',remark varchar(64) not null comment '配置描述' default '',operator_id varchar(64) not null default 'system' comment '操作员名称',create_time timestamp default CURRENT_TIMESTAMP not null comment '创建时间戳',update_time timestamp default CURRENT_TIMESTAMP not null on update CURRENT_TIMESTAMP comment '更新时间戳'
) comment '敏感词表' ENGINE=Innodb default charset=UTF8 auto_increment=1;
create unique index uk_word on word (word) comment '唯一索引';

根据更新时间可以吗?

如果我们所有的数据都不执行物理删除,那么直接根据 word 表的 update_time 即可判断。

但是如果一个数据真的被删除了,那么这种方式就不行了。

delete 的数据怎么办?

如果我们期望执行物理删除的话,那只有添加对应的日志表。

我们可以通过日志表的 update_time 来处理。

操作日志表

v1.2.0 的表设计

回顾一下 v1.2.0 表设计,如下:

create table word_log
(id int unsigned auto_increment comment '应用自增主键' primary key,batch_id varchar(128) not null comment '批次号',word varchar(128) not null comment '单词',type varchar(8) not null comment '类型',status char(1) not null default 'S' comment '单词状态。S:启用;F:禁用',remark varchar(64) not null comment '配置描述' default '',operator_id varchar(64) not null default 'system' comment '操作员名称',create_time timestamp default CURRENT_TIMESTAMP not null comment '创建时间戳',update_time timestamp default CURRENT_TIMESTAMP not null on update CURRENT_TIMESTAMP comment '更新时间戳'
) comment '敏感词操作日志表' ENGINE=Innodb default charset=UTF8 auto_increment=1;
create index ix_word on word_log (word) comment '单词普通索引';
create index ix_batch_id on word_log (batch_id) comment '批次号普通索引';

枚举:

insert into lc_enum_mapping (table_name, column_name, `key`, label)  values ('word_log', 'status', 'S', '正常');
insert into lc_enum_mapping (table_name, column_name, `key`, label)  values ('word_log', 'status', 'F', '失效');insert into lc_enum_mapping (table_name, column_name, `key`, label)  values ('word_log', 'type', 'ALLOW', '允许');
insert into lc_enum_mapping (table_name, column_name, `key`, label)  values ('word_log', 'type', 'DENY', '禁止');

表结构调整

我们对原来的表做一点调整。

调整后的建表语句

考虑到后续 sensitive-word 可能做精确的单个单词变化处理,我们最好可以知道每一次词内容的具体变化。

word 敏感词主题 word_before 变更前的单词 word_after 变更后的单词

调整后的建表语句:

drop table word_log;create table word_log
(id int unsigned auto_increment comment '应用自增主键' primary key,batch_id varchar(128) not null comment '批次号',word varchar(128) not null comment '单词',word_before varchar(128) null comment '变更前单词',word_after varchar(128) null comment '变更后单词',type varchar(8) not null comment '类型',status char(1) not null default 'S' comment '单词状态',remark varchar(64) not null comment '配置描述' default '',operator_type varchar(16) not null default '' comment '操作类别',operator_id varchar(64) not null default 'system' comment '操作员名称',create_time timestamp default CURRENT_TIMESTAMP not null comment '创建时间戳',update_time timestamp default CURRENT_TIMESTAMP not null on update CURRENT_TIMESTAMP comment '更新时间戳'
) comment '敏感词操作日志表' ENGINE=Innodb default charset=UTF8 auto_increment=1;
create index ix_word on word_log (word) comment '单词普通索引';
create index ix_batch_id on word_log (batch_id) comment '批次号普通索引';
create index ix_update_time on word_log (update_time) comment '更新时间普通索引';

添加操作类别(operator_type):

insert into lc_enum_mapping (table_name, column_name, `key`, label)  values ('word_log', 'operator_type', 'CREATE', '新增');
insert into lc_enum_mapping (table_name, column_name, `key`, label)  values ('word_log', 'operator_type', 'DELETE', '删除');
insert into lc_enum_mapping (table_name, column_name, `key`, label)  values ('word_log', 'operator_type', 'UPDATE', '更新');

例子

1)新增

新增 '敏感'

word 敏感
word_before null
word_after 敏感

2)修改

修改 '敏感',到 '敏感修改'

word 敏感
word_before 敏感
word_after 敏感修改

3) 删除

删除 '敏感修改'

word 敏感修改
word_before 敏感修改
word_after null

刷新核心逻辑

我们启动一个定时任务,判断存在更新时,则重新初始化对应的敏感词信息。

package com.github.houbb.sensitive.word.admin.web.config;import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.mapper.Wrapper;
import com.github.houbb.heaven.util.util.DateUtil;
import com.github.houbb.sensitive.word.admin.dal.entity.WordLog;
import com.github.houbb.sensitive.word.admin.service.service.WordLogService;
import com.github.houbb.sensitive.word.bs.SensitiveWordBs;
import groovy.util.logging.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;import javax.annotation.PostConstruct;
import java.util.Date;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;/*** 分布式部署的更新问题:** 模式1:push* 实时性好,但是需要感知系统的存在。** 模式2:pull* 存在延迟,但是无状态,简单。** 这里采用模式2** @since 1.2.0*/
@Component
@Slf4j
public class MySensitiveWordScheduleRefresh {private static final Logger logger = LoggerFactory.getLogger(MySensitiveWordScheduleRefresh.class);@Autowiredprivate SensitiveWordBs sensitiveWordBs;@Autowiredprivate WordLogService wordLogService;/*** 刷新时间间隔* @since 1.3.0*/@Value("${sensitive-word.refresh-interval-seconds}")private int refreshIntervalSeconds;@PostConstructpublic void init() {logger.info("MySensitiveWordScheduleRefresh init with refreshIntervalSeconds={}", refreshIntervalSeconds);// 单线程定时调度。// TODO: 调整对应的 word_log 实现ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor();executorService.scheduleAtFixedRate(new Runnable() {@Overridepublic void run() {try {logger.info("MySensitiveWordScheduleRefresh start");refresh();logger.info("MySensitiveWordScheduleRefresh end");} catch (Exception e) {logger.error("MySensitiveWordScheduleRefresh meet ex", e);}}}, refreshIntervalSeconds, refreshIntervalSeconds, TimeUnit.SECONDS);}/*** 更新词库** 每次数据库的信息发生变化之后,首先调用更新数据库敏感词库的方法。* 如果需要生效,则调用这个方法。** 说明:重新初始化不影响旧的方法使用。初始化完成后,会以新的为准。*/private void refresh() {// 延长10S,避免遗漏int timeDiffer = refreshIntervalSeconds + 10;// 判断当前一段时间内是否存在变化?Date date = DateUtil.addSecond(new Date(), -timeDiffer);Wrapper<WordLog> wordLogWrapper = new EntityWrapper<>();wordLogWrapper.gt("update_time", date);int count = wordLogService.selectCount(wordLogWrapper);if(count <= 0) {logger.info("MySensitiveWordScheduleRefresh 没有新增的变化信息,忽略更新。");return;}// 每次数据库的信息发生变化之后,首先调用更新数据库敏感词库的方法,然后调用这个方法。// 后续可以优化为针对变化的初始化。sensitiveWordBs.init();}}

sensitive-word.refresh-interval-seconds 属性指定了刷新的间隔,可配置。

小结

分布式环境下还是尽可能的追求架构的简洁性,这里只是一种实现的方式,也可以自己实现基于 push 的模式。

开源代码

sensitive-word-admin v1.3.0

参考资料

https://github.com/houbb/sensitive-word-admin

本文由博客一文多发平台 OpenWrite 发布!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/475322.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

6.s081 学习实验记录(十)file system

文章目录 一、Large files简介提示实验代码实验结果 二、Symbolic links简介提示实验代码实验结果 首先切换到 fs 分支 $ git fetch$ git checkout fs$ make clean 一、Large files 简介 该实验需要我们增大xv6文件的最大大小&#xff0c;目前xv6的最大文件大小为 268个块&…

Postman轻松签名,让SHA256withRSA保驾护航!

前言 在接口测试中&#xff0c;我们经常需要对请求进行签名&#xff0c;以保证数据的安全性。而SHA256withRSA是一种较为常见的签名算法&#xff0c;它可以使用私钥对数据进行签名&#xff0c;使用公钥进行验签。 但是&#xff0c;实现该算法签名可能会涉及到一些繁琐的操作&…

嵌入式 day23

链接命令 建立链接文件&#xff1a;ln 命令 命令名称&#xff1a;ln 命令所在路径&#xff1a;/bin/ln 执行权限&#xff1a;所有用户 语法&#xff1a;ln -s [原文件] [目标文件] -s 创建软链接 功能描述&#xff1a;生成链接文件 范例&#xff1…

【GPT-2】论文解读:Language Models are Unsupervised Multitask Learners

文章目录 介绍zero-shot learning 零样本学习 方法数据Input Representation 结果 论文&#xff1a;Language Models are Unsupervised Multitask Learners 作者&#xff1a;Alec Radford, Jeff Wu, Rewon Child, D. Luan, Dario Amodei, I. Sutskever 时间&#xff1a;2019 介…

Java集合篇之set,面试官:请说一说HashSet、LinkedHashSet、TreeSet的区别?

写在开头 Java的集合世界中主要由List&#xff0c;Set&#xff0c;Queue&#xff0c;Map构成&#xff0c;我们在之前的博文中已经学习了List&#xff0c;接下来我们继续学习Set集合。 Set特点&#xff1a;存取无序&#xff0c;不可以存放重复的元素&#xff0c;不可以用下标对…

Sentinel注解@SentinelResource详解

Sentinel注解SentinelResource详解 熔断 针对访问超过限制【sentinel中配置的限制】的资源&#xff0c;通过java代码配置&#xff0c;返回一个自定义的结果&#xff0c;需要用到 SentinelResource 注解的 blockHandlerClass 和 blockHandler 属性。 blockHandlerClass&#…

Electron实战之进程间通信

进程间通信&#xff08;IPC&#xff09;并非仅限于 Electron&#xff0c;而是源自甚至早于 Unix 诞生的概念。尽管“进程间通信”这个术语的确创造于何时并不清楚&#xff0c;但将数据传递给另一个程序或进程的理念可以追溯至 1964 年&#xff0c;当时 Douglas McIlroy 在 Unix…

review 10

整理磁盘操作的完整流程&#xff0c;如何接入虚拟机&#xff0c;是否成功识别&#xff0c;对磁盘分区工具的使用&#xff0c;格式化&#xff0c;挂载以及取消挂载、复习cp、mv和find指令 1&#xff1a;U盘接入虚拟机 在弹出窗口直接选择 虚拟机-可移动设备-找到u盘-连接 2&a…

04_device_bus_driverLinux内核模块

01_basicLinux内核模块-CSDN博客文章浏览阅读45次。环境IDubuntuMakefilemodules:clean:basic.creturn 0;运行效果。https://blog.csdn.net/m0_37132481/article/details/136157384?csdn_share_tail%7B%22type%22%3A%22blog%22%2C%22rType%22%3A%22article%22%2C%22rId%22%3A%…

实习日志15

1.大改了一下界面 1.1.识别与验真 1.2.历史记录 2.改了几个bug 2.1.改json格式用JSON.stringify(value,null,2); 2.2.内嵌页面值与原页面值重复 2.3.验真条件判断 if (isVerifyCell.getValue() "不需要") {if (verifyResultCell.getValue() ! "未查验")…

树和二叉树的基本知识

一、树的概念及结构 1.树的概念 树是一种 非线性 的数据结构&#xff0c;它是由 n &#xff08; n>0 &#xff09;个有限结点组成一个具有层次关系的集合。 把它叫做树是因 为它看起来像一棵倒挂的树&#xff0c;也就是说它是根朝上&#xff0c;而叶朝下的 。 有一个 特殊…

分享一个学英语的网站

名字叫&#xff1a;公益大米网​​​​​​​ Freerice 这个网站是以做题的形式来记忆单词&#xff0c;题干是一个单词&#xff0c;给出4个选项&#xff0c;需要选出其中最接近题干单词的选项。 答对可以获得10粒大米&#xff0c;网站的创办者负责捐赠。如图 触发某些条件&a…