ZbxTable——zabbix优秀报表二开 zbxTable是一个开源zabbix报表系统 , go语言编写(张思德,zabbix中国社区开源专家),目前版本已更新到1.15版本 , 支持zabbix5.4版本 。
zbxTable部署有两种方式:RPM部署和编译安装,如有特殊需要,可选择编译安装,zbxtable用go语言编写,对系统影响小,推荐用RPM安装 。
添加yum源
CentOS 6.x
rpm -Uvh
【go语言报表控件 golang 表格】CentOS 7.X
rpm -Uvh
CentOS 8.X
rpm -Uvh
安装
全新安装直接复制命令即可
yum clean all
yum -y install zbxtable
安装ms-agent
yum -y install ms-agent
配置
数据库初始化
mysql -uroot -ppassword
create database zbxtable character set utf8 collate utf8_bin;
create user zbxtable@localhost identified by ‘zbxtablepwd123’;
这里不讲其他数据库 , 有兴趣的可以看官网具体配置
系统初始化
配置文件需要初始化才能生成 , 步骤如下:
cd /usr/local/zbxtable/
./zbxtable init
这时候会进入交互命令行,根据实际情况正确输入数据库库的账号密码,zabbix链接信息,成功后会生成配置文件,否则无法看到配置文件 。
配置MS-Agent
MS-Agent作为告警消息采集客户端,采集zabbix产生的告警信息,发送到zbxtable平台中 , zbxtable需要在zabbix server配置相应的action 。配置如下 。
cd /usr/local/zbxtable
./zbxtable install
这时会在zabbix上创建ms-agent用户,密码随机,权限管理员,最后输出MS-Agent token为MS-Agent 与ZbxTable通信的token,需要和MS-Agent 配置文件里的token保持一致,否则无法正常收到告警 。Token可在conf/app.conf文件里找到 。
启动服务
systemctl enable --now zbxtable
重启
systemctl restart zbxtable
查看状态
systemctl status zbxtable
必须确保zbxtable服务是active状态,如果异常 , 查看日志文件:/usr/local/zbxtable/logs/zbxtable.log或者系统日志message
Zbxtable-web配置
zbxtable使用nginx做代理,安装即可
yum -y install nginx
拷贝nginx配置文件
cp /usr/local/zbxtable/nginx.conf /etc/nginx/conf.d/
启动nginx
systemctl start nginx
开机自启动
systemctl enable nginx
zbxtable访问地址:,默认账号密码:admin/Zbxtable 。
golang csv parse error on line 1, column 1: bare " in non-quoted-field根据需求做一个csv报表数据导入入库功能,运行多天突然运维告知导入数据有问题 , 有问题那就排查呗 。。。
题外话:这个问题足足浪费了我2天时间,期间还出了其他的一些问题着实让我抓狂,另外这篇文章希望能帮到你,不要在采坑了?。。?
说在前面,这个csv表格数据是有中文的 。ok继续
通过日志打点发现了以下错误
找了一圈,着实头痛,我也知道中文需要做处理转化这个我已经做了,并且已经明确是utf-8了通过标准库方法进行判断的还是报错 。着实让我摸不着头脑 。判断utf-8方法如下
ok,最后借助了百度,google找了一大圈功夫不负有心人,最后发现utf-8还有 utf-8 bom 这种编码格式,我想骂娘 。。。至于编码规则啥的就不详细说了,有兴趣自行百度吧 。
解决方案如下:
至于其他编码方式以及转换可以查看golang官方扩展库 golang.org/x/text/encoding 库中的源码 。
一个用golang的无名小卒
完~
如何实现支持数亿用户的长连消息系统此文是根据周洋在【高可用架构群】中的分享内容整理而成,转发请注明出处 。周洋,360手机助手技术经理及架构师,负责360长连接消息系统,360手机助手架构的开发与维护 。不知道咱们群名什么时候改为“Python高可用架构群”了 , 所以不得不说,很荣幸能在接下来的一个小时里在Python群里讨论golang....360消息系统介绍360消息系统更确切的说是长连接push系统 , 目前服务于360内部多个产品,开发平台数千款app , 也支持部分聊天业务场景 , 单通道多app复用,支持上行数据,提供接入方不同粒度的上行数据和用户状态回调服务 。目前整个系统按不同业务分成9个功能完整的集群,部署在多个idc上(每个集群覆盖不同的idc),实时在线数亿量级 。通常情况下,pc,手机,甚至是智能硬件上的360产品的push消息,基本上是从我们系统发出的 。关于push系统对比与性能指标的讨论很多同行比较关心go语言在实现push系统上的性能问题,单机性能究竟如何,能否和其他语言实现的类似系统做对比么?甚至问如果是创业,第三方云推送平台,推荐哪个?其实各大厂都有类似的push系统,市场上也有类似功能的云服务 。包括我们公司早期也有erlang,nodejs实现的类似系统,也一度被公司要求做类似的对比测试 。我感觉在讨论对比数据的时候,很难保证大家环境和需求的统一,我只能说下我这里的体会,数据是有的,但这个数据前面估计会有很多定语~第一个重要指标:单机的连接数指标做过长连接的同行 , 应该有体会,如果在稳定连接情况下 , 连接数这个指标,在没有网络吞吐情况下对比,其实意义往往不大,维持连接消耗cpu资源很小,每条连接tcp协议栈会占约4k的内存开销,系统参数调整后,我们单机测试数据,最高也是可以达到单实例300w长连接 。但做更高的测试,我个人感觉意义不大 。因为实际网络环境下,单实例300w长连接,从理论上算压力就很大:实际弱网络环境下 , 移动客户端的断线率很高,假设每秒有1000分之一的用户断线重连 。300w长连接,每秒新建连接达到3w,这同时连入的3w用户,要进行注册,加载离线存储等对内rpc调用,另外300w长连接的用户心跳需要维持,假设心跳300s一次,心跳包每秒需要1w tps 。单播和多播数据的转发 , 广播数据的转发,本身也要响应内部的rpc调用,300w长连接情况下,gc带来的压力 , 内部接口的响应延迟能否稳定保障 。这些集中在一个实例中,可用性是一个挑战 。所以线上单实例不会hold很高的长连接,实际情况也要根据接入客户端网络状况来决定 。第二个重要指标:消息系统的内存使用量指标这一点上,使用go语言情况下 , 由于协程的原因 , 会有一部分额外开销 。但是要做两个推送系统的对比 , 也有些需要确定问题 。比如系统从设计上是否需要全双工(即读写是否需要同时进行)如果半双工 , 理论上对一个用户的连接只需要使用一个协程即可(这种情况下 , 对用户的断线检测可能会有延时) , 如果是全双工,那读/写各一个协程 。两种场景内存开销是有区别的 。另外测试数据的大小往往决定我们对连接上设置的读写buffer是多大,是全局复用的,还是每个连接上独享的 , 还是动态申请的 。另外是否全双工也决定buffer怎么开 。不同的策略 , 可能在不同情况的测试中表现不一样 。第三个重要指标:每秒消息下发量这一点上,也要看我们对消息到达的QoS级别(回复ack策略区别),另外看架构策略,每种策略有其更适用的场景,是纯粹推?还是推拉结合?甚至是否开启了消息日志?日志库的实现机制、以及缓冲开多大?flush策略……这些都影响整个系统的吞吐量 。另外为了HA,增加了内部通信成本 , 为了避免一些小概率事件,提供闪断补偿策略,这些都要考虑进去 。如果所有的都去掉,那就是比较基础库的性能了 。所以我只能给出大概数据 , 24核 , 64G的服务器上,在QoS为message at least,纯粹推,消息体256B~1kB情况下,单个实例100w实际用户(200w )协程,峰值可以达到2~5w的QPS...内存可以稳定在25G左右,gc时间在200~800ms左右(还有优化空间) 。我们正常线上单实例用户控制在80w以内,单机最多两个实例 。事实上 , 整个系统在推送的需求上 , 对高峰的输出不是提速 , 往往是进行限速,以防push系统瞬时的高吞吐量,转化成对接入方业务服务器的ddos攻击所以对于性能上,我感觉大家可以放心使用,至少在我们这个量级上,经受过考验,go1.5到来后,确实有之前投资又增值了的感觉 。消息系统架构介绍下面是对消息系统的大概介绍 , 之前一些同学可能在gopher china上可以看到分享 , 这里简单讲解下架构和各个组件功能,额外补充一些当时遗漏的信息:架构图如下,所有的service都 written by golang.几个大概重要组件介绍如下:dispatcher service根据客户端请求信息,将应网络和区域的长连接服务器的,一组IP传送给客户端 。客户端根据返回的IP,建立长连接 , 连接Room service.room Service,长连接网关,hold用户连接,并将用户注册进register service,本身也做一些接入安全策略、白名单、IP限制等 。register service是我们全局session存储组件,存储和索引用户的相关信息,以供获取和查询 。coordinator service用来转发用户的上行数据,包括接入方订阅的用户状态信息的回调 , 另外做需要协调各个组件的异步操作,比如kick用户操作,需要从register拿出其他用户做异步操作.saver service是存储访问层,承担了对redis和mysql的操作,另外也提供部分业务逻辑相关的内存缓存 , 比如广播信息的加载可以在saver中进行缓存 。另外一些策略,比如客户端sdk由于被恶意或者意外修改,每次加载了消息,不回复ack,那服务端就不会删除消息,消息就会被反复加载,形成死循环,可以通过在saver中做策略和判断 。(客户端总是不可信的) 。center service提供给接入方的内部api服务器 , 比如单播或者广播接口,状态查询接口等一系列api,包括运维和管理的api 。举两个常见例子,了解工作机制:比如发一条单播给一个用户,center先请求Register获取这个用户之前注册的连接通道标识、room实例地址,通过room service下发给长连接 Center Service比较重的工作如全网广播 , 需要把所有的任务分解成一系列的子任务,分发给所有center,然后在所有的子任务里 , 分别获取在线和离线的所有用户,再批量推到Room Service 。通常整个集群在那一瞬间压力很大 。deployd/agent service用于部署管理各个进程,收集各组件的状态和信息,zookeeper和keeper用于整个系统的配置文件管理和简单调度关于推送的服务端架构常见的推送模型有长轮训拉?。?服务端直接推送(360消息系统目前主要是这种) , 推拉结合(推送只发通知,推送后根据通知去拉取消息).拉取的方式不说了,现在并不常用了,早期很多是nginx lua redis,长轮训,主要问题是开销比较大,时效性也不好,能做的优化策略不多 。直接推送的系统,目前就是360消息系统这种,消息类型是消耗型的,并且对于同一个用户并不允许重复消耗,如果需要多终端重复消耗,需要抽象成不同用户 。推的好处是实时性好 , 开销小,直接将消息下发给客户端,不需要客户端走从接入层到存储层主动拉取.但纯推送模型,有个很大问题,由于系统是异步的 , 他的时序性无法精确保证 。这对于push需求来说是够用的,但如果复用推送系统做im类型通信,可能并不合适 。对于严格要求时序性,消息可以重复消耗的系统,目前也都是走推拉结合的模型,就是只使用我们的推送系统发通知,并附带id等给客户端做拉取的判断策略,客户端根据推送的key,主动从业务服务器拉取消息 。并且当主从同步延迟的时候,跟进推送的key做延迟拉取策略 。同时也可以通过消息本身的QoS , 做纯粹的推送策略 , 比如一些“正在打字的”低优先级消息,不需要主动拉取了,通过推送直接消耗掉 。哪些因素决定推送系统的效果?首先是sdk的完善程度,sdk策略和细节完善度,往往决定了弱网络环境下最终推送质量.SDK选路策略,最基本的一些策略如下:有些开源服务可能会针对用户hash一个该接入区域的固定ip,实际上在国内环境下不可行,最好分配器(dispatcher)是返回散列的一组,而且端口也要参开,必要时候,客户端告知是retry多组都连不上,返回不同idc的服务器 。因为我们会经常检测到一些case , 同一地区的不同用户,可能对同一idc内的不同ip连通性都不一样,也出现过同一ip不同端口连通性不同,所以用户的选路策略一定要灵活,策略要足够完善.另外在选路过程中,客户端要对不同网络情况下的长连接ip做缓存 , 当网络环境切换时候(wifi、2G、3G),重新请求分配器,缓存不同网络环境的长连接ip 。客户端对于数据心跳和读写超时设置,完善断线检测重连机制针对不同网络环境 , 或者客户端本身消息的活跃程度,心跳要自适应的进行调整并与服务端协商,来保证链路的连通性 。并且在弱网络环境下 , 除了网络切换(wifi切3G)或者读写出错情况 , 什么时候重新建立链路也是一个问题 。客户端发出的ping包,不同网络下,多久没有得到响应,认为网络出现问题,重新建立链路需要有个权衡 。另外对于不同网络环境下 , 读取不同的消息长度,也要有不同的容忍时间,不能一刀切 。好的心跳和读写超时设置 , 可以让客户端最快的检测到网络问题,重新建立链路,同时在网络抖动情况下也能完成大数据传输 。结合服务端做策略另外系统可能结合服务端做一些特殊的策略,比如我们在选路时候,我们会将同一个用户尽量映射到同一个room service实例上 。断线时,客户端尽量对上次连接成功的地址进行重试 。主要是方便服务端做闪断情况下策略,会暂存用户闪断时实例上的信息,重新连入的 时候,做单实例内的迁移,减少延时与加载开销.客户端保活策略很多创业公司愿意重新搭建一套push系统,确实不难实现,其实在协议完备情况下(最简单就是客户端不回ack不清数据) , 服务端会保证消息是不丢的 。但问题是为什么在消息有效期内,到达率上不去?往往因为自己app的push service存活能力不高 。选用云平台或者大厂的,往往sdk会做一些保活策略,比如和其他app共生,互相唤醒,这也是云平台的push service更有保障原因 。我相信很多云平台旗下的sdk , 多个使用同样sdk的app,为了实现服务存活,是可以互相唤醒和保证活跃的 。另外现在push sdk本身是单连接,多app复用的,这为sdk实现 , 增加了新的挑战 。综上 , 对我来说,选择推送平台,优先会考虑客户端sdk的完善程度 。对于服务端,选择条件稍微简单,要求部署接入点(IDC)越要多,配合精细的选路策略,效果越有保证,至于想知道哪些云服务有多少点 , 这个群里来自各地的小伙伴们,可以合伙测测 。go语言开发问题与解决方案下面讲下,go开发过程中遇到挑战和优化策略,给大家看下当年的一张图,在第一版优化方案上线前一天截图~可以看到 , 内存最高占用69G,GC时间单实例最高时候高达3~6s.这种情况下,试想一次悲剧的请求,经过了几个正在执行gc的组件 , 后果必然是超时... gc照成的接入方重试,又加重了系统的负担 。遇到这种情况当时整个系统最差情况每隔2,3天就需要重启一次~当时出现问题 , 现在总结起来,大概以下几点1.散落在协程里的I/O,Buffer和对象不复用 。当时(12年)由于对go的gc效率理解有限,比较奔放 , 程序里大量short live的协程,对内通信的很多io操作,由于不想阻塞主循环逻辑或者需要及时响应的逻辑,通过单独go协程来实现异步 。这回会gc带来很多负担 。针对这个问题,应尽量控制协程创建,对于长连接这种应用 , 本身已经有几百万并发协程情况下,很多情况没必要在各个并发协程内部做异步io,因为程序的并行度是有限,理论上做协程内做阻塞操作是没问题 。如果有些需要异步执行,比如如果不异步执行 , 影响对用户心跳或者等待response无法响应,最好通过一个任务池,和一组常驻协程,来消耗,处理结果,通过channel再传回调用方 。使用任务池还有额外的好处,可以对请求进行打包处理 , 提高吞吐量,并且可以加入控量策略.2.网络环境不好引起激增go协程相比较以往高并发程序,如果做不好流控,会引起协程数量激增 。早期的时候也会发现,时不时有部分主机内存会远远大于其他服务器,但发现时候,所有主要profiling参数都正常了 。后来发现,通信较多系统中,网络抖动阻塞是不可免的(即使是内网),对外不停accept接受新请求,但执行过程中,由于对内通信阻塞,大量协程被 创建,业务协程等待通信结果没有释放 , 往往瞬时会迎来协程暴涨 。但这些内存在系统稳定后,virt和res都并没能彻底释放 , 下降后,维持高位 。处理这种情况 , 需要增加一些流控策略,流控策略可以选择在rpc库来做 , 或者上面说的任务池来做 , 其实我感觉放在任务池里做更合理些,毕竟rpc通信库可以做读写数据的限流,但它并不清楚具体的限流策略,到底是重试还是日志还是缓存到指定队列 。任务池本身就是业务逻辑相关的,它清楚针对不同的接口需要的流控限制策略 。3.低效和开销大的rpc框架早期rpc通信框架比较简单,对内通信时候使用的也是短连接 。这本来短连接开销和性能瓶颈超出我们预期,短连接io效率是低一些,但端口资源够 , 本身吞吐可以满足需要,用是没问题的,很多分层的系统,也有http短连接对内进行请求的但早期go版本,这样写程序,在一定量级情况,是支撑不住的 。短连接大量临时对象和临时buffer创建,在本已经百万协程的程序中,是无法承受的 。所以后续我们对我们的rpc框架作了两次调整 。第二版的rpc框架,使用了连接池,通过长连接对内进行通信(复用的资源包括client和server的:编解码Buffer、Request/response),大大改善了性能 。但这种在一次request和response还是占用连接的,如果网络状况ok情况下,这不是问题,足够满足需要了 , 但试想一个room实例要与后面的数百个的register,coordinator,saver , center , keeper实例进行通信,需要建立大量的常驻连接,每个目标机几十个连接,也有数千个连接被占用 。非持续抖动时候(持续逗开多少无解),或者有延迟较高的请求时候,如果针对目标ip连接开少了,会有瞬时大量请求阻塞,连接无法得到充分利用 。第三版增加了Pipeline操作,Pipeline会带来一些额外的开销 , 利用tcp的全双特性,以尽量少的连接完成对各个服务集群的rpc调用 。4.Gc时间过长Go的Gc仍旧在持续改善中,大量对象和buffer创建,仍旧会给gc带来很大负担,尤其一个占用了25G左右的程序 。之前go team的大咖邮件也告知我们,未来会让使用协程的成本更低 , 理论上不需要在应用层做更多的策略来缓解gc.改善方式,一种是多实例的拆分,如果公司没有端口限制,可以很快部署大量实例,减少gc时长 , 最直接方法 。不过对于360来说,外网通常只能使用80和433 。因此常规上只能开启两个实例 。当然很多人给我建议能否使用SO_REUSEPORT , 不过我们内核版本确实比较低,并没有实践过 。另外能否模仿nginx,fork多个进程监控同样端口,至少我们目前没有这样做,主要对于我们目前进程管理上,还是独立的运行的,对外监听不同端口程序,还有配套的内部通信和管理端口,实例管理和升级上要做调整 。解决gc的另两个手段 , 是内存池和对象池,不过最好做仔细评估和测试,内存池、对象池使用,也需要对于代码可读性与整体效率进行权衡 。这种程序一定情况下会降低并行度,因为用池内资源一定要加互斥锁或者原子操作做CAS,通常原子操作实测要更快一些 。CAS可以理解为可操作的更细行为粒度的锁(可以做更多CAS策略,放弃运行,防止忙等) 。这种方式带来的问题是,程序的可读性会越来越像C语言,每次要malloc,各地方用完后要free,对于对象池free之前要reset,我曾经在应用层尝试做了一个分层次结构的“无锁队列”上图左边的数组实际上是一个列表,这个列表按大小将内存分块,然后使用atomic操作进行CAS 。但实际要看测试数据了,池技术可以明显减少临时对象和内存的申请和释放,gc时间会减少,但加锁带来的并行度的降低 , 是否能给一段时间内的整体吞吐量带来提升 , 要做测试和权衡…在我们消息系统,实际上后续去除了部分这种黑科技 , 试想在百万个协程里面做自旋操作申请复用的buffer和对象,开销会很大,尤其在协程对线程多对多模型情况下,更依赖于golang本身调度策略 , 除非我对池增加更多的策略处理,减少忙等,感觉是在把runtime做的事情,在应用层非常不优雅的实现 。普遍使用开销理论就大于收益 。但对于rpc库或者codec库,任务池内部,这些开定量协程,集中处理数据的区域,可以尝试改造~对于有些固定对象复用 , 比如固定的心跳包什么的,可以考虑使用全局一些对象 , 进行复用,针对应用层数据,具体设计对象池,在部分环节去复用,可能比这种无差别的设计一个通用池更能进行效果评估.消息系统的运维及测试下面介绍消息系统的架构迭代和一些迭代经验,由于之前在其他地方有过分享,后面的会给出相关链接,下面实际做个简单介绍,感兴趣可以去链接里面看架构迭代~根据业务和集群的拆分,能解决部分灰度部署上线测试,减少点对点通信和广播通信不同产品的相互影响,针对特定的功能做独立的优化.消息系统架构和集群拆分 , 最基本的是拆分多实例,其次是按照业务类型对资源占用情况分类,按用户接入网络和对idc布点要求分类(目前没有条件,所有的产品都部署到全部idc)系统的测试go语言在并发测试上有独特优势 。对于压力测试,目前主要针对指定的服务器,选定线上空闲的服务器做长连接压测 。然后结合可视化 , 分析压测过程中的系统状态 。但压测早期用的比较多,但实现的统计报表功能和我理想有一定差距 。我觉得最近出的golang开源产品都符合这种场景,go写网络并发程序给大家带来的便利,让大家把以往为了降低复杂度,拆解或者分层协作的组件,又组合在了一起 。QAQ1:协议栈大小,超时时间定制原则?移动网络下超时时间按产品需求通常2g,3G情况下是5分钟,wifi情况下5~8分钟 。但对于个别场景,要求响应非常迅速的场景,如果连接idle超过1分钟 , 都会有ping,pong , 来校验是否断线检测,尽快做到重新连接 。Q2:消息是否持久化?消息持久化,通常是先存后发 , 存储用的redis,但落地用的mysql 。mysql只做故障恢复使用 。Q3:消息风暴怎么解决的?如果是发送情况下 , 普通产品是不需要限速的,对于较大产品是有发送队列做控速度,按人数 , 按秒进行控速度发放,发送成功再发送下一条 。Q4:golang的工具链支持怎么样?我自己写过一些小程序千把行之内,确实很不错,但不知道代码量上去之后,配套的debug工具和profiling工具如何 , 我看上边有分享说golang自带的profiling工具还不错,那debug呢怎么样呢,官方一直没有出debug工具,gdb支持也不完善,不知你们用的什么?是这样的,我们正常就是println , 我感觉基本上可以定位我所有问题,但也不排除由于并行性通过println无法复现的问题,目前来看只能靠经验了 。只要常见并发尝试 , 经过分析是可以找到的 。go很快会推出调试工具的~Q5:协议栈是基于tcp吗?是否有协议拓展功能?协议栈是tcp,整个系统tcp长连接 , 没有考虑扩展其功能~如果有好的经验,可以分享~Q6:问个问题,这个系统是接收上行数据的吧,系统接收上行数据后是转发给相应系统做处理么,是怎么转发呢,如果需要给客户端返回调用结果又是怎么处理呢?系统上行数据是根据协议头进行转发 , 协议头里面标记了产品和转发类型,在coordinator里面跟进产品和转发类型 , 回调用户,如果用户需要阻塞等待回复才能后续操作,那通过再发送消息,路由回用户 。因为整个系统是全异步的 。Q7:问个pushsdk的问题 。pushsdk的单连接 , 多app复用方式,这样的情况下以下几个问题是如何解决的:1)系统流量统计会把所有流量都算到启动连接的应用吧?而启动应用的连接是不固定的吧?2)同一个pushsdk在不同的应用中的版本号可能不一样,这样暴露出来的接口可能有版本问题 , 如果用单连接模式怎么解决?流量只能算在启动的app上了,但一般这种安装率很高的app承担可能性大,常用app本身被检测和杀死可能性较少,另外消息下发量是有严格控制 的 。整体上用户还是省电和省流量的 。我们pushsdk尽量向上兼容,出于这个目的,push sdk本身做的工作非常有限 , 抽象出来一些常见的功能,纯推的系统 , 客户端策略目前做的很少,也有这个原因 。Q8:生产系统的profiling是一直打开的么?不是一直打开,每个集群都有采样 , 但需要开启哪个可以后台控制 。这个profling是通过接口调用 。Q9:面前系统中的消息消费者可不可以分组?类似于Kafka 。客户端可以订阅不同产品的消息,接受不同的分组 。接入的时候进行bind或者unbind操作Q10:为什么放弃erlang,而选择go,有什么特别原因吗?我们现在用的erlang?erlang没有问题,原因是我们上线后 , 其他团队才做出来,经过qa一个部门对比测试 , 在没有显著性能提升下,选择继续使用go版本的push,作为公司基础服务 。Q11:流控问题有排查过网卡配置导致的idle问题吗?流控是业务级别的流控,我们上线前对于内网的极限通信量做了测试,后续将请求在rpc库内 , 控制在小于内部通信开销的上限以下.在到达上限前作流控 。Q12:服务的协调调度为什么选择zk有考虑过raft实现吗?golang的raft实现很多?。?比如Consul和ectd之类的 。3年前,还没有后两者或者后两者没听过应该 。zk当时公司内部成熟方案,不过目前来看,我们不准备用zk作结合系统的定制开发,准备用自己写的keeper代替zk,完成配置文件自动转数据结构,数据结构自动同步指定进程,同时里面可以完成很多自定义的发现和控制策略,客户端包含keeper的sdk就可以实现以上的所有监控数据,profling数据收集,配置文件更新,启动关闭等回调 。完全抽象成语keeper通信sdk,keeper之间考虑用raft 。Q13:负载策略是否同时在服务侧与CLIENT侧同时做的 (DISPATCHER 会返回一组IP)?另外,ROOM SERVER/REGISTER SERVER连接状态的一致性可用性如何保证? 服务侧保活有无特别关注的地方? 安全性方面是基于TLS再加上应用层加密?会在server端做,比如重启操作前,会下发指令类型消息 , 让客户端进行主动行为 。部分消息使用了加密策略,自定义的rsa des , 另外满足我们安全公司的需要,也定制开发很多安全加密策略 。一致性是通过冷备解决的 , 早期考虑双写,但实时状态双写同步代价太高而且容易有脏数据 , 比如register挂了,调用所有room,通过重新刷入指定register来解决 。Q14:这个keeper有开源打算吗?还在写 , 如果没耦合我们系统太多功能,一定会开源的,主要这意味着,我们所有的bind在sdk的库也需要开源~Q15:比较好奇lisence是哪个如果开源?
零基础学Python需要从哪里开始?分享Python学习路线:
第一阶段:Python基础与Linux数据库
这是Python的入门阶段,也是帮助零基础学员打好基础的重要阶段 。你需要掌握Python基本语法规则及变量、逻辑控制、内置数据结构、文件操作、高级函数、模块、常用标准库模板、函数、异常处理、mysql使用、协程等知识点 。
学习目标:掌握Python的基本语法,具备基础的编程能力;掌握Linux基本操作命令 , 掌握MySQL进阶内容,完成银行自动提款机系统实战、英汉词典、歌词解析器等项目 。
第二阶段:web全栈
这一部分主要学习web前端相关技术 , 你需要掌握html、cssJavaScript、JQuery、Bootstrap、web开发基础、Vue、FIask Views、FIask模板、数据库操作、FIask配置等知识 。
学习目标:掌握web前端技术内容,掌握web后端框架,熟练使用FIask、Tornado、Django,可以完成数据监控后台的项目 。
第三阶段:数据分析 人工智能
这部分主要是学习爬虫相关的知识点,你需要掌握数据抓取、数据提取、数据存储、爬虫并发、动态网页抓取、scrapy框架、分布式爬虫、爬虫攻防、数据结构、算法等知识 。
学习目标:可以掌握爬虫、数据采集,数据机构与算法进阶和人工智能技术 。可以完成爬虫攻防、图片马赛克、电影推荐系统、地震预测、人工智能项目等阶段项目 。
第四阶段:高级进阶
这是Python高级知识点 , 你需要学习项目开发流程、部署、高并发、性能调优、Go语言基础、区块链入门等内容 。
学习目标:可以掌握自动化运维与区块链开发技术,可以完成自动化运维项目、区块链等项目 。
按照上面的Python学习路线图学习完后,你基本上就可以成为一名合格的Python开发工程师 。当然,想要快速成为企业竞聘的精英人才,你需要有好的老师指导,还要有较多的项目积累实战经验 。
对于Python开发有兴趣的小伙伴们,不妨先从看看Python开发教程开始入门!B站搜索尚学堂官方号,Python教学视频,从基础到高级的都有,还挺不错的,知识点讲得很细致,还有完整版的学习路线图 。也可以自己去看看,下载学习试试 。
从PHP 到Golang 的笔记 ( 转 ) ———文章来源YamiOdymel/PHP-to-Golang
PHP和模块之间的关系令人感到烦躁 , 假设你要读取 yaml 档案,你需要有一个 yaml 的模块,为此,你还需要将其编译然后将编译后的模块摆放至指定位置,之后换了一台伺服器你还要重新编译,这点到现在还是没有改善;顺带一提之后出了PHP 7效能确实提升了许多(比Python 3快了些),但PHP仍令我感到臃肿,我觉得是时候
(转行)了 。
PHP 和Golang 的效能我想毋庸置疑是后者比较快(而且是以倍数来算),也许有的人会认为两种不应该被放在一起比较,但Golang 本身就是偏向Web 开发的,所以这也是为什么我考虑转用Golang 的原因,起初我的考虑有几个:Node.js 和Rust 还有最终被选定的Golang;先谈谈Node.js 吧 。
Node.js的效能可以说是快上PHP3.5倍至6倍左右 ,而且撰写的语言还是JavaScript,蒸蚌,如此一来就不需要学习新语言了!搭配Babel更可以说是万能,不过那跟「跳跳虎」一样的Async逻辑还有那恐怖的Callback Hell,有人认为前者是种优点,这点我不否认,但是对学习PHP的我来说太过于"Mind Fuck",至于后者的Callback Hell虽然有Promise,但是那又是另一个「Then Hell」的故事了 。相较于Golang之下,Node.js似乎就没有那么吸引我了 。你确实可以用Node.js写出很多东西,不过那V8引擎的效能仍然有限,而且要学习新的事物,不就应该是「全新」的吗;)?
题外话: 为什么Node.js不适合大型和商业专案?
在抛弃改用Node.js 之后我曾经花了一天的时间尝试Rust 和Iron 框架,嗯??Rust 太强大了,强大到让我觉得Rust 不应该用在这里,这想法也许很蠢,但Rust 让我觉得适合更应该拿来用在系统或者是部分底层的地方,而不应该是网路服务 。
Golang是我最终的选择,主要在于我花了一天的时间来研究的时候意外地发现Golang夭寿简洁( 关键字只有25个 ),相较之下Rust太过于「强大」令我怯步;而且Golang带有许多工具,例如 go fmt 会自动帮你整理程式码、 go doc 会自动帮你生产文件、 go test 可以自动单元测试并生产覆盖率报表、也有 go get 套件管理工具(虽然没有版本功能),不过都很实用,而且也不需要加上分号( ; ),真要说不好的地方??大概就是强迫你花括号不能换行放吧(没错,我就是花括号会换行放的人) 。
当我在撰写这份文件的时候 我会先假设你有一定的基础 ,你可以先阅读下列的手册,他们都很不错 。
你能够在PHP 里面想建立一个变数的时候就直接建立,夭寿赞,是吗?
蒸蚌!那么Golang 呢?在Golang 中变数分为几类:「新定义」、「预先定义」、「自动新定义」、「覆盖」 。让我们来看看范例:
在PHP中你会很常用到 echo 来显示文字,像这样 。
然而在Golang中你会需要 fmt 套件,关于「什么是套件」的说明你可以在文章下述了解 。
这很简单,而且两个语言的用法相差甚少,下面这是PHP:
只是Golang 稍微聒噪了一点,你必须在函式后面宣告他最后会回传什么资料型别 。
在PHP 中你要回传多个资料你就会用上阵列,然后将资料放入阵列里面,像这样 。
然而在Golang 中你可以不必用到一个阵列,函式可以一次回传多个值:
两个语言的撰写方式不尽相同 。
主要是PHP 的阵列能做太多事情了,所以在PHP 里面要储存什么用阵列就好了 。
在Golang里??没有这么万能的东西,首先要先了解Golang中有这些型态: array ,slice ,map ,interface ,
你他妈的我到底看了三洨,首先你要知道Golang是个强型别语言,意思是你的阵列中 只能有一种型态,什么意思?当你决定这个阵列是用来摆放字串资料的时候,你就只能在里面放字串 。没有数值、没有布林值,就像你没有女朋友一样 。
先撇开PHP 的「万能阵列」不管 , Golang 中的阵列既单纯却又十分脑残,在定义一个阵列的时候,你必须给他一个长度还有其内容存放的资料型态 , 你的阵列内容不一定要填满其长度,但是你的阵列内容不能超过你当初定义的长度 。
切片??这听起来也许很奇怪,但是你确实可以「切」他,让我们先谈谈「切片」比起「阵列」要好在哪里:「你不用定义其最大长度,而且你可以直接赋予值」,没了 。
我们刚才有提到你可以「切」他,记得吗?这有点像是PHP中的 array_slice(),但是Golang直接让Slice「内建」了这个用法,其用法是: slice[开始:结束]。
在PHP中倒是没有那么方便,在下列PHP范例中你需要不断地使用 array_slice()。
你可以把「映照」看成是一个有键名和键值的阵列,但是记?。骸改阈枰孪榷ㄒ迤浼⒓档淖柿闲吞梗?这仍限制你没办法在映照中存放多种不同型态的资料 。
在Golang里可就没这么简单了,你需要先用 make() 宣告 map。
也许你不喜欢「接口」这个词,但用「介面」我怕会误导大众,所以,是的,接下来我会继续称其为「接口」 。还记得你可以在PHP 的关联阵列里面存放任何型态的资料吗,像下面这样?
现在你有福了!正因为Golang中的 interface{} 可以接受任何内容,所以你可以把它拿来存放任何型态的资料 。
有时候你也许会有个不定值的变数 , 在PHP 里你可以直接将一个变数定义成字串、数值、空值、就像你那变心的女友一样随时都在变 。
在Golang中你必须给予变数一个指定的资料型别 , 不过还记得刚才提到的:「Golang中有个 interface{} 能够 存放任何事物 」吗( 虽然也不是真的任何事物啦?? )?
当我们程式中不需要继续使用到某个资源或是发生错误的时候 , 我们索性会将其关闭或是抛弃来节省资源开销,例如PHP 里的读取档案:
在Golang中,你可以使用 defer 来在函式结束的时候自动执行某些程式(其执行方向为反向) 。所以你就不需要在函式最后面结束最前面的资源 。
defer 可以被称为「推迟执行」,实际上就是在函式结束后会「反序」执行的东西,例如你按照了这样的顺序定义 defer : A-B-C-D,那么执行的顺序其实会是 D-C-B-A ,这用在程式结束时还蛮有用的,让我们看看Golang如何改善上述范例 。
这东西很邪恶,不是吗?又不是在写BASIC,不过也许有时候你会在PHP 用上呢 。但是拜托,不要 。
Golang中仅有 for 一种回圈但却能够达成 foreach 、 while 、 for 多种用法 。普通 for 回圈写法在两个语言中都十分相近 。
在Golang请记得:如果你的 i 先前并不存在,那么你就需要定义它,所以下面这个范例你会看见 i := 0。
在PHP里,foreach() 能够直接给你值和键名,用起来十分简单 。
Golang里面虽然仅有 for() 但却可以使用 range 达成和PHP一样的 foreach 方式 。
一个 while(条件) 回圈在PHP里面可以不断地执行区块中的程式,直到 条件 为 false 为止 。
在Golang里也有相同的做法,但仍是透过 for 回圈,请注意这个 for 回圈并没有任何的分号( ; ),而且一个没有条件的 for 回圈会一直被执行 。
PHP中有 do .. while() 回圈可以先做区块中的动作 。
在Golang中则没有相关函式,但是你可以透过一个无止尽的 for 回圈加上条件式来让他结束回圈 。
要是你真的希望完全符合像是PHP那样的设计方式,或者你可以在Golang中使用很邪恶的 goto。
在PHP中我们可以透过 date() 像这样取得目前的日期 。
在Golang就稍微有趣点了 , 因为Golang中并不是以 Y-m-d 这种格式做为定义,而是 1 、 2 、 3 , 这令你需要去翻阅文件,才能够知道 1 的定义是代表什么 。
俗话说:「爆炸就是艺术」,可爱的PHP用词真的很大胆 , 像是: explode() (爆炸)、 die() (死掉),回归正传,如果你想在PHP里面将字串切割成阵列,你可以这么做 。
简单的就让一个字串给「爆炸」了,那么Golang 呢?
对了,记得引用 strings 套件 。
这真的是很常用到的功能,就像物件一样有着键名和键值,在PHP 里面你很简单的就能靠阵列(Array)办到 。
真是太棒了,那么Golang呢?用 map 是差不多啦 。如果有必要的话,你可以稍微复习一下先前提到的「多资料储存型态-Stores」 。
你很常会在PHP里面用 isset() 检查一个索引是否存在,不是吗?
在Golang里面很简单的能够这样办到(仅适用于 map ) 。
指针(有时也做参照)是一个像是「变数别名」的方法,这种方法让你不用整天覆盖旧的变数,让我们假设 A = 1; B = A; 这个时候 B 会复制一份 A 且两者不相干,倘若你希望修改 B 的时候实际上也会修改到 A 的值,就会需要指针 。
指针比起复制一个变数,他会建立一个指向到某个变数的记忆体位置,这也就是为什么你改变指针,实际上是在改变某个变数 。
在Golang你需要用上 * 还有符号 。
有些时候你会回传一个阵列,这个阵列里面可能有资料还有错误代号,而你会用条件式判断错误代号是否非空值 。
在Golang中函式可以一次回传多个值 。为此,你不需要真的回传一个阵列 , 不过要注意的是你将会回传一个属于 error 资料型态的错误,所以你需要引用 errors 套件来帮助你做这件事 。
该注意的是Golang没有 try .. catch,因为 Golang推荐这种错误处理方式 ,你应该在每一次执行可能会发生错误的程式时就处理错误,而非后来用 try 到处包覆你的程式 。
在 if 条件式里宣告变数会让你只能在 if 内部使用这个变数,而不会污染到全域范围 。
也许你在PHP中更常用的会是 try .. catch ,在大型商业逻辑时经常看见如此地用法,实际上这种用法令人感到聒噪(因为你会需要一堆 try 区块):
Golang中并没有 try .. catch , 实际上Golang也 不鼓励这种行为 (Golang推荐逐一处理错误的方式),倘若你真想办倒像是捕捉异常这样的方式,你确实可以使用Golang中另类处理错误的方式(可以的话尽量避免使用这种方式): panic() ,recover() ,defer。
你可以把 panic() 当作是 throw (丢出错误),而这跟PHP的 exit() 有87%像 , 一但你执行了 panic() 你的程式就会宣告而终,但是别担心,因为程式结束的时候会呼叫 defer,所以我们接下来要在 defer 停止 panic()。
关于 defer 上述已经有提到了,他是一个反向执行的宣告,会在函式结束后被执行,当你呼叫了 panic() 结束程式的时候,也就会开始执行 defer , 所以我们要在 defer 内使用 recover() 让程式不再继续进行结束动作,这就像是捕捉异常 。
recover() 可以看作 catch (捕捉),我们要在 defer 里面用 recover() 解决 panic(),如此一来程式就会回归正常而不会被结束 。
还记得在PHP里要引用一堆档案的日子吗?到处可见的 require() 或是 include() ?到了Golang这些都不见了,取而代之的是「套件(Package)」 。现在让我们来用PHP解释一下 。
这看起来很正常对吧?但假设你有一堆档案 , 这马上就成了 Include Hell ,让我们看看Golang怎么透过「套件」解决这个问题 。
「 蛤???杀?。浚浚?」你可能如此地说道 。是的,main.go 中除了引用 fmt 套件( 为了要输出结果用的套件 )之外完全没有引用到 a.go。
「 蛤???杀?。浚浚浚浚浚?」你仿佛回到了几秒钟前的自己 。
既然没有引用其他档案,为什么 main.go 可以输出 foo 呢?注意到了吗,两者都是属于 main 套件 , 因此 他们共享同一个区域,所以接下来要介绍的是什么叫做「套件」 。
套件是每一个 .go 档案都必须声明在Golang原始码中最开端的东西 , 像下面这样:
这意味着目前的档案是属于 main 套件( 你也可以依照你的喜好命名 ),那么要如何让同个套件之间的函式沟通呢?
接着是Golang;注意!你不需要引用任何档案,因为下列两个档案同属一个套件 。
一个由「套件」所掌握的世界,比起PHP的 include() 和 require() 还要好太多了,对吗?
在Golang 中没有引用单独档案的方式,你必须汇入一整个套件,而且你要记?。骸敢欢慊闳肓?,你就一定要使用它」 , 像下面这样 。
假如你不希望使用你汇入的套件,你只是为了要触发那个套件的 main() 函式而引用的话??,那么你可以在前面加上一个底线( _ ) 。
如果你的套件出现了名称冲突,你可以在套件来源前面给他一个新的名称 。
现在你知道可以汇入套件了,那么什么是「汇出」?同个套件内的函式还有共享变数确实可以直接用,但那 并不表示可以给其他套件使用 ,其方法取决于 函式/变数的「开头大小写」。
是的 。Golang依照一个函式/变数的开头大小写决定这个东西是否可供「汇出」。
这用在区别函式的时候格外有用,因为小写开头的任何事物都是不供汇出的 , 反之,大写开头的任何事物都是用来汇出供其他套件使用的 。
一开始可能会觉得这是什么奇异的规定,但写久之后,你就能发现比起JavaScript和Python以「底线为开头的命名方式」还要来得更好;比起成天宣告 public 、 private 、 protected 还要来得更快 。
在Golang 中没有类别,但有所谓的「建构体(Struct)」和「接口(Interface)」 , 这就能够满足几乎所有的需求了,这也是为什么我认为Golang 很简洁却又很强大的原因 。
让我们先用PHP 建立一个类别,然后看看Golang 怎么解决这个问题 。
虽然Golang没有类别,但是「建构体(Struct)」就十分地堪用了,首先你要知道在Golang中「类别」的成员还有方法都是在「类别」外面所定义的 , 这跟PHP在类别内定义的方式有所不同,在Golang中还有一点,那就是他们没有 public 、 private 、 protected 的种类 。
在PHP中,当有一个类别被 new 的时候会自动执行该类别内的建构子( __construct() ),通常你会用这个来初始化一些类别内部的值 。
但是在Golang 里因为没有类别 , 也就没有建构子,不巧的是建构体本身也不带有建构子的特性 , 这个时候你只能自己在外部建立一个建构用函式 。
让我们假设你有两个类别 , 你会把其中一个类别传入到另一个类别里面使用,废话不多说!先上个PHP 范例(为了简短篇幅我省去了换行) 。
在Golang中你也有相同的用法,但是请记得:「 任何东西都是在「类别」外完成建构的 」 。
在PHP 中没有相关的范例,这部分会以刚才「嵌入」章节中的Golang 范例作为解说对象 。
你可以看见Golang在进行 Foo 嵌入 Bar 的时候,会自动将 Foo 的成员暴露在 Bar 底下,那么假设「双方之间有相同的成员名称」呢?
这个时候被嵌入的成员就会被「遮蔽」,下面是个实际范例,还有你如何解决遮蔽问题:
虽然都是呼叫同一个函式,但是这个函式可以针对不同的资料来源做出不同的举动,这就是多形 。你也能够把这看作是:「讯息的意义由接收者定义,而不是传送者」 。
目前PHP 中没有真正的「多形」,不过你仍可以做出同样的东西 。
嗯??那么Golang呢?实际上更简单而且更有条理了 , 在Golang中有 interface 可以帮忙完成这个工作 。
如果你对Interface还不熟悉,可以试着查看「 解释Golang中的Interface到底是什么 」文章 。
谢谢你看到这里,可惜这篇文章却没有说出Golang 最重要的卖点:「Goroutine」和「Channel」
go语言报表控件的介绍就聊到这里吧,感谢你花时间阅读本站内容,更多关于golang 表格、go语言报表控件的信息别忘了在本站进行查找喔 。
推荐阅读
- 西双版纳产品推广前景如何,西双版纳的目标市场
- 光哥用什么剪视频,短视频用什么打光
- mysql怎么脏读 mysql该怎么念
- ios1402什么时候更新,ios1421什么时候更新
- 停业物业如何营销,物业暂停
- php修改数据库配置 php怎么实现修改数据功能
- 特锐德特来电.net开发,特锐德特来电新能源有限公司
- java代码注解,java注解用法
- bt下载器下载,bt下载器好用吗