优大网

作者: 文广 ( 1 / 15)

Grafana 的一些使用技巧

文章目录

  • 数值类型的常用指标含义
    • 总量误区
    • 误差
  • 模板变量
    • 模板变量的写法
    • 新建模板变量
    • 模板变量的隐藏玩法
  • grafana 面板编辑器
    • Metrcis
    • Legend
    • Display
  • 高级函数
    • 聚合单个查询的多条匹配曲线的总量 Combine -> sumSeries
    • 时间线迁移 Transform -> timeShift
    • 去除异常值 Filter -> removeAboveValue
    • 重命名函数
    • 多条曲线数值的聚合 Special -> groupByNode
    • 计算多个 Query 组成的成功率 Calculate -> asPercent
  • 其他
    • 报警
    • statsd 打点的限制
    • 后端查询 grafana 数据
    • 匿名模式
  • 最后

grafana 是一个开源的时序性统计和监控平台,支持例如 elasticsearch、graphite、influxdb 等众多的数据源,并以功能强大的界面编辑器著称。我们在前端监控方面引入 grafana 后取得了一些不错的反馈,但是很多用户由于之前没有接触过 grafana 经常会来询问 grafana 的相关问题,因此希望本文对大家在 grafana 使用方面有所帮助。

grafana 的权限分为三个等级:Viewer、Editor 和 Admin,Viewer 只能查看 grafana 已经存在的面板而不能编辑,Editor 可以编辑面板,Admin 则拥有全部权限例如添加数据源、添加插件、增加 API KEY。

对于普通用户来说,Viewer 权限已经足够,本文接下来的内容主要和 Editor 权限有关。由于篇幅有限,本文作为范例的数据源为 graphite,同时也只介绍最常用的 Graph 图表的配置方法。

数值类型的常用指标含义

  • count_ps
    • 每秒的数量
  • count
    • 每十秒的数量
  • mean_90
    • 去除最高10%的数据后的平均值
  • upper_90
    • 去除最高10%的数据后的最高值

总量误区

这里有一个常见的 grafana 误区,因为经常有用数值类型的 count_ps 来顺便获取每秒打点数量的情况,注意在这种情况下,一段时间内的打点总量需要使用 count_ps 的 avg 平均值来乘以这段时间的秒数来计算,而不是通过界面上的 Total 直接读取。

这是因为,在界面上一条曲线能够展示的点的数量是有限的,grafana 会根据你的窗口宽度来决定返回的点数,因为像一天这样的时间段肯定没办法在界面上展示每一秒的点,毕竟总量为86400个点就算带鱼屏也不可能挤得下。对于无法展示的点,grafana 默认是使用 avg 平均值的行为来修正返回点的值,举个栗子,如下图:

image

上图时间范围是一天,上部分为曲线面板的值,下部分为 面饼图表的值,并且上部分图标的曲线为 count 类型(十秒聚一次),可以看到 avg 平均值为 683,那么总量应该为 682 乘以 6 (如果是count_ps 这里则是60) 乘以 60 (一小时60分钟)再乘以 24 (一天24小时)得到589万,与图片中下部分的582万相近,因此上部分 total 的117万是一个完完全全让人误解的值,可以认为它毫无意义进而直接无视掉。

误差

上文中我们计算出来的589万和界面上的582万其实也有一点误差,不过这是可以接受的,因为 statsd 一般情况下是 UDP 的形式(它其实有 TCP 的形式),所以如果想要完全正确的数据,那么最好把打点相关的数据也入库,从数据库里后置查询出来的才是完全可靠。

模板变量

模板变量能够动态地控制面板中的查询语句,是十分重要的功能。经常可以在面板的左上角发现它们,如下图:

image

模板变量的写法

模板变量支持 $name[[name]] 的写法,针对 graphite 数据源主要使用前者,例如:stats.timers.fe.test.$key.count_ps

新建模板变量

grafana 界面上齿轮按钮 -> Templating -> 点击 New,即可出现类似如下的界面:

image

本段主要介绍 Query 类型的写法。

  • Name
    • 该变量的名称,不支持特殊字符例如$
  • Refresh
    • 可选NeverOn Dashboard LoadOn Time Range Change
    • 如果该变量的值经常动态增加的话则选 On Time Range Change,否则 On Dashboard Load 就足够了,Query 类型千万不要选 Never,否则变量只会在你点进来编辑变量时才会更新
  • Query
    • 查询语句,例如 stats.timers.fe.test.*
    • 编写时 grafana 不会触发请求,需要在输入框外面点击一下,查询到的值就会显示在下边了

模板变量中的 Query 其实也支持模板变量,例如stats.timers.fe.test.$key.* 这样的语句,会在 $key 变量变化时自动刷新值,是不是有一点 MVVM 的感觉。这个功能用来联动多个模板变量可以大幅度减少 grafana 一次查询的时间。

模板变量的隐藏玩法

模板变量甚至可以用在 grafana 的跳转中,这是连文档中都没有提及的一个隐藏玩法,在 Link 或者 Dashboard 里 URL 中任意位置填入 $name ,那么在用户点击该链接跳转时 grafana 同样会替换该变量来让你跳到正确的链接去。这和其他系统整合起来能够做到很不错的用户体验,例如跳转到 kibana 那边去查询日志。

kibana 和 grafana 的时间范围格式并不一样,可以使用这篇文章 中的 chrome 插件来解决。

另外,Custom 模板变量可以允许用户在变量下拉框中自行输入值,也是一个经常用到的值,配合模板变量会和当前链接中的 querystring 部分的var-${name} 同步,配合起来可以轻松地从第三方系统中跳转到正确的 grafana 面板中来

grafana 面板编辑器

以 Editor 权限的账号进入到任意面板中,点击某个图表继而点击小弹窗中的 Edit 按钮,即可进入图表的编辑器界面。对于编辑器本文只介绍图表的重要配置,Metrics,Legend 和 Display

Metrcis

image
  • 编辑模式
    • 上图箭头指向的 toggle editor mode 可以控制编辑模式,关闭则需要手动输入查询语句,开启则是如上图的可以在界面上动态增删改的模式。
  • 数据源
    • Panel data source 一定要选对,否则查不到对应的路径,并且很有可能冒出来 Mock 数据让人一脸懵逼。
image

开启动态编辑模式时可以在点击上图中每个框框,这时 grafana 会自动加载该位置在数据源中的值,并且你也可以在这里选择模板变量来动态控制。

image

点击尾巴上的加号,会冒出来对应数据源的函数,可以做一些高级的功能,这个也是本文下半部分的重点,稍后再做介绍。graphite 的函数比较多,其他数据源会少一些。

Legend

Legend 主要控制曲线的名称和值的展示,比较简单,这里列出一下他们的含义

  • As Table
    • 是否以表格形式展示
  • To the right
    • 是展示在图表右边还是在下面
  • Width
    • 默认不填会自动伸缩,否则强制限定宽度
  • Min
    • 面板时间段内的最小值
  • Avg
    • 面板时间段内的平均值
  • Total
    • 面板时间段内的值的总量,如上文所说获取数值类型的总量时这个 Total 是一个很让人误解的参数
  • Max
    • 面板时间段内的最大值
  • Current
    • 面板时间段内的当前值

Display

Display 控制图表的点和线的展示,有一些比较重要的参数

  • Draw Modes -> Lines
    • 是否绘制点之间的线段
  • Draw Modes -> Points
    • 是否绘制点
  • Hover info -> Mode
    • 悬浮面板上展示的方式,值为 All serires(展示该时间点的所有线段的值)和 single(只展示鼠标指着的那一条线段)
  • Hover info -> Sort Order
    • 悬浮面板上线条的排序,一般选择 Decreasing
  • Stacking & Null value -> Null value
    • 这个比较重要,需要根据点的密度来动态决定,如果点少很容易让人误解两个点中间也存在点。
    • 点多时,选择 connected
    • 点少时,选择 null

高级函数

以 graphite 为例子,打点路径中的 KEY 只支持大小写字母、数字、中划线和下划线,这会导致前端的路径(经常包含 # 和 :path)存不下来,因此我们只能提前转译,例如将 # 转译为 ANCHOR,将 :path 转译为 PATH ,再将 / 转译为 -,这样在变量模板中展示的就是比较怪异的前端路径,不过好在我们有函数,可以在界面上把它替换回来。

image

点击编辑界面 Metrics 面板中编辑模式的加号,添加 aliaSub 函数,并依此填入上图的三种的替换规则,在界面上就可以看到如下图的正常路径了:

image

aliaSub 只是其中一个简单的 alias 函数,用来处理曲线的名称,更多的函数是被用来处理单个查询的聚合、多条曲线的聚合、展示不同时间线、计算和过滤,本节会介绍其中一些经常用到的函数。

聚合单个查询的多条匹配曲线的总量 Combine -> sumSeries

例如,假设 stats_count.fe.test.* 有几十个匹配值,那么这个查询就会在图表中展示几十条曲线,此时如何获取所有曲线的总值呢?不需要在打点时多打一份总量数据,直接使用 sumSeries 函数即可,sumSeries(stats_count.fe.test.*)

时间线迁移 Transform -> timeShift

想要在这个时间段内同时展示前一天的的曲线?timeShift(Query, '-1d')即可

去除异常值 Filter -> removeAboveValue

如果数值类型中出现了异常的值,例如平均为 1秒 的情况下出现了几百万秒的情况,那么就可以通过众多的过滤函数在界面上直接过滤掉而不是去修改打点代码,removeAboveValue(Query, 10000)即可

重命名函数

  • alias
    • 直接重命名该曲线,参数为曲线名称
  • aliasByNode(4, 5, 6)
    • 将曲线命名为原名称的第4、5、6段
  • aliasSub
    • 正则替换名称中的某一段

多条曲线数值的聚合 Special -> groupByNode

sumSeries 函数只能简单地将多条数据的最终值加起来,如果不是末尾位置的就不行了,而且也不支持除了 sum 外的功能,例如 avg 平均,使用 groupByNode 就可以动态地对指定位置的多个数值类型进行聚合了,如下图:

image

计算多个 Query 组成的成功率 Calculate -> asPercent

假设我们有如下几条打点:

stats.timers.fe.test.error1.count
stats.timers.fe.test.error2.count
stats.timers.fe.test.error3.count
stats.timers.fe.test.success.count

此时想要计算 success 的成功比例,如何做呢?

在这种相较复杂的情况下,就不能只靠一个 Query 来解决了,首先我们创建两个 Query,如下:

stats.timers.fe.test.*.count (Query 序列号为 #A)
stats.timers.fe.test.success.count (Query 序列号为 #B)

再创建第三个 Query,值为 asPercent(#B, sumSeries(#A),顾名思义,首先将 #A 的查询聚合起来得到总值,再用 asPercent 来进行除法即可。

通过如上的几个例子,可以看到函数强大的功能,即使是很复杂的在以前需要用后端代码来实现的部分,都可以通过多条Query和多个函数的互相嵌套来在界面上简单地实现。

每个数据源都有对应的函数开发文档,例如 graphite。grafana 正是凭借着对众多数据源以及函数的支持,才能在一个网页界面上完成这么多强大的功能。

其他

报警

grafana 在 4.0 版本后增加了报警功能,不过 grafana 的报警属于数据源的后置查询,实时性不大能满足需求,我们公司有一个开源的 banshee ,就是为了解决这个问题。

banshee 使用了三西格马定律,支持基于阈值和趋势的报警,同时提供开放的 API 和 webhook 并默认集成了 Slack。banshee 和数据源位于同一个位置(statsd 的后端),因此可以保证时效性,也因为报警的独立性质所以对 grafana 版本没有任何要求。

statsd 打点的限制

grafana 依赖的如果是时序性数据库,那么每一个 KEY 都会对应一个文件来存储数据,例如 stats.timers.fe.test.* 相当于 stats/timers/fe/test 文件夹下的所有文件,因此必须注意打点路径不要有过多的组合,比如将省份和市作为 KEY 时的组合很容易就能占到 1G 以上的数据导致磁盘爆掉。

为了避免组合过多导致路径污染,请尽量保证每个 KEY 中格式化掉点,例如替换成下划线,另外打点路径可以尽量多加一点前缀,例如将stats.timers.fe.test.* 改为 stats.timers.fe.test.v1.* ,这样一旦污染后,清理数据时可以直接把 v1 整个文件夹删除而不是删除 test 这个根路径,用以保留你的历史正常的打点数据。

后端查询 grafana 数据

一般推荐使用 API KEY 来查询 grafana 的数据,Admin 权限账号可以在界面中生成上文三种权限的 API KEY,不过 grafana 默认会开启 Basic Auth,使用账号密码即可通过 grafana 的鉴权,例如http://${account}:${password}@${grafana_host}/api/org

当然,最好是拥有数据源的读权限来直接读取数据。

匿名模式

有时候用户确实没有 grafana 的账号,但他就是想看面板,怎么办?此时就得 grafana 的匿名模式出马了。

grafana 配置文件中有 auth.anonymous 配置段,enabled 控制开关,org_name 控制开启匿名模式的组织,org_role 控制匿名者的权限。组织开启匿名意味着非登录用户能够直接跳过 grafana 无权限地查询数据源,因此请保证数据源的安全,例如限定内网访问。

最后

本文介绍了 grafana 相对高级的一些使用技巧,除了可以看到 grafana 的强大功能以外,也应该注意到 grafana 只是一个时序性很强的统计监控平台,一些非时序性质的功能例如报错的聚合和报错的日志等应该交给更专业的去做,例如 sentry 和 ELK。

作者:easyhappy
链接:https://segmentfault.com/a/1190000013565079
来源:SegmentFault 思否
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

grafana之Variables变量的使用

介绍

Variables变量提供了用户和面板交互,并动态刷新面板的功能。不需要硬编码,不需要每次都修改SQL查询语句。变量的下拉菜单显示在面板的顶部,这样改变下拉菜单的值,即可改变变量的值,而且所有使用该变量的仪表板都会随着变量的改变而改变。

变量.png

变量(Variables)的定义:

在dashboard的设置中定义的变量,可以作为该dashboard的全局变量使用,如下图所示

定义.png

变量的表示符号。如:IDC表示IDC这个变量,使用的时候,直接使用$IDC就可以获取IDC变量的值。

新建变量:

点击new按钮,填充如下,

add.png

Type为变量的类型,总共有六种类型:Interval(时间间隔类),Query(查询类),Datasource(数据源类型),Custom(自定义类),Constant(常量类),Ad hoc filters(我也不知道啥玩意,未知类)

Type.png

这里我选用了常用类型:Query,数据源为已经设置的mysql数据源,然后直接填入mysql查询语句:

SELECT DISTINCT cluster FROM jdos_node_base WHERE idc =  '$IDC'

注:IDC为已经设置的变量,直接使用取值即可。

Refresh变量刷新方式

Refresh.png

Refresh是指变量的刷新方式,总共三种: Never,On Dashboard Load,On Time Range Change.
Never : 从来不刷新
On Dashboard Load:面板加载的时候,刷新一次
On Time Range Change:跟随面板刷新时间刷新该变量,面板的刷新设置在面板的右上角,如下

面板刷新.png

变量设置完成之后,下方会出现变量的值。
点击Add按钮,设置完成。
返回面板,是这样的,

image.png

可以看到机房和集群已经设置成功了。

变量的使用

添加仪表板,进入编辑仪表板,如下图,

仪表板的编辑.png

选择数据源,输入查询语句:

SELECT
  UNIX_TIMESTAMP(start_time) as time_sec,
  cpu_max as value,
  "cpu_max" as metric
FROM jdos_idc_info
WHERE $__timeFilter(start_time) AND cluster = "$Cluster" 
ORDER BY start_time ASC

这里的Cluster就是之前在Variables设置的变量,还是使用$符号取值。

选择不同的机房&集群就会自动刷新面板的值,因为改变机房&集群,变量的值也会同步改变。如下:

示例1.png

示例2.png

欢迎在下方评论交流。

作者:风吹散了的回忆
链接:https://www.jianshu.com/p/fe8bab704716
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

CSRF攻击与防御

       CSRF概念:CSRF跨站点请求伪造(Cross—Site Request Forgery),跟XSS攻击一样,存在巨大的危害性,你可以这样来理解:
       攻击者盗用了你的身份,以你的名义发送恶意请求,对服务器来说这个请求是完全合法的,但是却完成了攻击者所期望的一个操作,比如以你的名义发送邮件、发消息,盗取你的账号,添加系统管理员,甚至于购买商品、虚拟货币转账等。 如下:其中Web A为存在CSRF漏洞的网站,Web B为攻击者构建的恶意网站,User C为Web A网站的合法用户。
 CSRF攻击介绍及防御

        CSRF攻击攻击原理及过程如下:

       1. 用户C打开浏览器,访问受信任网站A,输入用户名和密码请求登录网站A;

       2.在用户信息通过验证后,网站A产生Cookie信息并返回给浏览器,此时用户登录网站A成功,可以正常发送请求到网站A;

       3. 用户未退出网站A之前,在同一浏览器中,打开一个TAB页访问网站B;

       4. 网站B接收到用户请求后,返回一些攻击性代码,并发出一个请求要求访问第三方站点A;
       5. 浏览器在接收到这些攻击性代码后,根据网站B的请求,在用户不知情的情况下携带Cookie信息,向网站A发出请求。网站A并不知道该请求其实是由B发起的,所以会根据用户C的Cookie信息以C的权限处理该请求,导致来自网站B的恶意代码被执行。 

       CSRF攻击实例


       受害者 Bob 在银行有一笔存款,通过对银行的网站发送请求 http://bank.example/withdraw?account=bob&amount=1000000&for=bob2 可以使 Bob 把 1000000 的存款转到 bob2 的账号下。通常情况下,该请求发送到网站后,服务器会先验证该请求是否来自一个合法的 session,并且该 session 的用户 Bob 已经成功登陆。

        黑客 Mallory 自己在该银行也有账户,他知道上文中的 URL 可以把钱进行转帐操作。Mallory 可以自己发送一个请求给银行:http://bank.example/withdraw?account=bob&amount=1000000&for=Mallory。但是这个请求来自 Mallory 而非 Bob,他不能通过安全认证,因此该请求不会起作用。

        这时,Mallory 想到使用 CSRF 的攻击方式,他先自己做一个网站,在网站中放入如下代码: src=”http://bank.example/withdraw?account=bob&amount=1000000&for=Mallory ”,并且通过广告等诱使 Bob 来访问他的网站。当 Bob 访问该网站时,上述 url 就会从 Bob 的浏览器发向银行,而这个请求会附带 Bob 浏览器中的 cookie 一起发向银行服务器。大多数情况下,该请求会失败,因为他要求 Bob 的认证信息。但是,如果 Bob 当时恰巧刚访问他的银行后不久,他的浏览器与银行网站之间的 session 尚未过期,浏览器的 cookie 之中含有 Bob 的认证信息。这时,悲剧发生了,这个 url 请求就会得到响应,钱将从 Bob 的账号转移到 Mallory 的账号,而 Bob 当时毫不知情。等以后 Bob 发现账户钱少了,即使他去银行查询日志,他也只能发现确实有一个来自于他本人的合法请求转移了资金,没有任何被攻击的痕迹。而 Mallory 则可以拿到钱后逍遥法外。 

       CSRF漏洞检测:
       检测CSRF漏洞是一项比较繁琐的工作,最简单的方法就是抓取一个正常请求的数据包,去掉Referer字段后再重新提交,如果该提交还有效,那么基本上可以确定存在CSRF漏洞。

       随着对CSRF漏洞研究的不断深入,不断涌现出一些专门针对CSRF漏洞进行检测的工具,如CSRFTester,CSRF Request Builder等。

       以CSRFTester工具为例,CSRF漏洞检测工具的测试原理如下:使用CSRFTester进行测试时,首先需要抓取我们在浏览器中访问过的所有链接以及所有的表单等信息,然后通过在CSRFTester中修改相应的表单等信息,重新提交,这相当于一次伪造客户端请求。如果修改后的测试请求成功被网站服务器接受,则说明存在CSRF漏洞,当然此款工具也可以被用来进行CSRF攻击。
        防御CSRF攻击:

       目前防御 CSRF 攻击主要有三种策略:验证 HTTP Referer 字段;在请求地址中添加 token 并验证;在 HTTP 头中自定义属性并验证。

      (1)验证 HTTP Referer 字段

        根据 HTTP 协议,在 HTTP 头中有一个字段叫 Referer,它记录了该 HTTP 请求的来源地址。在通常情况下,访问一个安全受限页面的请求来自于同一个网站,比如需要访问 http://bank.example/withdraw?account=bob&amount=1000000&for=Mallory,用户必须先登陆 bank.example,然后通过点击页面上的按钮来触发转账事件。这时,该转帐请求的 Referer 值就会是转账按钮所在的页面的 URL,通常是以 bank.example 域名开头的地址。而如果黑客要对银行网站实施 CSRF 攻击,他只能在他自己的网站构造请求,当用户通过黑客的网站发送请求到银行时,该请求的 Referer 是指向黑客自己的网站。因此,要防御 CSRF 攻击,银行网站只需要对于每一个转账请求验证其 Referer 值,如果是以 bank.example 开头的域名,则说明该请求是来自银行网站自己的请求,是合法的。如果 Referer 是其他网站的话,则有可能是黑客的 CSRF 攻击,拒绝该请求。

        这种方法的显而易见的好处就是简单易行,网站的普通开发人员不需要操心 CSRF 的漏洞,只需要在最后给所有安全敏感的请求统一增加一个拦截器来检查 Referer 的值就可以。特别是对于当前现有的系统,不需要改变当前系统的任何已有代码和逻辑,没有风险,非常便捷。

        然而,这种方法并非万无一失。Referer 的值是由浏览器提供的,虽然 HTTP 协议上有明确的要求,但是每个浏览器对于 Referer 的具体实现可能有差别,并不能保证浏览器自身没有安全漏洞。使用验证 Referer 值的方法,就是把安全性都依赖于第三方(即浏览器)来保障,从理论上来讲,这样并不安全。事实上,对于某些浏览器,比如 IE6 或 FF2,目前已经有一些方法可以篡改 Referer 值。如果 bank.example 网站支持 IE6 浏览器,黑客完全可以把用户浏览器的 Referer 值设为以 bank.example 域名开头的地址,这样就可以通过验证,从而进行 CSRF 攻击。

即便是使用最新的浏览器,黑客无法篡改 Referer 值,这种方法仍然有问题。因为 Referer 值会记录下用户的访问来源,有些用户认为这样会侵犯到他们自己的隐私权,特别是有些组织担心 Referer 值会把组织内网中的某些信息泄露到外网中。因此,用户自己可以设置浏览器使其在发送请求时不再提供 Referer。当他们正常访问银行网站时,网站会因为请求没有 Referer 值而认为是 CSRF 攻击,拒绝合法用户的访问。

       (2)在请求地址中添加 token 并验证

         CSRF 攻击之所以能够成功,是因为黑客可以完全伪造用户的请求,该请求中所有的用户验证信息都是存在于 cookie 中,因此黑客可以在不知道这些验证信息的情况下直接利用用户自己的 cookie 来通过安全验证。要抵御 CSRF,关键在于在请求中放入黑客所不能伪造的信息,并且该信息不存在于 cookie 之中。可以在 HTTP 请求中以参数的形式加入一个随机产生的 token,并在服务器端建立一个拦截器来验证这个 token,如果请求中没有 token 或者 token 内容不正确,则认为可能是 CSRF 攻击而拒绝该请求。

        这种方法要比检查 Referer 要安全一些,token 可以在用户登陆后产生并放于 session 之中,然后在每次请求时把 token 从 session 中拿出,与请求中的 token 进行比对,但这种方法的难点在于如何把 token 以参数的形式加入请求。对于 GET 请求,token 将附在请求地址之后,这样 URL 就变成 http://url?csrftoken=tokenvalue。 而对于 POST 请求来说,要在 form 的最后加上 <input type=”hidden” name=”csrftoken” value=”tokenvalue”/>,这样就把 token 以参数的形式加入请求了。但是,在一个网站中,可以接受请求的地方非常多,要对于每一个请求都加上 token 是很麻烦的,并且很容易漏掉,通常使用的方法就是在每次页面加载时,使用 javascript 遍历整个 dom 树,对于 dom 中所有的 a 和 form 标签后加入 token。这样可以解决大部分的请求,但是对于在页面加载之后动态生成的 html 代码,这种方法就没有作用,还需要程序员在编码时手动添加 token。

         该方法还有一个缺点是难以保证 token 本身的安全。特别是在一些论坛之类支持用户自己发表内容的网站,黑客可以在上面发布自己个人网站的地址。由于系统也会在这个地址后面加上 token,黑客可以在自己的网站上得到这个 token,并马上就可以发动 CSRF 攻击。为了避免这一点,系统可以在添加 token 的时候增加一个判断,如果这个链接是链到自己本站的,就在后面添加 token,如果是通向外网则不加。不过,即使这个 csrftoken 不以参数的形式附加在请求之中,黑客的网站也同样可以通过 Referer 来得到这个 token 值以发动 CSRF 攻击。这也是一些用户喜欢手动关闭浏览器 Referer 功能的原因。

      (3)在 HTTP 头中自定义属性并验证

        这种方法也是使用 token 并进行验证,和上一种方法不同的是,这里并不是把 token 以参数的形式置于 HTTP 请求之中,而是把它放到 HTTP 头中自定义的属性里。通过 XMLHttpRequest 这个类,可以一次性给所有该类请求加上 csrftoken 这个 HTTP 头属性,并把 token 值放入其中。这样解决了上种方法在请求中加入 token 的不便,同时,通过 XMLHttpRequest 请求的地址不会被记录到浏览器的地址栏,也不用担心 token 会透过 Referer 泄露到其他网站中去。
        然而这种方法的局限性非常大。XMLHttpRequest 请求通常用于 Ajax 方法中对于页面局部的异步刷新,并非所有的请求都适合用这个类来发起,而且通过该类请求得到的页面不能被浏览器所记录下,从而进行前进,后退,刷新,收藏等操作,给用户带来不便。另外,对于没有进行 CSRF 防护的遗留系统来说,要采用这种方法来进行防护,要把所有请求都改为 XMLHttpRequest 请求,这样几乎是要重写整个网站,这代价无疑是不能接受的。

kafka命令大全

https://www.orchome.com/454

管理

## 创建主题(4个分区,2个副本)
bin/kafka-topics.sh --create --zookeeper localhost:2181 --replication-factor 2 --partitions 4 --topic test

查询

## 查询集群描述
bin/kafka-topics.sh --describe --zookeeper 

## topic列表查询
bin/kafka-topics.sh --zookeeper 127.0.0.1:2181 --list

## topic列表查询(支持0.9版本+)
bin/kafka-topics.sh --list --bootstrap-server localhost:9092

## 新消费者列表查询(支持0.9版本+)
bin/kafka-consumer-groups.sh --new-consumer --bootstrap-server localhost:9092 --list

## 新消费者列表查询(支持0.10版本+)
bin/kafka-consumer-groups.sh --bootstrap-server localhost:9092 --list

## 显示某个消费组的消费详情(仅支持offset存储在zookeeper上的)
bin/kafka-run-class.sh kafka.tools.ConsumerOffsetChecker --zookeeper localhost:2181 --group test

## 显示某个消费组的消费详情(0.9版本 - 0.10.1.0 之前)
bin/kafka-consumer-groups.sh --new-consumer --bootstrap-server localhost:9092 --describe --group test-consumer-group

## 显示某个消费组的消费详情(0.10.1.0版本+)
bin/kafka-consumer-groups.sh --bootstrap-server localhost:9092 --describe --group my-group

发送和消费

## 生产者
bin/kafka-console-producer.sh --broker-list localhost:9092 --topic test

## 消费者
bin/kafka-console-consumer.sh --zookeeper localhost:2181 --topic test

## 新生产者(支持0.9版本+)
bin/kafka-console-producer.sh --broker-list localhost:9092 --topic test --producer.config config/producer.properties

## 新消费者(支持0.9版本+)
bin/kafka-console-consumer.sh --bootstrap-server localhost:9092 --topic test --new-consumer --from-beginning --consumer.config config/consumer.properties

## 高级点的用法
bin/kafka-simple-consumer-shell.sh --brist localhost:9092 --topic test --partition 0 --offset 1234  --max-messages 10

平衡leader

bin/kafka-preferred-replica-election.sh --zookeeper zk_host:port/chroot

kafka自带压测命令

bin/kafka-producer-perf-test.sh --topic test --num-records 100 --record-size 1 --throughput 100  --producer-props bootstrap.servers=localhost:9092

分区扩容

bin/kafka-topics.sh --zookeeper localhost:2181 --alter --topic topic1 --partitions 2

迁移分区

  1. 创建规则json cat > increase-replication-factor.json {"version":1, "partitions":[ {"topic":"__consumer_offsets","partition":0,"replicas":[0,1]}, {"topic":"__consumer_offsets","partition":1,"replicas":[0,1]}, {"topic":"__consumer_offsets","partition":2,"replicas":[0,1]}, {"topic":"__consumer_offsets","partition":3,"replicas":[0,1]}, {"topic":"__consumer_offsets","partition":4,"replicas":[0,1]}, {"topic":"__consumer_offsets","partition":5,"replicas":[0,1]}, {"topic":"__consumer_offsets","partition":6,"replicas":[0,1]}, {"topic":"__consumer_offsets","partition":7,"replicas":[0,1]}, {"topic":"__consumer_offsets","partition":8,"replicas":[0,1]}, {"topic":"__consumer_offsets","partition":9,"replicas":[0,1]}, {"topic":"__consumer_offsets","partition":10,"replicas":[0,1]}, {"topic":"__consumer_offsets","partition":11,"replicas":[0,1]}, {"topic":"__consumer_offsets","partition":12,"replicas":[0,1]}, {"topic":"__consumer_offsets","partition":13,"replicas":[0,1]}, {"topic":"__consumer_offsets","partition":14,"replicas":[0,1]}, {"topic":"__consumer_offsets","partition":15,"replicas":[0,1]}, {"topic":"__consumer_offsets","partition":16,"replicas":[0,1]}, {"topic":"__consumer_offsets","partition":17,"replicas":[0,1]}, {"topic":"__consumer_offsets","partition":18,"replicas":[0,1]}, {"topic":"__consumer_offsets","partition":19,"replicas":[0,1]}, {"topic":"__consumer_offsets","partition":20,"replicas":[0,1]}, {"topic":"__consumer_offsets","partition":21,"replicas":[0,1]}, {"topic":"__consumer_offsets","partition":22,"replicas":[0,1]}, {"topic":"__consumer_offsets","partition":23,"replicas":[0,1]}, {"topic":"__consumer_offsets","partition":24,"replicas":[0,1]}, {"topic":"__consumer_offsets","partition":25,"replicas":[0,1]}, {"topic":"__consumer_offsets","partition":26,"replicas":[0,1]}, {"topic":"__consumer_offsets","partition":27,"replicas":[0,1]}, {"topic":"__consumer_offsets","partition":28,"replicas":[0,1]}, {"topic":"__consumer_offsets","partition":29,"replicas":[0,1]}, {"topic":"__consumer_offsets","partition":30,"replicas":[0,1]}, {"topic":"__consumer_offsets","partition":31,"replicas":[0,1]}, {"topic":"__consumer_offsets","partition":32,"replicas":[0,1]}, {"topic":"__consumer_offsets","partition":33,"replicas":[0,1]}, {"topic":"__consumer_offsets","partition":34,"replicas":[0,1]}, {"topic":"__consumer_offsets","partition":35,"replicas":[0,1]}, {"topic":"__consumer_offsets","partition":36,"replicas":[0,1]}, {"topic":"__consumer_offsets","partition":37,"replicas":[0,1]}, {"topic":"__consumer_offsets","partition":38,"replicas":[0,1]}, {"topic":"__consumer_offsets","partition":39,"replicas":[0,1]}, {"topic":"__consumer_offsets","partition":40,"replicas":[0,1]}, {"topic":"__consumer_offsets","partition":41,"replicas":[0,1]}, {"topic":"__consumer_offsets","partition":42,"replicas":[0,1]}, {"topic":"__consumer_offsets","partition":43,"replicas":[0,1]}, {"topic":"__consumer_offsets","partition":44,"replicas":[0,1]}, {"topic":"__consumer_offsets","partition":45,"replicas":[0,1]}, {"topic":"__consumer_offsets","partition":46,"replicas":[0,1]}, {"topic":"__consumer_offsets","partition":47,"replicas":[0,1]}, {"topic":"__consumer_offsets","partition":48,"replicas":[0,1]}, {"topic":"__consumer_offsets","partition":49,"replicas":[0,1]}] }
  2. 执行 bin/kafka-reassign-partitions.sh --zookeeper localhost:2181 --reassignment-json-file increase-replication-factor.json --execute
  3. 验证 bin/kafka-reassign-partitions.sh --zookeeper localhost:2181 --reassignment-json-file increase-replication-factor.json --verify

Flowable开发–核心数据库表(七)

一、数据模型设计

  1. 清单
数据表分类描述
ACT_GE_*通用数据表
ACT_RE_*流程定义存储表
ACT_ID_*身份信息表
ACT_RU_*运行时数据库表
ACT_HI_*历史数据库表
  1. 通用数据库
数据表描述
ACT_GE_PROPERTY属性表(保存流程引擎的kv键值属性)–PropertyEntityImpl
ACT_GE_BTYEARRAY资源表(存储流程定义相关的资源)–ByteArrayEntityImpl
  1. 流程定义存储表
数据表描述
ACT_RE_DEPLOYMENT流程部署表–DeploymentEntityImpl
ACT_RE_PROCDEF流程定义信息表–ProcessDefinitionEntityImpl
ACT_RE_MODEL模型信息表(用于Web设计器)–ModelEntityImpl
ACT_PROCDEF_INFO流程定义动态改变信息表–ProcessDefinitionInfoEntityImpl
  1. 身份数据表
数据表描述
ACT_ID_USER用户基本信息表–UserEntityImpl
ACT_ID_INFO用户扩展表–IdentityInfoEntityImpl
ACT_ID_GROUP群组表(用于Web设计器)–GroupEntityImpl
ACT_ID_MEMBERSHIP户与群主关系表–MemberShipEntityImpl
ACT_ID_BYTEARRAY二进制数据表(flowable)–
ACT_ID_PRIV权限表(flowable)–
ACT_ID_PRIV_MAPPING用户或组权限关系表(flowable)–
ACT_ID_PROPERTY属性表(flowable)–
ACT_ID_TOKEN系统登录日志表(flowable)–
  1. 运行时流程数据表
数据表描述
ACT_RU_EXECUTION流程实例与分支执行表–ExecutionEntityImpl
ACT_RU_TASK用户任务表–TaskEntityImpl
ACT_RU_VARIABLE变量信息–VariableInstanceEntityImpl
ACT_RU_IDENTITYLINK参与者相关信息表–IdentityLinkEntityImpl
ACT_RU_EVENT_SUBSCR事件订阅表–EventSubscriptionEntityImpl
ACT_RU_JOB作业表–JobEntityImpl
ACT_RU_TIMER_JOB定时器表–TimerJobEntityImpl
ACT_RU_SUSPENDED_JOB暂停作业表–SuspendedJobEntityImpl
ACT_RU_DEADLETTER_JOB死信表–DeadLetterJobEntityImpl
ACT_RU_HISTORY_JOB历史作业表(flowable)–
  1. 历史流程数据表
数据表描述
ACT_HI_PROCINST历史流程实例表–HistoricProcessInstanceEntityImpl
ACT_HI_ACTINST历史节点信息表–HistoricActivityInstanceEntityImpl
ACT_HI_TASKINST历史任务表–HistoricTaskInstanceEntityImpl
ACT_HI_VARINST历史变量–HistoricVariableInstanceEntityImpl
ACT_HI_IDENTITYLINK历史参与者表–HistoricIdentityLinkEntityImpl
ACT_HI_DETAIL历史的流程运行中的细节信息–HistoricDetailEntityImpl
ACT_HI_ATTACHMENT附件表–AttachmentEntityImpl
ACT_HI_COMMENT评论表–CommentEntityImpl
ACT_EVT_LOG事件日志表–EventLogEntryEntityImpl

二、表结构

  1. 通用类表

act_ge_property(全局配置文件)

字段字段名称字段默认值是否允许为空数据类型字段长度备注
NAME_名称NOvarchar64PRIschema.version schema.history next.dbid
VALUE_NULLYESvarchar3005.* create(5.*)
REV_版本号NULLYESintNULLversion

注:
1.全局参数, 默认三个参数next.dbid, IdGenerator区间, schema.history, 自动执行sql历史, schema.version, 当
前sql版本。
2.属性数据表。存储整个流程引擎级别的数据。

act_ge_bytearray(二进制文件)

字段字段名称字段默认值是否允许为空数据类型字段长度备注
ID_主键NOvarchar64PRI
REV_版本号NULLYESintNULLversion
NAME_名称NULLYESvarchar255部署的文件名称,如:mail.bpmn、mail.png 、mail.bpmn20.xml
DEPLOYMENT_ID_部署IDNULLYESvarchar64ACT_RE_DEPLOYMENT
BYTES_字节(二进制数据)NULLYESlongblob4294967295
GENERATED_是否系统生成NULLYEStinyintNULL0为用户上传,1为系统自动生成, 比如系统会自动根据xml生成png

注:
1.用来保存部署文件的大文本数据
2.所有二进制内容都会保存在这个表里, 比如部署的process.bpmn20.xml, process.png, user.form, 附件, bean序列
化为二进制的流程变量。
act_ge_property属性数据表存储整个流程引擎级别的数据,初始化表结构时,会默认插入三条记录。
  1. 历史类表

act_hi_actinst(历史节点表)

字段字段名称字段默认值是否允许为空数据类型字段长度备注
ID_主键NULLNOvarchar64PRI
PROC_DEF_ID_流程定义IDNULLNOvarchar64
PROC_INST_ID_流程实例IDNULLNOvarchar64MUL
ACT_ID_节点IDNULLNOvarchar255
TASK_ID_任务IDNULLYESvarchar64任务实例ID 其他节点类型实例ID在这里为空
CALL_PROC_INST_ID_调用外部的流程实例IDNULLYESvarchar64
ACT_NAME_节点名称NULLYESvarchar255
ACT_TYPE_节点类型NULLNOvarchar255如startEvent、userTask
ASSIGNEE_签收人NULLYESvarchar255经办人
START_TIME_开始时间NULLNOdatetimeNULLMUL
END_TIME_结束时间NULLYESdatetimeNULLMUL
DURATION_耗时NULLYESbigintNULL毫秒值
TENANT_ID_多租户YESvarchar255

注:
1. 历史活动信息。这里记录流程流转过的所有节点,与HI_TASKINST不同的是,taskinst只记录usertask内容。
2.  TENANT_ID 是后续才加入的多租户

act_hi_attachment(历史附件表)

字段字段名称字段默认值是否允许为空数据类型字段长度备注
ID_主键IDNULLNOvarchar64PRI
REV_版本号NULLYESintNULLversion
USER_ID_用户IDNULLYESvarchar255
NAME_名称NULLYESvarchar255
DESCRIPTION_描述NULLYESvarchar4000
TYPE_类型NULLYESvarchar255
TASK_ID_任务IDNULLYESvarchar64
PROC_INST_ID_流程实例IDNULLYESvarchar64
URL_附件地址NULLYESvarchar4000附件的URL地址
CONTENT_ID_字节表IDNULLYESvarchar64ACT_GE_BYTEARRAY的ID
TIME_时间NULLYESdatetimeNULL

注:
1.存放历史流程相关的附件。
2.时间是后续版本加入

act_hi_comment(历史审批意见表)

字段字段名称字段默认值是否允许为空数据类型字段长度备注
ID_主键NULLNOvarchar64PRI
TYPE_类型NULLYESvarchar255类型:event(事件) comment(意见)
TIME_时间NULLNOdatetimeNULL
USER_ID_用户IDNULLYESvarchar255
TASK_ID_任务IDNULLYESvarchar64
PROC_INST_ID_流程实例IDNULLYESvarchar64
ACTION_行为类型NULLYESvarchar255
MESSAGE_基本内容NULLYESvarchar4000用于存放流程产生的信息,比如审批意见
FULL_MSG_全部内容NULLYESlongblob4294967295附件

注:

  1. 存放历史流程的审批意见。
  2. 行为类型。值为下列内容中的一种:AddUserLink、DeleteUserLink、AddGroupLink、DeleteGroupLink、AddComment、AddAttachment、DeleteAttachment

act_hi_detail(历史详情信息表)

字段字段名称字段默认值是否允许为空数据类型字段长度备注
ID_主键NULLNOvarchar64PRI
TYPE_类型NULLNOvarchar255类型: FormProperty, //表单 VariableUpdate //参数
PROC_INST_ID_流程实例IDNULLYESvarchar64MUL
EXECUTION_ID_执行实例NULLYESvarchar64
TASK_ID_任务IDNULLYESvarchar64MUL
ACT_INST_ID_节点实例IDNULLYESvarchar64ACT_HI_ACTINST
NAME_名称NULLNOvarchar255MUL
VAR_TYPE_参数类型NULLYESvarchar255
REV_版本号NULLYESintNULLversion
TIME_时间戳NULLNOdatetimeNULLMUL创建时间
BYTEARRAY_ID_字节表IDNULLYESvarchar64ACT_GE_BYTEARRAY
DOUBLE_浮点值NULLYESdoubleNULL存储变量类型为Double
LONG_长整型NULLYESbigintNULL存储变量类型为long
TEXT_文本值NULLYESvarchar4000存储变量值类型为String
TEXT2_字符串NULLYESvarchar4000此处存储的是JPA持久化对象时,才会有值。此值为对象ID,jpa变量text存className,text2存id

注:
1.历史详情表:流程中产生的变量详细,包括控制流程流转的变量,业务表单中填写的流程需要用到的变量等。
2.参数类型: jpa-entity、boolean、bytes、serializable(可序列化)、自定义type(根据你自身配置)、CustomVariableType、date、double、integer、long、null、short、string

act_hi_identitylink(历史流程人员表)

字段字段名称字段默认值是否允许为空数据类型字段长度备注
NOvarchar64PRI
GROUP_ID_用户组IDNULLYESvarchar255
TYPE_类型NULLYESvarchar255类型,主要分为以下几种:assignee、candidate、owner、starter 、participant
USER_ID_用户IDNULLYESvarchar255MUL
TASK_ID_任务IDNULLYESvarchar64MUL
PROC_INST_ID_流程实例IDNULLYESvarchar64MUL

注:

  1. 任务参与者数据表。主要存储当前节点参与者的信息。

act_hi_procinst(流程实例历史*核心表)

字段字段名称字段默认值是否允许为空数据类型字段长度备注
ID_主键NULLNOvarchar64PRI
PROC_INST_ID_流程实例IDNULLNOvarchar64UNI
BUSINESS_KEY_业务标识NULLYESvarchar255MUL业务主键,业务表单的ID
PROC_DEF_ID_流程实例IDNULLNOvarchar64
START_TIME_开始时间NULLNOdatetimeNULL
END_TIME_结束时间NULLYESdatetimeNULLMUL
DURATION_耗时NULLYESbigintNULL
START_USER_ID_流程发起人IDNULLYESvarchar255
START_ACT_ID_开始节点IDNULLYESvarchar255
END_ACT_ID_结束节点IDNULLYESvarchar255
SUPER_PROCESS_INSTANCE_ID_父流程实例IDNULLYESvarchar64
DELETE_REASON_删除原因NULLYESvarchar4000
TENANT_ID_租户IDYESvarchar255
NAME_名称NULLYESvarchar255

注:
1.核心表之一。
2.存放历史的流程实例。
3.设计历史流程实例表的初衷之一就是为了使得运行时库数据量尽可能小,效率最优。

act_hi_taskinst(历史任务流程实例信息*核心表)

字段字段名称字段默认值是否允许为空数据类型字段长度备注
ID_主键NULLNOvarchar64PRI
PROC_DEF_ID_流程实例IDNULLYESvarchar64
TASK_DEF_KEY_任务节点定义IDNULLYESvarchar255任务定义标识(环节ID)
PROC_INST_ID_流程实例IDNULLYESvarchar64MUL
EXECUTION_ID_执行实例IDNULLYESvarchar64
NAME_任务名称NULLYESvarchar255
PARENT_TASK_ID_父任务节点IDNULLYESvarchar64
DESCRIPTION_描述NULLYESvarchar4000
OWNER_被代理人NULLYESvarchar255委托人(默认为空,只有在委托时才有值)
ASSIGNEE_经办人NULLYESvarchar255
START_TIME_开始时间NULLNOdatetimeNULL
CLAIM_TIME_签收时间NULLYESdatetimeNULL
END_TIME_结束时间NULLYESdatetimeNULL
DURATION_耗时NULLYESbigintNULL
DELETE_REASON_删除原因NULLYESvarchar4000删除原因(completed,deleted)
PRIORITY_优先级NULLYESintNULL
DUE_DATE_截止时间NULLYESdatetimeNULL过期时间,表明任务应在多长时间内完成
FORM_KEY_FORM表单的KEYNULLYESvarchar255desinger节点定义的 form_key属性
CATEGORY_分类NULLYESvarchar255
TENANT_ID_租户IDYESvarchar255

注:

1. 历史任务实例表。 
2. 存放已经办理的任务。 
3. CATEGORY和TNANT_ID是后续版本才加进来的。 

act_hi_varinst(历史变量表)

字段字段名称字段默认值是否允许为空数据类型字段长度备注
ID_主键NULLNOvarchar64PRI
PROC_INST_ID_流程实例IDNULLYESvarchar64MUL
EXECUTION_ID_执行实例IDNULLYESvarchar64
TASK_ID_任务IDNULLYESvarchar64MUL
NAME_名称NULLNOvarchar255MUL
VAR_TYPE_变量类型NULLYESvarchar100
REV_版本号NULLYESintNULLversion
BYTEARRAY_ID_字节流IDNULLYESvarchar64ACT_GE_BYTEARRAY
DOUBLE_浮点值NULLYESdoubleNULL存储DoubleType类型的数据
LONG_长整型NULLYESbigintNULL存储LongType类型的数据
TEXT_文本值NULLYESvarchar4000存储变量值类型为String,如此处存储持久化对象时,值jpa对象的class
TEXT2_文本值NULLYESvarchar4000
CREATE_TIME_创建时间NULLYESdatetimeNULL
LAST_UPDATED_TIME_最后更新时间NULLYESdatetimeNULL

注:

  1. 主要存放历史变量数据。

act_evt_log(事件日志)

字段字段名称字段默认值是否允许为空数据类型字段长度备注
LOG_NR_主键NULLNObigintNULLPRI
TYPE_类型NULLYESvarchar64
PROC_DEF_ID_流程定义IDNULLYESvarchar64
PROC_INST_ID_流程实例IDNULLYESvarchar64
EXECUTION_ID_执行IDNULLYESvarchar64
TASK_ID_任务IDNULLYESvarchar64
TIME_STAMP_时间CURRENT_TIMESTAMP(3)NOtimestampNULL
USER_ID_用户IDNULLYESvarchar255
DATA_数据NULLYESlongblob4294967295
LOCK_OWNER_锁定节点NULLYESvarchar255
LOCK_TIME_锁定时间NULLYEStimestampNULL
IS_PROCESSED_是否正在执行0YEStinyintNULL

注:
1.事件日志表
2.事件日志, 默认不开启。
3.从Activiti 5.16开始,引入了(试验性)的事件记录机制。记录机制基于Activiti引擎的事件机制的一般用途,并默认禁用。其思想是,来源于引擎的事件会被捕获,并创建一个包含了所有事件数据(甚至更多)的映射,提供给
org.activiti.engine.impl.event.logger.EventFlusher,由它将这些数据刷入其他地方。默认情况下,使用简单的基于数据库的事件处理/刷入,会使用Jackson将上述映射序列化为JSON,并将其作为EventLogEntryEntity接口存入数据库。如果不使用事件记录,可以删除这个表。
4.配置启用事件日志:
processEngineConfiguration.setEnableDatabaseEventLogging(true);
5.运行时启用事件日志:
databaseEventLogger = new EventLogger(processEngineConfiguration.getClock());
runtimeService.addEventListener(databaseEventLogger);
6.可以扩展EventLogger类。如果默认的数据库记录不符合要求,需要覆盖createEventFlusher()方法返回一个org.activiti.engine.impl.event.logger.EventFlusher接口的实例。可以通过Activiti的
managementService.getEventLogEntries(startLogNr, size)?获取EventLogEntryEntity实例。
容易看出这个表中的数据可以通过JSON放入大数据NoSQL存储,例如MongoDB,Elastic Search,等等。
也容易看出这里使用的类
(org.activiti.engine.impl.event.logger.EventLogger/EventFlusher与许多其他 EventHandler类)是可插入的,可以按你的使用场景调整(例如不将JSON存入数据库,而是将其直接发送给一个队列或大数据存储)。
请注意这个事件记录机制是额外于Activiti的“传统”历史管理器的。尽管所有数据都在数据库表中,但并未对查询或快速恢复做优化。实际使用场景是末端审计并将其存入大数据存储。

用户身份类
act_id_group(用户组)

字段字段名称字段默认值是否允许为空数据类型字段长度备注
ID_主键NOvarchar64PRI
REV_版本号NULLYESintNULLversion
NAME_名称NULLYESvarchar255
TYPE_类型NULLYESvarchar255

注:
1.Activiti自带的用户组表,用于组任务。

act_id_info(用户扩展信息表)

字段字段名称字段默认值是否允许为空数据类型字段长度备注
ID_主键NOvarchar64PRI
REV_版本号NULLYESintNULLversion
USER_ID_用户IDNULLYESvarchar64
TYPE_类型NULLYESvarchar64
KEY_属性名NULLYESvarchar255
VALUE_属性值NULLYESvarchar255
PASSWORD_密码NULLYESlongblob4294967295
PARENT_ID_父级IDNULLYESvarchar255

注:

act_id_membership( 用户与分组对应信息表)

字段字段名称字段默认值是否允许为空数据类型字段长度备注
USER_ID_用户IDNOvarchar64PRI(ACT_ID_USER)
GROUP_ID_用户组IDNOvarchar64PRI(ACT_ID_GROUP)

注:
1.用来保存用户的分组信息。

act_id_user(用户信息表)

字段字段名称字段默认值是否允许为空数据类型字段长度备注
ID_主键NOvarchar64PRI
REV_版本号NULLYESintNULLversion
FIRST_NULLYESvarchar255FIRST_NAME
LAST_NULLYESvarchar255LAST_NAME
EMAIL_邮箱NULLYESvarchar255
PWD_密码NULLYESvarchar255
PICTURE_ID_头像IDNULLYESvarchar64ACT_GE_BYTEARRAY

注:
1.Activiti用户信息表。

流程定义存储表

act_procdef_info(流程定义更新信息)

字段字段名称字段默认值是否允许为空数据类型字段长度备注
ID_主键NULLNOvarchar64PRI
PROC_DEF_ID_流程定义IDNULLNOvarchar64UNI(ACT_RE_PROCDEF)
REV_版本号NULLYESintNULLversion
INFO_JSON_ID_内容NULLYESvarchar64MUL(ACT_GE_BYTEARRAY)

注:
1.流程版本升级的数据。

act_re_deployment( 部署信息表*核心表)

字段字段名称字段默认值是否允许为空数据类型字段长度备注
ID_主键NOvarchar64PRI
NAME_名称NULLYESvarchar255
CATEGORY_分类NULLYESvarchar255
TENANT_ID_租户IDYESvarchar255
DEPLOY_TIME_部署时间NULLYEStimestampNULL

注:
1. 部署流程定义时需要被持久化保存下来的信息。

act_re_model( 流程设计模型部署表)

字段字段名称字段默认值是否允许为空数据类型字段长度备注
ID_主键NULLNOvarchar64PRI
REV_版本号NULLYESintNULLversion
NAME_名称NULLYESvarchar255
KEY_标识NULLYESvarchar255
CATEGORY_分类NULLYESvarchar255
CREATE_TIME_创建时间NULLYESimestampNULL
LAST_UPDATE_TIME_最后更新时间NULLYEStimestampNULL
VERSION_版本NULLYESintNULL
META_INFO_元数据NULLYESvarchar4000以json格式保存流程定义的信息
DEPLOYMENT_ID_部署IDNULLYESvarchar64MUL(ACT_RE_DEPLOYMENT)
EDITOR_SOURCE_VALUE_ID_二进制文件IDNULLYESvarchar64MUL(ACT_GE_BYTEARRAY)设计器原始信息
EDITOR_SOURCE_EXTRA_VALUE_ID_二进制文件IDNULLYESvarchar64MUL(ACT_GE_BYTEARRAY)设计器扩展信息
TENANT_ID_租户IDYESvarchar255

注:
1.该表是流程设计器设计流程模型保存的数据。

act_re_procdef(流程定义数据表*核心表)

字段字段名称字段默认值是否允许为空数据类型字段长度备注
ID_主键NULLNOvarchar64PRI
REV_版本号NULLYESintNULLversion
CATEGORY_分类NULLYESvarchar255流程定义的Namespace就是类别
NAME_名称NULLYESvarchar255
KEY_标识NULLNOvarchar255MUL
VERSION_版本NULLNOintNULL
DEPLOYMENT_ID_部署IDNULLYESvarchar64
RESOURCE_NAME_资源名称NULLYESvarchar4000流程bpmn文件名称
DGRM_RESOURCE_NAME_图片资源名称NULLYESvarchar4000
DESCRIPTION_描述NULLYESvarchar4000
HAS_START_FORM_KEY_拥有开始表单标识NULLYEStinyintNULLstart节点是否存在formKey 0否 1是
HAS_GRAPHICAL_NOTATION_拥有图形信息NULLYEStinyintNULL
SUSPENSION_STATE_挂起状态NULLYESintNULL暂停状态 1激活 2暂停
TENANT_ID_租户IDYESvarchar255

注:
1. 业务流程定义数据表。此表和ACT_RE_DEPLOYMENT是多对一的关系,即,一个部署的bar包里可能包含多个流程定义文件,每个流程定义文件都会有一条记录在ACT_REPROCDEF表内,每个流程定义的数据,都会对于ACT_GE_BYTEARRAY表内的一个资源文件和PNG图片文件。和ACT_GE_BYTEARRAY的关联是通过程序用ACT_GE_BYTEARRAY.NAME与ACT_RE_PROCDEF.NAME_完成的,在数据库表结构中没有体现。

运行时流程数据表
act_ru_event_subscr(事件订阅)

字段字段名称字段默认值是否允许为空数据类型字段长度备注
ID_主键NULLNOvarchar64PRI
REV_版本号NULLYESintNULLvarsion
EVENT_TYPE_事件类型NULLNOvarchar255
EVENT_NAME_事件名称NULLYESvarchar255
EXECUTION_ID_执行实例IDNULLYESvarchar64MUL(ACT_RU_EXECUTION)
PROC_INST_ID_流程实例IDNULLYESvarchar64
ACTIVITY_ID_节点IDNULLYESvarchar64
CONFIGURATION_配置NULLYESvarchar255MUL
CREATED_创建时间CURRENT_TIMESTAMP(3)NOtimestampNULL
PROC_DEF_ID_流程定义IDNULLYESvarchar64
TENANT_ID_租户IDYESvarchar255

注:
1.该表是后续版本加进来的。

act_ru_execution(运行时流程执行实例表*核心表)

字段字段名称字段默认值是否允许为空数据类型字段长度备注
ID_主键NOvarchar64PRI
REV_版本号NULLYESintNULL
PROC_INST_ID_流程实例IDNULLYESvarchar64MUL(ACT_RU_EXECUTION)
BUSINESS_KEY_业务标识NULLYESvarchar255MUL
PARENT_ID_父级IDNULLYESvarchar64MUL(ACT_RU_EXECUTION)
PROC_DEF_ID_流程定义IDNULLYESvarchar64MUL(ACT_RE_PROCDEF)
SUPER_EXEC_父流程实例中对应的执行NULLYESvarchar64MUL(ACT_RU_EXECUTION)
ACT_ID_节点IDNULLYESvarchar255
IS_ACTIVE_是否激活NULLYEStinyintNULL
IS_CONCURRENT_是否分支(并行)NULLYEStinyintNULL是否为并行(true/false)
IS_SCOPE_是否处于多实例或环 节嵌套状态NULLYEStinyintNULL
IS_EVENT_SCOPE_是否激活状态NULLYEStinyintNULL
SUSPENSION_STATE_挂起状态NULLYESintNULL暂停状态 1激活 2暂停
CACHED_ENT_STATE_缓存状态NULLYESintNULL缓存的状态, 1 事件 监听 2 人工任务 3 异步作业
TENANT_ID_租户IDYESvarchar255
NAME_名称NULLYESvarchar255
LOCK_TIME_锁定时间NULLYEStimestampNULL

注:
1.TENANT_ID、NAME、LOCK_TIME是后续版本加入的。

act_ru_identitylink( 运行时流程人员表)

字段字段名称字段默认值是否允许为空数据类型字段长度备注
ID_主键NOvarchar64PRI
REV_版本号NULLYESintNULLversion
GROUP_ID_用户组IDNULLYESvarchar255MUL
TYPE_类型NULLYESvarchar255
USER_ID_用户IDNULLYESvarchar255MUL
TASK_ID_任务IDNULLYESvarchar64MUL(ACT_RU_TASK)
PROC_INST_ID_流程实例IDNULLYESvarchar64MUL(ACT_RU_EXECUTION)
PROC_DEF_ID_流程定义IDNULLYESvarchar64MUL(ACT_RE_PROCDEF)

注:
1.任务参与者数据表。主要存储当前节点参与者的信息。

act_ru_job(运行时定时任务数据表)

字段字段名称字段默认值是否允许为空数据类型字段长度备注
ID_主键NULLNOvarchar64PRI
REV_版本号NULLYESintNULL
TYPE_类型NULLNOvarchar255
LOCK_EXP_TIME_锁定过期时间NULLYEStimestampNULL
LOCK_OWNER_挂起者NULLYESvarchar255
EXCLUSIVE_是否唯一NULLYEStinyintNULL
EXECUTION_ID_执行实例IDNULLYESvarchar64
PROCESS_INSTANCE_ID_流程实例IDNULLYESvarchar64
PROC_DEF_ID_流程定义IDNULLYESvarchar64
RETRIES_重试次数NULLYESintNULL
EXCEPTION_STACK_ID_异常堆栈NULLYESvarchar64MUL(ACT_GE_BYTEARRAY)
EXCEPTION_MSG_异常信息NULLYESvarchar4000
DUEDATE_截止时间NULLYEStimestampNULL
REPEAT_重复NULLYESvarchar255
HANDLER_TYPE_处理器类型NULLYESvarchar255
HANDLER_CFG_处理器配置NULLYESvarchar4000
TENANT_ID_租户IDYESvarchar255

注:
1.作业执行器数据。
2.需要启用JOB组件:JobExecutor 是管理一组线程的组件,这些线程用于触发定时器(包括后续的异步消息)。在单元测试场景下,使用多线程会很笨重。
因此API提供 ManagementService.createJobQuery 用于查询,以及 ManagementService.executeJob 用于执行作业。这样作业的执
行就可以在单元测试内部控制。为了避免作业执行器的干扰,可以将它关闭。
默认情况下, JobExecutor 在流程引擎启动时激活。当你不希望 JobExecutor 随流程引擎启动时,设置:
<property name=”jobExecutorActivate” value=”false” />
3.11. 启用异步执行器 Async executor activation
AsyncExecutor 是管理线程池的组件,这个线程池用于触发定时器与异步任务。
默认情况下,由于历史原因,当使用 JobExecutor 时, AsyncExecutor 不生效。然而我们建议使用新的 AsyncExecutor 代替
JobExecutor ,通过定义两个参数实现
<property name=”asyncExecutorEnabled” value=”true” />
<property name=”asyncExecutorActivate” value=”true” />
asyncExecutorEnabled参数用于启用异步执行器,代替老的作业执行器。 第二个参数asyncExecutorActivate命令Activiti引擎在启动时
启动异步执行器线程池。

act_ru_task( 运行时任务节点表*核心表)

字段字段名称字段默认值是否允许为空数据类型字段长度备注
ID_主键NOvarchar64PRI
REV_版本号NULLYESintNULLversion
EXECUTION_ID_执行实例IDNULLYESvarchar64MUL(ACT_RU_EXECUTION)
PROC_INST_ID_流程实例IDNULLYESvarchar64MUL(ACT_RU_EXECUTION)
PROC_DEF_ID_流程定义IDNULLYESvarchar64MUL(ACT_RE_PROCDEF)
NAME_名称NULLYESvarchar255
PARENT_TASK_ID_父任务IDNULLYESvarchar64
DESCRIPTION_描述NULLYESvarchar4000
TASK_DEF_KEY_人物定义标识NULLYESvarchar255
OWNER_被代理人NULLYESvarchar255(一般情况下为空,只有在委托时才有值)
ASSIGNEE_经办人NULLYESvarchar255签收人或者委托人
DELEGATION_委托状态NULLYESvarchar64委托状态 PENDING委托中,RESOLVED已处理
PRIORITY_优先级NULLYESintNULL
CREATE_TIME_创建时间NULLYEStimestampNULLMUL
DUE_DATE_截止时间NULLYESdatetimeNULL
CATEGORY_分类NULLYESvarchar255
SUSPENSION_STATE_挂起状态NULLYESintNULL暂停状态 1激活 2暂停
TENANT_ID_租户IDYESvarchar255
FORM_KEY_表单标识NULLYESvarchar255

注:
1.运行时任务数据表

act_ru_variable( 运行时流程变量数据表*核心表)

字段字段名称字段默认值是否允许为空数据类型字段长度备注
ID_主键NULLNOvarchar64PRI
REV_版本号NULLYESintNULLversion
TYPE_类型NULLNOvarchar255见备注
NAME_名称NULLNOvarchar255
EXECUTION_ID_执行实例IDNULLYESvarchar64MUL(ACT_RU_EXECUTION)
PROC_INST_ID_流程实例IDNULLYESvarchar64MUL(ACT_RU_EXECUTION)
TASK_ID_任务IDNULLYESvarchar64MUL(ACT_RU_TASK)
BYTEARRAY_ID_资源IDNULLYESvarchar64MUL(ACT_GE_BYTEARRAY)
DOUBLE_浮点值NULLYESdoubleNULL存储变量类型为Double
LONG_长整型NULLYESbigintNULL存储变量类型为long
TEXT_文本值NULLYESvarchar4000存储变量值类型为String 如此处存储持久化对象时,值jpa对象的class
TEXT2_文本值NULLYESvarchar4000此处存储的是JPA持久化对象时,才会有值。此值为对象ID

注:
1.运行时流程变量数据表。
2.类型:jpa-entity、boolean、bytes、serializable(可序列化)、自定义type(根据你自身配置)、
CustomVariableType、date、double、integer、long、null、short、string

作者:无剑_君
链接:https://www.jianshu.com/p/ccd017e9fd58
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

跑步运动员鞋带绑法

https://jingyan.baidu.com/article/acf728fd48859ef8e510a32d.html

方法/步骤

  1.  第一步是先解开你已经系好的鞋带,在如下图两边鞋带互相绕一圈,拉紧,成麻绳状。

     

    如何办了鞋带后不会松-跑步运动员鞋带绑法
  2. 第二步是将两边鞋带折起,交叉,如下图:

    如何办了鞋带后不会松-跑步运动员鞋带绑法
  3. 第三步是将一边折起的鞋带弯曲处下折,放在另一个鞋带上面,如下图:

    如何办了鞋带后不会松-跑步运动员鞋带绑法
  4. 第四步原理如同第三步,如下图:

    如何办了鞋带后不会松-跑步运动员鞋带绑法
  5.  第五步将两边鞋带分别穿过洞,如下图:

    如何办了鞋带后不会松-跑步运动员鞋带绑法
  6. 1.  第六步将穿过的两部鞋带拉紧,即可,如下图:

    如何办了鞋带后不会松-跑步运动员鞋带绑法

单点登录怎么实现?

一、单点登录简介

假设一个场景:公司内部有财务、OA、订单服务等各类相互独立的应用系统,员工张三对这些系统有操作权限,如果张三想要登录某个系统进行业务操作,那么他需要输入相应的账号与密码。想象一下,当公司内部有 100 个应用系统,张三是不是要输入 100 次用户名和密码进行登录,然后分别才能进行业务操作呢?显然这是很不好的体验,因此我们需要引入一个这样的机制:张三只要输入一次用户名和密码登录,成功登录后,他就可以访问财务系统、OA 系统、订单服务等系统。这就是单点登录。

1

单点登录的英文全称是 Single Sign On,简称是 SSO。它的意思是说用户只需要登录一次,就可以在个人权限范围内,访问所有相互信任应用的功能模块,不管整个应用群的内部有多么复杂,对用户而言,都是一个统一的整体。用户访问 Web 系统的整个应用群与访问单个系统一样,登录和注销分别只要一次就够了。举个简单的例子,你登录了百度网页之后,点击跳转到百度贴吧,这时可以发现你已经自动登录了百度贴吧。

二、我们的技术实现
2.5

SSO 的技术实现要想做好并不容易,我们认为需求优先级应该先是单点登录和单点注销功能,然后是应用接入的门槛,最后是数据安全性,安全性对于 SSO 也非常重要。SSO 的核心是认证中心,但要实现用户一次登录,到处访问的效果,技术实现需要建立在用户系统、认证中心、权限系统、企业门户的基础上,各职责如下:

  • 用户系统:负责用户名、密码等帐户信息管理,包括增加、修改、启用、停用用户帐号,同时为认证中心提供对用户名和密码的校验。
  • 认证中心:负责凭证 token 的生成、加密、颁发、验证、销毁、登入 Login、登出 Logout。用户只有拥有凭证并验证通过才能访问企业门户。
  • 权限系统:负责角色管理、资源设置、授权设置、鉴定权限,具体实现可参考 RBAC。权限系统可为企业门户提供用户权限范围内的导航。
  • 企业门户:作为应用系统的集成门户 (Portal),集成了多个应用系统的功能,为用户提供链接导航、用户信息和登出功能等。
 2.1、服务端功能实现
  • 登录认证:接收登录帐号信息,让用户系统验证用户的登录信息。
  • 凭证生成:创建授权凭证 token,生成的凭证一般包含用户帐号信息、过期时间等信息,它是一串加密的字符串,加密算法如 AES{凭证明文 +MD5 加信息},可采用 JWT 标准。
  • 凭证颁发:与 SSO 客户端通信,发送凭证给 SSO 客户端。
  • 凭证验证:接收并校验来自 SSO 客户端的凭证有效性,凭证验证包括算法验证和数据验证。
  • 凭证销毁与登出:接收来自 SSO 客户端的登出请求,记录并销毁凭证,跳转至登录页面。
 2.2、客户端功能实现
  • 1、请求拦截:拦截应用未登录请求,跳转至登录页面。
  • 2、获取凭证:接收并存储由 SSO 服务端发来的凭证,凭证存储的方式有 Cookie、Session、网址传参、Header 等。
  • 3、提交凭证验证:与 SSO 服务端通信,发出校验凭证有效性的请求。
  • 4、获取用户权限:获取该凭证的用户权限,并返回受保护资源给用户。
  • 5、凭证销毁与登出:销毁本地会话,然后跳转至登出页面。
 2.3、用户单点登录流程
3
  • 登录:将用户输入的用户名和密码发送至认证中心,然后认证中心调用用户系统来验证登录信息。
  • 生成并颁发凭证:通过登录信息的验证后,认证中心创建授权凭证 token,然后把这个授权凭证 token 返回给 SSO 客户端。SSO 客户端拿到这个 token,进行存储。在后续请求中,在 HTTP 请求数据中都得加上这个 token。
  • 凭证验证:SSO 客户端发送凭证 token 给认证中心,认证中心校验这个 token 的有效性。凭证验证有算法验证和数据验证,算法验证可在 SSO 客户端完成。
 2.4、用户访问流程和单点注销

4

以上是用户的访问流程,如果用户没有有效的凭证,认证中心将强制用户进入登录流程。对于单点注销,用户如果注销了应用群内的其中一个应用,那么全局 token 也会被销毁,应用群内的所有应用将不能再被访问。

 2.5、具体接入与集成
2.5

我们的应用接入与集成具体如下:

  • 1、用户系统:接入国内机票平台的用户系统,负责登录认证。
  • 2、权限系统:接入国内机票平台的权限系统。
  • 3、认证中心:负责生成并颁发凭证、销毁凭证,改造国内机票平台的登入、登出。
  • 4、凭证验证:在国内机票、国际机票应用系统中调用 SSO 客户端组件实现凭证的验证。
  • 5、企业门户:由国内机票平台、国际机票平台承担。
三、JWT 标准
3.0

JSON Web Token (JWT) 是目前应用最为广泛的 token 格式,是为了在网络应用环境间传递声明而执行的一种基于 JSON 的开放标准(RFC 7519)。该 token 设计紧凑且安全,特别适用于分布式站点的单点登录、API 网关等场景。JWT 的声明一般被用来在身份提供者和服务提供者间传递被认证的用户身份信息,以便于从资源服务器获取资源,也可以增加一些额外的其它业务逻辑所必须的声明信息。该 token 也可直接被用于认证,也可被加密。JWT 信息体由 3 部分构成:头 Header+ 载荷 Payload+ 签名 Signature,具体优点如下:

  • JWT 支持多种语言,C#、Java、JavaScript、Node.js、PHP 等很多语言都可以使用。
  • JWT 可以自身存储一些和业务逻辑有关的所必要的非敏感信息,因为有了 Payload 部分。
  • 利于传输,因为 JWT 的构成非常简单,字节占用很小。
  • 不需要在服务端保存会话信息,不仅省去服务端资源开销,而且使得应用易于扩展。
作者介绍

杨丽,拥有多年互联网应用系统研发经验,曾就职于古大集团,现任职中青易游的系统架构师,主要负责公司研发中心业务系统的架构设计以及新技术积累和培训。现阶段主要关注开源软件、软件架构、微服务以及大数据。

张辉清,10 多年的 IT 老兵,先后担任携程架构师、古大集团首席架构、中青易游 CTO 等职务,主导过两家公司的技术架构升级改造工作。现关注架构与工程效率,技术与业务的匹配与融合,技术价值与创新。

https://mp.weixin.qq.com/s?__biz=MzIwMzg1ODcwMw==&mid=2247487340&idx=1&sn=4063fdba487a860b8a576332c1ea3eb8&chksm=96c9b90ca1be301a985edbc1c2e340bdaf748364231636a33857233263ccdb847204451aae6b#rd

较早的文章

Copyright © 2020 优大网 浙ICP备13002865号-3

SITEMAP回到顶部 ↑