首页 文章 精选 留言 我的

精选列表

搜索[手动],共10007篇文章
优秀的个人博客,低调大师

CentOS7手动安装OpenStack Pike版--(horizon)

OpenStack安装指南_Mitakahttp://down.51cto.com/data/2331199 Openstack管理手册-Newton版-CentOS7.2http://down.51cto.com/data/2331201 #Configure horizon Edit the /etc/openstack-dashboard/local_settings OPENSTACK_HOST = "controller" ALLOWED_HOSTS = ['*', ] SESSION_ENGINE = 'django.contrib.sessions.backends.cache' CACHES = { 'default': { 'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache', 'LOCATION': 'controller:11211', }, } OPENSTACK_KEYSTONE_URL = "http://%s:5000/v2.0" % OPENSTACK_HOST OPENSTACK_KEYSTONE_MULTIDOMAIN_SUPPORT = True OPENSTACK_API_VERSIONS = { "data-processing": 1.1, "identity": 3, "image": 2, "volume": 2, "compute": 2, } OPENSTACK_KEYSTONE_DEFAULT_DOMAIN = 'Default' OPENSTACK_KEYSTONE_DEFAULT_ROLE = "user" TIME_ZONE = "Asia/Shanghai" systemctl restart httpd.service memcached.service controller节点安装完成,访问Dashboardhttp://192.168.137.145/dashboard/ 本文转自 OpenStack2015 博客,原文链接: http://blog.51cto.com/andyliu/2069169 如需转载请自行联系原作者

优秀的个人博客,低调大师

每日一博 | 请求分级与限流——手动打造服务网关

转载本文需注明出处:微信公众号EAWorld,违者必究。 项目背景 雪崩一词指的是山地积雪由于底部溶解等原因而突然大块塌落的现象,具有很强的破坏力。在系统架构中提到的雪崩,就是由于一台服务器或者一台服务器中的某个模块发生故障进而引起连锁反应,最后导致大量的服务器或者软件模块无法正常工作,这种现象也较做“急剧变化”现象。 在某通信集团统一流程平台项目上线初期就发生过几次服务雪崩的事故,由于业务系统接入持续增多,业务系统的查询请求数量大大高于了前期的设计。当集群中的一台节点宕机下线后,请求压力迅速传导给了整个集群,从而引发了集群整体宕机。 解决方案 为了保障平台整体能稳定运行,在重新对服务器负载进行估算、增加集群冗余后,项目组增加了在部署架构、压力负载分流方面考虑,以持续提升平台性能。 我们对现有平台集群的逻辑架构进行了调整,将业务访问请求按系统ID分流到各子集群,由各集群分开处理,通过对业务请求的细分,达到子集群隔离,提升系统的稳定性与可扩展性。 具体到实施层面,项目组预备在负载均衡上增加服务网关的功能,使得nginx集群不再单纯的做反向代理,而是扩展为服务网关。 服务网关 服务网关基于openresty开发,OpenResty是一个基于 Nginx 与 Lua 的高性能 Web 平台,其内部集成了大量精良的 Lua 库、第三方模块以及大多数的依赖项。用于方便地搭建能够处理超高并发、扩展性极高的动态 Web 应用、Web 服务和动态网关。 我们在其基础上实现了以下功能: 流量限制:设立限流名单制度,对于非VIP且请求量大的用户进行限流。对名单中用户的请求进行计数,限制用户每分钟的请求次数,避免重复调用或短期内大量无效请求。 请求分域:根据请求来源的租户实现请求分域,将不同的租户请求分发到该租户的专用集群。 健康检查:提供一个简单的查询页面,可以查询当前集群节点的健康状况。 部署架构调整 在改造网关之前,我们首先要对集群的物理架构进行调整。通过对统一平台的业务量以及调用量的统计,以及对业务请求的监控我们发现,无论从业务数量以及调用量来看,业务压力主要来自于其中的两个业务系统。 于是我们对现有架构进行了调整,将负载均衡随机分发请求到集群,调整为按系统分发,将一个大集群切割成若干个小集群,按请求所在的系统将请求分发到各自响应的集群中。 请求分域 首先我们已经通过调整集群的部署,将集群进行了物理分割,接下来我们只需要将相关系统的请求转发到对应的集群中即可。 首先通过获取每个请求的请求头,来获得该请求的所属系统、所属用户等关键信息。 map $host $fmt_localtime { default '';}map $host $bpm_method { default '';}map $host $bpm_tenantid { default '';}map $host $bpm_province { default '';}map $host $bpm_userid { default '';}map $host $bpm_provinceFlag { default '';}map$host$RequestId{default'';} (左右滑动查看全部代码) 然后我们在脚本中定义好每个系统的节点地址 #报账upstream bpm_cluster_rbs {server 10.24.20.45:8080;server 10.24.20.46:8080;……server 10.24.20.52:8080; }#合同upstream bpm_cluster_cms {server 10.24.20.53:8080;……server 10.24.20.60:8080;}#其他upstream bpm_cluster_other {server 10.24.20.10:8080;……server 10.24.20.16:8080;} (左右滑动查看全部代码) 最后当收到请求时,将对应请求转发到对应的upstream就可以了 functionforwardUpstream(tenantid)iftenantid=="CMS"--对于合同系统而且是查询待办相关操作thenngx.var.upstream="bpm_cluster_cms"elseiftenantid=="RBS"--对于报账系统而且是查询待办相关操作thenngx.var.upstream="bpm_cluster_rbs"elsengx.var.upstream="bpm_cluster_other"enden (左右滑动查看全部代码) 限流 lua-resty-limit-traffic是一个openresty中用于限制和控制流量的Lua库,使用这个库可以方便的对用户、IP进行限流 https://github.com/openresty/lua-resty-limit-traffic (左右滑动查看全部代码) lua-resty-limit-traffic模块限流分为两种: 第一种限制某用户每分钟只能调用120次(允许在时间段开始的时候一次性放过120个请求) local limit_count = require "resty.limit.count"local lim, err = limit_count.new("my_limit_count_store", 120, 60) (左右滑动查看全部代码) 第二种限制每分钟处理120个请求(平滑处理,每秒钟只放过两个请求) local limit_req = require "resty.limit.req"local lim, err = limit_req.new("my_limit_req_store", 2, 0) (左右滑动查看全部代码) 实战中,我们的策略是将流量大的用户加入到限流名单中,名单内的用户会在redis中维护一份配置表,包括 在请求进来后,我们先从请求头中获取当前请求的用户 map $host $bpm_userid { default '';} (左右滑动查看全部代码) 然后判断该用户是否在限流名单内,如果确定为限流用户则读取该用户的配置信息 local cache_ngx = ngx.shared.my_ngx_redis_cachelocal user_conf = cache_ngx:get(userid)local redis_josn = cjson.decode(user_conf)local maxReq = redis_josn['maxReq']local nextReqTime = redis_josn['nextReqTime'] (左右滑动查看全部代码) 根据配置调用限流方法,设置某用户每分钟只能调用XX次请求(允许一次性放过) local limit_count = require "resty.limit.count"local maxReq = redis_josn['maxReq']local nextReqTime = redis_josn['nextReqTime']local lim, err = limit_count.new("my_limit_count_store", maxReq, nextReqTime)if not lim then ngx.log(ngx.ERR, "failed to instantiate a resty.limit.count object: ", err) return ngx.exit(500)endlocal delay, err = lim:incoming(key, true)-- 如果发生错误则返回500,如果请求数超过了 count 限制则返回403if not delay then if err == "rejected" then return ngx.exit(403) end ngx.log(ngx.ERR, "failed to limit count:", err) return ngx.exit(500)end (左右滑动查看全部代码) 健康检查 upstream.healthcheck本质上是个定时器,它会定期发送指定的http请求并解析响应码,去探测upstream中每个peer的存活状态,再结合历史请求记录来判断并标记其状态。 模块的源码见下面的页面: https://github.com/openresty/lua-resty-upstream-healthcheck (左右滑动查看全部代码) 实战中我们的代码如下: local ok, err = hc.spawn_checker{ shm = "healthcheck", -- defined by "lua_shared_dict" upstream = "bpm_cluster_rbs", -- defined by "upstream" type = "http", http_req = "GET /default/engineState.jsp HTTP/1.0\r\nHost: bpm_cluster_rbs\r\n\r\n", -- raw HTTP request for checking interval = 2000, -- 每两秒检查一次 timeout = 1000, -- 1 sec is the timeout for network operations fall = 3, -- # 连续3次失败才认定为down rise = 2, -- # 对down状态的节点,连续2次成功认定为UP valid_statuses = {200, 302}, -- 状态正常的code concurrency = 10, -- 检查线程数} (左右滑动查看全部代码) 关于作者:李云涛,普元高级开发工程师,擅长性能调优、微服务、容器、消息队列等技术。先后参与邮储银行Java开发平台、中移总ERP流程平台、中煤信息技术中台等平台的的架构设计与平台研发工作。 关于EAWorld:使能数字转型,共创数智未来,长按二维码关注! 本文分享自微信公众号 - EAWorld(eaworld)。如有侵权,请联系 support@oschina.cn 删除。本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

优秀的个人博客,低调大师

SpreadJS 的 Table手动新增数据后获取完整字段的方法

问题背景 在 SpreadJS 表格控件中,当Table数据绑定后,对Table插入行,新行内填充部分单元格。在getDataSource()返回值中,关于新增行的数据对象,仅有被填充单元格对应的字段。如何获取完整字段,不论对应单元格是否填充了数据。 数据绑定使用的数据是一个JavaScript对象,在代码运行期间,这个对象被创建后即存在于内存中。这也是为什么把文件导出时虽然携带了绑定的数据源,但是导入至新应用的Workbook中再调用Worksheet:getDataSource()得到的结果为null的原因。即在新应用运行时的内存空间中没有原本的数据源对象。 解决方法 回到问题背景,虽然新增行在Table区域内,但是没有数据,意味着这行数据在数据源对象中是一个各字段属性均不存在的空对象,如图1所示。 (图1. 新行对应空数据对象) 紧接着,如果对新增行内的个别单元格写入数据,数据绑定功能的双向绑定特性将单元格值和相关字段对应起来,组成一个对象。对于没被填充数据的单元格,不做类似处理。因此,Worksheet:getDataSource()获取到新增行中的数据对象仅包含被填充单元格对应的字段属性,如图2所示。 (图2. 新行数据对象包含被填充字段属性) 那如何获取完整字段呢?即,无论填充了哪些字段,都能获取到这一行对应的完整字段。Worksheet:getDataSource()应该是做不到了,因为接口并未提供可回调操作的参数,所以需要在接口外想办法了。 回顾下对Table执行数据绑定的准备工作,对Table列设置绑定路径,而每个列的绑定路径实际上对应为数据源中的一个字段,也就是说数据源模型可知。那么,在代码上下文中存储数据源模型为元数据,同时为每个字段设置数据类型和默认值,后面会用到。如图3所示,这个元数据定义了数据源对象的各个字段,名称分别为a、b、c、d、e和f,为简单起见,定义类型均为string,且默认值为空字符串。 (图3. 数据源模型元数据) 在Worksheet:getDataSource()后,结合数据源模型元数据遍历每行单元格对应的数据对象,检查当前数据对象中是否包含元数据中的每项字段。对于未包含的字段项,在当前数据对象中扩充,并且根据元数据中该字段项的数据类型和默认值设置其值,如图4所示代码片段。由于数据源对象存在于内存空间中,因此这一修改动作会直接影响数据源对象状态。 (图4. 数据对象默认值设置代码) 最终效果如下图所示: 附上Html: <!DOCTYPE html> <html lang="zh"> <head> <meta charset="UTF-8"> <title>获取数据源全字段</title> <meta name="spreadjs culture" content="zh-cn"/> <link href="http://cdn.grapecity.com/spreadjs/hosted/css/gc.spread.sheets.excel2013white.18.1.3.css" rel="stylesheet" type="text/css"/> <link href="http://cdn.grapecity.com/spreadjs/hosted/css/gc.spread.sheets.designer.18.1.3.min.css" rel="stylesheet" type="text/css"/> <script src="http://cdn.grapecity.com/spreadjs/hosted/scripts/gc.spread.sheets.all.18.1.3.min.js"></script> <script src="http://cdn.grapecity.com/spreadjs/hosted/scripts/plugins/gc.spread.sheets.shapes.18.1.3.min.js"></script> <script src="http://cdn.grapecity.com/spreadjs/hosted/scripts/plugins/gc.spread.sheets.charts.18.1.3.min.js"></script> <script src="http://cdn.grapecity.com/spreadjs/hosted/scripts/plugins/gc.spread.sheets.slicers.18.1.3.min.js"></script> <script src="http://cdn.grapecity.com/spreadjs/hosted/scripts/plugins/gc.spread.sheets.print.18.1.3.min.js"></script> <script src="http://cdn.grapecity.com/spreadjs/hosted/scripts/plugins/gc.spread.sheets.barcode.18.1.3.min.js"></script> <script src="http://cdn.grapecity.com/spreadjs/hosted/scripts/plugins/gc.spread.sheets.pdf.18.1.3.min.js"></script> <script src="http://cdn.grapecity.com/spreadjs/hosted/scripts/plugins/gc.spread.pivot.pivottables.18.1.3.min.js"></script> <script src="http://cdn.grapecity.com/spreadjs/hosted/scripts/plugins/gc.spread.sheets.tablesheet.18.1.3.min.js"></script> <script src="http://cdn.grapecity.com/spreadjs/hosted/scripts/plugins/gc.spread.sheets.ganttesheet.18.1.3.min.js"></script> <script src="http://cdn.grapecity.com/spreadjs/hosted/scripts/plugins/gc.spread.report.reportsheet.18.1.3.min.js"></script> <script src="http://cdn.grapecity.com/spreadjs/hosted/scripts/plugins/gc.spread.sheets.formulapanel.18.1.3.min.js"></script> <script src="http://cdn.grapecity.com/spreadjs/hosted/scripts/plugins/gc.spread.sheets.io.18.1.3.min.js"></script> <script src="http://cdn.grapecity.com/spreadjs/hosted/scripts/interop/gc.spread.excelio.18.1.3.min.js"></script> <script src="http://cdn.grapecity.com/spreadjs/hosted/scripts/resources/zh/gc.spread.sheets.resources.zh.18.1.3.min.js"></script> <script src="http://cdn.grapecity.com/spreadjs/hosted/scripts/gc.spread.sheets.designer.resource.cn.18.1.3.min.js"></script> <script src="http://cdn.grapecity.com/spreadjs/hosted/scripts/gc.spread.sheets.designer.all.18.1.3.min.js"></script> <style> .sample-tutorial { position: relative; height: 100%; overflow: hidden; } body { position: absolute; margin: 0; top: 0; bottom: 0; left: 0; right: 0; } .gc-across-sheet-ftb { z-index: -1 !important; } .gc-across-sheet-func-popup { z-index: -1 !important; } </style> </head> <body> <!-- <button id="readyBtn">绑定事件</button> --> <button id="bindingBtn">绑定数据</button> <button id="copyToBtn">插入sheet行</button> <button id="getDataSourceBtn">获取数据源</button> <div class="sample-tutorial"> <div class="demo-options"> <div class="option-row"> <div id="formulaBar" contenteditable="true" spellcheck="false" style="font-family: Calibri;border: 1px solid #808080;width:100%;box-sizing: border-box;"></div> </div> </div> <div id="ss" style="width:100%; height: calc(100% - 20px)"></div> </div> </body> <script> window.onload = function () { var designer = new GC.Spread.Sheets.Designer.Designer(document.getElementById('ss')); var spread = designer.getWorkbook(); init(spread); } function init(spread) { var sheet = spread.getActiveSheet(); var table = sheet.tables.add('table1', 0, 0, 7, 6); document.getElementById('bindingBtn').addEventListener('click', function() { tableBinding(spread.getActiveSheet()); }); document.getElementById('getDataSourceBtn').addEventListener('click', function() { var dataSource = spread.getActiveSheet().getDataSource(); console.log('dataSource: ', dataSource); var metaData = { 'a': {type: 'string', defaultValue: ''}, 'b': {type: 'string', defaultValue: ''}, 'c': {type: 'string', defaultValue: ''}, 'd': {type: 'string', defaultValue: ''}, 'd': {type: 'string', defaultValue: ''}, 'f': {type: 'string', defaultValue: ''} }; setDefaultValues(dataSource.rT.tableData, metaData); console.log('after data process: ', dataSource); }); document.getElementById('copyToBtn').addEventListener('click', function() { var sheet = spread.getActiveSheet(); var selection = sheet.getSelections()[0]; console.log('selection: ', selection); sheet.addRows(selection.row, 1); sheet.copyTo(selection.row - 1, 1, selection.row, 1, 1, 6, GC.Spread.Sheets.CopyToOptions.span); }); } /** * 数据对象属性默认值设置 */ function setDefaultValues(objArray, metaData) { if (objArray) { objArray.forEach(obj => { for (const key in metaData) { if (metaData.hasOwnProperty(key)) { const {defaultValue} = metaData[key]; if (!obj.hasOwnProperty(key) || obj[key] == undefined) { obj[key] = defaultValue; } } } }); } return objArray; } function tableBinding(sheet) { var table = sheet.tables.all()[0]; var tableColmn1 = new GC.Spread.Sheets.Tables.TableColumn(); tableColmn1.dataField('a'); tableColmn1.name('a字段'); var tableColmn2 = new GC.Spread.Sheets.Tables.TableColumn(); tableColmn2.dataField('c '); tableColmn2.name('b字段'); var tableColmn3 = new GC.Spread.Sheets.Tables.TableColumn(); tableColmn3.dataField('b'); tableColmn3.name('c字段'); var tableColmn4 = new GC.Spread.Sheets.Tables.TableColumn(); tableColmn4.dataField('d'); tableColmn4.name('d字段'); var tableColmn5 = new GC.Spread.Sheets.Tables.TableColumn(); tableColmn5.dataField('e'); tableColmn5.name('e字段'); var tableColmn6 = new GC.Spread.Sheets.Tables.TableColumn(); tableColmn6.dataField('f'); tableColmn6.name('f字段'); table.bindColumns([tableColmn1, tableColmn2, tableColmn3, tableColmn4, tableColmn5, tableColmn6]); table.bindingPath('tableData'); table.expandBoundRows(true); var data = { 'tableData': [ { 'a': 1, 'b': 2, 'c': 3, 'd': 4, 'e': 5, 'f': 6 }, { 'a': 2, 'b': 3, 'c': 4, 'd': 5, 'e': 6, 'f': 7 }, { 'a': 3, 'b': 4, 'c': 5, 'd': 6, 'e': 7, 'f': 8 }, { 'a': 4, 'b': 5, 'c': 6, 'd': 7, 'e': 8, 'f': 9 }, { 'a': 5, 'b': 6, 'c': 7, 'd': 8, 'e': 9, 'f': 10 }, { 'a': 6, 'b': 7, 'c': 8, 'd': 9, 'e': 10, 'f': 11 }, ] }; var dataSource = new GC.Spread.Sheets.Bindings.CellBindingSource(data); sheet.setDataSource(dataSource); } </script> </html>

优秀的个人博客,低调大师

Centos0S7手动安装OpenStack Pike版--(glance)

#Configure Glance mysql -uroot -ppasswd123 -e "CREATE DATABASE glance" mysql -uroot -ppasswd123 -e "GRANT ALL PRIVILEGES ON glance.TO 'glance'@'localhost' IDENTIFIED BY 'passwd123'" mysql -uroot -ppasswd123 -e "GRANT ALL PRIVILEGES ON glance.TO 'glance'@'%' IDENTIFIED BY 'passwd123'" openstack user create --domain default --password passwd123 glance openstack role add --project service --user glance admin openstack service create --name glance --description "OpenStack Image" image openstack endpoint create --region RegionOne image publichttp://controller:9292 openstack endpoint create --region RegionOne image internalhttp://controller:9292 openstack endpoint create --region RegionOne image adminhttp://controller:9292 openstack-config --set /etc/glance/glance-api.conf database connection mysql+pymysql://glance:passwd123@controller/glance openstack-config --set /etc/glance/glance-api.conf keystone_authtoken auth_urihttp://controller:5000 openstack-config --set /etc/glance/glance-api.conf keystone_authtoken auth_urlhttp://controller:35357 openstack-config --set /etc/glance/glance-api.conf keystone_authtoken memcached_servers controller:11211 openstack-config --set /etc/glance/glance-api.conf keystone_authtoken auth_type password openstack-config --set /etc/glance/glance-api.conf keystone_authtoken project_domain_name Default openstack-config --set /etc/glance/glance-api.conf keystone_authtoken user_domain_name Default openstack-config --set /etc/glance/glance-api.conf keystone_authtoken project_name service openstack-config --set /etc/glance/glance-api.conf keystone_authtoken username glance openstack-config --set /etc/glance/glance-api.conf keystone_authtoken password passwd123 openstack-config --set /etc/glance/glance-api.conf paste_deploy flavor keystone openstack-config --set /etc/glance/glance-api.conf glance_store stores file,http openstack-config --set /etc/glance/glance-api.conf glance_store default_store file openstack-config --set /etc/glance/glance-api.conf glance_store filesystem_store_datadir /var/lib/glance/images/ /etc/glance/glance-registry.conf openstack-config --set /etc/glance/glance-registry.conf database connection mysql+pymysql://glance:passwd123@controller/glance openstack-config --set /etc/glance/glance-registry.conf keystone_authtoken auth_urihttp://controller:5000 openstack-config --set /etc/glance/glance-registry.conf keystone_authtoken auth_urlhttp://controller:35357 openstack-config --set /etc/glance/glance-registry.conf keystone_authtoken memcached_servers controller:11211 openstack-config --set /etc/glance/glance-registry.conf keystone_authtoken auth_type password openstack-config --set /etc/glance/glance-registry.conf keystone_authtoken project_domain_name Default openstack-config --set /etc/glance/glance-registry.conf keystone_authtoken user_domain_name Default openstack-config --set /etc/glance/glance-registry.conf keystone_authtoken project_name service openstack-config --set /etc/glance/glance-registry.conf keystone_authtoken username glance openstack-config --set /etc/glance/glance-registry.conf keystone_authtoken password passwd123 openstack-config --set /etc/glance/glance-registry.conf paste_deploy flavor keystone su -s /bin/sh -c "glance-manage db_sync" glance systemctl enable openstack-glance-api.service openstack-glance-registry.service systemctl start openstack-glance-api.service openstack-glance-registry.service systemctl status openstack-glance-api.service openstack-glance-registry.service source admin-openrc openstack image create "centos7" --file CentOS-7-x86_64-GenericCloud.qcow2 --disk-format qcow2 --container-format bare --public openstack image list 本文转自 OpenStack2015 博客,原文链接: http://blog.51cto.com/andyliu/2069164 如需转载请自行联系原作者

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册