瀏覽代碼

ft:部分代码整理 与 日志添加

SisMaker 4 年之前
父節點
當前提交
9b8d570158
共有 47 個文件被更改,包括 12208 次插入17 次删除
  1. +1
    -0
      rebar.config
  2. +293
    -0
      src/docs/arangodb/agDocs/Aql语法.md
  3. +1165
    -0
      src/docs/arangodb/agDocs/funs.md
  4. +0
    -0
      src/docs/arangodb/agDocs/graph语法.md
  5. +8
    -0
      src/docs/arangodb/agDocs/启动相关.md
  6. +44
    -0
      src/docs/arangodb/agDocs/命名规范.md
  7. +22
    -0
      src/docs/arangodb/agDocs/类型和值的顺序.md
  8. +237
    -0
      src/docs/arangodb/agDocs/索引.md
  9. +240
    -0
      src/docs/arangodb/agDocs/运算符.md
  10. +34
    -0
      src/docs/arangodb/arandodb初始化配置相关.md
  11. +77
    -0
      src/docs/arangodb/arangod.conf
  12. +16
    -0
      src/docs/arangodb/arangodb主要特特点.md
  13. +507
    -0
      src/docs/arangodb/arangodb服务器选项.md
  14. +32
    -0
      src/docs/arangodb/arangodb程序与工具.md
  15. +159
    -0
      src/docs/arangodb/减少服务器的内存占用.md
  16. +20
    -0
      src/docs/arangodb/基本安装与启动停止状态系统服务.md
  17. +0
    -0
      src/docs/arangodb/基础配置与系统优化选项配置.md
  18. +26
    -0
      src/docs/centos/centos8换源.md
  19. +34
    -0
      src/docs/centos/centosGcc升级.md
  20. +3
    -0
      src/docs/centos/centos不能显示中文解决办法.md
  21. +9
    -0
      src/docs/centos/centos同步时间.md
  22. +14
    -0
      src/docs/centos/ssh安装与配置.md
  23. +19
    -0
      src/docs/erlang/elangtrycatch说明.md
  24. +5600
    -0
      src/docs/erlang/erlang-DsBenchMark.txt
  25. +88
    -0
      src/docs/erlang/erlangApp相关.md
  26. +3
    -0
      src/docs/erlang/erlangNif中内存分配推荐使用enif_alloc.md
  27. +64
    -0
      src/docs/erlang/erlangNif编程相关.md
  28. +243
    -0
      src/docs/erlang/erlangSupervisor相关.md
  29. +44
    -0
      src/docs/erlang/erlangVS环境编译nifdll.md
  30. +95
    -0
      src/docs/erlang/erlang二进制.md
  31. +448
    -0
      src/docs/erlang/erlang套接字编程.md
  32. +220
    -0
      src/docs/erlang/erlang性能优化.md
  33. +300
    -0
      src/docs/erlang/erlang数据结构相关.md
  34. +1159
    -0
      src/docs/erlang/erlang规范.md
  35. +344
    -0
      src/docs/erlang/erlang进程.md
  36. +333
    -0
      src/docs/erlang/erlang集群相关.md
  37. 二進制
      src/docs/erlang/picture/erlang参数传递讲解.png
  38. 二進制
      src/docs/erlang/picture/erlang数据复制.png
  39. 二進制
      src/docs/erlang/picture/erlang汇编识别为递归标识符.png
  40. 二進制
      src/docs/erlang/picture/erlang进程状态图.png
  41. 二進制
      src/docs/erlang/picture/列表推导与二进制推导.png
  42. +181
    -0
      src/docs/erlang/time相关的日志.md
  43. +10
    -0
      src/docs/erlang/ubuntu安装erlang.md'
  44. +72
    -0
      src/docs/erlang/编译安装与简单安装.md
  45. +24
    -0
      src/docs/svnGit/svnGit相关.md
  46. +11
    -0
      src/docs/代码规范/提交规范.md
  47. +9
    -17
      src/stackStrace/utParseStack.erl

+ 1
- 0
rebar.config 查看文件

@ -1,5 +1,6 @@
{erl_opts, [no_debug_info, {i, "include"}]}.
{deps, [
{eFmt, ".*", {git, "http://192.168.0.88:53000/SisMaker/eFmt.git", {branch, "master"}}},
{eSync, ".*", {git, "http://192.168.0.88:53000/SisMaker/eSync.git", {branch, "master"}}}
]}.

+ 293
- 0
src/docs/arangodb/agDocs/Aql语法.md 查看文件

@ -0,0 +1,293 @@
# for语法
一般语法
FOR variableName IN expression
图遍历
FOR vertexVariableName, edgeVariableName, pathVariableName IN traversalExpression
视图 特殊关键字
FOR variableName IN viewName SEARCH searchExpression
需要注意 视图不能用作遍历中的边集合
FOR v IN 1..3 ANY startVertex viewName /* 错误的用法 */
选项 对于集合和视图,该FOR构造支持可选的OPTIONS 后缀以修改行为。通用语法为:
FOR variableName IN expression OPTIONS {option: value, ...}
示例
表达式返回的每个数组元素仅被访问一次。在所有情况下,表达式都必须返回一个数组。空数组也是允许的。当前数组元素可用于由variableName指定的变量中的进一步处理。
FOR u IN users
RETURN u
这将遍历数组用户中的所有元素(注意:在这种情况下,此数组由名为“ users”的集合中的所有文档组成),并使当前数组元素在变量u中可用。在此示例中,不对u进行修改,而只是使用RETURN关键字将其推入结果中。
注意:如此处所示,在基于集合的数组上进行迭代时,除非使用SORT 语句定义了明确的排序顺序,否则文档的顺序是不确定的。
引入的变量在关闭放置FOR范围之前一直可用FOR。
另一个示例使用静态声明的值数组进行迭代:
FOR year IN [ 2011, 2012, 2013 ]
RETURN { "year" : year, "isLeapYear" : year % 4 == 0 && (year % 100 != 0 || year % 400 == 0) }
FOR也允许嵌套多个语句。当FOR语句嵌套时,FOR 将创建由各个语句返回的数组元素的叉积。
FOR u IN users
FOR l IN locations
RETURN { "user" : u, "location" : l }
索引提示
对于集合,通过此内联选项机制提供了索引提示。提示可以两种不同的格式指定。
第一个格式选项是最简单的,只有一个索引名称。对于许多情况,这应该足够了。只要有可能在该FOR循环中使用索引的选择,优化器就会首先检查是否可以使用指定的索引。
如果是这样,它将使用它,而不管它通常是否使用其他索引。如果它不能使用该索引,则它将退回到其正常逻辑以选择另一个索引。
如果forceIndexHint: true指定了可选参数,那么它将不会回退,而是会产生错误。
OPTIONS {indexHint: 'byName'[, forceIndexHint: <boolean>]}
第二个是按优先顺序排列的索引名称数组。以这种方式指定时,优化器的行为将与上述相同,但是将按照给定的顺序检查每个指定索引的可行性,并退回其正常逻辑或仅在未指定指定条件时失败指标是可行的。
OPTIONS {indexHint: ['byName', 'byColor'][, forceIndexHint: <boolean>]}
# return语法
该RETURN语句可用于产生查询结果。必须RETURN在数据选择查询的每个块的末尾指定一条语句,否则查询结果将是不确定的。RETURN在数据修改查询的主级别使用 是可选的。
一般语法为RETURN:
RETURN expression or RETURN DISTINCT(如果查询的顶层没有FOR 循环,则不允许在查询的顶层。)
另外 arangodb3.3开始 return distinct 将不会改变其应用结果的顺序
注意:RETURN将关闭当前作用域并消除其中的所有局部变量。在处理子查询时,记住这一点很重要。
# filter语法
一般语法
FILTER expression
expression必须是评估为false或true的条件。如果条件结果为false,则将跳过当前元素,因此将不对其进行进一步处理,也不将其作为结果的一部分。
如果条件为true,则不跳过当前元素,可以对其进行进一步处理。有关条件中可以使用的比较运算符,逻辑运算符等的列表,请参见运算符。\
另外注意filter的位置 他会影响查询的结果
# search语法
该SEARCH关键字开始语言结构类型为ArangoSearch的过滤器视图。从概念上讲,视图只是另一个文档数据源,类似于数组或文档/边缘集合,您可以在其上使用AQL中的FOR操作进行迭代:
可选SEARCH操作提供以下功能:
1. 根据AQL布尔表达式和函数过滤文档
2. 匹配位于由快速索引支持的不同集合中的文档
3. 根据每个文档与搜索条件的匹配程度对结果集进行排序
一般语法
FOR doc IN viewName
SEARCH expression OPTIONS {…}
...
SEARCH与相比FILTER,该语句被视为FOR操作的一部分 ,而不是单独的语句。它不能随意放置在查询中,也不能多次放置在FOR循环体内。
FOR ... IN必须紧随其后的是View的名称,而不是集合的名称。该SEARCH操作必须遵循接下来,其他操作之前SEARCH,如FILTER,
COLLECT等没有在这个位置上允许的。SEARCH在表达式之后,可以进行后续操作, 但包括SORT根据ArangoSearch View计算的排名值对搜索结果进行排序。
expression必须是ArangoSearch表达式。在搜索和排序阶段,ArangoSearch的全部功能都通过特殊的ArangoSearch功能加以利用和公开。最重要的是,支持常见的AQL运算符:
AND, &&
OR, ||
NOT, !
==
<=
>=
<
>
!=
IN (数组或范围),也 NOT IN
ArangoSearch不会考虑字母的字母顺序,即针对视图的SEARCH操作中的范围查询将不会遵循已定义的Analyzer语言环境或服务器语言(启动选项--default-language)的语言规则!另请参阅已知问题。
FOR doc IN viewName
SEARCH ANALYZER(doc.text == "quick" OR doc.text == "brown", "text_en")
RETURN doc
支持数组比较运算符(在v3.6.0中引入):
LET tokens = TOKENS("some input", "text_en") // ["some", "input"]
FOR doc IN myView SEARCH tokens ALL IN doc.title RETURN doc // dynamic conjunction
FOR doc IN myView SEARCH tokens ANY IN doc.title RETURN doc // dynamic disjunction
FOR doc IN myView SEARCH tokens NONE IN doc.title RETURN doc // dynamic negation
FOR doc IN myView SEARCH tokens ALL > doc.title RETURN doc // dynamic conjunction with comparison
FOR doc IN myView SEARCH tokens ANY <= doc.title RETURN doc // dynamic disjunction with comparison
请注意,不支持内联表达式和其他一些功能 SEARCH。如果表达式无效,服务器将引发查询错误。
所述OPTIONS关键字和一个对象可以任选地按照搜索表达式来设置搜索选项。
处理非索引字段固定链接
未配置为由视图索引的文档属性被SEARCH视为不存在。这会影响仅从视图发出的文档的测试。
如果需要,可以使用特殊的includeAllFields View属性为源文档的所有(子)字段建立索引。
# sort语法
SORT expression direction(ASC or DESC)(默认升序ASC)
# limit语法
LIMIT count
LIMIT offset, count
# let语法
该LET语句可用于为变量分配任意值。然后将该变量引入LET放置该语句的作用域中。
通用语法为:
LET variableName = expression
变量在AQL中是不可变的,这意味着它们不能重新分配:
# collect语法
COLLECT关键字可用来组由一个或多个基团的标准阵列。
该COLLECT语句将消除当前范围内的所有局部变量。之后,COLLECT只有由COLLECT自身引入的变量才可用。
操作有几种语法变体COLLECT:
COLLECT variableName = expression
COLLECT variableName = expression INTO groupsVariable
COLLECT variableName = expression INTO groupsVariable = projectionExpression
COLLECT variableName = expression INTO groupsVariable KEEP keepVariable
COLLECT variableName = expression WITH COUNT INTO countVariable
COLLECT variableName = expression AGGREGATE variableName = aggregateExpression
COLLECT variableName = expression AGGREGATE variableName = aggregateExpression INTO groupsVariable
COLLECT AGGREGATE variableName = aggregateExpression
COLLECT AGGREGATE variableName = aggregateExpression INTO groupsVariable
COLLECT WITH COUNT INTO countVariable
所有变体都可以选择以OPTIONS { … }子句结尾。
# remove语法
REMOVE keyExpression IN collection options
REMOVE keyExpression IN collection options RETURN OLD
# udpate语法
更新操作的两种语法是:
UPDATE document IN collection options
UPDATE keyExpression WITH document IN collection options
UPDATE document IN collection options RETURN OLD
UPDATE document IN collection options RETURN NEW
UPDATE keyExpression WITH document IN collection options RETURN OLD
UPDATE keyExpression WITH document IN collection options RETURN NEW、
# replace语法
REPLACE document IN collection options
REPLACE keyExpression WITH document IN collection options
REPLACE document IN collection options RETURN OLD
REPLACE document IN collection options RETURN NEW
REPLACE keyExpression WITH document IN collection options RETURN OLD
REPLACE keyExpression WITH document IN collection options RETURN NEW
以下查询使用NEW伪值返回替换的文档(不包含某些系统属性):
FOR u IN users
REPLACE u WITH { value: "test" } IN users
LET replaced = NEW
RETURN UNSET(replaced, '_key', '_id', '_rev')
# insert语法
INSERT document INTO collection [ OPTIONS options ]
INSERT document INTO collection RETURN NEW
IN关键字可以代替INTO并具有相同的含义。
# upsert语法
UPSERT searchExpression INSERT insertExpression UPDATE updateExpression IN collection options
UPSERT searchExpression INSERT insertExpression REPLACE updateExpression IN collection options
当使用UPDATEupsert操作的变体时,找到的文档将被部分更新,这意味着仅updateExpression中指定的属性将被更新或添加。使用REPLACEupsert 的变体时,现有文档将被updateExpression的上下文替换。
更新文档将使用服务器生成的值来修改文档的修订号。系统属性_id,_key和_rev无法更新,_from和_to可以更新。
# with语法
WITH managers
FOR v, e, p IN OUTBOUND 'users/1' usersHaveManagers
RETURN { v, e, p }
插入文档
语法是INSERT document INTO collectionName。该文档是一个对象,您可以从JavaScript或JSON中了解它,它由属性键和值对组成。
属性键周围的引号在AQL中是可选的。键总是字符序列(字符串),而属性值可以有不同的类型:
空值
布尔值(true,false)
数字(整数和浮点数)
排列
宾语
该LET关键字定义一个带有名称数据的变量和一个对象数组作为值,因此LET variableName = valueExpression表达式是一个文字数组定义[ {...}, {...}, ... ]。
FOR variableName IN expression用于迭代数据数组的每个元素 。在每个循环中,将一个元素分配给变量d。然后在INSERT语句中使用此变量而不是文字对象定义。基本上是做什么的:
INSERT {
"name": "Robert",
"surname": "Baratheon",
"alive": false,
"traits": ["A","H","C"]
} INTO Characters
INSERT {
"name": "Jaime",
"surname": "Lannister",
"alive": true,
"age": 36,
"traits": ["A","F","B"]
} INTO Characters
...
注意:AQL不允许INSERT在单个查询中针对同一集合的多个操作。然而, 允许它作为FOR循环体,插入多个文档,就像我们对上面的查询所做的那样。
FOR c IN Characters_1 RETURN c
循环的语法是FOR variableName IN collectionName。对于集合中的每个文档,将为c分配一个文档,然后根据循环体返回该文档。查询返回我们先前存储的所有字符。
该文档包含我们存储的四个属性,以及数据库系统添加的另外三个属性。每个文档都需要一个唯一的文档_key,用于在集合中标识它。它_id是计算属性,集合名称,
正斜杠/和文档键的串联。它唯一标识数据库中的文档。_rev是系统管理的修订版ID。
用户可以在创建文档时提供文档键,也可以自动分配唯一值。它以后不能改变。以下划线开头的所有三个系统属性_都是只读的。
我们可以使用文档密钥或文档ID在AQL函数的帮助下检索特定文档DOCUMENT()
更新文档
UPDATE documentKey WITH object IN collectionName l列出的属性更新指定的文档(存在则添加它们)
要更新整个文档 整个用replace
可以用循环 更新或者替换属性
FOR c IN Character
UPDATE c with {swason: 1} IN Character
删除文件
要从集合中删除文档 执行 REMOVE
REMOVE "201213" IN Character
FOR C IN Characters
REMOVE c IN Characters
匹配条件
为了查找满足条件的文档 FILTER AQL
FOR c IN Characters
FILTER c.age >= 12
RETURN c.name
多种条件
FOR c IN Characters
FILTER c.age 《 13
FILTER c.age != null
RETURN {name: c.name, age: c.age} 可以用AND运算符
同时也有OR运算符
限制结果计数
FOR c IN Characters_1
LIMIT 5
RETURN c.name
FOR c IN Characters
LIMIT 2,5
RETURN c.name

+ 1165
- 0
src/docs/arangodb/agDocs/funs.md
文件差異過大導致無法顯示
查看文件


+ 0
- 0
src/docs/arangodb/agDocs/graph语法.md 查看文件


+ 8
- 0
src/docs/arangodb/agDocs/启动相关.md 查看文件

@ -0,0 +1,8 @@
Start ArangoDB shell client:
> /usr/bin/arangosh
Start ArangoDB service:
> systemctl start arangodb3.service
Enable ArangoDB service:
> systemctl enable arangodb3.service

+ 44
- 0
src/docs/arangodb/agDocs/命名规范.md 查看文件

@ -0,0 +1,44 @@
数据库名称
ArangoDB将始终从名为_system的默认数据库启动。用户可以在ArangoDB中创建其他数据库,前提是数据库名称符合以下约束:
数据库名称只能由字母a到z(允许大小写),数字0到9以及下划线(_)或破折号(-)符号组成。这也意味着,任何非ASCII数据库名称都不是允许的
数据库名称必须始终以字母开头。下划线开头的数据库名称被认为是系统数据库,用户不应创建或删除这些名称
数据库名称允许的最大长度为64个字节
数据库名称区分大小写
集合名称和视图名称
用户可以根据需要选择其集合和视图的名称,前提是不违反以下命名约束:
名称只能由字母a到z(大小写),数字0到9以及下划线(_)或破折号(-)符号组成。这也意味着不允许使用任何非ASCII名称。
视图名称必须始终以字母开头。
用户定义的集合名称必须始终以字母开头。系统集合名称必须以下划线开头。
所有以下划线开头的集合名称均被视为仅用于ArangoDB内部使用的系统集合。最终用户不应将系统集合名称用于自己的集合。
名称的最大允许长度为256个字节。
集合名称和视图名称区分大小写。
文档_key
用户可以为保存的文档定义自己的密钥。文档密钥将与文档一起保存在_key属性中。用户可以根据需要选择键值,只要这些键值符合以下限制:
键必须是字符串值。不允许使用数字键,但是可以将任何数字值放入字符串中,然后用作文档键。
密钥必须至少为1个字节,最大为254个字节。指定时不允许使用空键(尽管从文档中完全省略_key属性可能是有效的 )
它必须由字母az(小写或大写),数字0-9或以下任何标点字符组成: _ - : . @ ( ) + , = ; $ ! * ' %
键值内不能使用任何其他字符,尤其是多字节UTF-8序列,空格或标点字符
该密钥在使用的集合中必须唯一
键区分大小写,即myKey和MyKEY被认为是不同的键。
创建新文档时,指定文档密钥是可选的。如果用户未指定文档密钥,则ArangoDB将自己创建文档密钥,因为每个文档都必须具有密钥。
除上述限制外,无法保证自动生成的文档密钥的格式和模式。因此,客户应将自动生成的文档密钥视为不透明的值,而不应依赖于其格式。
生成密钥的当前格式是包含数字的字符串。从后面生成的_key值将包含比之前生成的_key值更高的数字的意义上,数字值反映了时间顺序。但是服务器将生成的确切值是不可预测的。请注意,如果按_key属性排序,则将使用字符串比较,这意味着"100"小于"99"。
属性名称
用户可以根据需要选择文档属性的属性名称,前提是不违反以下属性命名约束:
以下划线开头的属性名称被视为ArangoDB内部使用的系统属性。此类属性名称已被ArangoDB用于特殊目的:
_id用于包含文档的句柄
_key用于包含文档的用户定义键
_rev用于包含文档的修订号
在边缘收藏中,
_from
_to
属性用于引用其他文档。
将来可能会添加更多系统属性,恕不另行通知,因此最终用户应尽量避免使用以下划线开头的自己的属性名称。
从理论上讲,属性名称可以根据需要包括标点符号和特殊字符,前提是该名称是有效的UTF-8字符串。为了获得最大的可移植性,应避免使用特殊字符。例如,属性名称可能包含点符号,但是点在JavaScript和AQL中具有特殊含义,因此当以这些语言中的一种使用此类属性名称时,最终用户需要用引号引起来。总的来说,最好使用不需要使用所有语言进行任何引用/转义的属性名称。如果属性映射到客户端的对象成员,则包括客户端使用的语言(例如Ruby,PHP)。
当在AQL查询中使用属性名称时,以加号(@)开头的属性名称必须用反引号括起来,以区别绑定变量。因此,我们建议您不要使用以at-标记开头的属性,尽管它们在正确使用后仍然可以使用。
ArangoDB不对属性名称实施长度限制。但是,长属性名称可能会在结果集中使用更多的内存等。因此,不建议使用长属性名称。
属性名称区分大小写。
不允许使用名称为空(字符串为空)的属性。

+ 22
- 0
src/docs/arangodb/agDocs/类型和值的顺序.md 查看文件

@ -0,0 +1,22 @@
类型和值顺序
在检查是否相等或不相等或确定值的排序顺序时,AQL使用确定性算法,该算法同时考虑数据类型和实际值。
比较的操作数首先按其数据类型进行比较,如果操作数具有相同的数据类型,则仅按其数据值进行比较。
比较数据类型时,使用以下类型顺序:
null < bool < number < string < array/list < object/document
这意味着null是AQL中最小的类型,而document是具有最高顺序的类型。如果比较的操作数具有不同的类型,则确定比较结果并完成比较。
如果两个比较的操作数具有相同的数据类型,则将比较操作数的值。对于基本类型(null,布尔值,数字和字符串),结果定义如下:
null:null等于null
布尔值:false小于true
数字:数值按基数排序
字符串:使用本地化比较对字符串值进行排序,使用配置的 服务器语言 根据该语言的字母顺序规则进行排序
注意:与SQL不同,可以将null与任何值进行比较,包括null 本身,而不会自动将结果转换为null。
对于化合物,将应用以下特殊规则:
从第一个元素开始,通过逐个位置比较它们的各个元素来比较两个数组值。对于每个位置,首先比较元素类型。如果类型不相等,则确定比较结果,并且比较结束。如果类型相等,则将比较两个元素的值。如果其中一个数组已完成,而另一个数组在比较位置仍然有一个元素,则将null用作完全遍历数组的元素值。
如果数组元素本身是复合值(数组或对象/文档),则比较算法将递归检查元素的子值。递归比较元素的子元素。
通过检查属性名称和值来比较两个对象/文档操作数。首先比较属性名称。在比较属性名称之前,将创建两个操作数的所有属性名称的组合数组,并按字典顺序进行排序。这意味着在比较两个对象/文档时,在对象/文档中声明属性的顺序无关紧要。
然后遍历组合和排序的属性名称数组,然后从两个比较的操作数中查找相应的属性。如果对象/文档之一不具有具有所寻找名称的属性,则其属性值被视为null。最后,使用前面提到的数据类型和值比较来比较两个对象/文档的属性值。对所有对象/文档属性执行比较,直到明确的比较结果为止。如果找到明确的比较结果,则比较结束。如果没有明确的比较结果,则将两个比较的对象/文档视为相等。

+ 237
- 0
src/docs/arangodb/agDocs/索引.md 查看文件

@ -0,0 +1,237 @@
索引基础
索引允许快速访问文档,前提是在查询中使用了索引属性。尽管ArangoDB自动为某些系统属性建立索引,但用户可以自由地在文档的非系统属性上创建额外的索引。
可以在集合级别上创建用户定义的索引。可以通过指定索引属性的名称来创建大多数用户定义的索引。一些索引类型只允许索引一个属性(例如全文本索引),而其他索引类型只允许同时索引多个属性。
通过学习ArangoDB性能课程,学习如何有效地使用不同的索引 。
该系统属性_id,_key,_from并且_to通过ArangoDB会自动建立索引,而不需要用户为他们创造额外的索引。 _id并且_key被集合的主键 覆盖,_from并且_to被边缘集合的边缘索引自动覆盖。
使用该系统属性_id在用户定义的索引是不可能的,但索引_key,_rev,_from,和_to是。
默认情况下,创建新索引是在独占集合锁下完成的。创建索引时,该集合不可用。如果您必须在没有专用维护窗口的实时系统上执行索引创建,那么“前景”索引可能是不可取的。
对于可能长时间运行的索引创建操作,RocksDB存储引擎还支持在“后台”创建索引。该集合在索引创建期间仍然(大部分)可用,请参阅“ 在后台创建索引 ”部分以获取更多信息。
ArangoDB提供以下索引类型:
主要指标
对于每个集合,总会有一个主索引,该主索引是集合中所有文档的文档关键字(_key属性)的持久索引。主索引允许使用_key或_id属性快速选择集合中的文档。在_key或上执行相等查找时,将自动在AQL查询中使用它 _id。
还有一些专用功能来查找给定的文档,_key或者_id 始终使用主索引的文档:
db.collection.document("<document-key>");
db._document("<document-id>");
当对持久性索引进行排序时,主索引可用于范围查询和排序。
集合的主索引不能删除或更改,也没有创建用户定义的主索引的机制。
边缘指数
每个边缘集合还具有一个自动创建的边缘索引。边缘索引可通过文档的_from或_to属性快速访问文档。因此,它可用于快速查找顶点文档之间的连接,并在查询顶点的连接边时调用。
对边缘集合_from 或_to边缘集合中的值执行相等查找时,会从AQL中使用边缘索引。还有一些专用函数可以找到给定的边_from或边_to值,这些边将始终利用边索引:
db.collection.edges("<from-value>");
db.collection.edges("<to-value>");
db.collection.outEdges("<from-value>");
db.collection.outEdges("<to-value>");
db.collection.inEdges("<from-value>");
db.collection.inEdges("<to-value>");
边缘索引存储所有_from和_to属性的并集。它可以用于相等查找,但不能用于范围查询或排序。将自动为边缘集合创建边缘索引。
无法创建用户定义的边缘索引。但是,可以在用户定义的索引中自由使用_from和_to属性。
不能删除或更改边缘索引。
持久指数
持久索引是具有持久性的排序索引。存储或更新文档时,索引条目将写入磁盘。这意味着在重新启动服务器或初始加载索引的集合时,不需要从集合数据中重建索引条目。因此,使用持久索引可以减少集合加载时间。
持久索引类型目前可用于二级索引。这意味着持久性索引当前不能成为集合的唯一索引,因为该集合将始终存在内存中的主索引,并且可能还有更多的索引(例如Edge集合的edge索引)。
索引实现使用的是RocksDB引擎,它为插入,更新和删除操作提供了对数复杂性。由于持久索引不是内存索引,因此它不像所有内存索引一样将指针存储到主索引中,而是存储文档的主键。为了通过索引值查找通过持久索引检索文档,因此将在主索引中进行额外的O(1)查找以获取实际文档。
在对持久索引进行排序时,它可以用于点查找,范围查询和排序操作,但前提是必须在查询中提供所有索引属性,或者指定索引属性的最左前缀。
TTL(生存时间)索引
ArangoDB提供的TTL索引类型可用于自动从集合中删除过期的文档。
通过设置expireAfter值并选择包含文档创建日期和时间的单个文档属性来设置TTL索引。文档expireAfter在创建时间后几秒钟后过期。创建时间被指定为数字时间戳(Unix时间戳)或格式的日期字符串YYYY-MM-DDTHH:MM:SS,可以选择使用格式 的小数点后的毫秒数YYYY-MM-DDTHH:MM:SS.MMM和可选的时区偏移量。所有没有时区偏移的日期字符串都将被解释为UTC日期。
例如,如果expireAfter将设置为600秒(10分钟),并且索引属性为“ creationDate”,则存在以下文档:
{ "creationDate" : 1550165973 }
该文档将使用创建日期时间值索引,该值1550165973将转换为人类可读的date 2019-02-14T17:39:33.000Z。此文档将在时间戳记1550166573(或 2019-02-14T17:49:33.000Z人类可读版本)之后的600秒后过期。
实际删除过期文件并不一定会立即发生。过期的文档最终将由后台线程删除,该线程定期遍历所有TTL索引并删除过期的文档。可以使用--ttl.frequency 启动选项配置调用此后台线程的频率。
无法保证何时将完全删除过期的文档,因此查询仍然可以找到并返回已经过期的文档。这些文件最终将在后台线程启动并具有删除过期文档的能力时被删除。但是可以保证,只有超过其到期时间的文档才会被真正删除。
请注意,自1970年1月1日(Unix时间戳)以来,必须以秒为单位指定index属性的数字日期时间值。要以这种格式从JavaScript计算当前时间戳,可以使用Date.now() / 1000;。要从任意Date实例计算它,有Date.getTime() / 1000。在AQL中,您可以 DATE_NOW() / 1000将任意Unix时间戳(以毫秒为单位)除以1000,以将其转换为秒。
另外,可以将index属性值指定为date字符串,格式为 YYYY-MM-DDTHH:MM:SS,可选的格式是小数点后的毫秒YYYY-MM-DDTHH:MM:SS.MMM和可选的时区偏移量。所有没有时区偏移的日期字符串都将被解释为UTC日期。
上面使用datestring属性值的示例文档为
{ "creationDate" : "2019-02-14T17:39:33.000Z" }
如果index属性不包含数字值或正确的日期字符串,则该文档将不会存储在TTL索引中,因此不会成为过期和删除的候选对象。为索引属性提供非数字值或什至不提供值是防止文档过期和删除的一种受支持方法。
地理索引
用户可以在集合中的一个或多个属性上创建其他地理索引。地理索引用于快速找到地球表面的位置。
地理索引存储二维坐标。它可以在两个单独的文档属性(纬度和经度)上创建,也可以在包含纬度和经度的单个数组属性上创建。纬度和经度必须是数字值。
地理索引提供了以下操作:查找坐标最接近给定比较坐标的文档,以及查找坐标在围绕比较坐标的指定半径内的文档。
地理位置索引是通过AQL中的专用功能(简单查询功能)使用的,当在AQL中将SORT或FILTER与距离功能一起使用时,它会隐式应用。否则,它将不会用于其他类型的查询或条件。
全文索引
全文索引可用于在文档中查找单词或单词前缀。全文索引只能在单个属性上创建,并且将对文档中包含的具有该属性文本值的所有单词进行索引。仅索引(指定)最小长度的单词。使用libicu提供的单词边界分析来完成单词标记化,该分析考虑了服务器启动时提供的所选语言。单词以小写形式索引。该指数支持完全匹配的查询(满语)和前缀查询,加上基本的逻辑操作,例如 and,or和not用于组合部分结果。
全文索引是稀疏的,这意味着它只会索引设置了index属性且包含字符串值的文档。此外,索引中仅包含具有可配置的最小长度的单词。
全文索引通过AQL中的专用功能或简单查询使用,但不会为其他类型的查询或条件启用。
对于高级全文搜索功能,请考虑ArangoSearch。
索引属性和子属性
顶级以及嵌套属性都可以建立索引。对于顶级属性,仅需要属性名称。要为单个字段建立索引,请将具有单个元素(属性键的字符串)的数组传递给sureIndex()方法的fields参数 。要在多个字段上创建组合索引,只需将更多成员添加到fields数组中:
// { name: "Smith", age: 35 }
db.posts.ensureIndex({ type: "persistent", fields: [ "name" ] })
db.posts.ensureIndex({ type: "persistent", fields: [ "name", "age" ] })
要索引子属性,请使用点符号指定属性路径:
// { name: {last: "Smith", first: "John" } }
db.posts.ensureIndex({ type: "persistent", fields: [ "name.last" ] })
db.posts.ensureIndex({ type: "persistent", fields: [ "name.last", "name.first" ] })
索引数组值
如果索引属性包含一个数组,则默认情况下,ArangoDB将整个数组存储为索引值。这样就无法通过索引访问数组的各个成员。
若要使索引将单个数组成员而不是整个数组值插入到索引中,需要为该属性创建一个特殊的数组索引。使用该collection.ensureIndex()函数可以像常规持久性索引一样设置数组索引。为了使持久索引成为数组索引,[*] 在创建索引以及使用IN运算符在AQL查询中进行过滤时,需要扩展索引属性名称。
以下示例tags在名为的集合中的属性 上创建持久数组索引posts:
db.posts.ensureIndex({ type: "persistent", fields: [ "tags[*]" ] });
db.posts.insert({ tags: [ "foobar", "baz", "quux" ] });
然后,该数组索引可用于tags通过IN运算符从AQL查询中查找单个值:
FOR doc IN posts
FILTER 'foobar' IN doc.tags
RETURN doc
可以添加数组扩展运算符 [*],但这不是强制性的。您可以使用它来表示已使用数组索引,但是它纯粹是修饰性的:
FOR doc IN posts
FILTER 'foobar' IN doc.tags[*]
RETURN doc
以下FILTER条件将不使用数组索引:
FILTER doc.tags ANY == 'foobar'
FILTER doc.tags ANY IN 'foobar'
FILTER doc.tags IN 'foobar'
FILTER doc.tags == 'foobar'
FILTER 'foobar' == doc.tags
也可以在数组值的子属性上创建索引。如果index属性是一个对象数组,例如:
db.posts.ensureIndex({ type: "persistent", fields: [ "tags[*].name" ] });
db.posts.insert({ tags: [ { name: "foobar" }, { name: "baz" }, { name: "quux" } ] });
然后,以下查询将使用数组索引(这确实需要 数组扩展运算符):
FOR doc IN posts
FILTER 'foobar' IN doc.tags[*].name
RETURN doc
如果存储的文档中的数组确实包含不具有子属性的元素,则该文档也将被索引为value null,该值在ArangoDB中等于不存在的属性。
ArangoDB支持使用[*]每个索引属性使用单个运算符来创建数组索引。例如,不支持如下创建索引:
db.posts.ensureIndex({ type: "persistent", fields: [ "tags[*].name[*].value" ] });
数组值在插入数组索引之前将自动进行重复数据删除。例如,如果将以下文档插入到集合中,则重复的数组值bar将仅被插入一次:
db.posts.insert({ tags: [ "foobar", "bar", "bar" ] });
这样做是为了避免对同一文档重复存储相同索引值,这不会带来任何好处。
如果将数组索引声明为unique,则会在将数组值插入索引之前对数组值进行重复数据删除,因此上述具有两个相同值的插入操作 bar不一定会失败
如果索引已经包含该bar值的实例,它将总是失败。但是,如果bar索引中不存在该值,则对数组值进行重复数据删除将实际上导致bar仅插入一次。
要关闭数组值的重复数据删除,可以将数组索引的重复数据删除属性设置为false。但是,重复数据删除的默认值为true,因此,如果未明确关闭重复数据删除,则会进行重复数据删除。
db.posts.ensureIndex({ type: "persistent", fields: [ "tags[*]" ], deduplicate: false });
// will fail now
db.posts.insert({ tags: [ "foobar", "bar", "bar" ] });
如果声明了数组索引,并且您在指定的属性中存储没有数组的文档,则该文档不会插入索引中。因此,以下对象将不被索引:
db.posts.ensureIndex({ type: "persistent", fields: [ "tags[*]" ] });
db.posts.insert({ something: "else" });
db.posts.insert({ tags: null });
db.posts.insert({ tags: "this is no array" });
db.posts.insert({ tags: { content: [1, 2, 3] } });
数组索引能够索引显式null值。当查询null值时,它将仅返回那些已明确null存储在数组中的文档,而不会返回任何根本没有数组的文档。
db.posts.ensureIndex({ type: "persistent", fields: [ "tags[*]" ] });
db.posts.insert({tags: null}) // Will not be indexed
db.posts.insert({tags: []}) // Will not be indexed
db.posts.insert({tags: [null]}); // Will be indexed for null
db.posts.insert({tags: [null, 1, 2]}); // Will be indexed for null, 1 and 2
将数组索引声明为稀疏对索引的数组部分没有影响,这尤其意味着null在稀疏版本中也对显式值进行索引。如果将索引与数组和常规属性组合在一起,则稀疏性将适用于该属性,例如:
db.posts.ensureIndex({ type: "persistent", fields: [ "tags[*]", "name" ], sparse: true });
db.posts.insert({tags: null, name: "alice"}) // Will not be indexed
db.posts.insert({tags: [], name: "alice"}) // Will not be indexed
db.posts.insert({tags: [1, 2, 3]}) // Will not be indexed
db.posts.insert({tags: [1, 2, 3], name: null}) // Will not be indexed
db.posts.insert({tags: [1, 2, 3], name: "alice"})
// Will be indexed for [1, "alice"], [2, "alice"], [3, "alice"]
db.posts.insert({tags: [null], name: "bob"})
// Will be indexed for [null, "bob"]
请注意,仅在查询使用IN操作符对索引属性进行过滤时,使用数组索引的过滤仅在AQL查询中有效。其它比较运算符(==,!=,>,>=,<<=,ANY,ALL,NONE)不能目前使用阵列的索引。
顶点中心索引
如上所述,图形最重要的索引是边缘索引,它索引边缘集合的_from和_to属性。它们提供了对源自或到达给定顶点的所有边的非常快速的访问,这允许快速找到图中顶点的所有邻居。
在许多情况下,我们希望运行更具体的查询,例如,在给定顶点起源的边中仅查找那些时间戳大于或等于某个日期和时间的边。确切地说,这是通过“以顶点为中心的索引”实现的。从某种意义上讲,它们是每个单个顶点处的边缘集合的局部索引。
从技术上说,他们在ArangoDB实现为索引,其排序完整边集合首先_from,然后通过其他属性出境遍历,或者先通过_to,然后由其他属性入境遍历。对于在ANY方向上的遍历,需要两个索引,一个索引与_from另一个_to索引作为第一个索引字段。
例如,如果我们在属性_from和 timestamp边缘集合上有一个持久索引,则可以通过在索引中进行一次范围查找来非常快速地回答上述问题。
从ArangoDB 3.0开始,可以创建排序索引(类型为“持久”)来索引特殊边缘属性_from或_to 其他属性。从ArangoDB 3.1开始,当FILTER优化器找到适当的语句时,这些将用于图遍历。
例如,要创建上述类型的顶点中心索引,您只需
db.edges.ensureIndex({"type":"persistent", "fields": ["_from", "timestamp"]});
在阿兰戈什。然后,查询如
FOR v, e, p IN 1..1 OUTBOUND "V/1" edges
FILTER e.timestamp >= "2018-07-09"
RETURN p
如果有许多来自顶点的边,"V/1"但是只有少数带有最近时间戳记的边,则速度会更快。请注意,即使顶点中心索引实际上可能更快,优化器也可能会基于估计的成本而选择默认边缘索引而不是顶点中心索引。对于高度连接的图形和RocksDB存储引擎,更可能选择以顶点为中心的索引。
在后台创建索引
在v3.5.0中引入
默认情况下,创建新索引是在独占集合锁下完成的。这意味着只要创建索引,集合(或相应的分片)就不可用于写操作。如果您必须在没有专用维护窗口的实时系统上执行索引创建,那么“前景”索引可能是不可取的。
索引也可以在“后台”中创建,而不在整个索引创建过程中使用排他锁。该集合基本上保持可用,因此在创建索引时其他CRUD操作可以在该集合上运行。这可以通过在创建索引时设置inBackground属性来实现。
要在arangosh中在后台创建索引,只需指定inBackground: true,如以下示例所示:
// create the persistent index in the background
db.collection.ensureIndex({ type: "persistent", fields: [ "value" ], unique: false, inBackground: true });
db.collection.ensureIndex({ type: "persistent", fields: [ "email" ], unique: true, inBackground: true });
// also supported for geo and fulltext indexes
db.collection.ensureIndex({ type: "geo", fields: [ "latitude", "longitude"], inBackground: true });
db.collection.ensureIndex({ type: "geo", fields: [ "latitude", "longitude"], inBackground: true });
db.collection.ensureIndex({ type: "fulltext", fields: [ "text" ], minLength: 4, inBackground: true })
行为
仍在构建过程中的索引将无法通过ArangoDB API看到。但是,在仍然开始创建索引的同时,不可能通过sureIndex API 两次创建相同的索引。AQL查询也不会使用这些索引,直到索引报告已完全创建。请注意,在索引完全准备好之前,最初的sureIndex调用或HTTP请求仍将阻塞。因此,现有的单线程客户端程序可以安全地将inBackground选项设置为true并继续像以前一样工作。
如果要在后台建立索引,则不能重命名或删除集合。这些操作将阻塞,直到索引创建完成。前景索引也是如此。
在索引构建中断之后(即由于服务器崩溃),部分构建的索引将被删除。然后,在ArangoDB集群中,可能会在受影响的分片上自动重新创建索引。
性能
后台索引创建可能比“前景”索引创建慢,并且需要更多RAM。在繁重的写操作(特别是许多删除,更新或替换操作)下,后台索引创建需要在RAM中保留已删除文档的列表。如果此列表增加到数千万个条目,这可能变得难以为继。
建立索引始终(内部)是繁重的写操作,在负载较少的时候建立索引始终是一个好主意。

+ 240
- 0
src/docs/arangodb/agDocs/运算符.md 查看文件

@ -0,0 +1,240 @@
经营者
AQL支持许多可在表达式中使用的运算符。有比较,逻辑,算术和三元运算符。
比较运算符
比较(或关系)运算符比较两个操作数。它们可以与任何输入数据类型一起使用,并将返回布尔结果值。
支持以下比较运算符:
操作员 描述
== 平等
!= 不等式
< 少于
<= 小于或等于
> 比...更棒
>= 大于或等于
IN 测试值是否包含在数组中
NOT IN 测试值是否不包含在数组中
LIKE 测试字符串值是否与模式匹配
NOT LIKE 测试字符串值是否与模式不匹配
=~ 测试字符串值是否与正则表达式匹配
!~ 测试字符串值是否与正则表达式不匹配
如果可以评估比较结果,则每个比较运算符都将返回一个布尔值;如果比较结果为true,则返回true;否则返回false 。
比较运算符接受第一和第二操作数的任何数据类型。但是,IN并且NOT IN仅在其右侧操作数是数组的情况下才会返回有意义的结果。LIKE并且NOT LIKE仅在两个操作数均为字符串值时才执行。如果比较的操作数具有不同或不合理的类型,则比较运算符将不执行任何隐式类型转换。
AQL中比较操作的一些示例:
0 == null // false
1 > 0 // true
true != null // true
45 <= "yikes!" // true
65 != "65" // true
65 == 65 // true
1.23 > 1.32 // false
1.5 IN [ 2, 3, 1.5 ] // true
"foo" IN null // false
42 NOT IN [ 17, 40, 50 ] // true
"abc" == "abc" // true
"abc" == "ABC" // false
"foo" LIKE "f%" // true
"foo" NOT LIKE "f%" // false
"foo" =~ "^f[o].$" // true
"foo" !~ "[a-z]+bar$" // true
该LIKE运营商检查是否其左操作数以其右操作数指定的模式相匹配。该模式可以包含常规字符和通配符。支持的通配符_将匹配单个任意字符,并%匹配任意数量的任意字符。文字%,_需要以反斜杠转义。反斜杠需要自己转义,这实际上意味着两个反斜线字符必须在文字百分号或下划线之前。在arangosh中,需要进行额外的转义,使其在要转义的字符之前总共加四个反斜杠。
"abc" LIKE "a%" // true
"abc" LIKE "_bc" // true
"a_b_foo" LIKE "a\\_b\\_foo" // true
LIKE操作员执行的模式匹配区分大小写。
该NOT LIKE经营者具有相同特性的LIKE运营商,但与否定的结果。因此,它与相同NOT (… LIKE …)。请注意括号,这对于某些表达式是必需的:
FOR doc IN coll
RETURN NOT doc.attr LIKE "…"
return表达式将转换为LIKE(!doc.attr, "…"),从而产生意外结果。NOT(doc.attr LIKE "…")变得更加合理! LIKE(doc.attr, "…")。
正则表达式运算符=~并!~期望它们的左手操作数是字符串,而期望它们的右手操作数是包含有效的正则表达式的字符串,如AQL函数REGEX_TEST()的文档中所指定 。
数组比较运算符
比较运算符也作为数组变量存在。在阵列变型中,操作者的前缀的关键字之一ALL,ANY 或NONE。使用这些关键字之一可以更改操作员的行为,以便对其所有,任何或不使用其左手参数值执行比较操作。因此,期望数组运算符的左手参数是一个数组。
例子:
[ 1, 2, 3 ] ALL IN [ 2, 3, 4 ] // false
[ 1, 2, 3 ] ALL IN [ 1, 2, 3 ] // true
[ 1, 2, 3 ] NONE IN [ 3 ] // false
[ 1, 2, 3 ] NONE IN [ 23, 42 ] // true
[ 1, 2, 3 ] ANY IN [ 4, 5, 6 ] // false
[ 1, 2, 3 ] ANY IN [ 1, 42 ] // true
[ 1, 2, 3 ] ANY == 2 // true
[ 1, 2, 3 ] ANY == 4 // false
[ 1, 2, 3 ] ANY > 0 // true
[ 1, 2, 3 ] ANY <= 1 // true
[ 1, 2, 3 ] NONE < 99 // false
[ 1, 2, 3 ] NONE > 10 // true
[ 1, 2, 3 ] ALL > 2 // false
[ 1, 2, 3 ] ALL > 0 // true
[ 1, 2, 3 ] ALL >= 3 // false
["foo", "bar"] ALL != "moo" // true
["foo", "bar"] NONE == "bar" // false
["foo", "bar"] ANY == "foo" // true
请注意,这些运算符尚未优化。索引将不被使用。
逻辑运算符
AQL支持以下逻辑运算符:
&& 逻辑与运算符
|| 逻辑或运算符
! 逻辑非/否定运算符
AQL还支持逻辑运算符的以下替代形式:
AND 逻辑与运算符
OR 逻辑或运算符
NOT 逻辑非/否定运算符
替代形式是别名,在功能上等同于常规运算符。
AQL中的两个操作数逻辑运算符将使用短路求值执行(除非其中一个操作数是子查询或包含子查询。在这种情况下,子查询将在逻辑运算符之前被提取一个求值)。
AQL中逻辑运算符的结果定义如下:
lhs && rhslhs如果是false或将false转换为布尔值时将返回。如果将lhsis true或be true转换为布尔值, rhs则将返回。
lhs || rhslhs如果是true或将true转换为布尔值时将返回。如果将lhsis false或be false转换为布尔值, rhs则将返回。
! value将返回value转换为布尔值的取反值
AQL中逻辑操作的一些示例:
u.age > 15 && u.address.city != ""
true || false
NOT u.isInvalid
1 || ! 0
允许将非布尔值传递给逻辑运算符。任何非布尔操作数都将由运算符隐式转换为布尔值,而不会使查询中止。
在一个布尔值转换的工作原理如下:
null 将被转换为 false
布尔值保持不变
所有不等于零的数字为true,零为false
空字符串是false,所有其他字符串是true
数组([ ])和对象/文档({ })是true不论其内容如何
逻辑和与逻辑或运算的结果现在可以具有任何数据类型,并且不一定是布尔值。
例如,以下逻辑运算将返回布尔值:
25 > 1 && 42 != 7 // true
22 IN [ 23, 42 ] || 23 NOT IN [ 22, 7 ] // true
25 != 25 // false
…,而以下逻辑运算将不会返回布尔值:
1 || 7 // 1
null || "foo" // "foo"
null && true // null
true && 23 // 23
算术运算符
算术运算符对两个数字操作数执行算术运算。算术运算的结果还是一个数值。
AQL支持以下算术运算符:
+ 加成
- 减法
* 乘法
/ 师
% 模数
一元加号和一元减号也受支持:
LET x = -5
LET y = 1
RETURN [-x, +y]
// [5, 1]
为了求幂,有一个数字函数 POW()。base ** exp不支持语法。
对于字符串连接,必须使用字符串函数 CONCAT()。将两个字符串与加号("foo" + "bar")结合使用将不起作用!另请参阅常见错误。
一些算术运算示例:
1 + 1
33 - 99
12.4 * 4.5
13.0 / 0.1
23 % 7
-15
+9.99
算术运算符接受任何类型的操作数。将非数字值传递给算术运算符将使用TO_NUMBER()函数应用的类型转换规则将操作数转换为数字:
null 将被转换为 0
false将转换为0,将true转换为1
有效数值保持不变,但NaN和Infinity将转换为 0
如果字符串值包含数字的有效字符串表示形式,则将它们转换为数字。字符串开头或结尾的所有空格都将被忽略。具有其他内容的字符串将转换为数字0
将一个空数组转换为0,将具有一个成员的数组转换为其唯一成员的数字表示形式。具有更多成员的数组将转换为number 0。
对象/文档将转换为数字0。
产生无效值的算术运算,例如1 / 0(除以零)也将产生结果值null。该查询不会终止,但是您可能会看到警告。
这里有一些例子:
1 + "a" // 1
1 + "99" // 100
1 + null // 1
null + 1 // 1
3 + [ ] // 3
24 + [ 2 ] // 26
24 + [ 2, 4 ] // 0
25 - null // 25
17 - true // 16
23 * { } // 0
5 * [ 7 ] // 35
24 / "12" // 2
1 / 0 // 0
三元运算符
AQL还支持可用于条件评估的三元运算符。三元运算符期望布尔条件作为其第一个操作数,如果条件的计算结果为true,则返回第二个操作数的结果,否则返回第三个操作数。
例子
u.age > 15 || u.active == true ? u.userId : null
还有只有两个操作数的三元运算符的快捷方式。当布尔条件的表达式和返回值应该相同时,可以使用此变体:
例子
u.value ? : 'value is null, 0 or not present'
范围运算符
AQL支持使用..运算符表达简单的数字范围。该运算符可用于轻松地迭代数字序列。
所述..操作者将产生整数值的阵列在所定义的范围内,与两个边界值包括在内。
例子
2010..2013
将产生以下结果:
[ 2010, 2011, 2012, 2013 ]
使用范围运算符等效于编写一个整数值的数组,该整数值在范围的边界所指定的范围内。如果范围运算符的边界为非整数,则它们将首先转换为整数值。
还有一个RANGE()函数。
数组运算符
AQL提供阵列运营商[*]为 数组变量扩展和 [**]用于阵列收缩。
运算符优先级
AQL中的运算符优先级与其他熟悉的语言相似(最低优先级优先):
运营商 描述
, 逗号分隔符
DISTINCT 独特修饰符(返回操作)
? : 三元运算符
= 变量赋值(LET操作)
WITH 与运算符一起(WITH / UPDATE / REPLACE / COLLECT操作)
INTO 进入运算符(INSERT / UPDATE / REPLACE / REMOVE / COLLECT操作)
|| 逻辑或
&& 逻辑与
OUTBOUND,INBOUND,ANY,ALL,NONE 图遍历方向,数组比较运算符
==,!=,LIKE,NOT LIKE,=~,!~ (in)相等,通配符(非)匹配,正则表达式(非)匹配
IN, NOT IN (不是)在运算符中
<<=,>=,> 小于,小于等于,大于等于,大于
.. 范围运算符
+, - 加,减
*,/,% 乘法,除法,模
!,+,- 逻辑否定,一元加,一元减
() 函数调用
. 会员访问
[] 索引值访问
[*] 扩张
:: 范围
括号(和)可用于强制执行不同的操作员评估顺序。

+ 34
- 0
src/docs/arangodb/arandodb初始化配置相关.md 查看文件

@ -0,0 +1,34 @@
Updating / installing...
1:arangodb3e-3.5.3-1.0 ################################# [100%]
ArangoDB 3 (https://www.arangodb.com)
The multi-model NoSQL database: distributed free and open-source database
with a flexible data model for documents, graphs, and key-values. Build
high performance applications using a convenient SQL-like query language
or JavaScript extensions.
First Steps with ArangoDB:
https://docs.arangodb.com/latest/Manual/GettingStarted/
Configuring the storage Engine:
https://docs.arangodb.com/latest/Manual/Administration/Configuration/GeneralArangod.html#storage-engine
Configuration file:
/etc/arangodb3/arangod.conf
Start ArangoDB shell client:
> /usr/bin/arangosh
Start ArangoDB service:
> systemctl start arangodb3.service
Enable ArangoDB service:
> systemctl enable arangodb3.service
SECURITY HINT:
run 'arango-secure-installation' to set a root password
the current password is '7c8329a66d35a624bcfedfae0c944938'
(You should do this for a FRESH install! For an UPGRADE the password does not need to be changed)
2019-12-13T15:41:20Z [1134] INFO [a1c60] {syscall} file-descriptors (nofiles) hard limit is 65535, soft limit is 65535
2019-12-13T15:41:21Z [1134] INFO [7da27] {startup} server will now shut down due to upgrade, database initialization or admin restoration.

+ 77
- 0
src/docs/arangodb/arangod.conf 查看文件

@ -0,0 +1,77 @@
# ArangoDB configuration file
#
# Documentation:
# https://docs.arangodb.com/latest/Manual/Administration/Configuration/
#
[database]
directory = /var/lib/arangodb3
# maximal-journal-size = 33554432
[server]
# Specify the iendpoint for HTTP requests by clients.
# tcp://ipv4-address:port
# tcp://[ipv6-address]:port
# ssl://ipv4-address:port
# ssl://[ipv6-address]:port
# unix:///path/to/socket
#
# Examples:
endpoint = tcp://0.0.0.0:8529
# endpoint = tcp://171.221.139.17:8529
# endpoint = tcp://localhost:8529
# endpoint = tcp://myserver.arangodb.com:8529
# endpoint = tcp://[::]:8529
# endpoint = tcp://[fe80::21a:5df1:aede:98cf]:8529
#
# endpoint = tcp://127.0.0.1:8529
storage-engine = rocksdb
# reuse a port on restart or wait until it is freed by the operating system
# reuse-address = false
authentication = true
# number of maximal server threads. use 0 to make arangod determine the
# number of threads automatically, based on available CPUs
# maximal-threads = 0
# gather server statistics
statistics = true
# the user and group are normally set in the start script
# uid = arangodb
# gid = arangodb
uid = arangodb
[javascript]
startup-directory = /usr/share/arangodb3/js
app-path = /var/lib/arangodb3-apps
# app-path = //arangodb3/apps
# number of V8 contexts available for JavaScript execution. use 0 to
# make arangod determine the number of contexts automatically.
# v8-contexts = 0
[foxx]
# enable Foxx queues in the server
# queues = true
# interval (seconds) to use for polling jobs in Foxx queues
# queues-poll-interval = 1
[log]
level = info
file = /var/log/arangodb3/arangod.log
[cluster]
[rocksdb]
# encryption-keyfile=/your-encryption-file
#
[http]
keep-alive-timeout = 5000000
hide-product-header = true

+ 16
- 0
src/docs/arangodb/arangodb主要特特点.md 查看文件

@ -0,0 +1,16 @@
# 主要特点
ArangoDB是本机多模型,开源数据库,具有用于文档,图形和键值的灵活数据模型。使用方便的类似SQL的查询语言或JavaScript扩展来构建高性能应用程序。如果需要,请使用ACID交易。只需单击几下鼠标,即可水平和垂直缩放。
主要功能包括:
在群集上安装ArangoDB与在移动设备上安装应用程序一样容易
灵活的数据建模:将您的数据建模为键值对,文档或图表的组合-非常适合社交关系
强大的查询语言(AQL)来检索和修改数据
将ArangoDB用作应用程序服务器,并将应用程序和数据库融合在一起,以实现最大吞吐量
事务:对多个文档或集合运行查询,并具有可选的事务一致性和隔离性
复制和分片:在多个服务器建立数据库以主-从配置或传播更大的数据集
可配置的耐久性:让应用程序决定是否需要更高的耐久性或更高的性能
轻松的存储:ArangoDB使用了现代存储硬件的所有功能,例如SSD和大型缓存
面向所有人的JavaScript:您可以从浏览器到后端使用一种语言
ArangoDB可以轻松地部署为容错的分布式状态机,可以充当分布式设备的动物大脑
它是开源的(Apache License 2.0)

+ 507
- 0
src/docs/arangodb/arangodb服务器选项.md 查看文件

@ -0,0 +1,507 @@
# 服务器用法
arangod [<option>]
可以将数据库目录指定为位置 第一个参数
arangod /path/to/datadir
或者显示作为命名参数
arangod --database.directory /path/to/datadir
所有其他参数都需要作为命名参数传递
两个连字符(--)后跟选项名称 然后 等号或者空格 最后是参数值 如果参数值包含了空格 还需要用引号引起来
= 两边 有空格
# 各种配置选项
## Global
Name Typ
check-configuration boolean
检查配置并退出 这是一个命令,不需要指定任何值。执行命令后,进程终止。
config string
The configuration file or ‘none’
Default: ""
configuration string
The configuration file or ‘none’
Default: ""
console boolean
Start a JavaScript emergency console
This option can be specified without value to enable it.
Default: false
daemon boolean
Background the server, running it as daemon
This option can be specified without value to enable it.
Default: false
default-language string
ISO-639 language code
Default: ""
define string…
Define key=value for a @key@ entry in config file
Default: []
dump-dependencies boolean
Dump dependency graph
This is a command, no value needs to be specified. The process terminates after executing the command.
dump-options boolean
Dump configuration options in JSON format
This is a command, no value needs to be specified. The process terminates after executing the command.
fortune boolean
Show fortune cookie on startup
This option can be specified without value to enable it.
Default: false
gid string
Switch to group-id after reading config files
Default: ""
hund boolean
Make ArangoDB bark on startup
This option can be specified without value to enable it.
Default: false
log string…
The global or topic-specific log level
Default: ["info","info"]
Deprecated in: v3.5.0
pid-file string
Pid-file in daemon mode
Default: ""
supervisor boolean
Background the server, starts a supervisor
This option can be specified without value to enable it.
Default: false
uid string
Switch to user-id after reading config files
Default: ""
version boolean
Reports the version and exits
This is a command, no value needs to be specified. The process terminates after executing the command.
working-directory string
Working directory in daemon mode
Default: "/var/tmp"
## Agency
Name Type Description
agency.activate boolean Activate agency
This option can be specified without value to enable it.
Default: false
Effective on Agents only.
agency.compaction-keep-size uint64 Keep as many indices before compaction point
Default: 50000
Effective on Agents only.
agency.compaction-step-size uint64 Step size between state machine compactions
Default: 1000
Effective on Agents only.
agency.disaster-recovery-id string Allows for specification of the id for this agent; dangerous option for disaster recover only!
Default: ""
Effective on Agents only.
agency.election-timeout-max double Maximum timeout before an agent calls for new election (in seconds)
Default: 5
Effective on Agents only.
agency.election-timeout-min double Minimum timeout before an agent calls for new election (in seconds)
Default: 1
Effective on Agents only.
agency.endpoint string… Agency endpoints
Default: []
Effective on Agents only.
agency.max-append-size uint64 Maximum size of appendEntries document (# log entries)
Default: 250
Effective on Agents only.
agency.my-address string Which address to advertise to the outside
Default: ""
Effective on Agents only.
agency.pool-size uint64 Number of agent pool
Default: 1
Effective on Agents only.
agency.size uint64 Number of agents
Default: 1
Effective on Agents only.
agency.supervision boolean Perform arangodb cluster supervision
This option can be specified without value to enable it.
Default: false
Effective on Agents only.
agency.supervision-frequency double Arangodb cluster supervision frequency (in seconds)
Default: 1
Effective on Agents only.
agency.supervision-grace-period double Supervision time, after which a server is considered to have failed (in seconds)
Default: 10
Effective on Agents only.
agency.supervision-ok-threshold double Supervision time, after which a server is considered to be bad [s]
Default: 5
Effective on Agents only.
agency.wait-for-sync boolean Wait for hard disk syncs on every persistence call (required in production)
This option can be specified without value to enable it.
Default: true
Effective on Agents only.
## ArangoSearch
Name Type Description
arangosearch.threads uint64 The exact number of threads to use for asynchronous tasks (0 == autodetect)
Default: 0
arangosearch.threads-limit uint64 Upper limit to the autodetected number of threads to use for asynchronous
## Audit
Name Type Description
audit.hostname string Enterprise Edition only
Hostname to use
Default: ""
audit.output string… Enterprise Edition only
Audit destinatio
## Backup
Name Type Description
backup.api-enabled string Whether the backup api is enabled (true) or not (false), or only enabled for superuser JWT (jwt)
Default: "true"
backup.local-path-prefix This option restricts any backup target to a given path prefix Default: "/"
## Cache
cache.rebalancing-interval uint64 Microseconds between rebalancing attempts
Default: 2000000
cache.size uint64 Size of cache in bytes
Default: dynamic (e.g. 33252951040)
## Cluster
Name Type Description
cluster.agency-endpoint string… Agency endpoint to connect to
Default: []
Effective on Coordinators and DB-Servers only.
cluster.create-waits-for-sync-replication boolean Active coordinator will wait for all replicas to create collection
This option can be specified without value to enable it.
Default: true
Effective on Coordinators and DB-Servers only.
cluster.default-replication-factor uint32 Default replication factor for non-system collections
Default: 0
Effective on Coordinators only.
Introduced in: v3.6.0
cluster.force-one-shard boolean Force one-shard mode for all new collections
This option can be specified without value to enable it.
Default: false
Effective on Coordinators only.
Introduced in: v3.6.0
cluster.index-create-timeout double Amount of time (in seconds) the coordinator will wait for an index to be created before giving up
Default: 3600
Effective on Coordinators only.
cluster.max-number-of-shards uint32 Maximum number of shards when creating new collections (0 = unrestricted)
Default: 1000
Effective on Coordinators only.
Introduced in: v3.5.1
cluster.max-replication-factor uint32 Maximum replication factor for new collections (0 = unrestricted)
Default: 10
Effective on Coordinators only.
Introduced in: v3.6.0
cluster.min-replication-factor uint32 Minimum replication factor for new collections
Default: 1
Effective on Coordinators only.
Introduced in: v3.6.0
cluster.my-address string This server’s endpoint (cluster internal)
Default: ""
Effective on Coordinators and DB-Servers only.
cluster.my-advertised-endpoint string This server’s advertised endpoint (e.g. external IP address or load balancer, optional)
Default: ""
Effective on Coordinators and DB-Servers only.
cluster.my-role string This server’s role
Default: ""
cluster.require-persisted-id boolean If set to true, then the instance will only start if a UUID file is found in the database on startup. Setting this option will make sure the instance is started using an already existing database directory and not a new one. For the first start, the UUID file must either be created manually or the option must be set to false for the initial startup
This option can be specified without value to enable it.
Default: false
cluster.resign-leadership-on-shutdown boolean Create resign leader ship job for this dbsever on shutdown
This option can be specified without value to enable it.
Default: false
Effective on DB-Servers only.
cluster.synchronous-replication-timeout-factor double All synchronous replication timeouts are multiplied by this factor
Default: 1
cluster.synchronous-replication-timeout-minimum double All synchronous replication timeouts will be at least this value (in seconds)
Default: 30
cluster.synchronous-replication-timeout-per-4k double All synchronous replication timeouts are increased by this amount per 4096 bytes (in seconds)
Default: 0.1
cluster.system-replication-factor uint32 Default replication factor for system collections
Default: 2
Effective on Coordinators only.
cluster.upgrade string Perform a cluster upgrade if necessary (auto = perform upgrade and shut down only if --database.auto-upgrade true is set, disable = never perform upgrade, force = always perform an upgrade and shut down, online = always perform an upgrade but don’t shut down)
Default: "auto"
Possible values: “auto”, “disable”, “force”, “online”
cluster.write-concern uint32 Write concern used for writes to new collections
Default: 1
Effective on Coordinators only.
Introduced in: v3.6.0
## Database
Name Type Description
database.auto-upgrade boolean Perform a database upgrade if necessary
This option can be specified without value to enable it.
Default: false
database.check-version boolean Checks the versions of the database and exit
This is a command, no value needs to be specified. The process terminates after executing the command.
database.directory string Path to the database directory
Default: ""
database.force-sync-properties boolean Force syncing of collection properties to disk, will use waitForSync value of collection when turned off
This option can be specified without value to enable it.
Default: true
database.ignore-datafile-errors boolean Load collections even if datafiles may contain errors
This option can be specified without value to enable it.
Default: false
database.init-database boolean Initializes an empty database
This is a command, no value needs to be specified. The process terminates after executing the command.
database.password string Initial password of root user
Default: ""
database.required-directory-state string Required state of database directory at startup (non-existing: database directory must not exist, existing: database directory must exist, empty: database directory must exist but be empty, populated: database directory must exist and contain specific files already, any: any state allowed)
Default: "any"
Possible values: “any”, “empty”, “existing”, “non-existing”, “populated”
database.restore-admin boolean Resets the admin users and sets a new password
This is a command, no value needs to be specified. The process terminates after executing the command.
database.throw-collection-not-loaded-error boolean Throw an error when accessing a collection that is still loading
This option can be specified without value to enable it.
Default: false
Deprecated in: v3.7.0
database.upgrade-check boolean Skip a database upgrade
This option can be specified without value to enable it.
Default: true
database.wait-for-sync boolean Default wait-for-sync behavior, can be overwritten when creating a collection
This option can be
## Foxx
Name Type Description
foxx.api boolean Enables Foxx management REST APIs
This option can be specified without value to enable it.
Default: true
Effective on Coordinators and Single Servers only.
Introduced in: v3.5.0
foxx.queues boolean Enable Foxx queues
This option can be specified without value to enable it.
Default: true
Effective on Coordinators and Single Servers only.
foxx.queues-poll-interval double Poll interval (in seconds) for Foxx queue manager
Default: 1
Effective on Coordinators and Single Servers only.
foxx.store boolean Enables Foxx store in web interface
This option can be specified without value to enable it.
Default: true
Effective on Coordinators and Single Servers only.
Introduced in: v3.5.0
# Frontend
Name Type Description
frontend.proxy-request-check boolean Enable proxy request checking
This option can be specified without value to enable it.
Default: true
Effective on Coordinators and Single Servers only.
frontend.trusted-proxy string… List of proxies to trust (may be IP or network). Make sure --frontend.proxy-request-check is enabled
Default: []
Effective on Coordinators and Single Servers only.
frontend.version-check boolean Alert the user if new versions are available
This option can be specified without value to enable it.
Default: true
Effective on Coordinators and Single Servers only.
## HTTP
Name Type Description
http.allow-method-override boolean Allow HTTP method override using special headers
This option can be specified without value to enable it.
Default: false
http.hide-product-header boolean Do not expose “Server: ArangoDB” header in HTTP responses
This option can be specified without value to enable it.
Default: false
http.keep-alive-timeout double Keep-alive timeout in seconds
Default: 300
http.trusted-origin string… Trusted origin URLs for CORS requests with credentials
Default: []
# JavaScript
Name Type Description
javascript.allow-admin-execute boolean For testing purposes allow ‘_admin/execute’, NEVER enable on production
This option can be specified without value to enable it.
Default: false
Effective on Coordinators and Single Servers only.
javascript.allow-external-process-control boolean Allow execution and control of external processes from within JavaScript actions
This option can be specified without value to enable it.
Default: false
Effective on Coordinators and Single Servers only.
Introduced in: v3.5.0
javascript.allow-port-testing boolean Allow testing of ports from within JavaScript actions
This option can be specified without value to enable it.
Default: false
Effective on Coordinators and Single Servers only.
Introduced in: v3.5.0
javascript.app-path string Directory for Foxx applications
Default: "./js/apps"
Effective on Coordinators and Single Servers only.
javascript.copy-installation boolean Copy contents of ‘javascript.startup-directory’ on first start
This option can be specified without value to enable it.
Default: false
Effective on Coordinators and Single Servers only.
javascript.enabled boolean Enable the V8 JavaScript engine
This option can be specified without value to enable it.
Default: true
Effective on Coordinators and Single Servers only.
javascript.endpoints-blacklist string… Endpoints that cannot be connected to via @arangodb/request module in JavaScript actions if not whitelisted
Default: []
Effective on Coordinators and Single Servers only.
Introduced in: v3.5.0
javascript.endpoints-whitelist string… Endpoints that can be connected to via @arangodb/request module in JavaScript actions
Default: []
Effective on Coordinators and Single Servers only.
Introduced in: v3.5.0
javascript.environment-variables-blacklist string… Environment variables that will be inaccessible in JavaScript if not whitelisted
Default: []
Effective on Coordinators and Single Servers only.
Introduced in: v3.5.0
javascript.environment-variables-whitelist string… Environment variables that will be accessible in JavaScript
Default: []
Effective on Coordinators and Single Servers only.
Introduced in: v3.5.0
javascript.files-whitelist string… Filesystem paths that will be accessible from within JavaScript actions
Default: []
Effective on Coordinators and Single Servers only.
Introduced in: v3.5.0
javascript.gc-frequency double JavaScript time-based garbage collection frequency (each x seconds)
Default: 60
Effective on Coordinators and Single Servers only.
javascript.gc-interval uint64 JavaScript request-based garbage collection interval (each x requests)
Default: 2000
Effective on Coordinators and Single Servers only.
javascript.harden boolean Disables access to JavaScript functions in the internal module: getPid() and logLevel()
This option can be specified without value to enable it.
Default: false
Effective on Coordinators and Single Servers only.
Introduced in: v3.5.0
javascript.module-directory string… Additional paths containing JavaScript modules
Default: ["./enterprise/js"]
Effective on Coordinators and Single Servers only.
javascript.script string… Run scripts and exit
Default: []
javascript.script-parameter string… Script parameter
Default: []
javascript.startup-directory string Path to the directory containing JavaScript startup scripts
Default: "./js"
Effective on Coordinators and Single Servers only.
javascript.startup-options-blacklist string… Startup options whose names match this regular expression will not be exposed (if not whitelisted) to JavaScript actions
Default: []
Effective on Coordinators and Single Servers only.
Introduced in: v3.5.0
javascript.startup-options-whitelist string… Startup options whose names match this regular expression will be whitelisted and exposed to JavaScript
Default: []
Effective on Coordinators and Single Servers only.
Introduced in: v3.5.0
javascript.v8-contexts uint64 Maximum number of V8 contexts that are created for executing JavaScript actions
Default: 0
Effective on Coordinators and Single Servers only.
javascript.v8-contexts-max-age double Maximum age for each V8 context (in seconds) before it is disposed
Default: 60
Effective on Coordinators and Single Servers only.
javascript.v8-contexts-max-invocations uint64 Maximum number of invocations for each V8 context before it is disposed
Default: 0
Effective on Coordinators and Single Servers only.
javascript.v8-contexts-minimum uint64 Minimum number of V8 contexts that keep available for executing JavaScript actions
Default: 0
Effective on Coordinators and Single Servers only.
javascript.v8-max-heap uint64 Maximal heap size (in MB)
Default: 3072
javascript.v8-options string… Options to pass to v8
Default: []
## LDAP
Name Type Description
ldap.allow-offline boolean Enterprise Edition only
If a refresh attempt fails to connect to the LDAP server, continue with the cached authentication data
This option can be specified without value to enable it.
Default: false
ldap.async-connect boolean Enterprise Edition only
Whether or not the connection to the LDAP library will be done asynchronously
This option can be specified without value to enable it.
Default: false
ldap.basedn string Enterprise Edition only
Ldap basedn, eg. dc=example,dc=com
Default: ""
ldap.binddn string Enterprise Edition only
Ldap binddn, eg. cn=admin,dc=example,dc=com
Default: ""
ldap.bindpasswd string Enterprise Edition only
Ldap bindpassword, eg. admin
Default: ""
ldap.debug boolean Enterprise Edition only
Turn on internal OpenLDAP library output (warning: will print to stdout)
This option can be specified without value to enable it.
Default: false
ldap.enabled boolean Enterprise Edition only
Enable LDAP
This option can be specified without value to enable it.
Default: false
ldap.network-timeout double Enterprise Edition only
Timeout value (in seconds) after which network operations following the initial connection return in case of no activity (a value of 0 means default timeout)
Default: 0
ldap.port uint16 Enterprise Edition only
Port to use
Default: 389
ldap.prefix string Enterprise Edition only
Ldap prefix, eg. uid= xor dn= xor cn=
Default: ""
ldap.referrals boolean Enterprise Edition only
Whether or not the LDAP library should implicitly chase referrals
This option can be specified without value to enable it.
Default: false
ldap.refresh-rate double Enterprise Edition only
Refresh user settings after this time (in seconds)
Default: 300
ldap.restart boolean Enterprise Edition only
Whether or not the LDAP library should implicitly restart connections
This option can be specified without value to enable it.
Default: false
ldap.retries uint32 Enterprise Edition only
Number of tries to attempt connecting to the LDAP server. Setting it to values greater than one will retry connecting in case the LDAP server is unavailable or denies the connection
Default: 1
ldap.roles-attribute-name string Enterprise Edition only
Ldap attributename where the role are located.
Default: ""
ldap.roles-exclude string Enterprise Edition only
Regexp to exclude groups. Leave empty to exclude none.
Default: ""
ldap.roles-include string Enterprise Edition only
Regexp to include groups. Leave empty to include all.
Default: ""
ldap.roles-search string Enterprise Edition only
Ldap search for roles; ‘{USER}’ is replaced by the ‘dn’ of the user.
Default: ""
ldap.roles-transformation string… Enterprise Edition only
Regexp to normalizer role name, e.g. ‘/^ (.[^ ]])*/$2/’
Default: []
ldap.search-attribute string Enterprise Edition only
Ldap search attribute, eg. uid
Default: "uid"
ldap.search-filter string Enterprise Edition only
Ldap search filter, eg. (objectClass=simpleSecurityObject)
Default: "objectClass=*"
ldap.search-scope string Enterprise Edition only
Ldap search scope, one of base, one, sub
Default: "sub"
ldap.serialize-timeout double Enterprise Edition only
Maximum amount of time (in seconds) that will be waited for the serialization mutex
Default: 5
ldap.serialized boolean Enterprise Edition only
Whether or not calls into the LDAP library should be serialized. This option can be used to work around thread-unsafe LDAP library functionality
This option can be specified without value to enable it.
Default: false
ldap.server string Enterprise Edition only
Server to use
Default: ""
ldap.suffix string Enterprise Edition only
Ldap suffix, eg. ,dc=example,dc=com
Default: ""
ldap.superuser-role string Enterprise Edition only
Role mapping to the super-users
Default: ""
ldap.timeout double Enterprise Edition only
Timeout value (in seconds) for synchronous LDAP API calls (a value of 0 means default timeout)
Default: 0
ldap.tls boolean Enterprise Edition only
Enable TLS
This option can be specified without value to enable it.
Default: false
ldap.tls-cacert-dir string Enterprise Edition only
Ldap tls cacert dir
Default: ""
ldap.tls-cacert-file string Enterprise Edition only
Ldap tls cacert file
Default: ""
ldap.tls-cert-check-strategy string Enterprise Edition only
Ldap tls cert check strategy, one of never, hard, demand, allow, try
Default: "hard"
ldap.tls-version string Enterprise Edition only
Ldap tls version, one of 1.0, 1.1, 1.2
Default: "1.2"
ldap.url string Enterprise Edition only
Ldap url, eg. ldap://example.com:389/dc=example,dc=com?uid?sub
Default: ""

+ 32
- 0
src/docs/arangodb/arangodb程序与工具.md 查看文件

@ -0,0 +1,32 @@
# 完成的arangodb软件包工具
二进制名称 简要描述;简介
arangod ArangoDB服务器。该服务器程序旨在作为守护进程/服务运行,以通过TCP / HTTP与服务器建立各种客户端连接。它还提供了一个Web界面。
arangosh ArangoDB shell。客户端,该客户端实现读评估打印循环(REPL)并提供访问和管理ArangoDB服务器的功能。
arangodb ArangoDB Starter,可轻松部署ArangoDB实例。
arangodump 用于创建 ArangoDB数据库备份的工具。
arangorestore 将备份加载回ArangoDB数据库的工具。
arangobackup 工具来进行热备份操作上ArangoDB安装。
arangoimport ArangoDB服务器的批量导入器。它支持JSON和CSV。
arangoexport ArangoDB服务器的批量导出器。它支持JSON,CSV和XML。
arangobench 基准和测试工具。它可以用于性能和服务器功能测试。
arangoinspect 收集服务器设置信息的检查工具。
arangovpack 将VelocyPack数据转换为JSON的实用程序。 \
客户端软件包附带了一部分程序和工具:
arangosh
arangoimport
arangoexport
arangodump
arangorestore
arangobackup
arangobench
arangoinspect
arangovpack
# 单独提供其他工具
单独提供的其他工具:
名称 简要描述;简介
Foxx CLI 用于管理和开发Foxx服务的命令行工具
kube-arangodb 运营商来管理Kubernetes部署
Oasisctl 用于管理ArangoDB Oasis的命令行工具

+ 159
- 0
src/docs/arangodb/减少服务器的内存占用.md 查看文件

@ -0,0 +1,159 @@
# 可以通过不同的配置选项来限制ArangoDB的内存使用并降低CPU使用率
storage engine
edge cache
server statistics
background threads
V8 (JavaScript features)
operating system / memory allocator (Linux)
# 有两个功能可能会占用大量内存
Buffers & Caches
WAL(Write Ahead log)
# WAL和写缓冲区
RocksDB首先写入 映射到磁盘块的内存缓冲区 在某些时候, 内存缓冲区将已满必须将其写入磁盘
为了支持高写入负载, RocksDB可能会打开许多此类内存缓冲区
在正常情况下, 写缓冲区将使用1GB的内存, 如果内存紧张, 可以设置RocksDB设置
--rocksdb.max-total-wal-size 1024000 byte
--rocksdb.write-buffer-size 2048000
--rocksdb.max-write-buffer-number 2
--rocksdb.total-write-buffer-size 8192000
--rocksdb.dynamic-level-bytes false
以上将设置
限制未完成的内存缓冲区数量
将内存使用量限制在100MBbyte
在导入或者更新的过程中, 内存消耗可能仍会更大
另外一方面这些限制将影响最大写入性能,不应该设置低于上面的数字
# 读缓冲区
--rocksdb.block-cache-size 2560000
--rocksdb.enforce-block-cache-size-limit true
一旦内存缓冲区一直保存在磁盘上, 回答读取查询就意味着将他们读回到内存中,
上面的选项会将缓冲区数限制为几兆字节,
如果可能应将此设置为与数据集的热设置大小一样大
这些限制可能会影响查询效率
# 索引和过滤器块缓存
索引和过滤器块默认情况下不缓存, 这意味他们不计入--rocksdb.block-cache-size限制
启用--rocksdb.cache-index-and-fliter-blocks 将其包括上限中的选项
您可以启用其他选项,以避免索引和过滤器块从缓存中逐出。
--rocksdb.cache-index-and-filter-blocks`
--rocksdb.cache-index-and-filter-blocks-with-high-priority
--rocksdb.pin-l0-filter-and-index-blocks-in-cache
--rocksdb.pin-top-level-index-and-filter
# 边缓存
--cache.size 10485760
此选项将ArangoDB边缘缓存限制为10 MB。如果您没有图的用例并且不使用边集合,则可以使用最小值而不影响性能。通常,这应与热定形的大小相对应。
# 其他缓存
除所有缓冲区外,查询在执行期间还将使用其他内存,以处理数据并建立结果集。与缓冲区保留的内存相反,该内存仅在查询执行期间使用,之后将被释放。
# 查询内存使用率固定链接
默认情况下,查询将在内存中建立其完整结果。您可以使用光标逐批获取结果,但每个查询都需要先计算整个结果,然后才能检索第一个批。服务器还需要将结果保存在内存中,直到相应的游标被完全消耗或超时为止。建立完整的结果可以减少服务器不得不花费时间处理主存储器的时间。
在ArangoDB 3.4版中,我们引入了 具有某些倒置属性的流游标:减少了峰值内存使用,对集合的访问时间更长。流可以在文档级别进行,这意味着不能将其应用于所有查询部分。例如,子查询的所有结果的MERGE()不能流式传输(该操作的结果必须完全建立)。但是,周围的查询可能符合流式传输的条件。
除了流游标之外,ArangoDB还提供了指定查询不应超过的内存限制的可能性。如果是这样,查询将被中止。在执行块之间检查内存统计信息,这些块对应于说明输出中的行。这意味着需要功能的查询可能需要更多的内存来进行中间处理,但这不会因为内存而终止查询。
您可以在AQL查询中使用LIMIT操作来减少需要检查和处理的文档数量。然而,这并不总是在幕后发生。其他操作可能会导致在应用任何限制之前计算中间结果。最近,我们向优化器添加了一项新功能:AQL中的 排序限制优化。简而言之,将SORT与LIMIT操作结合使用时,在排序过程中只能将存储的文档数量保持为后续LIMIT所需的数量。从ArangoDB v3.5.0开始自动应用此优化。
# 统计的关闭开启选项
服务器会定期收集 统计信息,并在Web界面中向您显示。即使您的应用程序由于统计信息处于闲置状态,您的查询负载也很少。您可以根据需要禁用它们:
--server.statistics false
# JavaScript和Foxx固定链接
使用嵌入式V8引擎在ArangoDB进程中执行JavaScript:
Web界面的后端部分
Foxx应用
Foxx队列
GraphQL
基于JavaScript的交易
用户定义的AQL功能
有几个V8上下文可以并行执行。您可以将它们视为线程池。它们也称为隔离株。默认情况下,每个隔离区都有几GB的堆。如果不使用JavaScript或使用很少的JavaScript,则可以限制V8:
--javascript.v8-contexts 2
--javascript.v8-max-heap 512
这会将V8隔离株的数量限制为两个。所有与JavaScript相关的请求都将排队,直到其中一个隔离可用于新任务为止。它还将堆大小限制为512 MB,因此在最坏的情况下,两个V8上下文组合使用的内存不能超过1 GB。
# V8 for the Desperate
除非有充分的理由,否则不要使用以下设置,例如性能不重要的本地开发系统或硬件资源非常有限的嵌入式系统!
--javascript.v8-contexts 1
--javascript.v8-max-heap 256
您可以将V8的内存使用量减少到256 MB,而只有一个线程。例如,某些操作可能会因为某些操作耗尽内存而中止,例如在Web界面中。另外,JavaScript请求将被一一执行。
如果您的内存非常紧张,并且确定不需要V8,则可以将其完全禁用:
--javascript.enabled false
--foxx.queues false
因此,以下功能将不可用:
Web界面的后端部分
Foxx应用
Foxx队列
GraphQL
基于JavaScript的交易
用户定义的AQL功能
请注意,可以为群集中的DB-Server和Agency节点禁用JavaScript / V8,而没有这些限制。它们适用于单个服务器实例。它们也适用于Coordinator节点,但是您不应在Coordinators上禁用V8,因为某些集群操作依赖于此。
# CPU使用率固定链接
我们不能真正减少CPU使用率,但是可以并行运行的线程数。同样,除非有很好的理由(例如嵌入式系统),否则您不应这样做。请注意,这将限制并发请求的性能,这对于只有您作为用户的本地开发系统来说可能是可以的。
可以通过以下方式限制后台线程的数量:
--arangosearch.threads-limit 1
--rocksdb.max-background-jobs 4
--server.maintenance-threads 2
--server.maximal-threads 4
--server.minimal-threads 1
通常,选择线程数以适合机器。但是,每个线程至少需要8 MB的堆栈内存。通过牺牲一些用于并行执行的性能,可以减少此性能。
此选项将使日志记录同步:
--log.force-direct true
除非您仅记录错误和警告,否则不建议这样做。
# 缓存分配说明
例子固定链接
通常,您应该在标准服务器上调整读取缓冲区和边缘缓存。如果您有图用例,则应该使用更大的边缘缓存。例如,在读取缓冲区和边缘缓存之间以50:50的比例分配内存。如果没有边缘,则使用最小边缘缓存,并将大部分内存用于读取缓冲区。
例如,如果您有一台具有40 GB内存的计算机,并且想要将ArangoDB的内存限制为20 GB,则如果使用图形功能,则将10 GB用于边缘缓存,将10 GB用于读取缓冲区。
请记住,在查询执行期间,额外的内存将临时用于查询结果。如果您的内存不足,则可能需要每个7 GB。
如果您具有嵌入式系统或开发笔记本电脑,则可以使用上述所有设置来进一步减少内存占用。对于正常操作,特别是生产,不建议使用这些设置。
# Linux系统配置
ArangoDB的主要部署目标是Linux。正如您所了解的,ArangoDB及其内部结构在内存上的工作量很大。因此,至关重要的是要知道ArangoDB和Linux内核如何就此进行交互。linux内核提供了几种如何管理内存的模式。您可以通过proc文件系统,该文件/etc/sysctl.conf或/etc/sysctl.conf.d/系统在引导时将其应用于内核设置的文件来影响此设置。如下所述的设置适用于sysctl基础结构,这意味着它们以映射到proc文件系统/proc/sys/vm/overcommit_memory。
甲vm.overcommit_memory的设定2可以引起在一些环境问题结合捆绑内存分配器ArangoDB附带(jemalloc)。
分配器要求内核提供连续的内存块,这些内存块也映射到磁盘上的块。这是代表服务器进程(arangod)完成的。该过程可能会长时间使用一个块中的某些块,但仅在短时间内使用其他块,因此会释放内存。然后由分配器将释放的部分返回给内核。因为它只能返回连续的内存块,所以它必须将大块拆分为多个小块,然后可以返回未使用的块。
随着vm.overcommit_memory内核设置值2,分配器可能与拆分现有的内存映射,这使得故障数量 的arangod服务器进程随时间增长的内存映射。这可能导致内核拒绝将更多内存分配给Arangod进程,即使有更多物理内存可用。内核将最多只授予vm.max_map_count 每个进程的内存映射,在许多Linux环境中默认为65530。
运行vm.overcommit_memory设置为2的 jemalloc时的另一个问题是,对于某些工作负载,Linux内核随着已提交的内存跟踪的 内存量也会随着时间的推移而增长,而从未减少。最终, arangod可能仅由于达到配置的过量使用限制(物理RAM * overcommit_ratio+交换空间)而无法获得更多的内存。
解决的办法是 修改的值vm.overcommit_memory 从2至任一0或1。这将解决这两个问题。无论使用过量提交设置如何,使用jemalloc时,我们仍然观察到虚拟内存消耗不断增加,但是实际上这不会引起任何问题。0是Linux内核的默认值,也是我们建议的设置。
为了完整起见,让我们还提到另一种解决问题的方法:使用其他内存分配器。这要求从源代码编译ArangoDB而不使用jemalloc(-DUSE_JEMALLOC=Off在对cmake的调用中)。使用系统的libc分配器,您应该会看到相当稳定的内存使用情况。我们还尝试了另一个分配器,恰好是来自的分配器,libmusl随着时间的推移,这也显示出相当稳定的内存使用情况。阻碍我们更改捆绑分配器的原因在于,这是一次微不足道的更改,因为jemalloc对于大型多线程进程具有非常好的性能特征。
测试减少的I / O缓冲区的效果
效果图
15:50 –开始更大的进口
16:00 –一次开始写入〜60 KB大小的文档
16:45 –添加类似的第二作家
16:55 –使用上面建议的RocksDB写缓冲区配置重新启动ArangoDB
17:20 –缓冲区已满,写入性能下降
17:38 – WAL轮播
您在上面的性能图中看到的是限制写缓冲区的后果。在达到90%的写缓冲区填充率之前,服务器几乎可以遵循加载模式一段时间,但代价是不断增加缓冲区。一旦RocksDB达到90%的缓冲区填充率,它将显着将负载限制在〜50%。根据上游文档,这是预期的 :
如果可变存储器的总大小超过限制的90%,则会触发刷新。如果实际内存超出限制,则即使可变存储器的总大小小于90%,也可能触发更积极的刷新。
由于我们仅测量磁盘I / O字节,因此看不到文档保存操作的请求时间也增加了一倍。

+ 20
- 0
src/docs/arangodb/基本安装与启动停止状态系统服务.md 查看文件

@ -0,0 +1,20 @@
# 下载安装包[下载地址](https://www.arangodb.com/download/)
# 简单启动
类unix arangod &
win arangod.exe
# 安装后设置一下root密码
arango-secure-installation
# 创建新用户和新的数据库
arangosh> db._createDatabase("example");
arangosh> var users = require("@arangodb/users");
arangosh> users.save("root@example", "password");
arangosh> users.grantDatabase("root@example", "example");
现在,您可以使用root @ example用户连接到新数据库 。
shell> arangosh --server.username "root@example" --server.database example

+ 0
- 0
src/docs/arangodb/基础配置与系统优化选项配置.md 查看文件


+ 26
- 0
src/docs/centos/centos8换源.md 查看文件

@ -0,0 +1,26 @@
# CentOS 8 换源,设置dnf / yum镜像
aliyun更新了centos8的说明
1、备份
mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.backup
2、下载新的CentOS-Base.repo 到/etc/yum.repos.d/
curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-8.repo
3、生成缓存
yum makecache
4 配置镜像的。
cd /etc/yum.repos.d
#备份
cp CentOS-Base.repo CentOS-Base.repo.bak;
cp CentOS-AppStream.repo CentOS-AppStream.repo.bak;
cp CentOS-Extras.repo CentOS-Extras.repo.bak;
sed -i 's/mirrorlist=/#mirrorlist=/g' CentOS-Base.repo CentOS-AppStream.repo CentOS-Extras.repo;
sed -i 's/#baseurl=/baseurl=/g' CentOS-Base.repo CentOS-AppStream.repo CentOS-Extras.repo;
sed -i 's/http:\/\/mirror.centos.org/https:\/\/mirrors.aliyun.com/g' CentOS-Base.repo CentOS-AppStream.repo CentOS-Extras.repo

+ 34
- 0
src/docs/centos/centosGcc升级.md 查看文件

@ -0,0 +1,34 @@
# log
由于部分nif依赖于c99编译,而部分环境gcc版本低于依赖导致编译不过,特此记录Gcc升级命令
# 步骤
1. 安装centos-release-scl
sudo yum install centos-release-scl
2. 查看最新的版本并安装
yum list | grep devtoolset 然后选择你想要安装的版本,比如:
sudo yum install devtoolset-9-gcc*
3. 激活对应的devtoolset,所以你可以一次安装多个版本的devtoolset,需要的时候用下面这条命令切换到对应的版本
scl enable devtoolset-9 bash
gcc -v
注意:::这条激活命令只对本次会话有效,重启会话后还是会变回原来的版本 想随意切换可按如下操作。
首先,安装的devtoolset是在 /opt/sh 目录下的,如图
每个版本的目录下面都有个 enable 文件,如果需要启用某个版本,只需要执行
source ./enable
所以要想切换到某个版本,只需要执行
source /opt/rh/devtoolset-8/enable
可以将对应版本的切换命令写个shell文件放在配了环境变量的目录下,需要时随时切换,或者开机自启
4. 直接替换旧的gcc
旧的gcc是运行的 /usr/bin/gcc,所以将该目录下的gcc/g++替换为刚安装的新版本gcc软连接,免得每次enable
复制代码
mv /usr/bin/gcc /usr/bin/gcc-4.8.5
ln -s /opt/rh/devtoolset-8/root/bin/gcc /usr/bin/gcc
mv /usr/bin/g++ /usr/bin/g++-4.8.5
ln -s /opt/rh/devtoolset-8/root/bin/g++ /usr/bin/g++
gcc --version
g++ --version

+ 3
- 0
src/docs/centos/centos不能显示中文解决办法.md 查看文件

@ -0,0 +1,3 @@
# 解决办法
安装中文包即可
dnf install langpacks-zh_CN

+ 9
- 0
src/docs/centos/centos同步时间.md 查看文件

@ -0,0 +1,9 @@
# 安装ntpdate工具
yum -y install ntp ntpdate
# 设置系统时间与网络时间同步
ntpdate 0.asia.pool.ntp.org
这里主要就是通过时间服务器对系统时间进行同步,所以0.asia.pool.ntp.org并不是固定的,大家可以选择time.nist.gov、time.nuri.net、0.asia.pool.ntp.org、1.asia.pool.ntp.org、2.asia.pool.ntp.org、3.asia.pool.ntp.org中任意一个,只要保证可用就OK
# 将系统时间写入硬件时间
hwclock --systohc
这里是为了防止系统重启后时间被还原,因此需要写到硬件设备中去。

+ 14
- 0
src/docs/centos/ssh安装与配置.md 查看文件

@ -0,0 +1,14 @@
# 安装
yum install openssl
yum install openssl_server
# ssh 生成密钥
ssh-keygen -q -t rsa -b 2048 -f /etc/ssh/ssh_host_rsa_key -N '' ;
ssh-keygen -q -t ecdsa -f /etc/ssh/ssh_host_ecdsa_key -N '';
ssh-keygen -t dsa -f /etc/ssh/ssh_host_ed25519_key -N '';
8、配置ssh无密码登录
先退出 ssh客户端
ssh-keygen -t rsa
cd ~/.ssh
cat id_rsa.pub >> authorized_keys

+ 19
- 0
src/docs/erlang/elangtrycatch说明.md 查看文件

@ -0,0 +1,19 @@
# catch
catch Expr
除非评估期间发生异常,否则返回Expr的值。在这种情况下,将捕获异常。
对于类错误(即运行时错误)的异常,将返回 {'EXIT',{Reason,Stack}}。
对于类exit的异常,即返回称为exit(Term), {'EXIT',Term}的代码。
对于类throw的异常(即称为throw(Term)的代码), 将返回Term。
原因取决于发生的错误的类型, 堆栈是最近的函数调用的堆栈,
catch error会返回堆栈 性能低
catch exit/throw 不会返回堆栈 但是性能比普通函数调用低几倍
# try catch
匹配格式为Clcass:Reason:Strace 并且 使用了Strace的时候 会返回堆栈 性能 跟 catch error 差不多
如果不匹配strace或者匹配了不使用Strace, try catch exit error throw 性能跟catch exit/throw差不多, 无太大差别

+ 5600
- 0
src/docs/erlang/erlang-DsBenchMark.txt
文件差異過大導致無法顯示
查看文件


+ 88
- 0
src/docs/erlang/erlangApp相关.md 查看文件

@ -0,0 +1,88 @@
文件命名为
application_Name.app
格式如下:
{application,"app名字",
[
{description,"app描述"},
{vsn ,"版本号"},
{id ,Id},%%app id 同 erl -id ID
{modules,[Modules]},%%app包含的模块,systools模块使用它来生成script、tar文件
{maxP,Num},%%进程最大值
{maxT,Time},%%app运行时间 单位毫秒
{registered,[mod]},%%指定app 名字模块,systools用来解决名字冲突
{included_applictions ,[XX]},%%指定子 app,只加载,但是不启动
{applictions,[xxxx]},%%启动自己的app前,appliation:ensure_all_started将会首先启动此列表的app application:start会检查该列表是否都启动
{env,[xxxx]},%%配置app的env,可以使用application:get_env(AppName, Key)获取
{mod,{xxx,args}},%%指定app启动模块,参数,对应自己app的application behavior
{start_phases,[{xxx,xxx}]]%%指定启动阶段一些操作,对应otp application start_phase函数
]
}
必须要配置的为description,vsn,modules,registered,applications。
Application为应用名,
descripttion为应用的简单描述
id 产品标识
vsn 应用版本
modules 应用所涉及到的module
registered 注册进程
applications 本应用启动时需要事先启动的其他应用
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
erlang官网说明
{application, Application,
[{description, Description},
{id, Id},
{vsn, Vsn},
{modules, Modules}, 本应用程序引入的所有模块。systools 在生成启动脚本和tar文件时使用这个列表。一个模块只能在一个应用程序中定义
{maxP, MaxP}, 已经弃用了
{maxT, MaxT}, 时间单位为毫秒
{registered, Names}, 注册过程的所有名称均在此应用程序中启动。systools使用这个列表来检测不同应用程序之间的名字冲突
{included_applications, Apps}, 此应用程序包含的所有应用程序 当此应用程序启动时,应用程序控制器会自动加载所有包含的应用程序,但不会启动。假设包含应用程序的最高管理者由本应用程序的主管启动
{applications, Apps}, 允许启动此应用程序之前必须启动的所有应用程序。systools使用这个列表来生成正确的启动脚本。缺省为空列表,但请注意所有应用程序对(至少)Kernel和STDLIB都有依赖关系
{env, Env}, 应用程序使用的配置参数。通过调用application:get_env / 1,2来检索配置参数的值
{mod, Start}, 指定应用程序回调模块和启动参数
对于作为监督树实施的应用程序,密钥mod是必需的,否则应用程序控制器不知道如何启动它。 对于没有进程的应用程序(通常是代码库,例如STDLIB),可以省略mod
{start_phases, Phases},
{runtime_dependencies, RTDeps}]}. 应用程序依赖的应用程序版本列表
Value Default
----- -------
Application atom() -
Description string() ""
Id string() ""
Vsn string() ""
Modules [Module] []
MaxP int() infinity
MaxT int() infinity
Names [Name] []
Apps [App] []
Env [{Par,Val}] []
Start {Module,StartArgs} []
Phases [{Phase,PhaseArgs}] undefined
RTDeps [ApplicationVersion] []
Module = Name = App = Par = Phase = atom()
Val = StartArgs = PhaseArgs = term()
ApplicationVersion = string()
如果要使用systools中的函数 需要设置下面的key参数
description vsn modules registered applications
其他的key被systools忽略
应用的策略
application:start(Name, Type)
type:
• permanent: if the app terminates, the entire system is taken down, excluding manual termination of the app with application:stop/1.
• transient: if the app terminates for reason normal, that’s ok. Any other reason for termination shuts down the entire system.
• temporary: the application is allowed to stop for any reason. It will be reported, but nothing bad will happen.

+ 3
- 0
src/docs/erlang/erlangNif中内存分配推荐使用enif_alloc.md 查看文件

@ -0,0 +1,3 @@
# 为什么更加更加使用enif_alloc而不是使用malloc
enif_alloc使用内部erlang内存分配器,这意味着,如果内部VM高速缓存中已存在该内存,则它可以使用该内存,而不用执行系统调用来获取该内存。在某些情况下,这可能会导致更快的内存分配,您必须使用代码进行衡量,以找出是否有任何区别。通常,我建议使用enif_alloc。
如果我没记错的话,在发出erlang:memory命令时,还可以使用enif_alloc来包括所使用的内存。

+ 64
- 0
src/docs/erlang/erlangNif编程相关.md 查看文件

@ -0,0 +1,64 @@
# 描述
NIF库包含Erlang模块的某些功能的本机实现。像其他任何函数一样,调用本机实现的函数(NIF),与调用方没有任何区别。
NIF库被构建为动态链接的库文件,并通过调用erlang:load_nif / 2在运行时加载。
警告
谨慎使用此功能。
执行本机功能作为VM的本机代码的直接扩展。执行不是在安全的环境中进行的。VM 无法提供与执行Erlang代码时相同的服务,
例如抢先式调度或内存保护。如果本机功能运行不正常,则整个VM都会出现异常。
崩溃的本机功能将使整个VM崩溃。
错误实现的本机功能可能会导致VM内部状态不一致,从而导致VM崩溃或在调用本机功能后的任何时候VM的其他异常行为。
在返回之前进行长时间工作的本机功能会降低VM的响应能力,并可能导致其他奇怪的行为。这种奇怪的行为包括但不限于极端的内存
使用情况以及调度程序之间的不良负载平衡。在Erlang / OTP发行版之间,由于冗长的工作而可能发生的奇怪行为也会有所不同。
# 简单示例
```
/* niftest.c */
#include <erl_nif.h>
static ERL_NIF_TERM hello(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
return enif_make_string(env, "Hello world!", ERL_NIF_LATIN1);
}
static ErlNifFunc nif_funcs[] =
{
{"hello", 0, hello}
};
ERL_NIF_INIT(niftest,nif_funcs,NULL,NULL,NULL,NULL)
```
```
-module(niftest).
-export([init/0, hello/0]).
-on_load(init/0).
init() ->
erlang:load_nif("./niftest", 0).
hello() ->
erlang:nif_error("NIF library not loaded").
```
在上面的示例中,使用了on_load指令,该命令功能是在加载模块时自动调用的指定的函数-init/0。
init函数初始化依次调用erlang:load_nif / 2 ,
该加载器会加载NIF库,并用C中的本机实现替换hello函数。加载后,NIF库将保持不变。在清除它所属的模块代码版本之前,不会将其卸载。
如果在成功加载NIF库之前调用了该函数,则每个NIF必须具有用Erlang调用的实现。典型的此类存根实现是调用erlang:nif_error,
这将引发异常。如果NIF库缺少某些操作系统或硬件体系结构的实现,则Erlang函数也可以用作后备实现。
注意
NIF不必导出,它可以在模块本地。但是,编译器会优化未使用的本地存根函数,从而导致NIF库的加载失败。
# 功能性
NIF代码和Erlang运行时系统之间的所有交互都是通过调用NIF API函数来执行的。存在以下功能的功能:
读写Erlang术语
任何Erlang术语都可以作为函数参数传递给NIF,并作为函数返回值返回。这些术语属于C类型的 ERL_NIF_TERM,只能使用API​​函数读取或写入。大部分用于读取术语内容的函数都以enif_get_为前缀,并且如果该术语属于预期类型(或非预期类型),则通常返回 true(或false)。编写术语的函数都带有enif_make_前缀 ,通常返回创建的ERL_NIF_TERM。还有一些查询术语的函数,例如enif_is_atom,enif_is_identical和enif_compare。
类型的所有方面ERL_NIF_TERM属于类型的环境ErlNifEnv。术语的生存期由其环境对象的生存期控制。读取或写入术语的所有API函数都将术语所属的环境作为第一个函数参数
增加和减少资源的引用计数的次数必须匹配,否则可能引发问题。
至此,持久资源的主要接口的实现就介绍完了,用户使用时,可以先通过enif_open_resource_type建立资源类型的描述符,
然后利用此描述符,使用enif_alloc_resource分配资源所占用的内存空间,使用enif_make_resource将资源导出到erlang模块层,
在进程间传递资源描述符,资源再传回NIF时,可以通过enif_get_resource取回资源描述符中的资源数据结构,
同时可以通过enif_keep_resource来共享资源,通过enif_release_resource来放弃使用资源,gc系统也会正确回收引用计数为0的资源,
开发者再也不用担心内存没有被正确释放了。
持久资源为NIF的开发带来了极大的便利,用户可以将一些大规模的数据结构一次传入内存,生成一个资源描述符,
然后在进程间传递资源描述符而不是资源数据本身,减轻每次资源数据拷贝的开销,同时持久资源也是线程安全的,
写erlang程序也可以像写c程序一样高效了。

+ 243
- 0
src/docs/erlang/erlangSupervisor相关.md 查看文件

@ -0,0 +1,243 @@
### 监督原则
主管负责启动,停止和监视其子进程。主管的基本思想是,必须通过在必要时重新启动子进程来保持其子进程活动。
主管的孩子被定义为孩子规格列表 。当主管启动时,将根据此列表从左到右依次启动子进程。主管终止时,它首先以相反的启动顺序从右到左终止其子进程。
sup_flags() =
#{strategy => strategy(), % optional
intensity => non_neg_integer(), % optional
period => pos_integer() % optional
}
#### 重启策略
one_for_one-如果一个子进程终止并要重新启动,则仅影响该子进程。这是默认的重启策略。
one_for_all-如果一个子进程终止并要重新启动,则所有其他子进程均终止,然后重新启动所有子进程。
rest_for_one-如果一个子进程终止并要重新启动,则子进程的“剩余”(即,按照启动顺序终止的子进程之后的子进程)将终止。
然后,终止的子进程以及重新启动后的所有子进程。
simple_one_for_one-简化的one_for_one 主管,其中所有子进程都是动态添加的,具有相同进程类型(即,运行相同代码)的实例。
功能 delete_child / 2和 restart_child / 2 是无效simple_one_for_one监事和回报 {错误,simple_one_for_one}如果指定的主管使用此重启策略。
通过将子级的pid()指定为第二个参数,可以将函数terminate_child / 2用于simple_one_for_one主管下的子级。
如果改用子规范标识符,则 terminate_child / 2返回 {error,simple_one_for_one}。
由于simple_one_for_one主管可以有多个子代,因此它会异步关闭所有子代。这意味着孩子们并行进行清理,因此未定义他们停止的顺序
为了防止主管进入子进程终止和重新启动的无限循环,使用上面映射中的键强度和周期指定的两个整数值来定义最大重新启动强度。
假设值MAXR为强度 和MAXT为周期,然后,如果超过MAXR 重新启动内发生MAXT秒,监控终止所有的子进程,然后本身。在这种情况下,
主管本身的终止原因将被关闭。 强度默认为1,期间默认为 5。
#### 子进程规范
child_spec() =
#{
id => child_id(), % mandatory
start => mfargs(), % mandatory
restart => restart(), % optional
shutdown => shutdown(), % optional
type => worker(), % optional
modules => modules() % optional
}
id用于由主管内部标识子规范。该ID关键是强制性的。
请注意,这个在职业上的标识符被称为“名称”。现在尽可能使用术语“标识符”或“ id”,但为了保持向后兼容性,仍然可以找到“名称”的某些出现,例如在错误消息中。
start定义用于启动子进程的函数调用。它必须是用作apply(M,F,A)的模块功能参数元组{M,F,A}。
启动函数必须创建并链接到子进程,并且必须返回{ok,Child}或 {ok,Child,Info},其中Child是子进程的pid,Info是主管忽略的任何术语。
restart定义终止的子进程何时必须重新启动。
一个permanent 的子进程总是会重启。
一个temporary 的子进程不会再重新启动(甚至当主管的重启策略是rest_for_one或one_for_all和兄弟姐妹的死亡原因临时进程被终止)。
一个transient的子进程重新启动,只有当它异常终止,即与另一个出口原因,而不是 normal,shutdown,或{shutdown,Term}。
该restart是可选的。如果未指定,则默认为permanent.。
shutdown定义必须终止子进程的方式。
brutal_kill意味着子进程使用exit(Child,kill)无条件终止
整数超时值表示主管通过调用exit(Child,shutdown)告诉子进程终止 ,然后等待退出信号,原因是该子进程退出了shutdown。如果在指定的毫秒数内未收到退出信号,则使用exit(Child,kill)无条件终止子进程 。
infinity 如果子进程是另一个主管,则必须将关闭时间设置为infinity,以使子树有足够的时间关闭。
对于类型为Supervisor的孩子,将关闭时间设置为无穷大以外的任何时间,都 可能导致比赛状态,在该情况下,所讨论的孩子会取消其自己的孩子的链接,但无法在杀死孩子之前终止他们。
如果子进程是工作进程,也可以将其设置为infinity。
当子进程为工作进程时,将关闭时间设置为无穷大时要小心 。因为在这种情况下,监视树的终止取决于子进程,所以它必须以安全的方式实现,并且其清除过程必须始终返回。
在shutdown 是可选的。如果未指定,则在子类型为worker的情况下默认为5000,在子类型为supervisor的情况下默认为infinity。
type specifies if the child process is a supervisor or a worker.
该type关键是可选的。如果未指定,则默认为worker。.
modules 在代码替换期间,释放处理程序将使用modules模块来确定哪些进程正在使用某个模块。作为一个经验法则,如果孩子过程是一个 主管,gen_server或,
gen_statem,这是为与一个元素列表[模块],其中模块是回调模块。如果子进程是具有动态回调模块集的事件管理器(gen_event),则 必须使用动态值。
有关发布处理的更多信息,请参见 OTP设计原则中的发布处理。
该modules的关键是可选的。如果未指定,则默认为[M],其中M来自孩子的开头{M,F,A}。
Internally 主管还跟踪PID的 孩子的孩子的过程中,或者不确定如果没有PID存在。
#### 函数
count_children(SupRef) -> PropListOfCounts
Types SupRef = sup_ref()
PropListOfCounts = [Count]
Count =
{specs, ChildSpecCount :: integer() >= 0} | 已死或活着的孩子总数。
{active, ActiveProcessCount :: integer() >= 0} | 此主管管理的所有正在运行的子进程的计数
对于 simple_one_for_one主管,不会执行任何检查以确保每个子进程仍处于活动状态,尽管除非主管非常重载,否则此处提供的结果可能非常准确。
{supervisors, ChildSupervisorCount :: integer() >= 0} | 规范列表中标记为child_type =主管的所有子进程的计数 ,无论该子进程是否仍在运行
{workers, ChildWorkerCount :: integer() >= 0} -标记为所有儿童的数量 CHILD_TYPE =工人在规范列表中,如果不管孩子进程仍然活着。
delete_child(SupRef, Id) -> Result
Types SupRef = sup_ref()
Id = child_id()
Result = ok | {error, Error}
Error = running | restarting | not_found | simple_one_for_one
告诉主管SupRef删除Id标识的子规范。相应的子进程一定不能运行。使用 terminate_child / 2终止它。
如果成功,函数将返回ok。如果存在由ID标识的子规范,但相应的子进程正在运行或将要重新启动,则该函数分别返回{error,running}或 {error,restarting}。如果由ID标识的子规范不存在,则该函数返回{error,not_found}。
get_childspec(SupRef, Id) -> Result
Types
SupRef = sup_ref()
Id = pid() | child_id()
Result = {ok, child_spec()} | {error, Error}
Error = not_found
返回由Id在主管SupRef下标识的子项的子项规范图。返回的映射包含所有键,包括必需键和可选键。
restart_child(SupRef, Id) -> Result
Types
SupRef = sup_ref()
Id = child_id()
Result =
{ok, Child :: child()} |
{ok, Child :: child(), Info :: term()} |
{error, Error}
Error =
running | restarting | not_found | simple_one_for_one | term()
告诉主管SupRef重新启动与Id标识的子规范相对应的子进程。子规范必须存在,并且相应的子进程一定不能运行。
注意,对于临时子代,子代说明在子代终止时会自动删除;因此,不可能重新启动此类子级。
如果由ID标识的子规范不存在,则该函数返回{error,not_found}。如果子规范存在但相应的进程已在运行,则该函数返回{error,running}。
如果子进程启动函数返回{ok,Child} 或{ok,Child,Info},则将pid添加到主管,并且该函数返回相同的值。
如果子进程启动函数返回ignore,则pid保持设置为undefined,该函数返回{ok,undefined}。
如果子进程启动函数返回错误元组或错误值,或者失败,则该函数返回 {error,Error},其中Error是包含有关错误信息的术语。
start_child(SupRef, ChildSpec) -> startchild_ret()
Types
SupRef = sup_ref()
ChildSpec = child_spec() | (List :: [term()])
startchild_ret() =
{ok, Child :: child()} |
{ok, Child :: child(), Info :: term()} |
{error, startchild_err()}
startchild_err() =
already_present | {already_started, Child :: child()} | term()
ChildSpec必须是有效的子规范(除非主管是simple_one_for_one 主管;请参见下文)。通过使用子规范中定义的启动功能来启动子进程。
对于simple_one_for_one主管,将使用Module:init / 1中定义的子规范,而ChildSpec必须改为是List的任意列表。然后,通过将List附加到现有的启动函数参数(即,通过调用apply(M,F,A ++ List))来 启动子进程,其中{M,F,A}是子规范中定义的启动函数。
如果已经存在带有指定标识符的子规范,则将丢弃ChildSpec,并且该函数将根据相应的子进程是否在运行而返回{error,already_present}或 {error,{already_started,Child}}。
如果子进程启动函数返回 {ok,Child}或 {ok,Child,Info},则将子规范和pid添加到主管,并且该函数返回相同的值。
如果子进程启动函数返回ignore,则将子规范添加到主管(除非该主管是simple_one_for_one主管,请参见下文),将pid设置为undefined,并且该函数返回 {ok,undefined}。
对于simple_one_for_one主管,当子进程启动函数返回ignore时,该函数将返回 {ok,undefined},并且没有子级添加到主管。
如果子进程启动函数返回错误元组或错误值,或者失败,则子规范被丢弃,函数返回{error,Error},其中 Error是包含有关错误和子规范的信息的术语。
start_link(模块,Args)-> startlink_ret()
start_link(SupName,Module,Args)-> startlink_ret()
种类
SupName = sup_name()
模块= module()
Args = term()
startlink_ret()=
{确定,pid()} | 忽略| {错误,startlink_err()}
startlink_err()=
{已经开始,pid()} | {关机,term()} | 术语()
sup_name()=
{本地,名称:: atom()} |
{global,Name :: atom()} |
{via,Module :: module(),Name :: any()}
创建一个监督程序,作为监督树的一部分。例如,该功能可确保主管链接到呼叫过程(其主管)。
创建的主管进程将调用 Module:init / 1来查找有关重启策略,最大重启强度和子进程的信息。为了确保同步启动过程,在返回Module:init / 1并启动所有子进程之前,不会返回 start_link / 2,3。
如果SupName = {local,Name},则主管使用register / 2在本地注册为Name。
如果SupName = {global,Name},则使用 global:register_name / 2将主管全局注册为Name。
如果 SupName = {via,Module,Name},则使用Module表示的注册表将主管注册为Name。所述模块的回调必须导出功能REGISTER_NAME / 2, unregister_name / 1,和发送/ 2,它必须表现得像在相应的功能 全球。因此, {via,global,Name}是有效的引用。
如果未提供姓名,则主管未注册。
模块是回调模块的名称。
Args是作为参数传递给Module:init / 1的任何术语。
如果成功创建了主管及其子进程(即,如果所有子进程启动函数都返回 {ok,Child},{ok,Child,Info}或ignore),则该函数返回{ok,Pid},其中Pid是主管的pid。
如果已经存在具有指定SupName的进程,则 该函数返回 {error,{already_started,Pid}},其中Pid是该进程的pid。
如果Module:init / 1返回ignore,则此函数也返回ignore,并且supervisor因normal终止。
如果Module:init / 1失败或返回错误值,则此函数返回{error,Term},其中 Term是包含有关错误信息的术语,而主管则以Term终止。
如果任何子进程启动功能失败或返回错误的元组或错误值,则主管首先使用原因shutdown终止所有已启动的子进程, 然后终止自身并返回 {error,{shutdown,Reason}}。
Terminate_child(SupRef,Id)->结果
种类
SupRef = sup_ref()
ID = pid()| child_id()
结果=正常| {错误,错误}
错误=找不到| simple_one_for_one
告诉主管SupRef终止指定的孩子。
如果主管不是simple_one_for_one,则 ID必须是子规范标识符。该过程(如果有的话)将终止,并且除非它是一个临时子进程,否则该子进程规范将由主管保留。子进程以后可以由主管重新启动。子进程也可以通过调用restart_child / 2显式重启 。使用 delete_child / 2 删除子级规范。
如果子级是临时的,则该子级规范将在过程终止后立即删除。这意味着delete_child / 2没有意义,并且restart_child / 2不能用于这些子级。
如果主管是simple_one_for_one,则 ID 必须是子进程的pid()。如果指定的进程处于活动状态,但不是指定的主管的子进程,则该函数返回 {error,not_found}。如果指定了子规范标识符而不是pid(),则函数返回{error,simple_one_for_one}。
如果成功,函数将返回ok。如果没有带有指定ID的子规范,则该函数返回{error,not_found}。
有关SupRef的描述,请参见 start_child / 2。
which_children(SupRef)-> [{Id,Child,Type,Modules}]
种类
SupRef = sup_ref()
ID = child_id() | 未定义
子= 子() | 重新开始
类型= worker()
模块= modules()
返回一个新创建的列表,其中包含有关属于主管SupRef的所有子规范和子进程的信息。
请注意,在内存不足的情况下监视多个子项时调用此函数可能会导致内存不足异常。
有关SupRef的描述,请参见 start_child / 2。
为每个子规范/过程提供以下信息:
Id-在子规范中定义,或 为simple_one_for_one主管未定义。
子 -相应子进程的pid,如果该进程将要重新启动,则原子重新启动;如果没有这样的进程,则未定义。
类型 -子规范中定义的类型。
模块 -子规范中定义的模块。
Module:init(Args)->结果
种类
Args = term()
结果= {确定,{SupFlags,[ChildSpec]}} | 忽视
SupFlags = sup_flags()
ChildSpec = child_spec()
每当使用start_link / 2,3启动管理员时 ,新进程就会调用此函数以查找有关重新启动策略,最大重新启动强度和子级规范的信息。
Args是提供给start函数的Args参数。
SupFlags是主管标志,用于定义主管的重新启动策略和最大重新启动强度。[ChildSpec]是有效的子规范的列表,这些规范定义了主管必须启动和监视的子进程。请参阅前面的“ 监督原则”一节中的讨论 。
请注意,当重新启动策略为 simple_one_for_one时,子规范的列表必须是仅包含一个子规范的列表。(忽略子规范标识符。)然后,在初始化阶段不启动任何子进程,但是假定所有子进程都使用start_child / 2动态启动 。
该函数还可以返回ignore。
请注意,此功能也可以作为代码升级过程的一部分来调用。因此,该功能不应有任何副作用。有关管理程序代码升级的更多信息,请参阅《OTP设计原则》中的“ 更改管理程序”部分 。

+ 44
- 0
src/docs/erlang/erlangVS环境编译nifdll.md 查看文件

@ -0,0 +1,44 @@
# window下编译nif dll 需要安装vs
## 第一种 makefile配置(可参考jiffy的Makefile) 命令行下编译dll 需要设置vs相关环境变量
具体要设置的环境变量可参考下面几个
```
path 新增
D:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Tools\MSVC\14.24.28314\bin\Hostx64\x64
%% E:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\VC\Tools\MSVC\14.27.29110\bin\Hostx64\x64
LIB
D:\Windows Kits\10\Lib\10.0.18362.0\ucrt\x64
D:\Windows Kits\10\Lib\10.0.18362.0\um\x64
D:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Tools\MSVC\14.24.28314\lib\x64
%% E:\Windows Kits\10\Lib\10.0.18362.0\ucrt\x64
%% E:\Windows Kits\10\Lib\10.0.18362.0\um\x64
%% E:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\VC\Tools\MSVC\14.27.29110\lib\x64
INCLUDE
D:\Windows Kits\10\Include\10.0.18362.0\ucrt
D:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Tools\MSVC\14.24.28314\include
%% E:\Windows Kits\10\Include\10.0.18362.0\ucrt
%% E:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\VC\Tools\MSVC\14.27.29110\include
```
### 脚本配置
VsDevCmd.bat 文件设置适当的环境变量来生成命令行。
备注
Visual Studio 2015 及更早版本基于相同目的使用 VSVARS32.bat,而不是 VsDevCmd.bat。
此文件保存在
Program Files\Microsoft Visual Studio\Version \Common7\Tools 或
Program Files (x86)\Microsoft Visual Studio\Version \Common7\Tools。
## 第二种 在vs单独编译 然后拷贝使用
VS编译
1 新建空项目或者从现有代码创建项目
2 先选择 编辑框上边的 解决方案配置 与 解决方案平台
3 右键项目属性 设置 配置与第2步 解决方案配置 一样 设置 平台与第二步设置的 解决方案平台 一样
4 右键项目属性 配置属性 -> 常规 -> 配置类型 ->动态库(.dll)
5 右键项目属性 配置属性 -> VC++目录 -> 包含目录 新增 D:\Program Files\erl10.6\erts-10.6\include
6 右键项目属性 生成
注意编译使用的erlang include要合使用的erl版本对应

+ 95
- 0
src/docs/erlang/erlang二进制.md 查看文件

@ -0,0 +1,95 @@
## 二进制语法
Bin = <<E1, E2, ... En>>
<<E1, E2, ... En>> = Bin
每个E 1..n 指定bitstring的Segment
每个段具有以下一般语法:
Value:Size/TypeSpecifierList
可以省略Size或TypeSpecifier或两者。因此,允许以下变体:
Ei =
Value |
Value:Size |
Value/TypeSpecifierList |
Value:Size/TypeSpecifierList
### Value
当在二进制构造中使用时,Value部分是任何表达式,用于求值为整数,浮点或位串,如果表达式不是单个文字或变量,则将其括在括号中。
在二进制匹配中使用时,用于位串匹配,Value必须是变量,或整数,浮点或字符串,简单而言就是Value部分必须是文字或变量。
### Size
在位串构造中使用,Size是要求求整数的表达式。
用于位串匹配,Size必须是整数,或绑定到整数的变量。
Size的值以Unit指定段的大小,默认值取决于类型
• For integer it is 8.
• For float it is 64.
• For binary and bitstring it is the whole binary or bit string.
在匹配中,此默认值仅对最后一个元素有效。匹配中的所有其他位串或二进制元素必须具有大小规范,段的大小Size部分乘以TypeSpecifierList中的unit(稍后描述)给出了段的位数.对于utf8,utf16和utf32类型,不得给出Size的大小。段的大小由类型和值本身隐式确定。
### TypeSpecifierList
是一个类型说明符列表,按任何顺序,用连字符("-")分隔。默认值用于任何省略的类型说明符
#### Type
Type= integer | float | binary | bytes | bitstring | bits | utf8 | utf16 | utf32
默认值为integer。bytes是二进制的简写,bits是bitstring的简写。有关utf类型的更多信息,请参见下文。
#### Signedness
Signedness= signed | unsigned
只有匹配和类型为整数时才有意义。默认值为无符号。
#### Endianness
Endianness= big | little | native
Native-endian意味着字节顺序在加载时被解析为big-endian或little-endian,具体取决于运行Erlang机器的CPU的本机内容。仅当Type为integer,utf16,utf32或float时,字节顺序才有意义。默认值为big。
#### Unit
Unit= unit:IntegerLiteral
允许的范围是1..256。对于integer,float和bitstring,默认值为1;对于binary,默认值为8。对于utf8,utf16和utf32类型,不能给出Unit说明符。
它与Size说明符相乘,以给出段的有效大小。单位大小指定没有大小的二进制段的对齐方式,二进制类型的段必须具有可被8整除的大小
### 注意
构造二进制文件时,如果整数段的大小N太小而不能包含给定的整数,则整数的最高有效位将被静默丢弃,并且只有N个最低有效位被放入二进制。
#### 例子:
X:4/little-signed-integer-unit:8
该元素的总大小为4 * 8 = 32位,它包含一个小端序的有符号整数
### 关于 utf8 utf16 utf32
构造utf类型的段时,Value必须是0..16#D7FF或16#E000 .... 16#10FFFF范围内的整数。如果Value超出允许范围,则构造将失败并返回badarg异常。生成的二进制段的大小取决于类型或值,或两者:
• For utf8, Value is encoded in 1-4 bytes.
• For utf16, Value is encoded in 2 or 4 bytes.
• For utf32, Value is always be encoded in 4 bytes.
构造时,可以给出一个文字字符串,后跟一个UTF类型,例如:<<“abc”/ utf8 >>,这是<< $ a / utf8,$ b / utf8,$ c / utf8的语法糖>>。
成功匹配utf类型的段,得到0..16#D7FF或16#E000..16#10FFFF范围内的整数。
如果返回值超出这些范围,则匹配失败。
### 如何实现二进制文件
在内部,二进制和位串以相同的方式实现。
内部有四种类型的二进制对象:
两个是二进制数据的容器,称为:
• Refc binaries (short for reference-counted binaries)
• Heap binaries
两个仅仅是对二进制文件的一部分的引用,被称为:
• sub binaries
• match contexts
### Refc Binaries
Refc二进制文件由两部分组成:
•存储在进程堆上的对象,称为ProcBin
•二进制对象本身,存储在所有进程堆之外
任何数量的进程都可以通过任意数量的ProcBins引用二进制对象。该对象包含一个引用计数器,用于跟踪引用的数量,以便在最后一个引用消失时将其删除。
进程中的所有ProcBin对象都是链表的一部分,因此当ProcBin消失时,垃圾收集器可以跟踪它们并减少二进制文件中的引用计数器。
### Heap Binaries
堆二进制文件是小型二进制文件,最多64个字节,并直接存储在进程堆上。它们在进程被垃圾收集时以及作为消息发送时被复制。它们不需要垃圾收集器进行任何特殊处理。
### Sub Binaries
The reference objects sub binaries and match contexts can reference part of a refc binary or heap binary
子二进制文件由split_binary / 2创建或者当二进制文件以二进制模式匹配时。子二进制是对另一个二进制文件(refc或堆二进制文件的一部分,但从不进入另一个子二进制文件)的引用。因此,匹配二进制文件相对便宜,因为实际的二进制数据永远不会被复制。
### Match Context
匹配上下文类似于子二进制,但针对二进制匹配进行了优化
### 关于iolist
定义(直接引用霸爷的文章)
1. []
2. binary
3. 列表, 每个元素是int(0-255)或者binary或者iolist.
其中binary是指 bitsize % 8 == 0 .
int 是0-255
Iolist的作用是用于往port送数据的时候.由于底层的系统调用如writev支持向量写, 就避免了无谓的iolist_to_binary这样的扁平话操作, 避免了内存拷贝,极大的提高了效率.
另外额外补充:
erlang中列表时在头部添加比较高效,但是binary是在尾部追加更高效
### 关于消息接收转发解码和发送
erlang通常会将接收到的消息由网关进程转发给其他工作进程, 建议先匹配消息id, 然后转发二进制消息到工作进程,然后由工作进程解码再处理
同时广播消息可先编码成二进制之后再广播, 避免重复编码

+ 448
- 0
src/docs/erlang/erlang套接字编程.md 查看文件

@ -0,0 +1,448 @@
## gen_tcp 编程接口
#### listen(Port, Options) -> {ok, ListenSocket} | {error, Reason}
Types
Port = inet:port_number()
Options = [listen_option()]
ListenSocket = socket()
Reason = system_limit | inet:posix()
设置一个套接字以侦听本地主机上的端口Port。
用法:
listen(Port, Options) -> {ok, ListenSocket} | {error, Reason}
在本地开启一个监听某个端口的套接字(socket)。开启成功的话,会返回一个套接字标识符 Socket,其一般会传递给 get_tcp:accept/1 或 get_tcp:accept/2 调用。
如果参数 Port 为 0,那么底层操作系统将赋值一个可用的端口号,可以使用 inet:port/1 来获取一个 socket 监听的端口。
连接到IP地址为Address的主机的TCP端口Port上的服务器。参数 地址可以是主机名或IP地址。
提供以下选项:
{ip, Address}
如果主机有许多网络接口,则此选项指定要使用的接口。
{ifaddr, Address}
与{ip,Address}相同。如果主机有许多网络接口,则此选项指定要使用的接口。
{fd, integer() >= 0}
如果以某种方式未使用gen_tcp连接了套接字 ,请使用此选项传递文件描述符。如果将{ip,Address}和/或 {port,port_number()}与该选项结合使用,则 在连接前将fd绑定到指定的接口和端口。如果未指定这些选项,则假定fd已被适当绑定。
inet
为IPv4设置套接字。
inet6
设置用于IPv6的套接字。
local
设置Unix域套接字。见 inet:local_address()
{port,Port}
指定要使用的本地端口号。
{tcp_module, module()}
覆盖使用哪个回调模块。默认为 inet_tcp IPv4和inet6_tcp使用IPv6。
Opt
参见 inet:setopts / 2。
可以使用send / 2将数据包发送到返回的套接字Socket。 从对等方发送的数据包将作为消息传递:
{tcp, Socket, Data}
如果套接字处于{active,N}模式(有关详细信息,请参见inet:setopts / 2),并且其消息计数器降至0,则将传递以下消息以指示套接字已转换为被动({active,false}) 模式:
{tcp_passive, Socket}
如果套接字已关闭,则会发出以下消息:
{tcp_closed, Socket}
如果套接字上发生错误,则会传递以下消息(除非在套接字的选项列表中指定了{active,false},在这种情况下,可通过调用recv / 2来检索数据包):
{tcp_error, Socket, Reason}
可选的Timeout参数指定超时(以毫秒为单位)。默认为infinity。
注意:::
请记住,如果底层OS connect()的调用返回超时,调用gen_tcp:连接也将返回超时(即{错误,ETIMEDOUT} ),即使较大的超时指定。
指定要连接的选项的默认值会受到内核配置参数 inet_default_connect_options的影响。有关详细信息,请参见 inet(3)。
参数 Options 的一些常用选项:
{active, true}:套接字设置为主动模式。所有套接字接收到的消息都作为 Erlang 消息转发到拥有这个套接字进程上。当开启一个套接字时,默认是主动模式。
{active, false}:设置套接字为被动模式。套接字收到的消息被缓存起来,进程必须通过调用函数 gen_tcp:recv/2 或 gen_tcp:recv/3 来读取这些消息。
{active, once}:将设置套接字为主动模式,但是一旦收到第一条消息,就将其设置为被动模式,并使用 gen_tcp:recv/2 或 gen_tcp:recv/3 函数来读取后续消息。
{keepalive, true}:当没有转移数据时,确保所连接的套接字发送保持活跃(keepalive)的消息。因为关闭套接字消息可能会丢失,如果没有接收到保持活跃消息的响应,那么该选项可确保这个套接字能被关闭。默认情况下,该标签是关闭的。
{nodelay, true}:数据包直接发送到套接字,不过它多么小。在默认情况下,此选项处于关闭状态,并且与之相反,数据被聚集而以更大的数据块进行发送。
{packet_size, Size}:设置数据包允许的最大长度。如果数据包比 Size 还大,那么将认为这个数据包无效。
{packet, 0}:表示 Erlang 系统会把 TCP 数据原封不动地直接传送给应用程序
{reuseaddr, true}:允许本地重复使用端口号
{delay_send, true}:数据不是立即发送,而是存到发送队列里,等 socket 可写的时候再发送
{backlog, 1024}:缓冲区的长度
{exit_on_close, false}:设置为 flase,那么 socket 被关闭之后还能将缓冲区中的数据发送出去
{send_timeout, 15000}:设置一个时间去等待操作系统发送数据,如果底层在这个时间段后还没发出数据,那么就会返回 {error,timeout}
{Rand, _RandSeed} = random:uniform_s(9999, erlang:now()),
Port = 40000 + Rand,
gen_tcp:listen(Port, [binary, {packet, 0}, {active, false}]).
#### accept(ListenSocket) -> {ok, Socket} | {error, Reason} accept(ListenSocket, Timeout) -> {ok, Socket} | {error, Reason}
Types
ListenSocket = socket() Returned by listen/2.
Timeout = timeout() Socket = socket() Reason = closed | timeout | system_limit | inet:posix()
在侦听套接字上接受传入的连接请求。 套接字必须是从listen / 2返回的套接字 。 超时以毫秒为单位指定超时值。默认为infinity。
返回值:
{ok, Socket} if a connection is established
{error, closed} if ListenSocket is closed
{error, timeout} if no connection is established within the specified time
{error, system_limit} if all available ports in the Erlang emulator are in use
A POSIX error value if something else goes wrong, see inet(3) for possible error values
用法:
该函数会引起进程阻塞,直到有一个连接请求发送到监听的套接字。
如果连接已建立,则返回 {ok,Socket};
或如果 ListenSocket 已经关闭,则返回{error,closed};
或如果在指定的时间内连接没有建立,则返回{error,timeout};
或如果 Erlang 虚拟机里可用的端口都被使用了,则返回 {error, system_limit};
如果某些东西出错,也可能返回一个 POSIX 错误。一些有可能的错误请查看 inet 模块的相关说明。
使用 gen_tcp:send/2 向该函数返回的套接字 Socket 发送数据包。往端口发送的数据包会以下面格式的消息发送:
{tcp, Socket, Data}
如果在建立套接字 Socket 的时候选项列表中指定了 {active,false},这样就只能使用 gen_tcp:recv/2 或 gen_tcp:recv/3 来接收数据包了。
{Rand, _RandSeed} = random:uniform_s(9999, erlang:now()),
Port = 40000 + Rand,
case gen_tcp:listen(Port, [binary, {packet, 0}, {active, false}]) of
{ok, ListenSocket} ->
case gen_tcp:accept(ListenSocket) of
{ok, Socket} ->
Socket;
{error, SocketAcceptFail} ->
SocketAcceptFail
end;
_ ->
socket_listen_fail
end.
#### connect(Address, Port, Options) -> {ok, Socket} | {error, Reason}
#### connect(Address, Port, Options, Timeout) -> {ok, Socket} | {error, Reason}
Types
Address = inet:socket_address() |
inet:hostname() Port = inet:port_number()
Options = [connect_option()]
Timeout = timeout()
Socket = socket()
Reason = timeout | inet:posix()
连接一个 TCP 端口
用法:
connect(Address, Port, Options, Timeout) -> {ok, Socket} | {error, Reason}
用给出的端口 Port 和 IP 地址 Address 连接到一个服务器上的 TCP 端口上。参数 Address 即可以是一个主机名,也可以是一个 IP 地址。
提供以下选项:
{ip, Address}
如果主机有许多网络接口,则此选项指定要使用的接口。
{ifaddr, Address}
与{ip,Address}相同。如果主机有许多网络接口,则此选项指定要使用的接口。
{fd, integer() >= 0}
如果以某种方式未使用gen_tcp连接了套接字 ,请使用此选项传递文件描述符。如果将{ip,Address}和/或 {port,port_number()}与该选项结合使用,则 在连接前将fd绑定到指定的接口和端口。如果未指定这些选项,则假定fd已被适当绑定。
inet
为IPv4设置套接字。
inet6
设置用于IPv6的套接字。
local
设置Unix域套接字。见 inet:local_address()
{port,Port}
指定要使用的本地端口号。
{tcp_module, module()}
覆盖使用哪个回调模块。默认为 inet_tcp IPv4和inet6_tcp使用IPv6。
Opt
参见 inet:setopts / 2。
可以使用send / 2将数据包发送到返回的套接字Socket。 从对等方发送的数据包将作为消息传递:
{tcp, Socket, Data}
如果套接字处于{active,N}模式(有关详细信息,请参见inet:setopts / 2),并且其消息计数器降至0,则将传递以下消息以指示套接字已转换为被动({active,false}) 模式:
{tcp_passive, Socket}
如果套接字已关闭,则会发出以下消息:
{tcp_closed, Socket}
如果套接字上发生错误,则会传递以下消息(除非在套接字的选项列表中指定了{active,false},在这种情况下,可通过调用recv / 2来检索数据包):
{tcp_error, Socket, Reason}
可选的Timeout参数指定超时(以毫秒为单位)。默认为infinity。
注意:::
请记住,如果底层OS connect()的调用返回超时,调用gen_tcp:连接也将返回超时(即{错误,ETIMEDOUT} ),即使较大的超时指定。
指定要连接的选项的默认值会受到内核配置参数 inet_default_connect_options的影响。有关详细信息,请参见 inet(3)。
#### gen_tcp:close/1
Types
Socket = socket()
关闭一个 TCP 套接字
请注意,在大多数TCP实现中,执行关闭操作并不能保证在远程端检测到关闭之前,已发送的任何数据都会传递给接收方。如果要保证将数据传递给收件人,可以通过两种常用方法来实现。
使用gen_tcp:shutdown(Sock,write)发出信号,表明不再发送任何数据,并等待套接字的读取端关闭。
使用套接字选项{packet,N}(或类似的选项)可以使接收器在知道已接收到所有数据时关闭连接。
#### recv(Socket, Length) -> {ok, Packet} | {error, Reason}
#### recv(Socket, Length, Timeout) -> {ok, Packet} | {error, Reason}
Types
Socket = socket()
Length = integer() >= 0
Timeout = timeout()
Packet = string() | binary() | HttpPacket
Reason = closed | timeout | inet:posix()
HttpPacket = term() 看到的描述 HttpPacket中 的erlang:decode_packet / 3 在ERTS。
在被动模式下从套接字接收数据包。
返回值{error,closed}指示关闭的套接字。
Argument Length is only meaningful when the socket is in raw mode and denotes the number of bytes to read.
参数 Length 仅在套接字处于 raw mode 时才有意义,它表示要读取的字节数。
Length为0,则返回所有可用字节。
如果Length > 0,则返回确切的 Length字节,否则返回错误;
从另一侧关闭套接字时,可能会丢弃少于长度字节的数据
可选的Timeout参数指定超时(以毫秒为单位)。默认为infinity。
用法:
recv(Socket, Length, Timeout) -> {ok, Packet} | {error, Reason}
这个函数是从一个被动模式的套接字接受一个数据包。如果返回一个 {error, closed} 的返回值,那表明 Socket 已经关闭。
当 Socket 是 raw 模式下,参数 Length 才有意义的,并且 Length 表示接收字节的大小。如果 Length = 0,所有有效的字节数据都会被接收。如果 Length > 0,则只会接收 Length 长度的字节,或发生错误;当另一端 Socket 关闭时,接收的数据长度可能会小于 Length。
选项 Timeout 是一个以毫秒为单位的超时值,默认值是 infinity。
{Rand, _RandSeed} = random:uniform_s(9999, erlang:now()),
Port = 40000 + Rand,
case gen_tcp:listen(Port, [binary, {packet, 0}, {active, false}]) of
{ok, ListenSocket} ->
case gen_tcp:accept(ListenSocket) of
{ok, Socket} ->
gen_tcp:recv(Socket, 0, 5000);
{error, SocketAcceptFail} ->
SocketAcceptFail
end;
_ ->
socket_listen_fail
end.
#### send(Socket, Packet) -> ok | {error, Reason}
Types
Socket = socket()
Packet = iodata()
Reason = closed | inet:posix()
在一个套接字 Socket 发送一个数据包
用法:
send(Socket, Packet) -> ok | {error, Reason}
在一个套接字 Socket 发送一个数据包。
#### shutdown(Socket, How) -> ok | {error, Reason}
Types
Socket = socket()
How = read | write | read_write
Reason = inet:posix()
在一个或两个方向上关闭socket
以某种方式半关闭一个套接字。
如果参数 How 为 write 的形式,则套接字 socket 会关闭数据写入,读取仍可以正常执行。
如果How == read或Socket端口没有缓冲传出数据,则套接字将立即关闭,并且Reason中将返回遇到的任何错误。
要实现套接字半打开, 那么套接字要设置 {exit_on_close, false} 这个参数。
如果套接字端口中缓冲了数据,则将尝试关闭套接字的操作推迟到该数据写入内核套接字发送缓冲区中为止。
如果遇到任何错误,则关闭套接字,并在下一个recv / 2或 send / 2上返回 {error,closed}。
如果对等方在写端执行了关闭操作,则选项{exit_on_close,false}很有用。
#### gen_tcp:controlling_process/2
改变一个套接字的控制进程
将新的控制过程Pid分配给 Socket。控制过程是从套接字接收消息的过程。
如果由当前控制进程以外的任何其他进程调用, 则返回{error,not_owner}。
如果由Pid标识的进程不是现有的本地pid, 则返回{error,badarg}。
在某些情况下,在执行此函数期间关闭Socket时,也可能返回{error,badarg}。
如果套接字设置为活动模式,则此功能会将呼叫者邮箱中的所有消息传送到新的控制进程。
如果在传输过程中有任何其他进程正在与套接字交互,则传输可能无法正常进行,并且消息可能会保留在呼叫者的邮箱中。
例如,在传输完成之前更改套接字活动模式可能会导致此情况
#### 套接字选项
{active, true | false | once | -32768..32767} |
如果值为true,这是默认值,则将从套接字接收的所有内容作为消息发送到接收进程。
如果值为false(被动模式),则该进程必须通过调用gen_tcp:recv / 2,3, gen_udp:recv / 2,3或gen_sctp:recv / 1,2来显式接收传入的数据 (取决于套接字的类型) )。
如果该值为一次({active,once}), 则套接字中的一条数据消息将发送到该进程。要接收更多消息, 必须使用选项{active,一次}再次调用 setopts / 2。
如果该值是-32768到32767(含)之间的整数N,则将该值添加到发送到控制进程的套接字的数据消息计数中。
套接字的默认消息计数为0。如果指定了负值,并且其大小等于或大于套接字的当前消息计数,则套接字的消息计数将设置为0。
一旦套接字的消息计数达到0,则可能是由于 向进程发送接收到的数据消息或通过显式设置该消息,
然后通过特定于套接字类型的特殊消息通知该进程套接字已进入被动模式。 一旦套接字进入被动模式,为了接收更多消息,
必须再次调用setopts / 2才能将套接字设置回主动模式。
如果该值是-32768到32767(含)之间的整数N,则将该值添加到发送到控制进程的套接字的数据消息计数中。套接字的默认消息计数为0。
如果指定了负值,并且其大小等于或大于套接字的当前消息计数,则套接字的消息计数将设置为0。一旦套接字的消息计数达到0,
要么是由于向进程发送接收到的数据消息,要么是因为已显式设置它,然后通过特定于套接字类型的特殊消息通知该进程该套接字已进入被动模式。
一旦套接字进入被动模式,为了接收更多消息,必须再次调用setopts / 2才能将套接字设置回主动模式。
使用{active,一次}或{active,N}时,套接字在接收到数据时会自动更改行为。与面向连接的套接字(即gen_tcp)结合使用时,
可能会造成混淆,因为具有{active,false}行为的套接字报告的关闭方式与具有{active,true} 行为的套接字关闭的方式不同。为了简化编程,
当套接字在{active,false}模式下被关闭且对等方关闭时, 在设置为{active,一旦}时仍会生成消息 {tcp_closed,Socket },
{active,true}或{active,N}模式。因此可以肯定地假设,当套接字在{active,true}和 {active,false}模式之间来回切换时,
消息 {tcp_closed,Socket}可能最终会出现套接字端口终止(取决于选项exit_on_close)。
但是, 当检测到对等关闭时,完全取决于基础的TCP / IP堆栈和协议。
注意{active,true}模式不提供流量控制;快速的发送者可以轻松地使接收者的传入消息溢出。对于 {active,N}模式,消息数大于零时也是如此。
仅当高级协议提供自己的流控制(例如,确认收到的消息)或交换的数据量很少时,才使用活动模式。{active,false} 模式,
使用{active,一旦}模式或{active,N} 模式(具有适用于应用程序的N值)提供流量控制。另一端发送的速度不能超过接收器可以读取的速度。
{broadcast, Boolean} (UDP sockets)
启用/禁用发送广播的权限。
{buffer, integer() >= 0} |
驱动程序使用的用户级缓冲区的大小。不要与sndbuf 和recbuf选项混淆,它们与内核套接字缓冲区相对应。对于TCP,建议使用val(buffer)> = val(recbuf),
以避免由于不必要的复制而导致的性能问题。对于UDP,适用相同的建议,但最大值不应大于网络路径的MTU。
设置recbuf时,val(buffer)会自动设置为上述最大值。但是,为Recbuf设置的大小 通常变大,建议您使用 getopts / 2 来分析操作系统的行为。
请注意,这也是从单个recv调用可以接收的最大数据量。如果您使用的MTU高于正常值,请考虑将缓冲区设置为更高。
{delay_send, boolean()} |
通常,当Erlang进程发送到套接字时,驱动程序会尝试立即发送数据。如果失败,驱动程序将使用任何可用方法将要发送的消息排队,
只要操作系统表示可以处理该消息。设置{delay_send,true} 会使所有消息排队。这样,发送到网络的消息就更大,
但更少。该选项将影响发送请求与Erlang进程的调度,而不是更改套接字的任何实际属性。该选项是特定于实现的。默认为false。
{deliver, port | term} |
当{active,true}时,数据在以下端口上传递 {S, {data, [H1,..Hsz | Data]}} or term : {tcp, S, [H1..Hsz | Data]}.
{dontroute, boolean()} |
启用/禁用传出消息的路由旁路
{exit_on_close, boolean()} |
默认情况下,此选项设置为true。
将其设置为false的唯一原因是,如果要在检测到关闭后继续向套接字发送数据,例如,如果对等方使用 gen_tcp:shutdown / 2 关闭写端。
{header, integer() >= 0} |
仅当创建套接字时指定了选项binary 时,此选项才有意义。如果指定了选项 header,
则从套接字接收的数据的第一个 Size Number字节是列表的元素,其余数据是指定为同一列表尾部的二进制文件。例如,如果Size == 2,则接收到的数据与[Byte1,Byte2 | Binary]匹配
{high_msgq_watermark, integer() >= 1} |
当消息队列上的数据量达到此限制时,套接字消息队列将设置为繁忙状态。请注意,此限制仅涉及尚未达到ERTS内部套接字实现的数据。默认为8 kB。
如果套接字消息队列繁忙或套接字本身繁忙,则挂起套接字的数据发送器。
有关更多信息,请参见选项low_msgq_watermark, high_watermark和low_watermark。
Notice that distribution sockets disable the use of high_msgq_watermark and low_msgq_watermark. Instead use the distribution buffer busy limit, which is a similar feature.
{high_watermark, integer() >= 0} |
当ERTS套接字实现在内部排队的数据量达到此限制时,将套接字设置为繁忙状态。默认为8 kB。
如果套接字消息队列繁忙或套接字本身繁忙,则挂起套接字的数据发送器。
有关更多信息,请参见选项low_watermark, high_msgq_watermark和low_msqg_watermark。
{ipv6_v6only, Boolean}
限制套接字仅使用IPv6,禁止任何IPv4连接。这仅适用于IPv6套接字(选项inet6)。
在大多数平台上,必须先在套接字上设置此选项,然后才能将其与地址关联。因此,仅在创建套接字时指定它,而在调用包含此描述的函数(setopts / 2)时不使用它是合理的。
将此选项设置为true的套接字的行为 是唯一可移植的行为。现在,FreeBSD不建议使用IPv6的初衷是将IPv6用于所有流量(您可以使用 {ipv6_v6only,false}来覆盖建议的系统默认值),但OpenBSD(受支持的GENERIC内核)禁止使用,并且在Windows(具有单独的IPv4和IPv6协议栈)。大多数Linux发行版的系统默认值仍为false。逐渐改变了操作系统之间从IPv4流量中分离IPv6流量的策略,因为逐渐证明,要确保正确,安全地实现双堆栈实施是困难而复杂的。
在某些平台上,此选项唯一允许的值为true,例如OpenBSD和Windows。在这种情况下,尝试在创建套接字时将此选项设置为false会失败。
在不存在的平台上设置此选项将被忽略。使用getopts / 2获取此选项 不会返回任何值,即返回的列表不包含 {ipv6_v6only,_}元组。在Windows上,该选项不存在,但会将其模拟为值为true的只读选项。
因此, 在创建套接字时将此选项设置为true永远不会失败,除非可能是在您已将内核自定义为仅允许false的平台上进行,但在OpenBSD上这是可行的(但尴尬)。
如果使用getopts / 2读回选项值 而没有获取任何值,则该选项在主机操作系统中不存在。IPv6和IPv4套接字在同一端口上侦听的行为以及获取IPv4流量的IPv6套接字的行为不再可预测。
{keepalive, boolean()} |
没有其他数据交换时,启用/禁用连接的套接字上的定期传输。如果另一端没有响应,则认为连接已断开,并且将错误消息发送到控制过程。默认为禁用。
{linger, {boolean(), integer() >= 0}} |
确定在close / 1套接字调用中刷新未发送数据的超时(以秒为单位)。
第一个组件是如果启用了延迟,第二个组件是刷新超时(以秒为单位)。有3种选择:
{false,_}
close / 1或shutdown / 2会立即返回,而不是等待刷新数据,而在后台进行关闭。
{true,0}
关闭连接时中止连接。丢弃仍保留在发送缓冲区中的所有数据,并将RST发送给对等方。
这避免了TCP的TIME_WAIT状态,但是使创建该连接的另一个“化身”成为可能。
当时间> 0时,{true,时间}
在成功发送了套接字的所有排队消息或达到了超时(时间)之前,close / 1或shutdown / 2不会返回。
{low_msgq_watermark, integer() >= 1} |
如果套接字消息队列处于繁忙状态,则当消息队列中排队的数据量低于此限制时,套接字消息队列将设置为不繁忙状态。请注意,此限制仅涉及尚未达到ERTS内部套接字实现的数据。默认为4 kB。
当套接字消息队列和套接字不繁忙时,将恢复由于繁忙的消息队列或繁忙的套接字而挂起的发件人。
有关更多信息,请参见选项high_msgq_watermark, high_watermark和low_watermark。
请注意,分发套接字禁止使用 high_msgq_watermark和low_msgq_watermark。而是使用 分配缓冲区繁忙限制,这是一个类似功能。
{low_watermark, integer() >= 0} |
如果套接字处于繁忙状态,则当ERTS套接字实现在内部排队的数据量低于此限制时,会将套接字设置为不繁忙状态。默认为4 kB。
当套接字消息队列和套接字不繁忙时,将恢复由于繁忙的消息队列或繁忙的套接字而挂起的发件人。
有关更多信息,请参见选项high_watermark, high_msgq_watermark和low_msgq_watermark
{mode, list | binary} |
接收到的数据包按照list或者binary的定义进行传递。
list |
接收到的数据包以列表形式发送。
binary |
接收到的数据包以二进制形式传送
{bind_to_device,Ifname :: binary()}
将套接字绑定到特定的网络接口。必须在创建套接字的函数调用中使用此选项,即 gen_tcp:connect / 3,4, gen_tcp:listen / 2, gen_udp:open / 1,2或 gen_sctp:open / 0,1,2。
与getifaddrs / 0不同,Ifname编码为二进制。如果系统在网络设备名称中使用非7位ASCII字符(这种情况不太可能发生),则在对该参数进行编码时必须格外小心。
此选项使用特定于Linux的套接字选项 SO_BINDTODEVICE,例如在Linux内核2.0.30或更高版本中,因此仅在针对此类操作系统编译运行时系统时才存在。
在Linux 3.8之前,可以设置此套接字选项,但无法使用getopts / 2进行检索。从Linux 3.8开始,它是可读的。
虚拟机还需要提升的特权,这些特权可以以超级用户身份运行,或者(对于Linux)具有CAP_NET_RAW能力 。
此选项的主要用例是将套接字绑定到 Linux VRF实例。
{nodelay, boolean()} |
{nodelay,布尔值}(TCP / IP套接字)
如果Boolean == true, 则为套接字打开选项TCP_NODELAY,这意味着也会立即发送少量数据。
{nopush,布尔型}(TCP / IP套接字)
这相当于TCP_NOPUSH在BSD和TCP_CORK在Linux上。
如果Boolean == true,则为套接字打开相应的选项,这意味着将累积少量数据,直到可用完整的MSS数据为止或关闭此选项。
请注意,虽然OSX上提供了TCP_NOPUSH套接字选项,但其语义却大不相同(例如,取消设置它不会导致立即发送累积的数据)。因此,在OSX上有意忽略了nopush选项
{packet, 0 | 1 | 2 | 4 | raw | sunrm | asn1 | cdr | fcgi | line | tpkt | http | httph | http_bin | httph_bin} |
raw | 0 没有包装。
1 | 2 | 4 数据包包含一个标头,该标头指定了数据包中的字节数,然后是该字节数。标头长度可以是一个,
两个或四个字节,并包含一个按big-endian字节顺序排列的无符号整数。每个发送操作都会生成标头,并且在每个接收操作上都会剥离标头。4字节的标头限制为2Gb。
asn1 | cdr | sunrm | fcgi | tpkt | line
这些数据包类型仅对接收有效。发送数据包时,应用程序有责任提供正确的标头。但是,在接收时,对于接收到的每个完整数据包,将一条消息发送到控制过程,并且类似地,对gen_tcp:recv / 2,3的每次调用都 返回一个完整数据包。标头未剥离。
数据包类型的含义如下:
asn1 -ASN.1 BER
sunrm -Sun的RPC编码
CDR -CORBA(GIOP 1.1)
fcgi-快速CGI
tpkt -TPKT格式[RFC1006]
line-行模式,数据包以换行符结尾的行,比接收缓冲区长的行被截断
http | http_bin
超文本传输​​协议。按照ERTS的erlang:decode_packet / 3中 描述的 HttpPacket格式返回数据包。被动模式下的套接字从gen_tcp:recv返回{ok,HttpPacket}, 而主动套接字发送诸如 {http,Socket,HttpPacket}之类的消息。
httph | httph_bin
通常不需要这两种类型,因为在读取第一行之后,套接字会在内部自动从http / http_bin切换到 httph / httph_bin。但是,有时可能有用,例如从分块编码中解析预告片
{packet_size, integer() >= 0} |
设置数据包主体的最大允许长度。如果数据包头指示数据包的长度大于最大允许长度,则该数据包被视为无效。如果数据包头对于套接字接收缓冲区太大,则会发生相同的情况。
对于面向行的协议(line,http *),选项packet_size还可以保证接受指定长度的行,并且由于内部缓冲区的限制,该行不会被视为无效。
{line_delimiter, Char}(TCP/IP sockets)
设置面向行的协议(line)的行定界字符。默认为$ \ n。
{priority, integer() >= 0} |
在实现此功能的平台上设置SO_PRIORITY套接字级别选项。行为和允许范围在不同系统之间有所不同。该选项在未实现的平台上被忽略。请谨慎使用。
{raw,Protocol :: integer() >= 0,OptionNum :: integer() >= 0, ValueBin :: binary()} |
{read_packets,Integer}(UDP套接字)
设置在数据可用时无需套接字就可以读取的最大UDP数据包数。当读取了这么多的数据包并将其传送到目标进程后,新的数据包才被读取,直到有可用数据的新通知到达为止。默认为5。如果此参数设置得太高,由于UDP数据包泛洪,系统可能会变得无响应。
{recbuf, integer() >= 0} |
用于套接字的接收缓冲区的最小大小。建议您使用 getopts / 2 来检索操作系统设置的大小。
{reuseaddr, boolean()} |
允许或禁止端口号的本地重用。默认情况下,不允许重用。
{send_timeout, integer() >= 0 | infinity} |
仅允许用于面向连接的套接字。
指定最长时间等待基础TCP堆栈接受发送操作。当超过限制时,发送操作将返回 {error,timeout}。未知发送了多少数据包;因此,只要发生超时,套接字就将关闭(请参见 下面的send_timeout_close)。默认为infinity。
{send_timeout_close, boolean()} |
仅允许用于面向连接的套接字。
与send_timeout一起使用,以指定当send操作返回{error,timeout}时是否自动关闭套接字。推荐的设置为 true,它将自动关闭套接字。由于向后兼容,默认为false。
{show_econnreset, boolean()} |
当此选项设置为false时(默认情况下),将从TCP对等方接收到的RST视为正常关闭(就像已发送FIN一样)。gen_tcp:recv / 2的调用者 获得{错误,关闭}。在活动模式下,控制进程收到 {tcp_closed,Socket}消息,指示对等方已关闭连接。
将此选项设置为true可让您区分正常关闭的连接和TCP对等方中止(有意或无意)的连接。调用 gen_tcp:recv / 2 返回{error,econnreset}。在活动模式下,控制过程会在通常的{tcp_closed,Socket}之前接收到 {tcp_error,Socket,econnreset}消息,就像其他套接字错误一样。调用 gen_tcp:send / 2 也会返回{error,econnreset} 当检测到TCP对等体已发送RST时。
从gen_tcp:accept / 1返回的已连接套接字 从侦听套接字 继承了show_econnreset设置。
{sndbuf, integer() >= 0} |
用于套接字的发送缓冲区的最小大小。鼓励您使用 getopts / 2来检索操作系统设置的大小。
{tos, integer() >= 0} |
在实现此功能的平台上设置IP_TOS IP级别选项。行为和允许范围在不同系统之间有所不同。该选项在未实现的平台上被忽略。请谨慎使用。
{tclass, integer() >= 0} |
在实现此功能的平台上 设置IPV6_TCLASS IP级别选项。行为和允许范围在不同系统之间有所不同。该选项在未实现的平台上被忽略。请谨慎使用。
{ttl, integer() >= 0} |
{recvtos, boolean()} |
{recvtclass, boolean()} |
{recvttl, boolean()} |
option_name() =
active | buffer | delay_send | deliver | dontroute |
exit_on_close | header | high_msgq_watermark |
high_watermark | keepalive | linger | low_msgq_watermark |
low_watermark | mode | nodelay | packet | packet_size |
pktoptions | priority |
{raw,Protocol :: integer() >= 0, OptionNum :: integer() >= 0, ValueSpec ::(ValueSize :: integer() >= 0) | (ValueBin :: binary())} |
recbuf | reuseaddr | send_timeout | send_timeout_close |
show_econnreset | sndbuf | tos | tclass | ttl | recvtos |
recvtclass | recvttl | pktoptions | ipv6_v6only
connect_option() =
{ip, inet:socket_address()} |
{fd, Fd :: integer() >= 0} |
{ifaddr, inet:socket_address()} |
inet:address_family() |
{port, inet:port_number()} |
{tcp_module, module()} |
{netns, file:filename_all()} |
{bind_to_device, binary()} |
option()
listen_option() =
{ip, inet:socket_address()} |
{fd, Fd :: integer() >= 0} |
{ifaddr, inet:socket_address()} |
inet:address_family() |
{port, inet:port_number()} |
{backlog, B :: integer() >= 0} |
{tcp_module, module()} |
{netns, file:filename_all()} |
{bind_to_device, binary()} |
option()
socket()
As returned by accept/1,2 and connect/3,4.

+ 220
- 0
src/docs/erlang/erlang性能优化.md 查看文件

@ -0,0 +1,220 @@
#### erlang 各种 优化设置
一、 erl启动时参数:
+K true 开启epoll调度,在linux中开启epoll,会大大增加调度的效率
+A 100 异步线程池,为某些port调用服
+P 1024000 最大进程数
+Q 65535 最大port数
+sbt db 绑定调度器,绑定后调度器的任务队列不会在各个CPU线程之间跃迁,结合sub使用,可以让CPU负载均衡的同时也避免了大量的跃迁发生。
将scheduler绑定到具体的cpu核心上,再配合erlang进程和port绑定,可以显著提升性能,但是如果绑定错误,反而会有反效果
( 进程调度器绑定:erlang:process_flag(scheduler, 1),当进程使用了port时,还需要port绑定支持,防止进程在不同调度器间迁移引起性能损失,如cache、跨numa node拷贝等,当进程使用了port时,主要是套接字,若进程与port不在一个scheduler上,可能会引发严重的epoll fd锁竞争及跨numa node拷贝,导致性能严重下降)
注意:一个linux系统中,最好只有一个evm开启此选项,若同时有多个erlang虚拟机在系统中运行,还是关闭为好
+sub true 开启CPU负载均衡,false的时候是采用的CPU密集调度策略,优先在某个CPU线程上运行任务,直到该CPU负载较高为止。
+swct eager 此选项设置为eager后,CPU将更频繁的被唤醒,可以增加CPU利用率
+spp true 开启并行port并行调度队列,当开启后会大大增加系统吞吐量,如果关闭,则会牺牲吞吐量换取更低的延迟。
+zdbbl 65536 分布式erlang的端口buffer大小,当buffer满的时候,向分布式的远程端口发送消息会阻塞
二、erlang内部进程启动参数
示例:创建一个新进程并进行注册,该进程是全局唯一的自增ID生成进程,因此无法做多进程处理,这个时候单进程的性能就是至关重要的
首先,出于性能和功能考虑,这个进程不是gen_server;其次进行了部分参数调优能
register(num_generator, spawn_opt(?MODULE, init, [],[{priority,high},{scheduler,0},{min_heap_size, 65536 * 2},{min_bin_vheap_size,65536 * 2}])).
参数讲解:
1.priority
erlang是公平调度策略,因此默认情况下每个进程得到的运行时间片是相同的:2000reductions,但是对于我们的应用场景来说,这个进程应该是优先级较高的,需要得到更多的调度,因此设置为high,还可以设置为max,但是max是系统进程的预留优先级,用high即可
2. scheduler
将该进程绑定到指定的scheduler上,防止进程的任务被scheduler分配来分配去,可以减少CPU调用,注意这个和+sbt db是不同的,+sbt db是防治调度器的任务队列在CPU线程间跃迁,scheduler是为了防止进程在时间片切换过程中被分配给其它的调度器
3.min_heap_size
进程初始堆大小,用内存换CPU的典型做法,增大初始大小,可以显著降低GC次数和内存再分配次数, 减少处理过程中产生大量term,尤其是list时的gc次数
4.min_bin_vheap_size
进程初始二进制堆大小,当该进程对于binary数据的处理交换很多时,可以获得和增大min_heap_size一样的效果, 减少大量消息到达或处理过程中产生大量binary时的gc次数
三、port(socket)调优
示例:服务器监听端口,接受客户端请求。典型应用场景web服务器,需要实现高吞吐,低延迟的目标
Res = gen_tcp:listen(Port, [binary,
{reuseaddr, true},
{nodelay, true},
{delay_send,true},
{high_watermark,64 * 1024},
{send_timeout, 30000},
{send_timeout_close, true},
{keepalive, true}])
参数详解:
binary:
接收到客户端的消息后,作为binary来处理,binary在erlang中是很高效的数据结构,超过64字节,就是全局保存的,因此在很多操作下是不需要复制的,仅仅复制binary的指针即可,详细请搜索refc binary,注意:binary大量使用需要有丰富的经验,不然可能会内存泄漏
reuseaddr:
允许系统复用port,对于高吞吐的系统,这个参数很重要,请搜索:linux port 复用
nodelay:
开启linux中的TCP_NODELAY参数,请搜索:TCP_NODELAY 40毫秒延迟
delay_send:
默认的erlang port消息发送,是直接发送,若失败则排队处理,然后由调度器进行队列poll操作,如果设置为true,那么就不尝试直接发送,而且扔进队列,等待poll,开启选项会增加一点点消息延迟,换来吞吐量的大量提升
high_watermark:
port的发送缓存,缓存满了后,下次发送会直接阻塞,直到缓存低于某个阈值low_watermark。如果是密集网络IO系统,请增大该buffer,避免发送阻塞
延迟发送:{delay_send, true},聚合若干小消息为一个大消息,性能提升显著
发送高低水位:{high_watermark, 128 * 1024} | {low_watermark, 64 * 1024},辅助delay_send使用,delay_send的聚合缓冲区大小为high_watermark,数据缓存到high_watermark后,将阻塞port_command,使用send发送数据,直到缓冲区大小降低到low_watermark后,解除阻塞,通常这些值越大越好,但erlang虚拟机允许设置的最大值不超过128K
发送缓冲大小:{sndbuf, 16 * 1024},操作系统对套接字的发送缓冲大小,在延迟发送时有效,越大越好,但有极值
接收缓冲大小:{recbuf, 16 * 1024},操作系统对套接字的接收缓冲大小
send_timeout:
在high_watermark中提到了发送阻塞,如果阻塞超过这个时间,那么就会超时,发送直接返回,停止发送
send_timeout_close:
如果发生了send_timeout同时设置了send_timeout_close选项,那么超时后,会直接关闭socket.如果发送进程不是很重要,例如web用户进程,强烈建议开启这个选项,当发送30秒超时的时候,就说明该用户出现了很大的麻烦,断开连接是最理想的做法,否则可能出现很多奇怪的bug.
keepalive:
遵循HTTP/1.1协议的keepalive规定,这个根据业务需求选择是否开启,如果同一个客户端会连续发起http请求,那么建议设置为true,避免多次TCP握手
示例:服务器发起大量的http请求,在优化了参数后,同样的吞吐量所耗费的时间是未优化前的1/3 - 1/2(经过严苛的测试得出的数据)
inets:start(),
httpc:set_options([{max_keep_alive_length,500},{max_sessions,100},{nodelay,true},{reuseaddr,true}]),
参数详解:
max_keep_alive_length:
在同一条http连接上允许发送的最大包数,默认为5,超过5个包,就会重连
max_sessions:
跟目标服务器之间最大的并行http连接数目,大大的增加了数据上行吞吐量
nodelay_true:
见上文
reuseaddr:
  6. 数据结构:
     减少遍历,尽量使用API提供的操作
     由于各种类型的变量实际可以当做c的指针,因此erlang语言级的操作并不会有太大代价
     lists:reverse为c代码实现,性能较高,依赖于该接口实现的lists API性能都不差,避免list遍历,[||]和foreach性能是foldl的2倍,不在非必要的时候遍历list
     dict:find为微秒级操作,内部通过动态hash实现,数据结构先有若干槽位,后根据数据规模变大而逐步增加槽位,fold遍历性能低下
     gb_trees:lookup为微秒级操作,内部通过一个大的元组实现,iterator+next遍历性能低下,比list的foldl还要低2个数量级
9. 文件预读,批量写,缓存:
这些方式都是局部性的体现:
预读:读空间局部性,文件提供了read_ahead选项
批量写:写空间局部性
 对于文件写或套接字发送,存在若干级别的批量写:
   1. erlang进程级:进程内部通过list缓存数据
   2. erlang虚拟机:不管是efile还是inet的driver,都提供了批量写的选项delayed_write|delay_send,
      它们对大量的异步写性能提升很有效
   3. 操作系统级:操作系统内部有文件写缓冲及套接字写缓冲
   4. 硬件级:cache等
缓存:读写时间局部性,读写空间局部性,主要通过操作系统系统,erlang虚拟机没有内部的缓存
10.套接字标志设置:
延迟发送:{delay_send, true},聚合若干小消息为一个大消息,性能提升显著
发送高低水位:{high_watermark, 128 * 1024} | {low_watermark, 64 * 1024},辅助delay_send使用,delay_send的聚合缓冲区大小为high_watermark,数据缓存到high_watermark后,将阻塞port_command,使用send发送数据,直到缓冲区大小降低到low_watermark后,解除阻塞,通常这些值越大越好,但erlang虚拟机允许设置的最大值不超过128K
发送缓冲大小:{sndbuf, 16 * 1024},操作系统对套接字的发送缓冲大小,在延迟发送时有效,越大越好,但有极值
接收缓冲大小:{recbuf, 16 * 1024},操作系统对套接字的接收缓冲大小
#### Erlang 虚拟机调优
目录
SMP
Schedulers
Port Settings
Asynchronous Thread Pool
Kernel Polling
Warning Messages
Process Limit
Distribution Buffer
Erlang Built-in Storage
Crash Dumps
Net Kernel Tick Time
Shutdown Time
Riak 是用Erlang语言写的,运行在Erlang虚拟机之上.所以Erlang虚拟机的调优对Riak的性能优化就显得尤为重要. Erlang虚拟机本身提供了非常多的配置参数对性能调优, Riak支持其中的一部分参数,你可以在每个node的Riak配置文件中进行设置.
下表列出了其中的一部分,左边一列是Erlang中的参数名称, 右边一列是在Riak中的参数名称.
```Erlang parameter Riak parameter
+A erlang.async_threads
+K erlang.K
+P erlang.process_limit
+Q erlang.max_ports
+S erlang.schedulers.total, erlang.schedulers.online
+W erlang.W
+a erlang.async_threads.stack_size
+e erlang.max_ets_tables
+scl erlang.schedulers.compaction_of_load
+sfwi erlang.schedulers.force_wakeup_interval
-smp erlang.smp
+sub erlang.schedulers.utilization_balancing
+zdbbl erlang.distribution_buffer_size
-kernel net_ticktime erlang.distribution.net_ticktime
-env FULLSWEEP_AFTER erlang.fullsweep_after
-env ERL_CRASH_DUMP erlang.crash_dump
-env ERL_MAX_ETS_TABLES erlang.max_ets_tables
-name nodename
```
Note on upgrading to 2.0
在Riak2.0版本之前, Erlang虚拟机相关的参数放在配置文件 vm.args 里面. 在2.0及之后的版本中, 所有Erlang虚拟机相关的配置参数放在配置文件 riak.conf 里面. 如果你从Riak2.0之前的版本升级到Riak 2.0, 你仍然可以继续使用旧的配置文件 vm.args. 但是, 如果你同时设置了配置文件 vm.args 和riak.conf, 在 vm.args里面的配置将会覆盖riak.conf里面的配置.
##### SMP
有些操作系统提供Erlang虚拟机对称多处理器能力(SMP)以利用多处理器硬件架构的优势. SMP的支持可以通过设置erlang.smp参数来打开和关闭, 默认是打开的. 下面的例子是关闭SMP的支持.
riak.conf
erlang.smp = disable
由于Riak也可以运行在一些不支持SMP的操作系统上, 所以在使用之前需要确认操作系统是否支持SMP,如果操作系统本身不支持,那么需要在启动Riak集群之前在配置文件riak.conf中关闭SMP的选项.
比较安全的一个选择是把erlang.smp设置成auto, 这个选项会指示Erlang虚拟机启动SMP支持之前检查操作系统是否支持以及是否有一个以上的逻辑处理器,只有这两个条件都满足的时候,Erlang虚拟机才启动SMP支持.
##### Schedulers
Note on missing scheduler flags
We recommend that all users set the +sfwi to 500 (milliseconds) and the +sclflag to false if using the older, vm.args-based configuration system. If you are using the new, riak.conf-based configuration system, the corresponding parameters are erlang.schedulers.force_wakeup_interval anderlang.schedulers.compaction_of_load.
Please note that you will need to uncomment the appropriate lines in your riak.conf for this configuration to take effect.
如果在Erlang虚拟机里已经打开了支持SMP的选项, 比如erlang.smp已经被设置成enabled 或者auto,而且机器本身超过一个逻辑处理器同时也支持SMP, 那么当你启动Riak的时候, 你可以配置逻辑处理器的数量或者调度线程的数量,同时也可以设置online线程的数量.
全部调度线程的数量可以通过参数erlang.schedulers.total来设置, online线程的数量则是通过参数erlang.schedulers.online来配置. 这两个参数可以分别对应到Erlang虚拟机的参数Schedulers 和SchedulersOnline.
两个参数的最大值都是1024, 参数并没有统一的默认值. 但是, Erlang 虚拟机自己会尝试去判定有多少配置的CPU(core)和可用的CPU(core). 如果Erlang虚拟机能够做出这个判定,那么参数schedulers.total会默认设置成配置的CPU(core)数量,
参数schedulers.online会默认设置成可用的CPU(core)数量. 但是, 如果Erlang虚拟机不能做出判定, 两个参数的默认值将会设置成1.
如果两个参数中的任意一个被设置成负数, 那么意味着这个参数值将会被设成默认配置的处理器数量(如果scheduler.total是负数)或者可用的处理器数量(如果schedulers.online是负数) 减去配置的负值. 比如, 如果机器配置有100个cpu(cores)然后参数schedulers.total配置为-50, 计算以后的值就是50.
如果两个参数中的任意一个被设置为0,两个值都会被重新设为默认值.
如果SMP支持被关闭, 比如erlang.smp被设成disabled或者设成auto 但是机器本身不支持SMP或者机器只有一个逻辑处理器,那么两个参数schedulers.total 和 schedulers.online都将会被忽略.
Scheduler Wakeup Interval
调度器唤醒是一个可选处理, 通过这个Erlang 虚拟机调度器被周期性的扫描来判定是否已经陷入睡眠, 比如是否调度器有一个空的运行列表. 这个扫描时间间隔可以通过参数erlang.schedulers.force_wakeup_interval设置, 单位为毫秒.这个参数对应于Erlang虚拟机的+sfwi选项.该参数默认设为0, 不激活调度器唤醒功能.
Erlang在R15Bx版本里有把调度器睡眠过于频繁的倾向,如果你使用的是更新的版本,比如Riak2.0 及以后, 那多数情况下不需要启动唤醒功能.
注: OTP的工程师曾经解释过这个功能,如果需要调度的任务不是很多,没有很多task在运行列表上的话, R15B的Erlang虚拟机会倾向于把这些task尽量集中到尽可能少的调度器上来调度, 睡眠没有调度任务的调度器, 这样可以减少调度器之间的通信花费overhead, 提高CPU的利用率. 但这个也是一个trade off, 具体还是需要用户来根据自己的实际环境来调优. 因为一旦task的数量增加比较多,或者task数量没有增加但是task本身比较耗时,那么很可能就会触发调度器的唤醒, 而唤醒调度器是比较expensive的操作, 如果频繁睡眠唤醒的话,可能会得不偿失.
##### Scheduler Compaction and Balancing
Erlang调度器提供了两种方式来分发负载到不同的调度器上, 集中负载和utilization balancing.
集中负载是默认打开的, 打开的时候Erlang虚拟机会尝试去尽可能多的使调度器繁忙,比如通过把任务集中到有限的几个调度器上(假设这几个有限的调度器充分运行的情况下可以调度完目前的tasks)使这几个调度器一直有工作做(not run out of work). 为了达到这个目的, 当虚拟机分配任务的时候会考虑哪些调度器应该被分配任务. 用户可以设置参数erlang.schedulers.compaction_of_load为false来关闭这个功能.
另外一个选项, utilization balancing, 为了支持负载平衡, 默认是关闭的. 如果打开了这个选项, Erlang虚拟机则努力在不同调度器之间平衡调度器的利用. 如果不考虑每个调度器没有任务可调度的频度的话, 可以打开这个设置, erlang.schedulers.utilization_balancing 设为true(老版本里面通过设置+scl false)
在任何时候, 只可以是使用两个功能中的一个. 如果同时设置这两个选项为false的话, Riak 会默认使用集中负载选项.如果同时设置为true, Riak会使用那个在配置文件riak.conf中最先出现的那个.(如果是旧版本的话,配置文件会是vm.args)
##### Port Settings
Riak 使用epmd, Erlang 端口映射Daemon来进行大多数的节点间的通信. 在这个系统里, 集群里的其他节点使用由nodename参数(或者是name in vm.args)来作为节点ID. 比如, riak@10.9.8.7. 在每个节点上, daemon把这些节点ID解析成一个TCP的端口. 用户可以指定一个端口范围给Riak节点来监听使用,同时也可以知道最大数量的并ports/sockets.
Port Range
默认情况下 , epmd绑定到TCP端口4369上并且侦听通配符接口. epmd 默认使用一个不能预测的端口作为节点间的通信, 通过绑定到端口0上, 意味着会使用第一个可用的端口. 这样就使得防火墙非常难配置.
为了是防火墙配置简化, 用户可以指导Erlang虚拟机使用一个有限范围的端口或者单一端口. 这个最小和最大值可以设置在参数erlang.distribution.port_minimum和erlang.distribution.port_maximum里面. 比如, 下面的值被设为3000和5000.
riak.conf
app.config
erlang.distribution.port_range.minimum = 3000
erlang.distribution.port_range.maximum = 5000
用户可以设置Erlang虚拟机使用一个单一端口, 如果只设置了最小值没有设置最大值,则表示使用单一端口. 比如, 下面设置使用单一端口5000.
riak.conf
app.config
erlang.distribution.port_range.minimum = 5000
如果最小端口没有设置, Erlang虚拟机将会在随机的高编号端口上侦听.
##### Maximum Ports
用户可以通过设置参数erlang.max_ports来指定Erlang虚拟机可以使用的最大并发的 ports/sockets数量, 范围从1024到134217727. 默认值是65536. 在vm.args里面对应的参数是+Q 或者-env ERL_MAX_PORTS.
Asynchronous Thread Pool
如果Erlang虚拟机支持线程可用, 用户可以为Erlang虚拟机设置异步线程池的线程数量, 使用参数erlang.async_threads(+A in vm.args). 线程数量范围从0至1024, 默认值是64,下面的例子是设置成600的情况.
riak.conf
vm.args
erlang.async_threads = 600
##### Stack Size
除了可以指定异步线程的数量之外, 用户还可以为每个异步线程指定stack size. 参数是erlang.async_threads.stack_size, 对应到Erlang的+a参数. 用户可以在Riak中为这个参数指定size以KB, MB,GB 为单位, 有效的范围值是16至8192个字, 在32位的系统上就是64至32768字节. 该参数没有默认值, 我们建议设置为16K words, 对应为64 KB在32位系统上. 我们建议这么小一个值是考虑到异步线程数量可能会很大.
注:The 64 KB default is enough for drivers delivered with Erlang/OTP but might not be large enough to accommodate drivers that use the driver_async()functionality, documented here. We recommend setting higher values with caution, always keeping the number of available threads in mind.
Kernel Polling
如果系统支持, 用户可以在Erlang中利用内核轮询. 内核轮询可以在使用很多文件描述符的时候提高性能. 在使用中的文件描述符越多, 内核轮询发挥的作用就越大. 该选择在Riak的Erlang虚拟机中是默认打开的, 该参数对应到Erlang虚拟机中的+K参数
##### Warning Messages
Erlang虚拟机的error_logger 是一个事件管理器, 从Erlang运行时系统注册错误, 告警和信息事件. 默认情况下, error_logger的信息事件被映射为告警,但是用户可以设置映射成错误或者信息. 该设置为参数erlang.W, 可以设置的值为w(warning), errors 或者i(info reports).
##### Process Limit
参数erlang.process_limit可以用来设置系统同时存在的最大进程数量(对应到Erlang的+P参数), 有效范围从1024至134217727. 默认值是256000.
##### Distribution Buffer
用户可以通过参数erlang.distribution_buffer_size设置Erlang虚拟机的distribution buffer busy limit(对应到Erlang的+zdbbl参数). 修改这个参数对那些有许多busy dist port事件的节点可能会有帮助, 默认值是32MB, 最大值是2097151KB. 增大这个参数可以允许进程缓存更多的待发消息, 当缓存满的时候,发送线程被挂起直到缓存减小到设定值. 所以, 更大的缓存有助于降低延迟以及增加吞吐量,代价就是使用了更多的RAM. 用户需要根据机器的RAM资源来考虑设定这个值.
##### Erlang Built-in Storage
Erlang使用一个内置的数据库,ets(Erlang Term Storage)用来快速访问内存(constant access time rather than logarithmic access time). erts 表的最大数量设置在参数erlang.max_erts_tables里面, 默认值是256000,这个值要大于Erlang虚拟机自身的默认值1400(对应到vm.args 的参数e). 更大的erlang.max_erts_tables值可以提供更快的数据访问,代价是消耗更高的内存.
##### Crash Dumps
默认情况下, Riak 的Erlang crash dumps文件是存放在位置./log/erl_crash.dump. 用户可以通过设置参数erlang.crash_dump来更改存放位置. 该参数对应到Erlang虚拟机的ERL_CRASH_DUMP环境变量.
##### Net Kernel Tick Time
网络内核是Erlang的一个系统进程, 提供了不同的网络监视形式. 在一个Riak集群里面, 网络内核的功能之一就是去周期性的检测节点存活. Tick time就是这个检查频度, 可以通过erlang.distribution.net_ticktime设置,单位是秒. 该参数对应到vm.args里面的参数-kernal net_ticktime.
##### Shutdown Time
用户可以设定Erlang虚拟机的关闭时间, 该设置参数为erlang.shutdown_time,默认是10秒, 一旦10秒过了, 所有存在的进程就会被杀掉. 减少关闭时间在某些情景下可能是有帮助的, 比如说在测试的时候需要频繁的启停Riak集群. 在vm.args里参数是shutdown_time, 单位是毫秒.

+ 300
- 0
src/docs/erlang/erlang数据结构相关.md 查看文件

@ -0,0 +1,300 @@
# erlang各种数据类型占用的内存大小
有效编程的一个好的开始是知道不同数据类型和操作需要多少内存。
Erlang数据类型和其他项目消耗多少内存与实现方式有关,但是下表显示了OTP 19.0中erts-8.0系统的一些数据。
度量单位是存储字。 同时存在32位和64位实现。 因此,一个字分别是4字节或8字节。
erlang:system_info(wordsize).
```
Data Type Memory Size
Small integer
1 word.
On 32-bit architectures: -134217729 < i < 134217728
(28 bits).
On 64-bit architectures: -576460752303423489 < i <
576460752303423488 (60 bits).
Large
integer 3..N words.
Atom
1 word.
An atom refers into an atom table, which also consumes
memory. The atom text is stored once for each unique
atom in this table. The atom table is not garbage-collected.
Float
On 32-bit architectures: 4 words.
On 64-bit architectures: 3 words.
Binary
3..6 words + data (can be shared).
List
1 word + 1 word per element + the size of each element.
String (is the same as a list of integers)
1 word + 2 words per character.
Tuple
2 words + the size of each element.
Small Map
5 words + the size of all keys and values.
Large Map (> 32 keys)
N x F words + the size of all keys and values.
N is the number of keys in the Map.
F is a sparsity factor that can vary
between 1.6 and 1.8 due to the probabilistic nature of
the internal HAMT data structure.
Pid
1 word for a process identifier from the current local
node + 5 words for a process identifier from another
node.
A process identifier refers into a process table and a
node table, which also consumes memory.
Port
1 word for a port identifier from the current local node +
5 words for a port identifier from another node.
A port identifier refers into a port table and a node table,
which also consumes memory.
Reference
On 32-bit architectures: 5 words for a reference from
the current local node + 7 words for a reference from
another node.
On 64-bit architectures: 4 words for a reference from
the current local node + 6 words for a reference from
another node.
A reference refers into a node table, which also
consumes memory.
Fun
9..13 words + the size of environment.
A fun refers into a fun table, which also consumes
memory.
Ets table
Initially 768 words + the size of each element (6 words
+ the size of Erlang data). The table grows when
necessary.
Erlang process
338 words when spawned, including a heap of 233 words.
```
# System Limits
Erlang语言规范对进程数,原子长度等没有任何限制。 但是,出于性能和内存节省的原因,在Erlang语言和执行环境的实际实现中始终会受到限制。
```
Processes
The maximum number of simultaneously alive Erlang
processes is by default 262,144. This limit can be
configured at startup. For more information, see the
+P command-line flag in the erl(1) manual page in
ERTS.
Known nodes
A remote node Y must be known to node X if there
exists any pids, ports, references, or funs (Erlang data
types) from Y on X, or if X and Y are connected. The
maximum number of remote nodes simultaneously/ever
known to a node is limited by the maximum number of
atoms available for node names. All data concerning
remote nodes, except for the node name atom, are
garbage-collected.
Connected nodes
The maximum number of simultaneously connected
nodes is limited by either the maximum number of
simultaneously known remote nodes, the maximum
number of (Erlang) ports available, or the maximum
number of sockets available.
Characters in an atom
255.
Atoms
By default, the maximum number of atoms is 1,048,576.
This limit can be raised or lowered using the +t option.
Elements in a tuple
The maximum number of elements in a tuple is
16,777,215 (24-bit unsigned integer).
Size of binary
In the 32-bit implementation of Erlang, 536,870,911
bytes is the largest binary that can be constructed
or matched using the bit syntax. In the 64-
bit implementation, the maximum size is
2,305,843,009,213,693,951 bytes. If the limit
is exceeded, bit syntax construction fails with a
system_limit exception, while any attempt to
match a binary that is too large fails. This limit is
enforced starting in R11B-4.
In earlier Erlang/OTP releases, operations on too large
binaries in general either fail or give incorrect results.
In future releases, other operations that create binaries
(such as list_to_binary/1) will probably also
enforce the same limit.
Total amount of data allocated by an Erlang node
The Erlang runtime system can use the complete 32-bit
(or 64-bit) address space, but the operating system often
limits a single process to use less than that.
Length of a node name
An Erlang node name has the form host@shortname
or host@longname. The node name is used as an atom
within the system, so the maximum size of 255 holds
also for the node name.
Open ports
The maximum number of simultaneously open Erlang
ports is often by default 16,384. This limit can be
configured at startup. For more information, see the
+Q command-line flag in the erl(1) manual page in
ERTS.
Open files and sockets
同时打开的文件和套接字的最大数量取决于可用的Erlang端口的最大数量,以及特定于操作系统的设置和限制。
Number of arguments to a function or fun
255
Unique References on a Runtime System Instance
Each scheduler thread has its own set of references,
and all other threads have a shared set of references.
Each set of references consist of 2## - 1 unique
references. That is, the total amount of unique
references that can be produced on a runtime system
instance is (NoSchedulers + 1) × (2## -
1).
If a scheduler thread create a new reference each nano
second, references will at earliest be reused after more
than 584 years. That is, for the foreseeable future they
are unique enough.
Unique Integers on a Runtime System Instance
There are two types of unique integers both created
using the erlang:unique_integer() BIF:
1. Unique integers created with the monotonic
modifier consist of a set of 2## - 1 unique integers.
2. Unique integers created without the monotonic
modifier consist of a set of 2## - 1 unique integers
per scheduler thread and a set of 2## - 1 unique
integers shared by other threads. That is, the total
amount of unique integers without the monotonic
modifier is (NoSchedulers + 1) × (2## -
1).
If a unique integer is created each nano second, unique
integers will at earliest be reused after more than 584
years. That is, for the foreseeable future they are unique
enough.
```
# Erlang 常用数据结构实现
erlang虚拟机中用Eterm表示所有的类型的数据,具体的实施方案通过占用Eterm的后几位作为类型标签,然后根据标签类型来解释剩余位的用途。这个标签是多层级的,最外层占用两位,有三种类型:
list,剩下62位是指向列表Cons的指针
boxed对象,即复杂对象,剩余62位指向boxed对象的对象头。包括元组,大整数,外部Pid/Port等
immediate立即数,即可以在一个字中表示的小型对象,包括小整数,本地Pid/Port,Atom,NIL等
这三种类型是Erlang类型的大框架,前两者是可以看做是引用类型,立即数相当于是值类型,但无论对于哪种类型,Erlang Eterm本身只占用一个字,理解这一点是很重要的。
对于二三级标签的细分和编码,一般我们无需知道这些具体的底层细节,以下是几种常用的数据结构实现方式。
一. 常用类型
1. atom
atom用立即数表示,在Eterm中保存的是atom在全局atom表中的索引,依赖于高效的哈希和索引表,Erlang的atom比较和匹配像整数一样高效。atom表是不回收的,并且默认最大值为1024*1024,超过这个限制Erlang虚拟机将会崩溃,可通过+t参数调整该上限。
2.Pid/Port
在R9B之后,随着进程数量增加和其它因素,Pid只在32位中表示本地Pid(A=0),将32位中除了4位Tag之外的28位,都可用于进程Pid表示,
出于Pid表示的历史原因,仍然保留三段式的显示,本地Pid表示变成了<0, Pid低15位, Pid高13位>。对于外部Pid,采用boxed复合对象表示,
在将本地Pid发往其它node时,Erlang会自动将为Pid加上本地节点信息,并打包为一个boxed对象,占用6个字。另外,Erlang需要维护Pid表,
每个条目占8个字节,当进程数量过大时,Pid表将占用大量内存,Erlang默认可以使用18位有效位来表示Pid(262144),可通过+P参数调节,
最大值为27位(2^27-1),此时Pid表占用内存为2G。
3. ists
列表以标签01标识,剩余62位指向列表的Cons单元,Cons是[Head|Tail]的组合,在内存中体现为两个相邻的Eterm,Head可以是任何类型的Eterm,
。因此形如L2 = [Elem|L1]的操作,实际上构造了一个新的Cons,其中Head是Elem Eterm,Tail是L1 Eterm,然后将L2的Eterm指向了这个新的Cons,
因此L2即代表了这个新的列表。对于[Elem|L2] = L1,实际上是提出了L1 Eterm指向的Cons,将Head部分赋给Elem,Tail部分赋给L2,
注意Tail本身就是个List的Eterm,因此list是单向列表,并且构造和提取操作是很高效的。需要再次注意的是,Erlang所有类型的Eterm本身只占用一个字大小。
这也是诸如list,tuple能够容纳任意类型的基础。
Erlang中进程内对对象的重复引用只需占用一份对象内存(只是Eterm本身一个字的拷贝),但是在对象跨进程时,对象会被展开,执行速深度拷贝:
4. tuple
tuple属于boxed对象的一种,每个boxed对象都有一个对象头(header),boxed Eterm即指向这个header,这个header里面包含具体的boxed对象类型,
如tuple的header末6位为000000,前面的位数为tuple的size:
tuple实际上就是一个有头部的数组,其包含的Eterm在内存中紧凑排列,tuple的操作效率和数组是一致的。
list,tuple中添加元素,实际上都是在拷贝Eterm本身,Erlang虚拟机会追踪这些引用,并负责垃圾回收。
5. binary
Erlang binary用于处理字节块,Erlang其它的数据结构(list,tuple,record)都是以Eterm为单位的,用于处理字节块会浪费大量内存
,如”abc”占用了7个字(加上ETerm本身),binary为字节流提供一种操作高效,占用空间少的解决方案。
之前我们介绍的数据结构都存放在Erlang进程堆上,进程内部可以使用对象引用,在对象跨进程传输时,会执行对象拷贝。
为了避免大binary跨进程传输时的拷贝开销,Erlang针对binary作出了优化,将binary分为小binary和大binary。
heap binary
小于64字节(定义于erl_binary.h ERL_ONHEAP_BIN_LIMIT宏)的小binary直接创建在进程堆上,称为heap binary,heap binary是一个boxed对象:
refc binary
大于64字节的binary将创建在Erlang虚拟机全局堆上,称为refc binary(reference-counted binary),可被所有Erlang进程共享,
这样跨进程传输只需传输引用即可,虚拟机会对binary本身进行引用计数追踪,以便GC。refc binary需要两个部分来描述,
位于全局堆的refc binary数据本身和位于进程堆的binary引用(称作proc binary),这两种数据结构定义于global.h中。
下图描述refc binary和proc binary的关系:
所有的OffHeap(进程堆之外的数据)被组织为一个单向链表,进程控制块(erl_process.h struct process)中的off_heap字段维护链表头和所有OffHeap对象的总大小,
当这个大小超过虚拟机阀值时,将导致一次强制GC。注意,refc binary只是OffHeap对象的一种,以后可扩展其它种类。
sub binary
sub binary是Erlang为了优化binary分割的(如split_binary/2),由于Erlang变量不可变语义,拷贝分割的binary是效率比较底下的做法,Erlang通过sub binary来复用原有binary。
bit string
当我们通过如<<2:3,3:6>>的位语法构建binary时,将得到<<65,1:1>>这种非字节对齐的数据,即二进制流,
在Erlang中被称为bitstring,Erlang的bitstring基于ErlSubBin结构实现,此时bitsize为最后一个字节的有效位数,
size为有效字节数(不包括未填满的最后一个字节),对虚拟机底层来说,sub bianry和bit string是同一种数据结构。
## 复合类型
1. record
这个类型无需过多介绍,它就是一个tuple,所谓record filed在预编译后实际上都是通过数值下标来索引,因此它访问field是O(1)复杂度的。
2. map
该结构体之后就是依次存放的Value,因此maps的get操作,需要先遍历keys tuple,找到key所在下标,然后在value中取出该下标偏移对应的值。因此是O(n)复杂度的。详见maps:get源码($BEAM_SRC/erl_map.c erts_maps_get)。
如此的maps,只能作为record的替用,并不是真正的Key->Value映射,因此不能存放大量数据。而在OTP18中,maps加入了针对于big map的hash机制,
当maps:size < MAP_SMALL_MAP_LIMIT时使用flatmap结构也就是上述OTP17中的结构当maps:size >= MAP_SMALL_MAP_LIMIT时,
将自动使用hashmap结构来高效存取数据。MAP_SMALL_MAP_LIMIT在erl_map.h中默认定义为32。
仍然要注意Erlang本身的变量不可变原则,每次执行更新maps,都会导致新开辟一个maps,并且拷贝原maps的keys和values,在这一点上,maps:update比maps:put更高效,因为前者keys数量不会变,因此无需开辟新的keys tuple,拷贝keys tuples ETerm即可。实际使用maps时:
更新已有key值时,使用update(:=)而不是put(=>),不仅可以检错,并且效率更高
当key/value对太多时,对其进行层级划分,保证其拷贝效率
实际测试中,OTP18中的maps在存取大量数据时,效率还是比较高的,这里有一份maps和dict的简单测试函数,可通过OTP17和OTP18分别运行来查看效率区别。通常情况下,我们应当优先使用maps,比起dict,它在模式匹配,mongodb支持,可读性上都有很大优势。
3. array
array下标从0开始
array有两种模式,一种固定大小,另一种按需自动增长大小,但不会自动收缩
支持稀疏存储,执行array:set(100,value,array:new()),那么[0,99]都会被设置为默认值(undefined),该默认值可修改。
在实现上,array最外层被包装为一个record:
... 其他等待被添加
## 顺序
number < atom < reference < fun < port < pid < tuple < map < nil < list < bit string
%% Module Description
%% sets sets, a collection of unique elements.
%% gb_sets sets, but based on a general balanced data structure
%% gb_tree a general balanced tree
%% dict maps, also called associative arrays
%% queue double-ended queues
%% ets hash tables and ordered sets (trees), stored outside the process
%% dets on-disk hash tables
(请注意:不常用的模块ordset和 orddict只是有序列表,因此对于诸如插入之类的常见操作具有O(n))
# Erlang标准数据结构的选择
实际上,Erlang程序使用列表(本机或通过dict)来处理涉及多达数百个元素的数据结构,
并使用ETS(Erlang术语存储)或mnesia来处理更大的数据。
ETS使用散列来允许几乎恒定时间访问几乎任意数量的数据。
对于由几个(几十个或几百个)项组成的数据集合,列表通常要优于ETS和树。 对于大量小物品,ETS往往效果最好。
对于较大的项目,数据插入ets和从ets读取都会复制数据, 需要掂量。
lists ,maps 和record是erlang最为常用的数据结构,lists使用方便简单,maps则查询高效,record则需要预定义,
对比测试数据maps在查询性能上比lists高, 而在遍历上lists则更优。对于频繁插入和查询的数据,maps是最佳的选择,
record在数据量小的情况下 插入 更新 查询效率都很高, 而且使用的是模式匹配也很方便
lists则适用于广播列表之类需要遍历的数据和数据量少的情况。
更多数据结构
utPdDs, utArrayDs, utTupleDs, utListsDs, utMapsDs, utEtsSetDs, utEtsOrdDs, utDictDs, utGb_treesDs, utSetsDs, utGb_setsDs, utOrddictDs, utOrdsetsDs, utAtomicsDs, utPTermDs
测试代码见 testCase/DsTest
数据结构测评结果见 dosc/erlang-DsBenchMark.txt

+ 1159
- 0
src/docs/erlang/erlang规范.md
文件差異過大導致無法顯示
查看文件


+ 344
- 0
src/docs/erlang/erlang进程.md 查看文件

@ -0,0 +1,344 @@
Erlang 进程相关学习
====================================
# 目录
1. [actor模型和进程特性](#actor模型和进程特性)
2. [进程创建](#进程创建)
3. [进程监控与注册](#进程注册与监控)
4. [进程调度](#进程调度)
5. [进程发送消息](#进程发送消息)
6. [进程接收消息](#进程接收消息)
7. [进程GC](#进程GC)
8. [更多](#更多)
## actor模型和进程特性
### actor模型
在计算机科学中,它是一个并行计算的数学模型,最初为由大量独立的微处理器组成的高并行计算机所开发,Actor模型的理念非常简单:
天下万物皆为Actor。Actor之间通过发送消息来通信,消息的传送是异步的,通过一个邮件队列(mail queue)来处理消息。每个Actor
是完全独立的,可以同时执行它们的操作。每一个Actor是一个计算实体,映射接收到的消息到以下动作:
1. 发送有限个消息给其它Actor
2. 创建有限个新的Actor
3. 为下一个接收的消息指定行为
以上三种动作并没有固定的顺序,可以并发地执行。Actor会根据接收到的消息进行不同的处理。
简而言之: 一个Actor指的是一个最基本的计算单元,它能接收一个消息并且基于其执行计算。
综上,我们知道可以把系统中的所有事物都抽象成一个Actor,那么在一个系统中,可以将一个大规模的任务分解为一些小任务,这些小任务
可以由多个Actor并发处理,从而减少任务的完成时间和任务复杂度。
为什么会在讲Erlang进程的时候讲Actor模型的概念,就是因为对于Erlang的并发编程模型正是基于Actor模型,Erlang的代码运行在
进程中,而进程就是Erlang称呼Actor的方式,Eralng也是最著名的使用Actor规则的编程的语言。
### Eralng进程特性
在Erlang的进程不是我们传统上的进程,Erlang进程是轻量级进程,它的生成、上下文切换和消息传递是由虚拟机管理的,操作系统
线程进程和Erlang进程之间没有任何联系,这使并发有关的操作不仅独立于底层的操作系统,而且也是非常高效和具有很强可扩展性。
它运行在 Erlang 虚拟机上,非常小,非常轻,可以瞬间创建上万,甚至几十万个,进程间完全是独立的内存空间执行,不共享内存,
这些独立的内存空间可以独立的进行垃圾回收,基于独立运行,在发生错误的时候也是隔离的,其他不相关的进程可以继续运行。
在进程运行时若出现错误,由于进程的轻量级,Erlang 采取的措施是“任其崩溃”和“让其他进程修复”。
在Erlang上查看默认限制数量是26万多,可以进行修改。每个进程创建后都会有一个独一无二的 Pid,这些进程之间通过 Pid 来互相发
送消息,进程的唯一交互方式也是消息传递,消息也许能被对方收到,也许不能,收到后可以处理该消息。消息发送是异步的如果想知道某
个消息是否被进程收到,必须向该进程发送一个消息并等待回复。
## 进程创建
Erlang 中的并发编程只需要如下几个简单的函数。
```erlang
Pid = spawn(Mod,Func, Args)
```
创建一个新的并发进程来执行Mod模块中的 Fun(),Args 是参数。
跟上面提供的spawn/3功能相同的函数还有:
```erlang
spawn(Fun) -> pid()
spawn(Node, Fun) -> pid()
spawn(Module, Function, Args) -> pid()
spawn(Node, Module, Function, Args) -> pid()
spawn_link(Fun) -> pid()
spawn_link(Node, Fun) -> pid()
spawn_link(Module, Function, Args) -> pid()
spawn_link(Node, Module, Function, Args) -> pid()
spawn_monitor(Fun) -> {pid(), reference()}
spawn_monitor(Module, Function, Args) -> {pid(), reference()}
spawn_opt(Fun, Options) -> pid() | {pid(), reference()}
spawn_opt(Node, Fun, Options) -> pid() | {pid(), reference()}
spawn_opt(Module, Function, Args, Options) ->pid() | {pid(), reference()}
spawn_opt(Node, Module, Function, Args, Options) ->pid() | {pid(), reference()}
```
创建好进程,返回对应的Pid之后向就可以向进程进程发送消息,erlang用 “!”来发送消息,格式如下。notice:消息发送是异步的,
发送方不等待而是继续之前的工作。
```erlang
Pid !Message,
Pid1 ! Pid2 ! Pid3 ! Pid..n ! Message.
```
erlang用 receve ... end 来接受发送给某个进程的消息,匹配后处理,格式如下。
```erlang
receive
Pattern1 [when Guard1] ->
Expression1;
Pattern2 [when Guard2] ->
Expression2;
...
after T ->
ExpressionTimeout
end
```
某个消息到达后,会先与 Pattern 进行匹配,匹配相同后执行,若未匹配成功消息则会保存起来待以后处理,进程会开始下一轮操作,
若等待超时T,则会执行表达式 ExpressionTimeout。
## 进程注册与监控
### 进程注册
有些时候使用通过进程Pid来标识进程需要维护进程Pid,出于某些原因维护进程Pid,不方便灵活,比如你给某个服务器进程请求数据,
你还得考虑怎么得到服务器进程的Pid,有些时候进程由于某种异常重启后Pid会发生变化,如果没有及时同步机制,会导致功能异常,
于是乎Erlang提供了一套进程注册管理的机制----注册进程Erlang中管理注册进程的有4个内置函数,register、unregister、
whereis、registered,它们的用法如下:
1)register(Atom, Pid):将一个进程Pid注册一个名为AnAtom的原子,如果原子AnAtom已经被另一个注册进程所使用,
那么注册就会失败。
2)unregister(Atom):移除与AnAtom相对应进程的所有注册信息。如果一个注册死亡,那么它也会被自动取消注册。
3)whereis(Atom) -> Pid | undefined:判断AnAtom是否已经被其他进程注册。如果成功,则返回进程标识符Pid。
如果AnAtom没有与之相对应的进程,那么就返回原子undefined。
4)registered() -> [AnAtom ::atom()]:返回一个系统中所有已经注册的名称列表。
### 进程监控
Erlang 对于进程处理理念之一是“任其崩溃”和“让其他进程修复”,常规Erlang系统中有很多进程同时运行,进程之间可能相互依赖,
这么复杂的情况之下怎么实现该理念呢?Erlang除了提供exception,try catch等语法,还支持Link和Monitor两种监控进程的机制,
使得所有进程可以连接起来,组成一个整体。当某个进程出错退出时,其他进程都会收到该进程退出的消息通知。有了这些特点,使用erlang
建立一个简单,并且健壮的系统就不是什么难事。
#### 进程双向监控-Link
相关API link(Pid), A进程调用了link(Pid) 则A进程与Pid之间就建立起了双向连接,如果两个进程相连接,如果其中一个终止时,
讲发送exit信号给另一方,使其终止,同时终止进程会依次发送exit信号给所有与其连接的进程,这使得exit信号在系统内层层蔓延。
该函数连接不存在的进程时会导致发起连接的进程终止
spawn_link()系列函数 它与link(Pid)的差别就是 原子性与非原子性
unlink(Pid) 移除调用进程与Pid的连接
通过调用process_flag(trap_exit, true)可以设置捕捉exit信号,
假如有A,B两个进程且彼此link
总结...
1.当A的结束原因是normal时(进程正常执行完就是normal),B是不会退出的,此时link机制不发生作用
2.若A的结束原因是killed,例如调用exit(PidA,kill) ,则无论B是否有设置trap_exit,B都会terminate,此时退出信号捕捉机制是无效的
3.若A的结束原因不是normal也不是killed(例如exit(PidA,Reason)),那么B在设置了trap_exit时,会捕捉到退出信号,
取而代之的是收取到一条消息{‘EXIT’,Pid,Reason},这时B不会结束,用户可以根据收到的消息对A进程的结束进行处理;若B没有设置trap_exit,B就会terminate
|捕获状态 |退出信号(原因) |动作 |
| :-------------------| ------------------: | :--------------------------------------:|
|false | normal | 不做任何事 |
|false | kill | 消亡,向链接的进程广播退出信号(killed) |
|false | X | 消亡,向链接的进程广播退出信号X |
|true | normal | 接收到{'EXIT', Pid, nomal} |
|true | kill | 消亡,向链接的进程广播退出信号(killed) |
|true | X | 将{'EXIT', Pid, X} 加入到邮箱 |
#### 监视器(monitor)
相关API
monitor(process, monitor_process_identifier()) %monitor_process_identifier() 为Pid或者已注册的进程名称
demonitor(MonitorRef)
demonitor(MonitorRef, OptionList)
监视器与link不同的是它是单向式观察一些进程终止,各个监视器通过Erlang的引用相互区分,是调用monitor返回的,具有唯一性,
而且A进程可以设置多个对B进程的监视器,每一个通过不同的引用区分。
当被监视的进程终止时,一条格式{'Down',Reference, process, Pid, Reason}的消息会被发给监视此进程的进程
调用erlang:demonitor(Reference)可以移除监视器,
调用erlang:demonitor(Reference,[flush])可以让该监视进程邮箱中所有与Reference对应的{'DOWN', Reference,process,Pid,Reason}
的消息被冲刷掉。
如果尝试监视一个不存在的进程会导致收到一条{'DOWN', Reference, process, Pid,Reason}的消息,其中Reason为noproc,这和link()不一样
## 进程调度
就目前计算机体系结构而言,任何进程或线程要执行就需要得到CPU资源,对于erlang的进程同样如此。erlang虚拟机同时存在成千上万的进程,
但是cpu核心数又是有限的,所有erlang并发特性就需要一个合适的调度规则来安排各个进程的运行,
简单而言,erlang虚拟机调度程序保留两个队列,准备好运行的就绪队列以及等待接收消息的进程的等待队列。当等待队列中的进程收到消息或获
得超时时,它将被移动到就绪队列。调度程序从就绪队列中选择第一个进程并将其交给BEAM执行一个时间片。当时间片用完时,BEAM会抢占正在
运行的进程,并将进程添加到就绪队列的末尾。如果在时间片用完之前在接收中阻止了进程,则会将其添加到等待队列中。
Erlang调度器主要有以下特点:
1. 进程调度运行在用户空间 :Erlang进程不同于操作系统进程,Erlang的进程调度也跟操作系统完全没有关系,是由Erlang虚拟机来完成的;
2. 调度是抢占式的:每一个进程在创建时,都会分配一个固定数目的reduction(这个数量默认值是2000),每一次操作(函数调用),
reduction就会减少,当这个数量减少到0时或者进程没有匹配的消息时,抢占就会发生(无视优先级);
3. 每个进程公平的使用CPU:每个进程分配相同数量的reduction,可以保证进程可以公平的(不是相等的)使用CPU资源
4. 调度器保证软实时性:Erlang中的进程有优先级,调度器可以保证在下一次调度发生时,高优先级的进程可以优先得到执行。
Reduction
受操作系统中基于时间片调度算法的影响,一开始知道有reduction这个概念时,一直想搞清楚这个reduction到底对应多长的绝对时间,不过,
从Erlang本身对reduction的使用来看,完全没有必要纠结这个问题。《Erlang编程指南》一书中对reduction的说明如下:
程序中的每一个命令,无论它是一个函数调用,还是一个算术操作,或者内置函数,都会分配一定数量的reduction。虚拟机使用这个值来衡量一个
进程的活动水平。
进程优先级
Erlang进程有四种优先级:max, high, normal, low(max只在Erlang运行时系统内部使用,普通进程不能使用)。Erlang运行时有两个
运行队列对应着max和high优先级的运行任务,normal和low在同一个队列中。调度器在调度发生时,总是首先查看具体max优先级的进程队列,
如果队列中有可以进行的进程,就会运行,直到这个队列为空。然后会对high优先级的进程队列做同样的操作(在SMP环境,因为同时有几个调度器,所以在同一时间,可能会有不同优先级的任务在同时运行;
但在同一个调度器中,同一时间,肯定是高优先级的任务优先运行)。普通进程在创建时,一般是normal优先级。normal和low优先级的进程只有
在系统中没有max和high优先级的进程可运行时才会被调度到。通常情况下,normal和low优先级的进程交替执行,low优先级获得CPU资源相对
更少(一般情况下):low优先级的任务只有在运行了normal优先级任务特定次数后(在R15B中,这个数字是8)才会被调度到(也就是说只有
在调度了8个normal优先级的进程后,low优先级的进程才会被调度到,即使low优先级的进程比normal优先级的进程更早进入调度队列,这种
机制可能会引起优先级反转:假如你有成千上万的活动normal进程,而只有几个low优先级进程,那么相比normal进程,low优先级可能会获得
更多的CPU资源)。
## 进程发送消息
Erlang系统中,进程之间的通信是通过消息传递来完成的。消息使用Pid ! Message的形式发送,通过receive语句获取。每个Erlang进程
都有用来存储传入消息的信箱。当一个消息发送的时候,它会从发送进程中拷贝到接收进程的信箱,并以它们到达的时间次序存储。消息的传递是
异步的,一个发送进程不会在发送消息后被暂停。
上面提到发送消息时,会在两个进程之间存在消息复制,为什么需要复制呢?这就跟进程的堆内存有关。虽然在Erlang的文档(heap_type)中
说明堆内存有三种类型:private,shared,hybrid,但是在实际的代码中,只有两种private和hybrid
(参见[$R15B_OTP_SRC/erts/emulator/beam/erl_bif_info.c --> system_info_1]),
(参见[$R15B_OTP_SRC/erts/Makefile.in:# Until hybrid is nofrag, don't build it.),
也就是说Erlang目前的堆内存只有一种:private。
private类型的堆内存是跟shared类型相对的:shared是指所有线程共享同一块内存(比如Java),多个线程对同一块内存的访问需要锁保护;
而private类型的堆内存是指每个进程独享一块内存,对于内存的访问不需要锁保护。
在Erlang的private堆内存架构下,发送消息需要做三件事件:
1. 计算消息的大小,并在接收进程的内存空间中给消息分配内存;
2. 将消息的内容拷贝到接收进程的堆内存中;
3. 最后将消息的地址添加到接收进程的消息队列。
从上面的步骤可以看出,拷贝消息的代码是O(n),n是消息的长度,也就是说消息越长,花费越大。所以在使用Erlang时,要避免大数据量的大消息传递。
在shared堆内存架构下,发送消息只需要O(1)(只传递消息地址),那为什么Erlang要默认选择private类型的堆内存呢?
其实这跟后面要讲到的Erlang的GC相关:private的优势就是GC的延迟很低,可以很快的完成(因为只保存一个进程的数据,
GC扫描时的数据量很小)。在SMP环境下,实际上每个进程有两个消息队列。进程发送消息时,实际上消息是添加到目标进程的公有队列
(通过锁来保证互斥访问);而目标进程在消费消息时,实际上是在自己的私有消息队列上处理的,从而减小锁带来的访问开销。但是,
如果目标进程在自己的私有消息队列上无法匹配到消息,那么公有队列中的消息将被添加到私有队列。
## 进程接收消息
```erlang
receive
Pattern1 [when Guard1] ->
Expression1;
Pattern2 [when Guard2] ->
Expression2;
...
after T ->
ExpressionTimeout
end
```
整个过程如下
1. 当我们输入receive语句时,我们启动一个计时器(如果有after T)。
2. 获取邮箱中的第一个消息,并尝试将其与Pattern1、Pattern2等进行匹配。
如果匹配成功,则从邮箱中删除消息,并计算模式后面的表达式。
3. 如果receive语句中的任何模式都不匹配邮箱中的第一个消息,那么第一个消息将从邮箱中删除并放入“save队列”中。
然后尝试邮箱中的第二条消息。重复此过程,直到找到匹配的消息或检查邮箱中的所有消息为止。
4. 如果邮箱中的所有消息都不匹配,则进程将被挂起,并在下次将新消息放入邮箱时重新安排执行时间。注意,当新消息到达时,
保存队列中的消息不会重新匹配;只匹配新消息( Erlang的实现是非常“聪明”的,并且能够最小化每个消息被接收方的receive测试的次数)
5. 一旦匹配了消息,那么所有放入save队列的消息都将按照到达进程的顺序重新进入邮箱。如果设置了计时器,
则清除计时器。
6. 如果计时器在等待消息时超时,则计算表达式ExpressionsTimeout,并按到达进程的顺序将任何保存的消息放回邮箱。
## 进程GC
erlang 进程GC
Memory Layout 内存分布
在我们深入垃圾回收机制之前,我们先来看看Erlang进程的内存布局. 一个Erlang进程的内存布局通常分为是三个部分(有人认为是四个部分,
把mailbox作为单独的一个部分), 进程控制块, 堆和栈,和普通的Linux进程的内存布局非常类似.
```
Shared Heap Erlang Process Memory Layout
+----------------------------------+ +----------------------------------+
| | | |
| | | PID / Status / Registered Name | Process
| | | | Control
| | | Initial Call / Current Call +----> Block
| | | | (PCB)
| | | Mailbox Pointers |
| | | |
| | +----------------------------------+
| | | |
| | | Function Parameters |
| | | | Process
| | | Return Addresses +----> Stack
| | | |
| +--------------+ | | Local Variables |
| | | | | |
| | +------------+--+ | +-------------------------------+--+
| | | | | | | |
| | | +-------------+--+ | | ^ v +----> Free
| | | | | | | | | Space
| | | | +--------------+-+ | +--+-------------------------------+
| +-+ | | | | | |
| +-+ | Refc Binary | | | Mailbox Messages (Linked List) |
| +-+ | | |   |
| +------^---------+ | | Compound Terms (List, Tuples) | Process
| | | | +----> Private
| | | | Terms Larger than a word | Heap
| | | | |
| +--+ ProcBin +-------------+ Pointers to Large Binaries |
| | | |
+----------------------------------+ +----------------------------------+
```
进程控制块: 进程控制块持有关于进程的一些信息, 比如PID, 进程状态(running, waitting), 进程注册名, 初始和当前调用,
指向进程mailbox的指针
栈: 栈是向下增长的, 栈持有函数调用参数,函数返回地址,本地变量以及一些临时空间用来计算表达式.
堆: 堆是向上增长的, 堆持有进程的mailbox, 复合terms(Lists, Tuples, Binaries),以及大于一个机器字的对象(比如浮点数对象).
大于64个字节的二进制terms,被称为Reference Counted Binary, 他们不是存在进程私有堆里面,他们是存在一个大的共享堆里,所有进程
都可以通过指向RefC Binary的指针来访问该共享堆,RefC Binary指针本身是存在进程私有堆里面的.
GC Details
为了更准确的解释默认的Erlang垃圾回收机制, 实际上运行在每个独立Erlang进程内部的是分代拷贝垃圾回收机制, 还有一个引用计数的
垃圾回收运行在共享堆上.
Private Heap GC 私有堆垃圾回收
私有堆的垃圾回收是分代的. 分代机制把进程的堆内存分为两个部分,年轻代和年老代. 区分是基于这样一个考虑, 如果一个对象在运行
一次垃圾回收之后没有被回收,那么这个对象短期内被回收的可能性就很低. 所以, 年轻代就用来存储新分配的数据,年老代就用来存放运行
一定次数的垃圾回收之后依然幸存的数据. 这样的区分可以帮助GC减少对那些很可能还不是垃圾的数据不必要的扫描. 对应于此, Erlang的
GC扫描有两个策略, Generational(Minor) 和 Fullsweep(Major). Generational GC只回收年轻代的区域, 而Fullsweep则同时回收年轻代和
年老代.
下面我们一起来review一下一个新创建的Erlang进程触发GC的步骤, 假设以下不同的场景:
场景 1:
Spawn > No GC > Terminate
假设一个生存期较短的进程, 在存活期间使用的堆内存也没有超过 min_heap_size,那么在进程结束是全部内存即被回收.
场景 2:
Spawn > Fullsweep > Generational > Terminate
假设一个新创建的进程,当进程的数据增长超过了min_heap_size时, fullsweep GC即被触发, 因为在此之前还没有任何GC被触发,所以堆区
还没有被分成年轻代和年老代. 在第一次fullsweep GC结束以后, 堆区就会被分为年轻代和年老代了, 从这个时候起, GC的策略就被切换为
generational GC了, 直到进程结束.
场景 3:
Spawn > Fullsweep > Generational > Fullsweep > Generational > ... > Terminate
在某些情景下, GC策略会从generation再切换回fullsweep. 一种情景是, 在运行了一定次数(fullsweep_after)的genereration GC之后,
系统会再次切换回fullsweep. 这个参数fullsweep_after可以是全局的也可以是单进程的. 全局的值可以通过函数erlang:system_info(fullsweep_after)获取,
进程的可以通过函数erlang:process_info(self(),garbage_collection)来获取. 另外一种情景是, 当generation GC(minor GC)不能够收集到足够的内存空间时.
最后一种情况是, 当手动调用函数garbage_collector(PID)时. 在运行fullsweep之后, GC策略再次切换回generation GC直到以上的任意一个情景再次出现.
场景 4:
Spawn > Fullsweep > Generational > Fullsweep > Increase Heap > Fullsweep > ... > Terminate
假设在场景3里面,第二个fullsweep GC依然没有回收到足够的内存, 那么系统就会为进程增加堆内存, 然后该进程就回到第一个场景,像刚创建的进程一样首先
开始一个fullsweep,然后循环往复.
那么对Erlang来说, 既然这些垃圾回收机制都是自动完成的, 为什么我们需要花时间去了解学习呢? 首先, 通过调整GC的策略可以使你的系统运行的更快. 其次,
了解GC可以帮助我们从GC的角度来理解为什么Erlang是一个软实时的系统平台. 因为每个进程有自己的私有内存空间和私有GC,所以每次GC发生的时候只在进程
内部进行,只stop本进程, 不会stop其他进程,这正是一个软实时系统所需要的.
Shared Heap GC 共享堆垃圾回收
共享堆的GC是通过引用计数来实现的. 共享堆里面的每个对象都有一个引用计数,这个计数就是表示该对象被多少个Erlang进程持有(对象的指针存在进程的私有堆里).
如果一个对象的引入计数变成0的时候就表示该对象不可访问可以被回收了.
进程调度
## ## 进程调度
就目前计算机体系结构而言,任何进程或线程要执行就需要得到CPU资源,对于erlang的进程同样如此。erlang虚拟机同时存在成千上万的进程,
但是cpu核心数又是有限的,所有erlang并发特性就需要一个合适的调度规则来安排各个进程的运行,
简单而言,erlang虚拟机调度程序保留两个队列,准备好运行的就绪队列以及等待接收消息的进程的等待队列。当等待队列中的进程收到消息或获
得超时时,它将被移动到就绪队列。调度程序从就绪队列中选择第一个进程并将其交给BEAM执行一个时间片。当时间片用完时,BEAM会抢占正在
运行的进程,并将进程添加到就绪队列的末尾。如果在时间片用完之前在接收中阻止了进程,则会将其添加到等待队列中。
Erlang调度器主要有以下特点:
1. 进程调度运行在用户空间 :Erlang进程不同于操作系统进程,Erlang的进程调度也跟操作系统完全没有关系,是由Erlang虚拟机来完成的;
2. 调度是抢占式的:每一个进程在创建时,都会分配一个固定数目的reduction(这个数量默认值是2000),每一次操作(函数调用),
reduction就会减少,当这个数量减少到0时或者进程没有匹配的消息时,抢占就会发生(无视优先级);
3. 每个进程公平的使用CPU:每个进程分配相同数量的reduction,可以保证进程可以公平的(不是相等的)使用CPU资源
4. 调度器保证软实时性:Erlang中的进程有优先级,调度器可以保证在下一次调度发生时,高优先级的进程可以优先得到执行。
1. What operators does Erlang have?
```
Arithmetic operators: + - * / div rem
Comparison operators: =:= == =/= /= > >= < =<
Logical operators: and andalso or orelse
Bitwise operators: bsl bsr Bitwise logical operators: band Bor bxor bnot
```
---------------------

+ 333
- 0
src/docs/erlang/erlang集群相关.md 查看文件

@ -0,0 +1,333 @@
节点连接
分布式erlang系统中的节点是松散连接的, 第一次使用另一个节点名称 例如调用 spawn(Node, M, F, A)或者
net_adm:ping(Node)的时候 就会尝试连接该节点
默认情况下 节点连接是可以传递的 如果节点A连接了节点B 节点B连接了节点C 则节点A会尝试连接到节点C
可以通过命令 `-connect_all false` 来关闭这个功能
如果想主动断开与某个节点的连接 可以使用 `erlang:disconnect_node(Node)` 强制断开节点连接
Erlang Port Mapper Daemon epmd会在启动Erlang节点的每个主机上自动启动。它负责将符号节点名映射到机器地址。请参见ERTS中的 epmd(1)手册页。
四、跨机器连通防火墙问题
要想连通某个节点,该节点(即被连接的)要保证:
1. epmd的端口(默认是4369)在防火墙打开;
2. erl要加 `-kernel inet_dist_listen_min Min inet_dist_listen_max Max` 设定使用的端口范围(若只有一个端口,则Min==Max),要保证这些端口在防火墙打开,并且这些端口不能全部被占用
也就是要连接某个节点,是和该节点所在机器的epmd以及该节点通讯。所以发起连接的节点不需要上面的2个要求,即所在机器不需要防火墙打开4369端口,也不需要加-kernel inet_dist_listen_min Min inet_dist_listen_max Max
隐藏节点 在分布式erlang系统中 有时候连接到所有节点是不好的 可以用使用 命令行标记 `-hidden` 隐藏节点和其他节点的连接是不可传递的 同样隐藏节点也不会显示在nodes()函数返回的节点列表
这也意味这未将隐藏节点添加到global跟踪的节点集群中,另外`nodes(hidden) or nodes(connected)` 会返回隐藏的节点
节点cookie
身份验证确定允许哪些节点相互通信。在不同Erlang节点的网络中,它以最低的级别内置到系统中。每个节点都有自己的cookie,它是一个Erlang原子。
当一个节点尝试连接到另一个节点时,将对魔术cookie进行比较。如果它们不匹配,则连接的节点拒绝连接。
可以使用 `erlang:set_cookie(node(), Cookie)` 将本地节点的Cookie设置为Cookie, `erlang:get_cookie()` 返回本地节点的cookie
为了使cookie为Cookie1的节点Node1能够连接到具有不同cookie Cookie2的节点Node2或者让Node2接收到Node1的连接,必须首先在Node1处调用
`erlang:set_cookie(Node2, Cookie2)`(该调用不会修改 Node1本地的cookie, 而且这样操作之后 Node1会自动与Node2所连节点列表中的节点cookie都为Cookie1的节点互联,不相同的cookie不会自动互联)
这样具有多个cookie的分布式系统就可以互联了
关于分布式的BIFS
Some useful BIFs for distributed programming (for more information, see the erlang(3) manual page in ERTS:
BIF Description
erlang:disconnect_node(Node) Forces the disconnection of a node.
erlang:get_cookie() Returns the magic cookie of the current node.
is_alive() Returns true if the runtime system is a node and can connect to other nodes, false otherwise.
monitor_node(Node, true|false) Monitors the status of Node. A message{nodedown, Node} is received if the connection to it is lost.
node() Returns the name of the current node. Allowed in guards.
node(Arg) Returns the node where Arg, a pid, reference, or port, is located.
nodes() Returns a list of all visible nodes this node is connected to.
nodes(Arg) Depending on Arg, this function can return a list not only of visible nodes, but also hidden nodes and previously known nodes, and so on.
erlang:set_cookie(Node, Cookie) Sets the magic cookie used when connecting to Node. If Node is the current node, Cookie is used when connecting to all new nodes.
spawn[_link|_opt](Node, Fun) Creates a process at a remote node.
spawn[_link|opt](Node, Module, FunctionName, Args) Creates a process at a remote node.
Distribution Command-Line Flags
Examples of command-line flags used for distributed programming (for more information, see the erl(1) manual page in ERTS:
Command-Line Flag Description
-connect_all false Only explicit connection set-ups are used.
-hidden Makes a node into a hidden node.
-name Name Makes a runtime system into a node, using long node names.
-setcookie Cookie Same as calling erlang:set_cookie(node(), Cookie).
-sname Name Makes a runtime system into a node, using short node names.
Distribution Modules Examples of modules useful for distributed programming:
In the Kernel application:
Module Description
global A global name registration facility.
global_group Grouping nodes to global name registration groups.
net_adm Various Erlang net administration routines.
net_kernel Erlang networking kernel.
Kernel Modules Useful For Distribution. In the STDLIB application:
Module Description
slave Start and control of slave nodes.
%% ***************************************** net_adm 模块 **********************************************
## dns_hostname(Host) -> {ok, Name} | {error, Host}
Types
Host = atom() | string()
Name = string()
返回的正式名称主机,或 {错误,主机}如果没有这样的名字中找到
## host_file() -> Hosts | {error, Reason}
Types
Hosts = [Host :: atom()]
Reason =
file:posix() |
badarg | terminated | system_limit |
{Line :: integer(), Mod :: module(), Term :: term()}
读取文件.hosts.erlang,请参阅文件部分 。以列表形式返回此文件中的主机。如果无法读取文件或无法解释文件上的Erlang术语,则返回{error,Reason}。
## localhost() -> Name
Types
Name = string()
返回本地主机的名称。如果Erlang以命令行标志-name开头,则Name是标准名称。
## names() -> {ok, [{Name, Port}]} | {error, Reason}
## names(Host) -> {ok, [{Name, Port}]} | {error, Reason}
Types
Host = atom() | string() | inet:ip_address()
Name = string()
Port = integer() >= 0
Reason = address | file:posix()
ie.
(arne@dunn)1> net_adm:names().
{ok,[{"arne",40262}]}
与epmd -names类似,请参阅 erts:epmd(1)。 主机默认为本地主机。返回epmd在指定主机上注册的Erlang节点的名称和关联的端口号 。如果epmd无法运行,则返回 {error, address}。
## ping(Node) -> pong | pang
Types
Node = atom()
Sets up a connection to Node. Returns pong if it is successful, otherwise pang.
## world() -> [node()]
## world(Arg) -> [node()]
Types
Arg = verbosity()
verbosity() = silent | verbose
调用Erlang主机文件.hosts.erlang中指定的所有主机的names(Host),收集答复,然后在所有这些节点上评估ping(Node)。返回已成功ping通的所有节点的列表。
Arg默认为silent。如果Arg == verbose,则该函数将写入有关将其ping到标准输出的节点的信息。
当启动一个节点并且最初不知道其他网络节点的名称时,此功能很有用。
Returns {error, Reason} if host_file() returns {error, Reason}.
## world_list(Hosts) -> [node()]
## world_list(Hosts, Arg) -> [node()]
Types
Hosts = [atom()]
Arg = verbosity()
verbosity() = silent | verbose
Same as world/0,1, but the hosts are specified as argument instead of being read from .hosts.erlang.
## .hosts.erlang
文件.hosts.erlang由许多以Erlang术语编写的主机名组成。在当前工作目录,用户的主目录和$OTP_ROOT (Erlang / OTP的根目录)中依次查找。
文件.hosts.erlang的格式必须是每行一个主机名。主机名必须用引号引起来。
example
'super.eua.ericsson.se'.
'renat.eua.ericsson.se'.
'grouse.eua.ericsson.se'.
'gauffin1.eua.ericsson.se'.
^ (new line)
%% ***************************************** net_kernel 模块 **********************************************
## 描述
网络内核是注册为net_kernel的系统进程, 必须运行才能使分布式Erlang正常工作。该过程的目的是实现BIF的部分spawn / 4和spawn_link / 4并提供对网络的监视。
使用命令行标志-name或-sname启动一个Erlang节点 :
$ erl -sname foobar
也可以 直接从普通的Erlang Shell提示符下调用net_kernel:start([foobar]):
1> net_kernel:start([[foobar, shortnames])。
{ok,<0.64.0>}
(foobar @ gringotts)2>
如果节点以命令行标志-sname开头,则节点名称为foob​​ar @ Host,其中Host是主机的简称(不是完全限定的域名)。如果以flag -name开头,则节点名称为foob​​ar @ Host,其中Host是标准域名。有关更多信息,请参见 erl。
通常,引用另一个节点时会自动建立连接。可以通过将内核配置参数dist_auto_connect设置为never来禁用此功能 ,请参阅 kernel(6)。在这种情况下,必须通过调用connect_node / 1显式建立连接 。
## allow(Nodes) -> ok | error
Types
Nodes = [node()]
允许访问指定的节点集。
在第一次调用allow / 1之前,可以连接具有正确cookie的任何节点。当允许/ 1被调用,建立允许节点列表。从(或到)不在该列表中的节点进行的任何访问尝试都将被拒绝。
随后对allow / 1的调用会将指定的节点添加到允许的节点列表中。无法从列表中删除节点。
如果Nodes中的任何元素都不是原子,则返回错误。
## connect_node(Node) -> boolean() | ignored
Types
Node = node()
建立与Node的连接。如果已建立连接或已经建立连接,或者Node是本地节点本身,则返回 true。如果连接尝试失败,则返回false;如果本地节点未处于活动状态, 则将其忽略。
## get_net_ticktime() -> Res
Types
Res = NetTicktime | {ongoing_change_to, NetTicktime} | ignored
NetTicktime = integer() >= 1
获取net_ticktime(请参阅 kernel(6))。
定义的返回值(Res):
NetTicktime
net_ticktime is NetTicktime seconds.。
{ongoing_change_to,NetTicktime}
net_kernel is currently changing net_ticktime to NetTicktime seconds.
ignored
The local node is not alive.
##getopts(Node, Options) -> {ok, OptionValues} | {error, Reason} | ignored
Types
Node = node()
Options = [inet:socket_getopt()]
OptionValues = [inet:socket_setopt()]
Reason = inet:posix() | noconnection
获取连接到Node的配电插座的一个或多个选项。
如果Node是连接的节点,则返回值与inet:getopts(Sock,Options) 中的返回值相同 ,其中Sock是Node的分发套接字。
返回忽略,如果本地节点是不是活的或 {错误,noconnection}如果节点未连接。
## monitor_nodes(Flag) -> ok | Error
## monitor_nodes(Flag, Options) -> ok | Error
Types
Flag = boolean()
Options = [Option]
Option = {node_type, NodeType} | nodedown_reason
NodeType = visible | hidden | all
Error = error | {error, term()}
调用过程订阅或取消订阅节点状态更改消息。当新的节点连接时nodeup消息,一个节点断开时nodedown消息被传递到所有订阅的进程
如果Flag为true,则开始新的订阅。如果Flag为false,则将 停止所有使用相同选项启动的先前订阅。如果两个选项列表包含相同的选项集,则认为它们是相同的。
从内核版本2.11.4和ERTS版本5.5.4开始,保证以下内容:
在从远程节点传递通过新建立的连接传递的任何消息之前,先传递nodeup消息。
直到已传递了来自远程节点的通过连接传递的所有消息后,才会传递nodedown消息。
从内核2.13版和ERTS 5.7版开始,保证以下内容:
在erlang:nodes / X结果中出现相应节点后,将传递nodeup消息 。
在erlang:nodes / X的结果中对应的节点消失之后,将传递nodedown消息 。
节点状态更改消息的格式取决于 Options。如果Options为 [],这是默认设置,则格式如下:
{nodeup,Node} | {nodedown,Node} Node= node()
如果Options不是[],则格式如下:
{nodeup,Node,InfoList} | {nodedown,Node,InfoList} Node= node() InfoList = [{Tag,Val}]
InfoList是一个元组列表。其内容取决于 Options,请参见下文。
另外,当OptionList == []时,仅监视可见节点,即出现在erlang:nodes / 0结果中的 节点。
选项可以是以下任意一项:
{node_type,NodeType} NodeType的有效值:
visible
订阅仅针对可见节点的节点状态更改消息。元组{node_type,visible}包含在InfoList中。
hidden
订阅仅针对隐藏节点的节点状态更改消息。元组{node_type,hidden}已包含在InfoList中。
all
订阅可见和隐藏节点的节点状态更改消息。元组 {node_type,visible | hidden}已包含在 InfoList中。
nodedown_reason
元组{nodedown_reason,Reason}包含 在nodedown消息的InfoList中。
原因可以取决于所使用的分发模块或进程是任何术语,但是对于标准TCP分发模块,可以是以下任意一种:
connection_setup_failed
连接设置失败( 发送nodeup消息后)。
no_network
没有可用的网络。
net_kernel_terminated
所述net_kernel过程终止。
shutdown
未指定的连接关闭。
connection_closed
连接已关闭。
disconnect
连接已断开连接(从当前节点强制连接)。
net_tick_timeout
Net tick time-out.
send_net_tick_failed
Failed to send net tick over the connection.
get_status_failed
从保持连接的端口检索状态信息失败。
## set_net_ticktime(NetTicktime)-> Res
## set_net_ticktime(NetTicktime,TransitionPeriod)-> Res
Types
NetTicktime = integer() >= 1
TransitionPeriod = integer() >= 0
Res =
unchanged | change_initiated |
{ongoing_change_to, NewNetTicktime}
NewNetTicktime = integer() >= 1
将net_ticktime(请参阅 kernel(6))设置为 NetTicktime秒。 TransitionPeriod默认为60。
一些定义:
Minimum transition traffic interval (MTTI)
minimum(NetTicktime, PreviousNetTicktime)*1000 div 4 milliseconds.
Transition period
调用set_net_ticktime / 2之后,要覆盖TransitionPeriod秒的最少连续MTTI的时间(即(((TransitionPeriod * 1000-1)div MTTI + 1)* MTTI 毫秒)。
如果 NetTicktime <PreviousNetTicktime则net_ticktime更改在过渡期结束时进行否则在开始时在过渡期间net_kernel确保至少每MTTI毫秒在所有连接上都有传出流量
注意
所述net_ticktime变化必须在网络中的所有节点(具有相同的上启动NetTicktime任何节点上的任何过渡期结束前); 否则可能会错误地断开连接。
返回以下之一:
unchanged
net_ticktime已经拥有的价值 NetTicktime和保持不变。
change_initiated
net_kernel启动了将net_ticktime更改 为NetTicktime 秒。
{ongoing_change_to,NewNetTicktime}
该请求被忽略,因为 net_kernel忙于将net_ticktime更改为 NewNetTicktime秒。
## setopts(Node, Options) -> ok | {error, Reason} | ignored
Types
Node = node() | new
Options = [inet:socket_setopt()]
Reason = inet:posix() | noconnection
Set one or more options for distribution sockets。参数节点可以是一个节点名称,也可以是新的原子,以影响所有将来连接的节点的分配套接字。
如果Node不是连接的节点或new,则返回值与 inet:setopts / 2 或{error,noconnection}相同。
如果Node是新的,则Options 还将添加到内核配置参数 inet_dist_listen_options 和 inet_dist_connect_options。
如果本地节点不活动,则返回忽略。
## start([Name]) -> {ok, pid()} | {error, Reason}
## start([Name, NameType]) -> {ok, pid()} | {error, Reason}
## start([Name, NameType, Ticktime]) -> {ok, pid()} | {error, Reason}
Types
Name = atom()
NameType = shortnames | longnames
Reason = {already_started, pid()} | term()
通过启动net_kernel和其他必要的过程,将非分布式节点转变为分布式节点。
请注意,该参数是仅包含一个,两个或三个参数的列表。NAMETYPE默认为longnames 和滚动时间至15000。
## stop() -> ok | {error, Reason}
Types
Reason = not_allowed | not_found
将分布式节点转变为非分布式节点。对于网络中的其他节点,这与发生故障的节点相同。仅当使用start / 1启动网络内核时才可能 ,否则返回{error,not_allowed}。如果本地节点未处于活动状态,则返回 {error,not_found}。

二進制
src/docs/erlang/picture/erlang参数传递讲解.png 查看文件

Before After
Width: 724  |  Height: 880  |  Size: 55 KiB

二進制
src/docs/erlang/picture/erlang数据复制.png 查看文件

Before After
Width: 686  |  Height: 762  |  Size: 21 KiB

二進制
src/docs/erlang/picture/erlang汇编识别为递归标识符.png 查看文件

Before After
Width: 1527  |  Height: 175  |  Size: 23 KiB

二進制
src/docs/erlang/picture/erlang进程状态图.png 查看文件

Before After
Width: 787  |  Height: 584  |  Size: 47 KiB

二進制
src/docs/erlang/picture/列表推导与二进制推导.png 查看文件

Before After
Width: 1343  |  Height: 217  |  Size: 302 KiB

+ 181
- 0
src/docs/erlang/time相关的日志.md 查看文件

@ -0,0 +1,181 @@
erlang 模块的时间函数---------》》》》
localtime_to_universaltime/1
如果基础操作系统支持,则将本地日期和时间转换为世界标准时间(UTC). 否则,不进行任何转换,并 返回Localtime
localtime_to_universaltime/2
将本地日期和时间转换为erlang:localtime_to_universaltime / 1,以协调世界时(UTC),但调用者确定夏令时是否处于活动状态。
如果IsDst == true,则本地 时间位于夏令时,如果IsDst == false ,则不是。如果IsDst == undefined,则底层操作系统可以猜测,
这与调用 erlang:localtime_to_universaltime(Localtime)相同。
universaltime_to_localtime/1
如果基础操作系统支持,则以{{Year,Month,Day},{Hour,Minute,Second}}的形式将世界标准时间(UTC)日期和时间转换为本地日期和时间 。
否则,不进行任何转换,并 返回Universaltime。例:
time/0
以{Hour,Minute,Second}的形式返回当前时间。时区和夏令时校正取决于基础操作系统。
date/0
返回当前日期为{Year,Month,Day}。时区和夏令时校正取决于基础操作系统。
localtime/0
返回当前的本地日期和时间 {{Year,Month,Day},{Hour,Minute,Second}} 时区和夏令时校正取决于基础操作系统。
universaltime/0
如果基础操作系统支持,则根据世界标准时间(UTC)以{{Year,Month,Day},{Hour,Minute,Second}}的形式返回当前日期和时间 。
否则,erlang:universaltime()等效于 erlang:localtime()。例:
posixtime_to_universaltime/1
posixtime 转为 universaltime
universaltime_to_posixtime/1
universaltime换为posixtime时间戳
system_time/0,
以本地时间单位返回当前的 Erlang系统时间。
system_time/1
返回当前的 Erlang系统时间, 该时间已转换为作为参数传递的Unit。
convert_time_unit/3
转换时间的时间单位的值 FromUnit到相应 ConvertedTime时间单元的值 ToUnit。使用下限功能对结果进行四舍五入。
警告:在时间单位之间进行转换时,可能会失去准确性和精度。为了最大程度地减少此类损失,请以本地时间单位收集所有数据,然后对最终结果进行转换。
time_offset/0
以 本地时间单位返回Erlang单调时间和 Erlang系统时间之间的当前时间偏移 。添加到Erlang单调时间的当前时间偏移会给出相应的Erlang系统时间。
时间偏移可能会或可能不会在操作期间更改,具体取决于所使用的时间扭曲模式。
注意:
通过不同的过程,可以在稍有不同的时间点观察到时间偏移量的变化。
如果运行时系统处于 多时间扭曲模式,则当运行时系统检测到OS系统时间已更改时,时间偏移也会 更改。但是,运行时系统不会立即检测到它。
检查时间偏移的任务计划至少每分钟执行一次;因此,在正常操作下,一分钟内即可检测到,但是在重负载下可能需要更长的时间。
time_offset/1
返回Erlang单调时间和 Erlang系统时间之间的当前时间偏移, 该时间已转换为作为参数传递的Unit。
timestamp/0
以{MegaSecs,Secs,MicroSecs}格式返回当前的 Erlang系统时间。此格式与os:timestamp / 0 和不赞成使用的erlang:now / 0相同 。
存在erlang:timestamp()的原因纯粹是为了简化对采用这种时间戳格式的现有代码的使用。可以使用erlang:system_time / 1以您选择的时间单位
更有效地检索当前Erlang系统时间 。
The erlang:timestamp() BIF is equivalent to:
timestamp() ->
ErlangSystemTime = erlang:system_time(microsecond),
MegaSecs = ErlangSystemTime div 1000000000000,
Secs = ErlangSystemTime div 1000000 - MegaSecs*1000000,
MicroSecs = ErlangSystemTime rem 1000000,
{MegaSecs, Secs, MicroSecs}.
calendar 时间模块 -------》》》》》
模块总结
本地和世界时间,星期几,日期和时间转换。
描述
此模块提供本地和通用时间,星期几以及许多时间转换功能的计算。
根据当前时区和夏令时进行调整时,时间是本地时间。当它反映的是经度为零的时间时,它是通用的,无需为夏时制进行任何调整。
世界标准时间(UTC)时间也称为格林威治标准时间(GMT)。
此模块中的时间函数local_time / 0和 Universal_time / 0都返回日期和时间。这是因为日期和时间的单独功能可能导致日期/时间组合错开24小时。
如果其中一个功能在午夜之前调用,而另一个功能在午夜之后调用,则会发生这种情况。此问题也适用于Erlang BIF date / 0和time / 0,
如果需要可靠的日期/时间戳,强烈建议不要使用它们。
所有日期均符合公历。此历法由教皇格雷戈里十三世在1582年引入,从今年开始在所有天主教国家中使用。德国和荷兰的新教部分在1698年采用了它,
英格兰随后在1752年采用了,俄国在1918年(根据格里高利历法,1917年10月的革命发生在11月)。
此模块中的公历将回溯到0年。对于给定的日期,公历天数是指指定日期之前(包括该日期)的天数。同样,指定日期和时间的公历秒数是直至并包括指定日期和时间的秒数。
要计算时间间隔之间的差异,请使用计算公历天或秒的功能。如果将纪元指定为本地时间,则必须将其转换为通用时间,以获取各纪元之间经过时间的正确值
。不建议使用功能time_difference / 2。
一年中的一周存在不同的定义。该模块包含符合ISO 8601标准的一年中的一周实施。由于指定日期的星期数可以落在上一个,当前或下一年,
因此指定年号和星期数很重要。函数iso_week_number / 0和iso_week_number / 1 返回年份和星期数的元组。
calendar:
date_to_gregorian_days/1
date_to_gregorian_days/3
计算从0年开始到指定日期结束的公历天数。
datetime_to_gregorian_seconds/1
计算从年份0开始到指定的日期和时间的公历秒数。
gregorian_days_to_date/1
根据指定的公历天数计算日期。
gregorian_seconds_to_datetime/1
根据指定的公历秒数计算日期和时间。
day_of_the_week/1
day_of_the_week/3
从指定的Year,Month和 Day计算星期几 。将星期几返回为 1:星期一,2:星期二,依此类推。
is_leap_year/1
检查指定的年份是否为闰年。
iso_week_number/0
返回表示实际日期的ISO周编号的元组{Year,WeekNum}。要确定实际日期,请使用函数 local_time / 0。
iso_week_number/1
返回表示指定日期的ISO周编号的元组{Year,WeekNum}。
last_day_of_the_month/2
计算一个月中的天数。
local_time/0
等效于 erlang:localtime()
local_time_to_universal_time/1 %% 不推荐使用了 额豁
从本地时间转换为世界标准时间(UTC)。 DateTime1必须引用1970年1月1日之后的本地日期。
警告:不推荐使用此功能。请改用 local_time_to_universal_time_dst / 1 ,因为它可以提供更正确和完整的结果。
尤其是对于不存在的时间段,由于在切换到夏时制时会被跳过,因此此功能仍会返回结果。
local_time_to_universal_time/2
local_time_to_universal_time_dst/1
从本地时间转换为世界标准时间(UTC)。 参数DateTime1必须引用1970年1月1日之后的本地日期。
返回值是0、1或2个可能的UTC时间的列表:
[]
对于当地时间{Date1,Time1},在切换到夏令时时会跳过该时间段,因此没有相应的UTC,因为当地时间是非法的(从未发生过)。
[DstDateTimeUTC,DateTimeUTC]
对于从夏令时开始重复的时段中的本地{Date1,Time1},存在两个对应的UTC;一个用于夏令时仍处于活动状态的时段的第一个实例,另一个用于第二个实例。
[DateTimeUTC]
对于所有其他本地时间,仅存在一个对应的UTC。
now_to_datetime/1 % = now_to_universal_time/1
返回从erlang:timestamp / 0的返回值转换的通用协调时间(UTC) 。
now_to_local_time/1
返回从erlang:timestamp / 0的返回值转换的本地日期和时间 。
now_to_universal_time/1
返回从erlang:timestamp / 0的返回值转换的通用协调时间(UTC) 。
rfc3339_to_system_time/1
rfc3339_to_system_time/2
将RFC 3339时间戳转换为系统时间。RFC 3339描述了RFC 3339时间戳的数据格式 。
seconds_to_daystime/1
将指定的秒数转换为天,小时,分钟和秒。时间始终是非负的,但是如果参数Seconds是,则 Days是负的 。
seconds_to_time/1
根据指定的秒数计算时间。 秒数必须小于每天的秒数(86400)。
system_time_to_local_time/2
将指定的系统时间转换为本地日期和时间。 TODO 优化此函数
system_time_to_universal_time/2 TODO 优化此函数
将指定的系统时间转换为通用日期和时间。
system_time_to_rfc3339/1
system_time_to_rfc3339/2
将系统时间转换为RFC 3339时间戳。RFC 3339描述了RFC 3339时间戳的数据格式 。偏移量的数据格式也由RFC 3339描述。
time_difference/2 %% 改函数过时 不用
time_to_seconds/1
返回自午夜到指定时间的秒数。
universal_time/0
等效于erlang:universaltime().
universal_time_to_local_time/1
erlang:universaltime_to_localtime(DateTime).
valid_date/1
valid_date/3
此功能检查日期是否有效。

+ 10
- 0
src/docs/erlang/ubuntu安装erlang.md' 查看文件

@ -0,0 +1,10 @@
# 下载dep包
# 执行安装
dpkg -i esl-erlang_21.0-1_ubuntu_artful_amd64.deb
# 按照需求安装依赖包
apt-get install libwxbase3.0-0v5
一键安装所有的依赖包(这个命令可以把依赖都解决掉)
apt-get -f install

+ 72
- 0
src/docs/erlang/编译安装与简单安装.md 查看文件

@ -0,0 +1,72 @@
# 安装 wxWidgets
先安装
安装wxWidgets相关依赖,不装这个就会报以下错误
yum -y install ncurses-devel unixODBC-devel openssl-devel gcc gcc-c++ autoconf automake
yum -y install gtk2-devel binutils-devel
编译安装
./configure --with-regex=builtin --with-gtk --enable-unicode --disable-shared --prefix=/usr/local/wxWidgets
make && make install
sudo ldconfig
# erlang 简单安装
wxWidgets插件
1- 添加源
# wget http://packages.erlang-solutions.com/erlang-solutions-1.0-1.noarch.rpm
# rpm -Uvh erlang-solutions-1.0-1.noarch.rpm
# rpm --import http://packages.erlang-solutions.com/rpm/erlang_solutions.asc
2- 看一下新装上的源
# vim /etc/yum.repos.d/erlang_solutions.repo
[erlang-solutions]
name=Centos $releasever - $basearch - Erlang Solutions
baseurl=http://packages.erlang-solutions.com/rpm/centos/$releasever/$basearch
gpgcheck=0
gpgkey=http://packages.erlang-solutions.com/debian/erlang_solutions.asc
enabled=1
3- 安装
# %%yum install erlang
# yum install erlang-wx
按照源的地址在网页上下载
http://packages.erlang-solutions.com/rpm/centos/7/x86_64/
erlang-18.0-1.el7.centos.x86_64.rpm 和 erlang-wx-18.0-1.el7.centos.x86_64.rpm
# yum install erlang-18.0-1.el7.centos.x86_64.rpm erlang-wx-18.0-1.el7.centos.x86_64.rpm
# erlang编译安装
安装 erlang
3 安装java环境
3.1 下载java安装文件 wget http://download.oracle.com/otn-pub/java/jdk/7u1-b08/jdk-7u1-linux-i586.rpm
3.2 使用rpm 安装 rpm -ivh jdk-7u1-linux-i586.rpm
yum -y install ncurses-devel unixODBC-devel openssl-devel gcc gcc-c++ autoconf automake libxslt gtk3-devel.x86_64
运行configure配置
./configure --prefix=/usr/local/erlang --with-ssl -enable-threads -enable-smmp-support -enable-kernel-poll --without-javac
fop is missing可以忽略
运行make install安装
8 安装
8.1 将erlang源码包解压到/root目录下(一定要/root目录, 非/root目录需要配置参数,还没搞明白)
8.2 运行./configrue
8.3 运行 make install
CentOS添加环境变量
在Linux CentOS系统上安装完php和MySQL后,为了使用方便,需要将php和mysql命令加到系统命令中,如果在没有添加到环境变量之前,执行“php -v”命令查看当前php版本信息时时,则会提示命令不存在的错误,下面我们详细介绍一下在linux下将php和mysql加入到环境变量中的方法(假设php和mysql分别安装在/usr/local/webserver/php/和/usr/local/webserver/mysql/中)。
方法一:直接运行命令export PATH=$PATH:/usr/local/webserver/php/bin 和 export PATH=$PATH:/usr/local/webserver/mysql/bin
使用这种方法,只会对当前会话有效,也就是说每当登出或注销系统以后,PATH 设置就会失效,只是临时生效。
方法二:执行vi ~/.bash_profile修改文件中PATH一行,将/usr/local/webserver/php/bin 和 /usr/local/webserver/mysql/bin 加入到PATH=$PATH:$HOME/bin一行之后
这种方法只对当前登录用户生效
方法三:修改/etc/profile文件使其永久性生效,并对所有系统用户生效,在文件末尾加上如下两行代码
PATH=$PATH:/usr/local/webserver/php/bin:/usr/local/webserver/mysql/bin
PATH=$PATH:/usr/local/erlang/bin
export PATH
最后:执行 命令source /etc/profile或 执行点命令 ./profile使其修改生效,执行完可通过echo $PATH命令查看是否添加成功。

+ 24
- 0
src/docs/svnGit/svnGit相关.md 查看文件

@ -0,0 +1,24 @@
# SVN 显示两个版本之间修改过的文件名
svn diff --summarize -r 2119:head
svn diff --summarize -r 2119:2120
# SVN 获取最新head 的commit id
svn info --show-item revision
# Git 显示两个版本之间修改过的文件名
git diff 456bcb head --name-only
git diff 456bcb 93593a --name-only
# Git 获取最新head 的commit id
git rev-parse HEAD
# SVN A C D M G U R I 的含义
A:add,新增
C:conflict,冲突
D:delete,删除
M:modify,本地已经修改
G:modify and merGed,本地文件修改并且和服务器的进行合并
U:update,从服务器更新
R:replace,从服务器替换
I:ignored,忽略

+ 11
- 0
src/docs/代码规范/提交规范.md 查看文件

@ -0,0 +1,11 @@
# Git/SVN提交代码规范
feat ft - 新功能 feature
fix fx - 修复 bug
docs dc - 文档注释
style st - 代码格式(不影响代码运行的变动)
refactor rf - 重构、优化(既不增加新功能,也不是修复bug)
perf pf - 性能优化
test tt - 增加测试
chore cr - 构建过程或辅助工具的变动
revert rt - 回退
build bd - 打包

+ 9
- 17
src/stackStrace/utParseStack.erl 查看文件

@ -16,30 +16,21 @@
%% [{file, , }, {line, , > 0} :
%% term序列化, term转为string
termToStr(Bin) when is_binary(Bin) ->
binary_to_list(Bin);
termToStr(Term) ->
case catch io_lib:format("~w", [Term]) of
{'EXIT', _} -> lists:flatten(io_lib:format("~p", [Term]));
GoodString -> lists:flatten(GoodString)
end.
parseStack(Stacktrace, Class, Reason) ->
CR = io_lib:format("~n Class:~s~n Reason:~p~n Stacktrace:", [Class, Reason]),
[CR | parseStack(Stacktrace)].
parseStack(Class, Reason, Stacktrace) ->
eFmt:formatBin(<<"~n Class:~s~n Reason:~p~n Stacktrace:~s">>, [Class, Reason, parseStack(Stacktrace)]).
parseStack(Stacktrace) ->
[begin
<<begin
case Location of
[] ->
[<<"\n ">>, atom_to_list(Mod), <<":">>, atom_to_list(Func), <<"(">>, termToStr(Arity), <<")">>];
<<" ", (atom_to_binary(Mod, utf8))/binary, ":", (atom_to_binary(Func, utf8))/binary, "(", (eFmt:formatBin("~w", [Arity]))/binary, ")\n">>;
[{file, File}, {line, Line}] ->
[<<"\n ">>, atom_to_list(Mod), <<":">>, atom_to_list(Func), <<"/";>>;, integer_to_binary(Arity), <<" (">>, File, <<":">>, integer_to_binary(Line), <<")">>];
<<" ", (atom_to_binary(Mod, utf8))/binary, ":", (atom_to_binary(Func, utf8))/binary, "/", (integer_to_binary(Arity))/binary, "(", (unicode:characters_to_binary(File))/binary, ":", (integer_to_binary(Line))/binary, ")\n">>;
_ ->
[<<"\n ">>, atom_to_list(Mod), <<":">>, atom_to_list(Func), <<" (">>, termToStr(Arity), <<")">>, termToStr(Location)]
<<" ", (atom_to_binary(Mod, utf8))/binary, ":", (atom_to_binary(Func, utf8))/binary, "(", (eFmt:formatBin("~w", [Arity]))/binary, ")", (eFmt:formatBin("~w", [Location]))/binary, "\n">>
end
end || {Mod, Func, Arity, Location} <- Stacktrace
].
>>.
printStack(Tag) ->
?PRINT_STACK(Tag).
@ -68,8 +59,9 @@ testStack(Index) ->
catch
?EXCEPTION(Class, Reason, Stacktrace) ->
Stacktrace = ?GET_STACK(Stacktrace),
io:format("~p~n", [Stacktrace]),
io:format(parseStack(Stacktrace)),
io:format(parseStack(Stacktrace, Class, Reason))
io:format(parseStack(Class, Reason, Stacktrace))
%% lagere使用示例
%% lager:error(parse_stack(Stacktrace)),
%% lager:error(parse_stack(Stacktrace, Class, Reason))

Loading…
取消
儲存