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

业务背景
如果我们的敏感词部署之后,不会变化,那么其实不用考虑这个问题。
但是实际业务,敏感词总是随着时间不断变化的,所以我们需要支持敏感词的动态修改。
整体设计
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 敏感修改
- 删除
删除 '敏感修改'
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);
@Autowired
private SensitiveWordBs sensitiveWordBs;
@Autowired
private WordLogService wordLogService;
/**
* 刷新时间间隔
* @since 1.3.0
*/
@Value("${sensitive-word.refresh-interval-seconds}")
private int refreshIntervalSeconds;
@PostConstruct
public void init() {
logger.info("MySensitiveWordScheduleRefresh init with refreshIntervalSeconds={}", refreshIntervalSeconds);
// 单线程定时调度。
// TODO: 调整对应的 word_log 实现
ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor();
executorService.scheduleAtFixedRate(new Runnable() {
@Override
public 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 的模式。
开源代码
参考资料
https://github.com/houbb/sensitive-word-admin
本文由博客一文多发平台 OpenWrite 发布!
sensitive-word-admin v1.3.0 发布 如何支持敏感词控台分布式部署?的更多相关文章
- Jsonnet-PHP v1.3.0 发布,支持 PHP 7 使用 Jsonnet
JsonNet-PHP 是 Google Jsonnet 对 PHP的支持扩展. pecl: http://pecl.php.net/package/jsonnet github: https://g ...
- Selenium WebDriver 2.34.0 发布,支持Firefox22
Selenium WebDriver 2.34.0 发布,支持Firefox22http://automationqa.com/forum.php?mod=viewthread&tid=270 ...
- RapidJSON v1.1.0 发布简介
时隔 15.6 个月,终于发布了一个新版本 v1.1.0. 新版本除了包含了这些日子收集到的无数的小改进及 bug fixes,也有一些新功能.本文尝试从使用者的角度,简单介绍一下这些功能和沿由. P ...
- FineUIMvc v1.4.0 发布了(ASP.NET MVC控件库)!
FineUIMvc v1.4.0 已经于 2017-06-30 发布,FineUIMvc 是基于 jQuery 的专业 ASP.NET MVC 控件库,是我们的新产品.由于和 FineUI(专业版)共 ...
- AgileConfig轻量级配置中心1.3.0发布,支持多用户权限控制
AgileConfig 当初是设计给我自己用的一个工具,所以只设置了一道管理员密码,没有用户的概念.但是很多同学在使用过后都提出了需要多用户支持的建议.整个团队或者整个公司都使用同一个密码来管理非常的 ...
- Kube-OVN1.5.0新版本发布,支持鲲鹏云平台网络平面部署
近日,Kube-OVN发布了最新的1.5.0版本.自2019年4月开源以来,Kube-OVN经历了15次重要版本迭代,以及社区成立,建设者贡献代码,稳定性测试,国内外用户开始在生产环境中投入使用,企业 ...
- 【Andorid】短视频拍摄SDK——Vitamio Recorder 2.0 发布(支持ffmpeg命令行)
简介 VCamera SDK Android 版(短视频拍摄SDK)是炫一下(北京)科技有限公司推出的软件开发工具包,为Android开发者提供简单.快捷的接口,帮助开发者实现Android平台上的短 ...
- Yearning v1.3.0 发布,Web 端 SQL 审核平台
企业级MYSQL web端 SQL审核平台. Website 官网 www.yearning.io Feature 功能 数据库字典自动生成 SQL查询 查询工单 导出 自动补全,智能提示 查询语句审 ...
- Solon v1.11.0 发布,Hello Java
一个更现代感的 Java 应用开发框架:更快.更小.更自由.没有 Spring,没有 Servlet,没有 JavaEE:独立的轻量生态.主框架仅 0.1 MB. @Controller public ...
- Solon Java Framework v1.12.0 发布
一个更现代感的 Java 应用开发框架:更快.更小.更自由.没有 Spring,没有 Servlet,没有 JavaEE:独立的轻量生态.主框架仅 0.1 MB. @Controller public ...
随机推荐
- CSS3之transition
随着css3不断地发展,越来越多的页面特效可以被实现. 例如当我们鼠标悬浮在某个tab上的时候,给它以1s的渐进变化增加一个背景颜色.渐进的变化可以让css样式变化得不那么突兀,也显得交互更加柔和. ...
- QT启动问题--找不到python36.dll-cnblog
1.报错:找不到python36.dll 2.解决 通过该查询CSDN下载相应的python36.dll放到C:\Windows\System32目录下即可 https://blog.csdn.net ...
- PR 调整时间线宽度
1.问题 这里的宽度太小,不好进行下一步的调整 2.解决方法 方法一 按下=可以放宽 按下-(=左边的那个键)可以缩小宽度 方法二 拖动下方的滑动条即可 方法三 按住ALT+滚轮,即可调节
- android studio 如何把依赖导出成 jar
反编译工具 dex-tools-2.1-SNAPSHOT 第一步 用一个普通的app工程,引用所有的库,然后生成apk文件 第二步 把apk文件,改扩展名为zip,解压后,里面有几个*.dex文件,拷 ...
- QT5.9移植到海思HI3520设备上运行
前言: 在海思HI3520DV300上调试QT5.9.0有一小段时间了,这里将遇到的比较典型的问题做一个记录,以备后续查询,也可给同行一个参考.本人只使用过QT5.9.0这一个版本,如有描述错误欢迎指 ...
- Mygin实现动态路由
本篇是Mygin的第四篇 目的 使用 Trie 树实现动态路由解析. 参数绑定 前缀树 本篇比前几篇要复杂一点,原来的路由是用map实现,索引非常高效,但是有一个弊端,键值对的存储的方式,只能用来索引 ...
- 【Mysql系列】(一)MySQL语句执行流程
首发博客地址 首发博客地址 系列文章地址 参考文章 MySQL 逻辑架构 连接器 连接命令一般是这么写的 mysql -h$ip -P$port -u$user -p 那么 什么是连接器? MySQL ...
- [转帖]15--k8s之安全认证
https://www.cnblogs.com/caodan01/p/15137987.html 目录 一.访问控制概述 二.认证管理 三.授权管理 虽然authorization-clusterro ...
- [转帖]HTTP 框架 Hertz 实践入门:性能测试指南
https://maimai.cn/article/detail?fid=1767401397&efid=R2_kM5y-yEUDCK88FZWrGA 干货不迷路2021 年 9 月 8 日, ...
- JavaScript一种新的数据结构类型Map
什么是map 它类似于对象,是键值对的集合,但键的范围不局限在于字符串.各种类型的值(包含对象)都可以作为键. 如果同一个键被多次赋值,后面的值将会覆盖其那面的值.如果读取一个未知的键,返回的是und ...