iRules 101 - #3 - 变量

当你开始可以轻松的读懂并编写iRules的时候,你需要继续扩展自己的工具箱,同时你所要应付的任务也将变得越来越复杂。如果你的经历和我的有某些相似的地方,那么很快,而不是很久之后,你就会找到读取,保存和操作不同类型内容的方法。它就是你的“iRules生涯”中,将越来越频繁的使用的变量,理解他们是什么以及如何在iRules中更加有效的使用它们将会非常有用。
 
定义、注销和操作变量
 
iRules使用标准的TCL变量,大多数时候你在TCL语言中使用的用来定义、注销、求值和影响变量的命令iRules中也是有效的。这些命令中的绝大多数是一样并你所定义的数据结构(变量)无关,而且直接体现他们的命名和行为。例如,定义(或创建)一个变量,你只要简单的使用一个Set命令:
 
set msg "Hello, World!"
 
即使你要建立更加复杂的结构并用不同类型的数据(静态动态都一样)并对其进行填充的时候,所用到的命令也是相同的。更多的例子看起来是下面这样的:
 
set r [expr rand()]
set vbl in[expr {rand() >= 0.5}]
set reqArray([IP::client_addr]) [getfield [string tolower [HTTP::uri]] "?" 2]
 
现在你知道如何定义变量了,你所要学习的下一件事就是当你使用完某个变量的时候,如何去删除它,虽然iRules处理内存垃圾的能力非常强,不过这是后话。删除一个你已经创建的变量,你只需要使用Unset命令,就像这样:
 
unset msg
 
这个特殊的命令可以使用多个参数。如果要删除之前我们创建的所有基本变量,只需要使用您可以简单的使用命令:
 
unset msg r vbl
 
现在你已经知道如何创建和删除变量了,还能用它们来做哪些有趣的事情呢?我是说,我们都知道他们可以用来处理一些静态数据,例如Pool和Log的相关命令,但是还有什么命令能够对已经在内存中的变量产生“影响”呢?答案是“很多!”,这里有一些很有意思的命令:
append 追加
append是用来给已经存在的变量追加数据的。(注意:如果变量不存在的话,这个命令也可以用来创建变量):

 
set var 0
for {set i 1} {$i<=10} {incr i} {
   append var "," $i
puts $var
# Prints 0,1,2,3,4,5,6,7,8,9,10
concat 合并
合并命令可以将所有以参数形式提供的值合并到一个列表中,这些参数会被空格分隔开。
 

 
concat " a b {c   " d " e} f"
will return "a b {c d e} f" as its result.
incr 增加
使用增加命令,你可以将变量的值加1(如果不提供任何值的话),或者增加任意的值。
 

 
Add one to the contents of the variable x:
 incr x 
Add 42 to the contents of the variable x:
 incr x 42
变量作用范围 (局部 vs. 全局)
标准TCL语言和iRules的一个最大区别在于,变量一旦被构造就会涉及到互相影响的问题,也就是说对于iRules有两个名字空间-局部和全局。所有“普通”变量都位于局部范围内。这就意味着他们是基于连接的。你在iRules中创建了变量,它就会持续在连接存在的时候有效,并在连接断开的时候注销。这就是一个典型的请求/响应对,但也可以基于协议、设置等来跨越多对请求/响应对。这些变量是最有效率,最安全的,我们在98%的情况下使用并推荐使用它。
 
就这样了?你或许会问,其它2%的时候呢?全局变量!一个iRules里的全局变量创建的方法和局部变量几乎是一样的,并且可以被和“普通”(局部)变量一样的命令-就像上文所提到的那些-所影响,但是它们最关键的区别在于:全局变量并不会和会话相关联,而是与TMM实例相关联,这意味着你不仅可以跨越事件,还可以跨越连接去存取包含在一个全局变量内部的数据。它的范围可以从不必要的需求到绝对必要的需求取决于你所要完成的任务。(例如一个需要扩展的跨连接的计数器,就比如速率限制过滤器)。
 
我们倾向于只在完全必要的时候使用全局变量,原因如下:首先是效率,其次是易用性。由于这些变量不会在每个连接释放之后被TMM轻易注销,你需要开始考虑变量的范围和管理性,而不是创建之后就忘记了他的存在。这并不是危言耸听,但在你可能要使用全局变量的时候,你必须要记住,如果你要定义一个全局变量,你最好也计划好如何注销它。尤其是当你有多个虚拟IP并且或者单个变量的上一次被修改的值会被保留至该变量被更新或注销的时候,这可能导致意料之外的行为,甚至在特定的情况下出错。
 
最后,我们怎样才能知道变量的类型?幸运的是,这很简单。全局变量在被定义和调用的时候需要在名字前面加上两个冒号,例如::myGlobal。在iRules中,所有以双冒号开头的变量都作为全局变量来处理,因此你可以很轻松的识别它们。所以当看见set ::r [expr rand()]set r [expr rand()]这两个变量的时候,你不应该有任何的混淆。唯一可能会略微混淆的情况就是在RULE_INIT事件中定义的所有的变量都被看作是全局变量,这一点需要特别注意。还有要小心的地方就是,同一个命令可能对局部变量和全局变量都起作用。
跟多的关于我谈到的这些命令请参考:
Set
Unset
Append
Concat
Incr
 
如果您需要查看更多的关于如何处理变量的TCL 命令,请参考:
 
Published Feb 02, 2009
Version 1.0

Was this article helpful?