log0.6在哪两个连续的整数之间两个数之间?

本教程包含策略编写的初级知识,包括API介绍、回测、图表等内容。学习完此基础教程后,用户将能够熟练使用基础的API,编写出稳定的实盘策略。在学习本教程之前,需要先学习

旧版教程:, 这个教程列出了很多帖子索引,也推荐浏览看看。

程序化交易就是用程序通过API和交易所连接,实现按照设计的意图自动进行买卖或实现其他功能。API全称Application Programming Interface,即应用程序编程接口。

目前数字货币交易所主要有两种接口协议:REST和Websocket。REST协议每获取一次数据,需要访问一次。以模拟交易所wex.app的API为例,直接在浏览器中打开 ,得到结果:

这就可以看到交易随BTC_USDT交易对的最新行情,每次刷新还会有变化。其中market=后面接的是具体交易对参数,可以修改以获取其它交易对数据。对于公开接口,如市场行情,所有人都可以获取到,因此不需要验证,而有些接口如下单和获取账户就需要确定用户身份,这时候就需要使用API-KEY进行签名。Websocket是订阅模式,发送需要订阅的内容之后,交易所会将更新的数据发给程序,不需要每次都重新访问,因此更加高效。

FMZ量化交易平台封装了各个交易所的REST接口,使用统一的方式调用和数据格式,使策略编写更加简单通用。在FMZ平台可以很方便的支持Websocket,将在下篇教程中详细介绍。

FMZ平台API文档大部分以JavaScript为例子,但由于封装,不同语言几乎没有差别,只需要注意语法问题即可。C++稍微特殊,以后的教程会有专门的介绍。由于Js比较简单并且没有兼容性问题,推荐新手使用。FMZ量化平台支持完整的Python,可以自由的安装各种包,推荐有一定编程基础的使用。对于不想学习编程语言,只想快速写出策略的用户,FMZ平台还支持麦语言,基本兼容文华财经策略,有相关经验的推荐使用,缺点是没有编程语言强大灵活。FMZ还支持可视化编程,类似与搭积木的方式实现策略,但不是很推荐,不如代码清晰。由于编程语言相似性很高,不必纠结于选择哪种,都学习一下掌握基础花不了多少精力。

Python由于有不同的版本,可以在程序开头指定,如#!Python2,#!Python3。注意JavaScript只支持ES5语法,像let这种命名方式是ES6语法无法使用。下面展示了同样功能的Python和Javascript代码,可见仅有语法差异,因此API文档仅给出了Javascript的例子,本教程也会兼顾Python的特殊用例。

  • FMZ平台API文档,本教程不会详细介绍每个接口,具体可查此文档:
  • Javascript、Python快速入门,编写简单的策略不需要复杂的语法,只需要掌握一些基础概念就行,可以边学编程,边学习本教程:
  • 麦语言文档,对于趋势性策略,麦语言还是很方便的。
  • 旧的FMZ编程指南,内容详细,可作为索引:
  • 一个C++调用例子,对C++感兴趣的可以看看,但由于不是解释性语言,调试很困难,不推荐使用:
  • 网易云课堂《数字货币量化交易课程》,FMZ官方出品,仅需20元,内容详细丰富,由浅入深,适合新手入门
  • 一些教学策略,适合前期入门,边学习基础边写策略:

FMZ量化平台提供了调试工具供调试API接口, 。调试工具只支持JavaScript,只能执行一段时间,不用创建机器人就可以调试实盘接口。return的数据将作为结果返回,调试工具的代码不会保存。在学习本教程中,可以同时使用调试工具进行试验。

策略程序和正常的程序一样,按代码顺序执行,特殊之处是必须有一个main函数。由于策略需要不间断运行,通常情况下,需要一个循环加上休眠时间不间断执行。因为交易所有API访问频率限制,需要相应的调整休眠时间。这种架构是典型的固定间隔执行,也可以使用websockt来写事件驱动型策略,如只要深度有变化立即执行,将在中级教程中介绍。

其它有特殊作用的函数如下:

  • onexit() 为正常退出扫尾函数,最长执行时间为5分钟,可以不声明,如果超时会报错interrupt错误。可用于退出程序时保存一些结果。
  • onerror() 为异常退出函数,最长执行时间为5分钟,可以不声明。
  • init() 为初始化函数,策略程序会在开始运行时自动调用,可不声明。
//在这里写策略逻辑,将会不断调用

在调用任何交易所相关的API时,都需要明确交易所和交易对。如果创建机器人时只添加了一个交易所-交易对,exchange代表这个对象,如exchange.GetTicker()获取的将是这个交易所-交易对的行情ticker。

FMZ平台同时支持添加多个交易所-交易对,如可以同时操作同一个交易所账户的BTC和ETH,也可以同时操作一个交易所的BTC和另一个交易所的ETH。注意同一个交易所不同账户也可以同时添加,它们根据添加到FMZ网站的label区分。当存在多个交易所-交易对时,用exchanges数组来表示,按照创建机器人添加顺序分别为exchanges[0]exchanges[1]...以此类推。交易对的格式如BTC_USDT,前者BTC是交易货币,USDT是计价货币。

显然,如果我们操作的交易对很多,这种方式将会很麻烦,此时可以用来切换交易对,如exchange.IO("currency", "BTC_USDT"),此时exchange所绑定的交易对就变为了BTC_USDT,在下次调用IO改变交易对之前将会一直有效。注意回测不支持IO切换交易对。下面是一个具体的例子。

正如前面举得例子,行情接口一般都是公开接口,所有人都能获取。通常的行情接口有:获取行情ticker、获取深度depth、获取K线records、获取成交记录trades。行情是策略进行交易判断的基础,下面将一一介绍,最好能够在调试工具中自己尝试,需要详细的解释可以查看API文档。

各个接口一般都有Info字段,表示交易所返回的原始数据字符串,可用于补充额外的信息,用之前需要解析,JavaScript使用JSON.parse(),Python使用json库。Time字段表示请求的时间戳,可用于判断延时。

在实盘中使用API接口都有可能访问失败而返回null,Python返回None,这时在使用其中的数据就会报错并且导致机器人停止,所以容错非常重要。本教程将单独介绍。

获取挂单深度信息。虽然GetTicker中包含了买一卖一,但如果要查询更深的挂单,可以用这个接口,一般可以查到上下200个挂单。可以使用这个接口计算冲击价格。下面是一个真实的返回结果。其中Asks表示卖单挂单,数组中分别是“卖一”、“卖二”...所以价格也依次上升。Bids表示买单挂单,数组中分别是“买一”、“买二”...价格依次下降。

使用深度获取买单卖单例子:

获取K线,最常用的接口之一,可一次返回较长时间的价格信息,计算各种指标的基础。K线周期如果不指定表示将使用添加机器人时的默认周期。K线长度不能指定,随着时间积累会不断增加,最大2000根,第一次调用大概200根。最后一根K线是最新的K线,所以数据会随着行情不断变化,第一根K线是最旧的数据。

注意教程中还会遇到类似PERIOD_M1这种全大写变量,它们是FMZ默认的全局变量,感兴趣的可以自己Log它们的具体的值,平时直接使用就行。

获取一定时间范围的成交数据(不是自己的成交数据),有的交易所不支持。比较不常用,可以在API文档上查询详细介绍。

这些接口由于和账户相关,并不能直接获取到,需要使用API-KEY签名。FMZ平台已经后台统一自动处理过,可以直接使用。

注意到返回结果是指定交易对的结果,交易账户中其它币种的信息在Info字段中,操作多个交易对也不用调用多次。

一个不断打印当前交易对总价值的机器人:

Msg),Price是价格,Amount是数量,Msg是一个额外的字符串可以在机器人日志中展示出来,非必须。此方式为挂单,如果无法立即完全成交则会产生未成交订单,下单成功返回结果为订单id,失败为null,用于查询订单状态。

如果要下市价买单,Price为-1,Amount为下单价值,如exchange.Buy(-1, 0.5),交易对是ETH_BTC,则代表市价买入0.5BTC的ETH。部分交易所不支持市价单,期货回测也不不支持。

部分交易所有价格和数量的精度要求,可用用_N()精度函数来控制。对于期货交易Buy和Sell有另外的含义,将单独介绍。

一个达到相应价格就买入的例子:

下卖单。参数和Buy相同。市价单的参数意义不同,市价卖单如exchange.Sell(-1, 0.2),代表市价卖出0.2ETH。

一个购买指定数量币种的策略:

获取当前交易对所有未成交订单列表。订单列表具体的结果如GetOrder。

撤销当前交易对所有订单的例子:

数字货币期货交易和现货交易有所不同,上面的现货交易的函数同样适用于期货,单期货交易有专有的函数。在进行数字货币期货程序化交易之前,要在网站上熟悉手工操作,明白基础概念,如开仓、平仓、全仓、逐仓、杠杆、平仓盈亏、浮动收益、保证金等概念以及相应的计算公式,在各个期货交易所都可以找到相关教程,需要自己学习。

永续合约和期货合约类似,不同的是没有同时持有多空的概念。

期货交易的第一步就要设置要交易的合约,如创建机器人或回测时OKEX期货选择BTC合约,还需要设置是当周、下周还是季度合约。如果不设置会提示symbol not set。各个与现货交易对不同,期货合约无计价货币,具体添加如下:

获取当前持仓信息列表, OKEX(OKCOIN)期货可以传入一个参数, 指定要获取的合约类型。如果没有持仓则返回空列表[]。持仓信息返回如下,具体的信息很多,需要结合交易对具体分析。

首先需要设置杠杆大小,调用方式:exchange.SetMarginLevel(10),10表示10倍杠杆,具体支持的杠杆大小查看相应的交易所。

最后是具体的开仓平仓,注意期货回测不支持市价单。

需要在代码里切换为杠杆账户即可,其它与现货交易相同。

使用 ("trade_margin") 切换为杠杠账户模式,下单、获取账户资产将访问交易所杠杆接口。

  • OKEX V3:杠杆账户模式的交易对和普通的有所不同,有些交易对可能没有。
  • 火币:杠杆账户模式的交易对和普通的有所不同,有些交易对可能没有。
  • ZB:资金为QC才可转入,杠杆交易板块,不同交易对之间资金独立,即在ETH_QC交易对下的QC币数,在BTC_QC中看不到

商品期货交易和数字货币期货交易有着很大的不同。首先商品期货的交易时间很短,数字货币24h交易;商品期货的协议也不是常用的REST API;商品期货的交易频率和挂单数量限制,数字货币则很宽松,等等。因此交易商品期货有很多需要特殊注意的地方,建议有丰富的操作手动操作经验。FMZ支持simnow商品期货模拟盘,参考:

商品期货与2019年6月实行了看穿式监管,个人程序化个人用户需要的开户的期货商申请授权码,一般需要4-5天,步骤较为繁琐。FMZ量化平台作为程序化交易提供商向各个期货服务商申请了软件授权码,用户可以无需申请直接使用,在添加期货商是搜索”看穿式“可以看到FMZ已经申请的列表。具体参考帖子: 。如果你的期货商不再列表中,只能自己申请,或者重新在支持的交易商开户,一般需要2天。FMZ和一些服务商有深入的合作关系,如宏源期货,手续费可以做到最低,开户参考: 。如国泰君安,购买了FMZ平台的机构版,可以给用户使用,开户自动成为VIP,开户参考: 。

由于FMZ平台架构的优势,用户同样可以添加多个期货商账户,并且实现一些其它商品期货程序化交易软件无法完成的功能,如高频tick的合成,参考:

首先由于不是24h交易并且需要登陆操作,在进行交易之前,需要判断链接状态。exchange.IO("status")true则表示连接上交易所。

商品期货的行情获取和交易代码与数字货币期货相同,这里将介绍不同和需要注意的地方。

实盘只支持获取行情。但是麦语言可以操作主力合约,程序会自动换仓,即平掉非主力仓位,在主力仓位上开新仓。

“套保”, 不设置默认为投机,

商品期货支持自定义订单类型 (支持实盘,回测不支持),以后缀方式指定, 附加在”_“后面比如

在机器人界面Log一条日志,字符串后面加上@字符则消息会进入推送队列,绑定微信或telegram后会直接推送。Log('推送到微信@')

所有的日志文件都存在托管者所在目录机器人的sqlit数据库内。

记录收益,并且在机器人界面画出收益曲线,机器人重启后也能保留。调用方式:LogProfit(1000)。注意LogProfit的参数并不一定是收益,可以是任何数字,需要自己填写。

机器人状态,由于Log日志会保存先来并不断刷新,如果需要一个只展示不保存的信息,可以用LogStatus函数。LogStatus的参数是字符串,也可以用于表示表格信息。

一个具体的的机器人状态位置展示表格的例子:

参数为毫秒数,如Sleep(1000)为休眠一秒。由于交易所有访问频率限制,一般策略中都要在死循环中加入休眠时间。

机器人重启后,程序会重新开始,如果想保存一些持久信息,_G就非常方便实用,可以保存JSON序列化的内容。_G函数写在onexit()内,这样每次停止策略,会自动保存需要的信息。
如果想要保存更多的格式化数据,_G函数不太适用,可以使用Python直接写入数据库。

在下单时,往往要控制价格和数量精度,FMZ内置了_N函数,确定保存小数点位数,如_N(4.253,2)结果为4.25。

调用交易所API是,不能保证每次都访问成功,_C是一个自动重试的函数。会一直调用指定函数到成功返回(函数返回null或者false会重试),比如_C(exchange.GetTicker), 默认重试间隔为3秒, 可以调用_CDelay函数来控制重试间隔,比如_CDelay(1000), GetOrder都是用_C容错,防止访问失败造成程序中断。

CancelOrder不能使用_C函数,因为撤单失败有各种原因,如果一个单子已经成交,再撤单会返回失败,使用_C函数会导致一直重试。

_C函数也可以传入参数,也使用于自定义函数。

直接调用_D()返回当前时间字符串,如: 03:46:14。如果是回测中调用则返回回测时间。

对于一些常用的指标函数,如MA\MACD\KDJ\BOLL等常用指标,FMZ平台直接内置,具体的支持的指标可查API文档。

使用指标函数之前,最好要判断K线长度。当前面的K线长度无法满足计算所需周期时,结果为null。如输入的K线长度为100,计算MA的周期为10,则前9个值都是null,后面才正常计算。

JavaScript也支持完整的talib,作为第三方库支持,调用如talib.CCI(records)。参考 。对于Python可以自行安装talib库,由于需要编译,不能简单的使用pip安装,可自行搜索安装方式。

指标函数除了传入K线数据外,还可以传入任意数组

这里介绍一些实盘常用的JavaScript函数。

  • FMZ引用的JavaScript第三方underscore库,推荐了解下,方便了很多Js繁琐的操作,参考:

写出一个实盘策略功能需要考虑的情况非常多,比如买入5个币这么一个简单的功能,我们要考虑到:当前的余额足够吗?下单的价格是多少?精度是多少?需不需要拆分订单避免冲击市场?未完成订单如何处理?等等细节。在不同的策略中,这些功能是同样的,可以做成一个模板。仿照官方模板,用户也可以自己写模板策略。这里将介绍FMZ官方出的几个十分常用的模板类库,方便用户快速写出自己的策略。

JavaScript数字货币交易类库和商品期货交易类库是默认内置的,不用复制。其它模板类库在策略广场可以找到 。将模板类库复制并保存,并且在创建自己策略时勾选要使用的类库就可以使用了。

如果 n 等于 0, 指刚好15周期的EMA与30周期的EMA当前价格相等 如果传给Cross不是数组, 则函数自动获取K线进行均线计算 如果传给Cross的是数组, 则直接进行比较

商品期货交易类库使用稳定,推荐使用。源代码地址: 。已经内置,无需复制。

  • 实盘会自动把指数映射到主力连续
  • 回测可以指定映射比如 rb000/rb888 就是把rb指数交易映射到主力连续
  • 也可以映射到别的合约, 比如rb000/MA888 就是看rb指数的K线来交易MA主力连续
// 多品种时使用交易队列来完成非阻塞的交易任务 // 在空闲时调用poll来完成未完成的任务

由于原始的画图函数比较复杂,将在下个教程介绍,新手推荐直接使用画图类库,非常简单的画折线图、K线条等。由于FMZ没有内置,需要用户自己复制并保存后才能在策略里引用。

Python版画线类库复制地址:

在策略编辑下方有策略参数设置,相当于策略的全局变量,可以在代码的任意位置访问到。策略参数可以在机器人界面修改,重启后生效。因此可将一些变量设置为参数,不用修改策略也能改变参数。

  • 变量名:即上图中的 number、string、combox等,在策略组可以直接使用。
  • 描述 :参数在策略界面上的名字,便于理解参数的意义。
  • 备注 :参数的详细解释,该描述会在鼠标停留在参数上时 相应的显示出。
  • 类型 :该参数的类型,以下详细介绍。
  • 默认值 :该参数的默认值。

字符串类型和数字类型很容易理解,也是最常用的类型。下拉框将在参数界面展示可选项的下拉框,如可设置下拉框SYMBOL参数值为BTC|USDT|ETH,在参数页面下拉中选择了USDT,则策略中SYMBOL的值为USDT的索引1。勾选项是一个可选框,勾上为true,否则为false。

参数还有很多可供设置,参考

当完成一个策略的量化工作后,可以用历史数据来测试您的策略,看看您的策略在历史数据中盈利如何。当然回测结果仅供作为参考。FMZ量化平台支持数字货币现货、期货、BitMEX永续合约、商品期货的回测,其中数字货币主要支持主流品种。
Javascript回测在浏览器进行,Python回测需要在托管者上,可使用平台提供公用托管者。麦语言的回测又更多的参数需要设置,具体参考麦语言文档。

onbar回测机制是基于K线的,即每一个K线产生一个回测时间点,在此时间点上可以获取到当前K线的高开低收价格、交易量等信息,以及此时间点之前的历史K线信息。这种机制的弊端很明显:在一根K线上,只能产生一次买卖,通常依据的价格是K线的收盘价。并且一根K线只能获取到高开低收四个价格,至于在一根K线内价格如何变化的,是最高价先发生、还是最低价先发生等等信息都无从获取。以1小时K线为例,实盘时肯定每隔几秒获取一次行情信息,交易指令也会在盘中发出而不是等待K线结束。onbar回测机制的好处是易于理解,回测速度极快。

FMZ平台回测分模拟级回测和实盘级回测两种。模拟级回测根据底层K线周期生成模拟的tick,每个底层K线周期上将生成14个回测时间点,而实盘级则是真实收集的tick,大约几秒就有一次,数据量很大,回测速度慢,因此不能回测特别长的时间。FMZ的回测机制可以使策略在一根K线上交易多次,避免了只能收盘价成交的情况,更加精准又兼顾了回测速度。具体的说明可参考:

回测的策略框架和实盘相同,都是一个死循环。由于回测是在不同回测点上跳跃,此时可以不用Sleep,在一个循环结束会自动跳到下一个时间点。但Python由于程序机制,需要强制一个Sleep(10),以避免卡死。

  • 1.回测页面的选择,左侧是策略编辑页面。
  • 2.回测起始结束时间,由于数据不完整,回测可能直接从有数据的时间开始。
  • 3.回测GetRecords()函数的默认周期,也可以在代码中指定周期参数。
  • 5.展示或隐藏跟多回测设置。
  • 6.最大日志数、收益数据数、图表数据数等,为了防止数据量过大导致浏览器卡死。
  • 6.底层tick生成依据K线周期。
  • 7.容错,会模拟API请求出错情况,检查策略容错能力。
  • 8.是否绘制行情图标,回测中如果使用了TA指标函数,会自展示在图标上,买卖也会标记。
  • 10.添加交易所-交易对和资产。
  • 11.回测参数设置,如果参数是数字还支持一键优化参数,自动按照一定范围遍历参数回测。
  • 1.回测时有效的行情只有GetTicker和GetRecords,其它如获深度、成交历史都不是真实的(因为数据量太大)。
  • 2.回测添加的交易所都是独立账户,目前不支持切换交易对。因此无法在一个账户里操作两个交易对。
  • 3.回测中无法使用网络请求。
  • 4.回测无法使用IO扩展,只能操作最基础的API。
  • 5.回测只能获取标准的数据,像Info之类的牵扯到实盘的数据不存在。
  • 6.回测中也有可能不成交,注意冻结订单情况。
  • 7.商品期货回测不支持市价单。

前面说过在实盘中使用API接口都有可能访问失败而返回null,这时在使用其中的数据就会报错并且导致机器人停止,所以策略要做好容错。

  • API访问网络错误,接口访问超时将返回null,此时使用就会报错。
  • 交易所限制错误,如ip限制、下单精度、访问频率、参数错误、资产不足、市场不能交易、撤销已成交订单等等。可具体根据错误代码查询API文档。
  • 交易所返回数据错误,偶有发生,如返回空的深度、延时的账户信息、延时的订单状态等。

在使用API返回数据之前,都要对其是否为null进行判断,下面将介绍集中常用方法:

如果想要获取错误信息,可以使用GetLastError(),将返回上一次出错信息字符串,可以对错误进行差异处理。

论坛置顶帖有许多常见错误汇总: 。这里将摘要一些,遇到问题可以ctrl+F搜索以下。

是指访问交易所接口超时,如果偶尔出现不是问题,如果一直提示做说明所在网络无法访问,需要使用海外服务器。

回测系统报错,一般为策略编写错误,在没有持仓或者持仓数量不足时,尝试下单平仓,会引起该报错。

访问交易所接口频率过高。

服务器时间戳超出范围需要更新服务器时间,不能偏差过大

些交易所订单取消,交易所就不在维护这个订单信息,无法获取。

无效的交易对,检查下是不是交易对设置错误。

API KEY 解析失败,如果配置了APIKEY后修改过FMZ密码,尝试在FMZ添加交易所页面,重新配置交易所APIKEY。

建议使用Linux服务器,或者在这些出现该问题的windows系统安装时间同步软件。

10.为什么设置了全局代理,托管者任然无法访问交易所API?

全局代理并没有代理托管者网络端口,由于延迟问题,最好部署海外服务器的托管者

}

kubernetes中的一切都可以理解为是一种资源对象,pod,rc,service,都可以理解是 一种资源对象。pod的组成示意图如下,由一个叫”pause“的根容器,加上一个或多个用户自定义的容器构造。pause的状态带便了这一组容器的状态,pod里多个业务容器共享pod的Ip和数据卷。在kubernetes环境下,pod是容器的载体,所有的容器都是在pod中被管理,一个或多个容器放在pod里作为一个单元方便管理。

pod是kubernetes可以部署和管理的最小单元,如果想要运行一个容器,先要为这个容器创建一个pod。同时一个pod也可以包含多个容器,之所以多个容器包含在一个pod里,往往是由于业务上的紧密耦合。需要注意】这里说的场景都非必须把不同的容器放在同一个pod里,但是这样往往更便于管理,甚至后面会讲到的,紧密耦合的业务容器放置在同一个容器里通信效率更高。具体怎么使用还要看实际情况,综合权衡。

在Kubrenetes集群中Pod有如下两种使用方式:
a)一个Pod中运行一个容器。这是最常见用法。在这种方式中,你可以把Pod想象成是单个容器的封装,kuberentes管理的是Pod而不是直接管理容器。
b)在一个Pod中同时运行多个容器。当多个应用之间是紧耦合的关系时,可以将多个应用一起放在一个Pod中,同个Pod中的多个容器之间互相访问可以通过localhost来通信(可以把Pod理解成一个虚拟机,共享网络和存储卷)。也就是说一个Pod中也可以同时封装几个需要紧密耦合互相协作的容器,它们之间共享资源。这些在同一个Pod中的容器可以互相协作成为一个service单位 (即一个容器共享文件),另一个“sidecar”容器来更新这些文件。Pod将这些容器的存储资源作为一个实体来管理。

就像每个应用容器,pod被认为是临时实体。在Pod的生命周期中,pod被创建后,被分配一个唯一的ID(UID),调度到节点上,并一致维持期望的状态直到被终结(根据重启策略)或者被删除。如果node死掉了,分配到了这个node上的pod,在经过一个超时时间后会被重新调度到其他node节点上。一个给定的pod(如UID定义的)不会被“重新调度”到新的节点上,而是被一个同样的pod取代,如果期望的话甚至可以是相同的名字,但是会有一个新的UID(查看replication

直接部署一个容器看起来更简单,但是这里也有更好的原因为什么在容器基础上抽象一层呢?根本原因是为了管理容器,kubernetes需要更多的信息,比如重启策略,它定义了容器终止后要采取的策略;或者是一个可用性探针,从应用程序的角度去探测是否一个进程还存活着。基于这些原因,kubernetes架构师决定使用一个新的实体,也就是pod,而不是重载容器的信息添加更多属性,用来在逻辑上包装一个或者多个容器的管理所需要的信息。

pod里的容器运行在一个逻辑上的"主机"上,它们使用相同的网络名称空间 (即同一pod里的容器使用相同的ip和相同的端口段区间) 和相同的IPC名称空间。它们也可以共享存储卷。这些特性使它们可以更有效的通信,并且pod可以使你把紧密耦合的应用容器作为一个单元来管理。也就是说当多个应用之间是紧耦合关系时,可以将多个应用一起放在一个Pod中,同个Pod中的多个容器之间互相访问可以通过localhost来通信(可以把Pod理解成一个虚拟机,共享网络和存储卷)。

因此当一个应用如果需要多个运行在同一主机上的容器时,为什么不把它们放在同一个容器里呢?首先,这样何故违反了一个容器只负责一个应用的原则。这点非常重要,如果我们把多个应用放在同一个容器里,这将使解决问题变得非常麻烦,因为它们的日志记录混合在了一起,并且它们的生命周期也很难管理。因此一个应用使用多个容器将更简单,更透明,并且使应用依赖解偶。并且粒度更小的容器更便于不同的开发团队共享和复用。

【需要注意】这里说到为了解偶把应用分别放在不同容器里,前面我们也强调为了便于管理管紧耦合的应用把它们的容器放在同一个pod里。一会强调耦合,一个强调解偶看似矛盾,实际上普遍存在,高内聚低耦合是我们的追求,然而一个应用的业务逻辑模块不可能完全完独立不存在耦合,这就需要我们从实际上来考量,做出决策。

因为,虽然可以使用一个pod来承载一个多层应用,但是更建议使用不同的pod来承载不同的层,因这这样你可以为每一个层单独扩容并且把它们分布到集群的不同节点上。

Pod中如何管理多个容器
Pod中可以同时运行多个进程(作为容器运行)协同工作,同一个Pod中的容器会自动的分配到同一个 node 上,同一个Pod中的容器共享资源、网络环境和依赖,它们总是被同时调度。需要注意:一个Pod中同时运行多个容器是一种比较高级的用法。只有当你的容器需要紧密配合协作的时候才考虑用这种模式。

Pod***享的环境包括Linux的namespace,cgroup和其他可能的隔绝环境,这一点跟Docker容器一致。在Pod的环境中,每个容器中可能还有更小的子隔离环境。Pod中的容器共享IP地址和端口号,它们之间可以通过localhost互相发现。它们之间可以通过进程间通信,需要明白的是同一个Pod下的容器是通过lo网卡进行通信。例如SystemV信号或者POSIX共享内存。不同Pod之间的容器具有不同的IP地址,不能直接通过IPC通信。Pod中的容器也有访问共享volume的权限,这些volume会被定义成pod的一部分并挂载到应用容器的文件系统中。

总而言之。Pod中可以共享两种资源:网络 和 存储
pletions参数为一个正数,当正常结束的Pod数量达到该值则Job结束。

-  每个Pod能独立判断和决定是否还有任务项需要处理;
-  如果一个Pod成功结束,则此时应该不存在其他Pod还在干活的情况,它们应该都处于即将结束、退出的状态;
-  如果所有的Pod都结束了,且至少一个Pod成功结束,则整个Job算是成功结束;

kubernetes中RC是用来保持集群中始终运行指定数目的实例,通过RC的scale机制可以完成Pod的扩容和缩容(伸缩)。

CPU使用率。Pod CPU使用率来源于heapster组件,因此需安装该组件。

Kubernetes是一个很好的容器应用集群管理工具,尤其是采用ReplicationController这种自动维护应用生命周期事件的对象后,将容器应用管理的技巧发挥得淋漓尽致。在容器应用管理的诸多特性中,有一个特性是最能体现Kubernetes强大的集群应用管理能力的,那就是滚动升级。

滚动升级的精髓在于升级过程中依然能够保持服务的连续性,使外界对于升级的过程是无感知的。整个过程中会有三个状态:全部旧实例,新旧实例皆有,全部新实例。旧实例个数逐渐减少,新实例个数逐渐增加,最终达到旧实例个数为0,新实例个数达到理想的目标值。

kubernetes中的RC的滚动升级通过执行 kubectl rolling-update 命令完成,该命令创建一个新的RC(与旧的RC在同一个命名空间中),然后自动控制旧的RC中的Pod副本数逐渐减少为0,同时新的RC中的Pod副本数从0逐渐增加到目标值,来完成Pod的升级。 需要注意的是:新旧RC要再同一个命名空间内。但滚动升级中Pod副本数(包括新Pod和旧Pod)保持原预期值。

与使用配置文件实现不同在于,该执行结果旧的RC被删除,新的RC仍使用旧的RC的名字。

采用RS来管理Pod实例。如果当前集群中的Pod实例数少于目标值,RS会拉起新的Pod,反之,则根据策略删除多余的Pod。Deployment正是利用了这样的特性,通过控制两个RS里面的Pod,从而实现升级。滚动升级是一种平滑过渡式的升级,在升级过程中,服务仍然可用,这是kubernetes作为应用服务化管理的关键一步!!服务无处不在,并且按需使用。Kubernetes

通常来说,不鼓励更新Deployment的标签选择器,因为这样会导致Deployment选择的Pod列表发生变化,也可能与其它控制器产生冲突。

Deployment滚动升级的过程大致为:
- 查找新的RS和旧的RS,并计算出新的Revision(这是Revision的最大值);
- 对新的RS进行扩容操作;
- 对旧的RS进行缩容操作;
- 完成之后,删掉旧的RS;

产品部署完成上线之后,经常遇到需要升级服务的要求(只考虑更新镜像),以往比较粗糙的操作流程大致如下:
方式一:找到 master具体调度到的所有目标node,删除其对应的镜像文件
 
删掉旧pod,并重新创建
但是这样有一个比较棘手的问题,就是如果升级失败的回滚策略。因此想到利用kubernetes自身的滚动升级的工具,部署及升级流程如下:
1)在初次创建的时候,尽量加入参数--record,这样k8s会记录下本次启动的脚本 。
2)执行查看发布的历史记录,会显示现在已经记录的脚本及其序号。
4)查看pod状态,如果失败需要回滚操作
回滚到指定版本,版本号由第二步查看获得
需要注意:执行rollout undo操作之后,版本号会移动,需要确认版本号无误再undo

在Docker的范畴内,我们知道可以对运行的容器进行请求或消耗的资源进行限制。而在Kubernetes中也有同样的机制,容器或Pod可以进行申请和消耗的计算资源就是CPU和内存,这也是目前仅有的受支持的两种类型。相比较而言,CPU属于可压缩资源,即资源额度可按需收缩;而内存则是不可压缩型资源,对其执行收缩操作可能会导致某种程度的问题

资源的隔离目前是属于容器级别,CPU和内存资源的配置需要Pod中的容器spec字段下进行定义。其具体字段,可以使用"requests"进行定义请求的确保资源可用量。也就是说容器的运行可能用不到这样的资源量,但是必须确保有这么多的资源供给。而"limits"是用于限制资源可用的最大值,属于硬限制。

在Kubernetes中,1个单位的CPU相当于虚拟机的1颗虚拟CPU(vCPU)或者是物理机上一个超线程的CPU,它支持分数计量方式,一个核心(1core)相当于1000个微核心(millicores),因此500m相当于是0.5个核心,即二分之一个核心。内存的计量方式也是一样的,默认的单位是字节,也可以使用E、P、T、G、M和K作为单位后缀,或者是Ei、Pi、Ti、Gi、Mi、Ki等形式单位后缀。

-  容器的资源需求,资源限制
requests:需求,最低保障;
limits:限制,硬限制;

自主式pod要求为stress容器确保128M的内存及五分之一个cpu核心资源可用,它运行stress-ng镜像启动一个进程进行内存性能压力测试,满载测试时它也会尽可能多地占用cpu资源,另外再启动一个专用的cpu压力测试进程。stress-ng是一个多功能系统压力测试工具,master/worker模型,master为主进程,负责生成和控制子进程,worker是负责执行各类特定测试的子进程。

集群中的每个节点都拥有定量的cpu和内存资源,调度pod时,仅那些被请求资源的余量可容纳当前调度的pod的请求量的节点才可作为目标节点。也就是说,kubernetes的调度器会根据容器的requests属性中定义的资源需求量来判定仅哪些节点可接受运行相关的pod资源,而对于一个节点的资源来说,每运行一个pod对象,其requestes中定义的请求量都要被预留,直到被所有pod对象瓜分完毕为止。

上面的配置清单中,nginx请求的CPU资源大小为200m,这意味着一个CPU核心足以满足nginx以最快的方式运行,其中对内存的期望可用大小为128Mi,实际运行时不一定会用到这么多的资源。考虑到内存的资源类型,在超出指定大小运行时存在会被OOM killer杀死的可能性,于是该请求值属于理想中使用的内存上限。

容器的资源需求仅能达到为其保证可用的最少资源量的目的,它并不会限制容器的可用资源上限,因此对因应用程序自身存在bug等多种原因而导致的系统资源被长期占用的情况则无计可施,这就需要通过limits属性定义资源的最大可用量。资源分配时,可压缩型资源cpu的控制阈可***调节,容器进程无法获得超出其cpu配额的可用时间。不过,如果进程申请分配超出其limits属性定义的硬限制的内存资源时,它将被OOM killer杀死。不过,随后可能会被其控制进程所重启。例如,容器进程的pod对象会被杀死并重启(重启策略为always或onfailure时),或者是容器进程的子进程被其父进程所重启。也就是说,CPU是属于可压缩资源,可进行***地调节。内存属于硬限制性资源,当进程申请分配超过limit属性定义的内存大小时,该Pod将被OOM

与requests不同的是,limits并不会影响pod的调度结果也就是说,一个节点上的所有pod对象的limits数量之和可以大于节点所拥有的资源量,即支持资源的过载使用。不过,这么一来一旦资源耗尽,尤其是内存资源耗尽,则必然会有容器因OOMKilled而终止。另外,kubernetes仅会确保pod能够获得他们请求的cpu时间额度,他们能否获得额外的cpu时间,则取决于其他正在运行的作业对cpu资源的占用情况。例如,对于总数为1000m的cpu来说,容器a请求使用200m,容器b请求使用500m,在不超出它们各自的最大限额的前提下,余下的300m在双方都需要时会以2:5的方式进行配置。

Pod资源默认的重启策略为Always,在上面例子中memleak因为内存限制而终止会立即重启,此时该Pod会被OOM killer杀死,在多次重复因为内存资源耗尽重启会触发Kunernetes系统的重启延迟,每次重启的时间会不断拉长,后面看到的Pod的状态通常为"CrashLoopBackOff"

对于容器中运行top等命令观察资源可用量信息时,即便定义了requests和limits属性,虽然其可用资源受限于此两个属性的定义,但容器中可见资源量依然是节点级别可用总量。

这里还需要明确的是,kubernetes允许节点资源对limits的过载使用,这意味着节点无法同时满足其上的所有pod对象以资源满载的方式运行。在一个Kubernetes集群上,运行的Pod众多,那么当node节点都无法满足多个Pod对象的资源使用时 (节点内存资源紧缺时),应该按照什么样的顺序去终止这些Pod对象呢?kubernetes无法自行对此做出决策,它需要借助于pod对象的优先级来判定终止Pod的优先问题。根据pod对象的requests和limits属性,kubernetes将pod对象归类到BestEffortBurstableGuaranteed三个服务质量类别:
Guaranteed:每个容器都为cpu资源设置了具有相同值的requests和limits属性,以及每个容器都为内存资源设置了具有相同值的requests和limits属性的pod资源会自动归属于此类别,这类pod资源具有最高优先级.
Burstable:至少有一个容器设置了cpu或内存资源的requests属性,但不满足Guaranteed类别要求的pod资源将自动归属此类别,它们具有中等优先级。
BestEffort:未为任何一个容器设置requests和limits属性的pod资源将自动归属于此类别,它们的优先级为最低级别。

内存资源紧缺时,BestEfford类别的容器将首当其冲地终止,因为系统不为其提供任何级别的资源保证,但换来的好处是:它们能够在可用时做到尽可能多地占用资源。若已然不存在BestEfford类别的容器,则接下来是有着中等优先级的Burstable类别的pod被终止。Guaranteed类别的容器拥有最高优先级,它们不会被杀死,除非其内存资源需求超限,或者OOM时没有其他更低优先级的pod资源存在。

每个运行状态的容器都有其OOM得分,得分越高越会被优先杀死。OOM得分主要根据两个维度进行计算:由QoS类别继承而来的默认分值和容器的可用内存资源比例。同等类别的pod资源的默认分值相同。同等级别优先级的pod资源在OOM时,与自身requests属性相比,其内存占用比例最大的pod对象将被首先杀死。需要特别说明的是,OOM是内存耗尽时的处理机制,它们与可压缩型资源cpu无关,因此cpu资源的需求无法得到保证时,pod仅仅是暂时获取不到相应的资源而已。

Pod中多个容器访问的共享目录。volume被定义在pod上,被这个pod的多个容器挂载到相同或不同的路径下。volume的生命周期与pod的生命周期相同,pod内的容器停止和重启时一般不会影响volume中的数据。所以一般volume被用于持久化pod产生的数据。Kubernetes提供了众多的volume类型,包括emptyDir、hostPath、nfs、glusterfs、cephfs、ceph

Volume主要用于某些应用程序无需永久保存的临时目录,多个容器的共享目录等。下面是pod挂载emptyDir的示例:

hostPath Volume为pod挂载宿主机上的目录或文件,使得容器可以使用宿主机的高速文件系统进行存储。缺点是,在k8s中,pod都是动态在各node节点上调度。当一个pod在当前node节点上启动并通过hostPath存储了文件到本地以后,下次调度到另一个节点上启动时,就无法使用在之前节点上存储的文件。下面是pod挂载hostPath的示例:

静态提供:管理员手动创建多个PV,供PVC使用。
动态提供:动态创建PVC特定的PV,并绑定。

方式二: 手动创建PV

持久化卷下PV和PVC概念
Persistent Volume(PV)是由管理员设置的存储,它是群集的一部分。就像节点是集群中的资源一样,PV 也是集群中的资源。 PV 是 Volume 之类的卷插件,但具有独立于使用 PV 的 Pod 的生命周期。此 API 对象包含存储实现的细节,即 NFS、iSCSI 或特定于云供应商的存储系统。

PersistentVolumeClaim(PVC)是用户存储的请求。它与 Pod 相似,Pod 消耗节点资源,PVC 消耗 PV 资源。Pod 可以请求特定级别的资源(CPU 和内存)。PVC声明可以请求特定的大小和访问模式(例如,可以以读/写一次或只读多次模式挂载)。

它和普通Volume的区别是什么呢?
普通Volume和使用它的Pod之间是一种静态绑定关系,在定义Pod的文件里,同时定义了它使用的Volume。Volume是Pod的附属品,我们无法单独创建一个Volume,因为它不是一个独立的Kubernetes资源对象。

PV可以设置三种回收策略:保留(Retain),回收(Recycle)和删除(Delete)。
保留策略:允许人工处理保留的数据。
删除策略:将删除pv和外部关联的存储资源,需要插件支持。
回收策略:将执行清除操作,之后可以被新的pvc使用,需要插件支持。

pod配置文件中应用pv

Kubernetes有一个强大的功能,它能在运行的服务上进行编码并配置弹性伸缩。如果没有弹性伸缩功能,就很难适应部署的扩展和满足SLAs。这一功能称为Horizontal Pod Autoscaler (HPA),这是kubernetes的一个很重要的资源对象。HPA是Kubernetes中弹性伸缩API组下的一个API资源。当前稳定的版本是autoscaling/v1,它只提供了对CPU自动缩放的支持

Horizontal Pod Autoscaling,即pod的水平自动扩展。自动扩展主要分为两种,其一为水平扩展,针对于实例数目的增减;其二为垂直扩展,即单个实例可以使用的资源的增减。HPA属于水平自动扩展。HPA的操作对象是RC、RS或Deployment对应的Pod,根据观察到的CPU等实际使用量与用户的期望值进行比对,做出是否需要增减实例数量的决策。

使用HPA,可以根据资源的使用情况或者自定义的指标,实现部署的自动扩展和缩减,让部署的规模接近于实际服务的负载。HPA可以为您的服务带来两个直接的帮助:
- 在需要计算和内存资源时提供资源,在不需要时释放它们
- 按需增加/降低性能以实现SLA

它根据Pod当前系统的负载来自动水平扩容,如果系统负载超过预定值,就开始增加Pod的个数,如果低于某个值,就自动减少Pod的个数。目前Kubernetes的HPA只能根据CPU等资源使用情况去度量系统的负载。HPA会根据监测到的CPU/内存利用率(资源指标),或基于第三方指标应用程序(如Prometheus等)提供的自定义指标,自动调整副本控制器、部署或者副本集合的pods数量(定义最小和最大pods数)。HPA是一种控制回路,它的周期由Kubernetes的controller

定义了副本的最大值10

HPA通过定期(定期轮询的时间通过--horizontal-pod-autoscaler-sync-period选项来设置,默认的时间为30秒)通过Status.PodSelector来查询pods的状态,获得pod的CPU使用率。然后,通过现有pods的CPU使用率的平均值(计算方式是最近的pod使用量(最近一分钟的平均值,从heapster中获得)除以设定的每个Pod的CPU使用率限额)跟目标使用率进行比较,并且在扩容时,还要遵循预先设定的副本数限制:MinReplicas

计算扩容后Pod的个数:sum(最近一分钟内某个Pod的CPU使用率的平均值)/CPU使用上限的整数+1

- 创建HPA资源,设定目标CPU使用率限额,以及最大、最小实例数
- 收集一组中(PodSelector)每个Pod最近一分钟内的CPU使用率,并计算平均值
- 读取HPA中设定的CPU使用限额
- 计算:平均值之和/限额,求出目标调整的实例个数
- 目标调整的实例数不能超过1中设定的最大、最小实例数,如果没有超过,则扩容;超过,则扩容至最大的实例个数

考虑到自动扩展的决策可能需要一段时间才会生效,甚至在短时间内会引入一些噪声。例如当pod所需要的CPU负荷过大,从而运行一个新的pod进行分流,在创建过程中,系统的CPU使用量可能会有一个攀升的过程。所以,在每一次作出决策后的一段时间内,将不再进行扩展决策。对于ScaleUp (纵向扩展)而言,这个时间段为3分钟,Scaledown为5分钟。

Scale Up (纵向扩展) :主要是利用现有的存储系统,通过不断增加存储容量来满足数据增长的需求。但是这种方式只增加了容量,而带宽和计算能力并没有相应的增加。所以,整个存储系统很快就会达到性能瓶颈,需要继续扩展。

Scale-out (横向扩展):通常是以节点为单位,每个节点往往将包含容量、处理能力和I / O带宽。一个节点被添加到存储系统,系统中的三种资源将同时升级。这种方式容量增长和性能扩展(即增加额外的控制器)是同时进行。而且,Scale-out架构的存储系统在扩展之后,从用户的视角看起来仍然是一个单一的系统,这一点与我们将多个相互独立的存储系统简单的叠加在一个机柜中是完全不同的。所以scale out方式使得存储系统升级工作大大简化,用户能够真正实现按需购买,降低TCO。

为了简便,选用了相对比率(90%的CPU资源)而不是0.6个CPU core来描述扩容、缩容条件。如果选择使用绝对度量,用户需要保证目标(限额)要比请求使用的低,否则,过载的Pod未必能够消耗那么多,从而自动扩容永远不会被触发:假设设置CPU为1个核,那么这个pod只能使用1个核,可能Pod在过载的情况下也不能完全利用这个核,所以扩容不会发生。在修改申请资源时,还有同时调整扩容的条件,比如将1个core变为1.2core,那么扩容条件应该同步改为1.2core,这样的话,就真是太麻烦了,与自动扩容的目标相悖。

多台机器不断访问service的clusterIP地址,然后可以看出是否增加pod数了
}

每天早上六点到十点营业,生意挺好,就是发愁一个事情,应该准备多少个馒头才能既不浪费又能充分供应?

老板统计了一周每日卖出的馒头(为了方便计算和讲解,缩小了数据):

按道理讲均值是不错的选择(参见“”),但是如果每天准备5个馒头的话,从统计表来看,至少有两天不够卖,40\% 的时间不够卖:

你“甜在心馒头店”又不是小米,搞什么饥饿营销啊?老板当然也知道这一点,就拿起纸笔来开始思考。

老板尝试把营业时间抽象为一根线段,把这段时间用T 来表示:

然后把\color{SkyBlue}{周一} 的三个馒头(“甜在心馒头”,有褶子的馒头)按照销售时间放在线段上:

T 均分为四个时间段:

此时,在每一个时间段上,要不卖出了(一个)馒头,要不没有卖出:

在每个时间段,就有点像抛硬币,要不是正面(卖出),要不是反面(没有卖出):

T 内卖出3个馒头的概率,就和抛了4次硬币(4个时间段),其中3次正面(卖出3个)的概率一样了。

这样的概率通过二项分布来计算就是:

但是,如果把\color{blue}{周二} 的七个馒头放在线段上,分成四段就不够了:

从图中看,每个时间段,有卖出3个的,有卖出2个的,有卖出1个的,就不再是单纯的“卖出、没卖出”了。不能套用二项分布了。

解决这个问题也很简单,把T 分为20个时间段,那么每个时间段就又变为了抛硬币:

这样,T 内卖出7个馒头的概率就是(相当于抛了20次硬币,出现7次正面):

为了保证在一个时间段内只会发生“卖出、没卖出”,干脆把时间切成n 份:

越细越好,用极限来表示:

更抽象一点,T 时刻内卖出k 个馒头的概率为:

“那么”,老板用笔敲了敲桌子,“只剩下一个问题,概率p 怎么求?”

在上面的假设下,问题已经被转为了二项分布。二项分布的期望为:

我们来算一下这个极限:

上面就是泊松分布的概率密度函数,也就是说,在T 时间内卖出k 个馒头的概率为:

一般来说,我们会换一个符号,让\mu=\lambda ,所以:

这就是教科书中的泊松分布的概率密度函数。

5 馒头店的问题的解决

老板依然蹙眉,不知道\mu 啊?

没关系,刚才不是计算了样本均值:

画出概率密度函数的曲线就是:

可以看到,如果每天准备8个馒头的话,那么足够卖的概率就是把前8个的概率加起来:

这样93\% 的情况够用,偶尔卖缺货也有助于品牌形象。

老板算出一脑门的汗,“那就这么定了!”

6 二项分布与泊松分布

鉴于二项分布与泊松分布的关系,可以很自然的得到一个推论,当二项分布的p 很小的时候,两者比较接近:

这个故事告诉我们,要努力学习啊,要不以后馒头都没得卖。

生活中还有很多泊松分布。比如物理中的半衰期,我们只知道物质衰变一半的时间期望是多少,但是因为,我们没有办法知道具体哪个原子会在什么时候衰变?所以可以用泊松分布来计算。

还有比如交通规划等等问题。

这篇文章可以继续扩充:

文章最新版本在(有可能会有后续更新):

更多内容推荐马同学图解数学系列

}

我要回帖

更多关于 两个整数的和是8,积是7 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信