人工智能基础架构市场规模20.9亿美元,同比增长58.7%

人工智能基础架构市场规模20.9亿美元,同比增长58.7%

国际数据公司(IDC)发布了最新的《人工智能基础架构市场(2019下半年)跟踪》报告。报告中显示,2019年人工智能基础架构市场规模达到20.9亿美元,同比增长58.7%。其中GPU服务器占据96.1%的市场份额。IDC预测,到2024年中国GPU服务器市场规模将达到64亿美元。

640.png

从厂商角度看,浪潮、华为和曙光依然稳居前三位,占据了74%以上的市场份额。

从行业角度看,互联网依然为主要采购行业,占有近50%的市场份额,并且最终用户也不仅仅局限于BAT这类大型互联网公司;服务和政府行业次之,分别占有18.4%和16.9%市场份额。其中服务、教育、金融和制造四个行业在2019年中出现了大幅度上涨。

从服务器配置的角度看,可搭载8片加速卡的服务器更为主流,占有40%以上的市场份额;2路服务器依然是最终用户的首选,占有近80%的市场份额。

从工作负载角度看,用于推理的服务器在2019年占有40%以上的市场份额。IDC预测,到2021年,用于推理的服务器将超过用于训练的服务器,达到51.3%的市场占比。
IDC 中国 AI基础架构市场分析师杜昀龙认为:2019年由于中美贸易战的影响,给AI基础架构市场的发展带来了一定的影响,与此同时,也推动了一些国产芯片和服务器厂商的发展;目前GPU加速服务器依然占据主导地位,但是FPGA和ASIC加速技术也开始在政府、教育等行业开始有所应用。另外由于新冠疫情的影响,让很多传统行业更深刻的认识到人工智能、物联网、5G等技术的重要性,促使各企业加大对于IT基础架构的投资,这将给各厂商带来更多的发展机会——构建完整的生态和解决方案将有助于在市场竞争中脱颖而出。(完)

贺力平谈全球经济衰退:中国一季度负增长与稳定器作用不矛盾

专家简介

贺力平:著名经济学家、中国经济50人论坛原成员、中国世界经济学会副会长、北京师范大学国际金融研究所原所长,现为北京师范大学经济与工商管理学院教授。

大洋网讯 目前,新冠肺炎疫情在全球200多个国家和地区蔓延扩散,全球经济出现衰退已成定局。根据IMF最新预测,受此次疫情影响,全球将遭遇上世纪30年代大萧条以来最严重的经济衰退。在各国政府奋力战“疫”和“经济求生”的过程中,也出现了一些“逆全球化”声音和倾向。中国如何在这场经济衰退中化危为机?如何通过“六稳”和“六保”的具体举措,稳住经济基本盘,确保脱贫攻坚的战略任务如期完成?广州日报全媒体记者专访了著名经济学家、中国经济50人论坛原成员、中国世界经济学会副会长贺力平教授,请他为我们释疑解惑。

各国实体经济受疫情“轮番”抑制

记者:您怎么看这一轮全球经济衰退?预计可能持续多长时间?

贺力平:这一轮全球经济衰退与以往各次金融危机或经济危机不同的是,实体经济首当其冲受到冲击,各大板块之间呈现此起彼伏的接力局面,下降深度也将超过以前。

实体经济方面,主要是各国针对疫情纷纷出台限制人员流动的措施,使得消费需求在隔离期间的急剧收缩。这种收缩的程度超过以往任何一次经济周期水平。已有疫情最严重的地区发布了1季度宏观经济指标,其中社会消费品零售总额同比下降44.9%。这意味着,在特殊时期,人们的消费需求几乎萎缩到正常时期的一半。

我国疫情最严重的时期是2月和3月。亚洲部分国家遭受疫情冲击是3月下旬到4月中旬。欧美国家大多数是4月。亚非拉国家中不少是在4月中旬后才见疫情曲线抬头上升。显然,各国各地区的疫情曲线走势在时间上有一定差别,这就给各国经济尤其是国际经贸往来带来“轮番”抑制效应。当一地的疫情接近结束时,本地管制措施开始松懈、经济生活走向恢复时,其他地区却又陷入了封闭和管制状态,两地之间的贸易和人员往来关系就不得不继续处于“冻结”局面。

5月到6月是世界疫情形势的重要时间转折点。那时,世界主要经济体和各人口大国的疫情预计都将趋于缓和,经济生活将开始全面恢复,但不会在短时间内立即恢复到疫情前水平。

粗略地说,全球范围内疫情直接冲击时间长度约为3~5个月。在这之后,由于各国采取的基本“退出”策略是渐进型,即逐步和局部性放松对人员外出和流动的管制,经济复苏在可见未来也将是一个渐进类型。

记者:4月中旬,IMF(国际货币基金组织)发布《世界经济展望报告》预计,2020年全球经济将萎缩3%,为上世纪30年代大萧条以来最糟糕的经济衰退。主要经济体中仅中国和印度有望保持增长。日前,IMF总裁格奥尔基耶娃接受采访称,因疫情冲击全球经济前景已进一步恶化,IMF还将向下修正此前预测的全球经济萎缩3%的数据。您怎样看这样的预测?

贺力平:国际货币基金组织(IMF)对世界各国经济增长的预测主要基于他们对各国经济的脆弱性或坚韧性而做出判断。发达经济体和一些发展中经济体在疫情冲击下,表现出若干脆弱性,主要是消费需求继续大幅度收缩,跨境人员流动中止,对外贸易活动停摆等。

当然,在疫情冲击下,不是说中国经济没有一点脆弱性。IMF对中国经济相对乐观的预测在于他们对中国经济政策及其效力的考虑。他们知道,中国政府为保经济增长将“不遗余力”地采取积极措施,而且,这些政策将在相对短的时间内发挥效力。他们应该是把这些因素也考虑进去了。我们看到,中国第一季度GDP同比下降6.8%,这的确归因于短时间内的意外冲击效应。但是,大幅度的季度性回落与中国之于全球经济衰退的“稳定器”作用并不矛盾。原因有二:一是这个回落持续时间较短,二是由于中国经济结构方面的原因,在疫情期间和复苏进程中,中国进口的表现都好于出口。可以预计,在复苏进程中,中国进口业绩将继续好于出口,并对全球需求做出贡献。

“逆全球化”倾向受政治因素驱动

记者:近日,美国白宫国家经济委员会主任劳伦斯·库德洛呼吁,为愿意迁离中国的美国企业支付搬家成本;在日本政府制定的抗疫振兴计划中,也有资助日本企业撤离中国的内容。这意味着全球产业链今后会有大幅调整,会不会形成逆全球化趋势?

贺力平:的确,最近一段时间国际舆论场关于全球化未来走向有许多议论。客观地说,关于全球化未来走势的不确定性问题,在疫情发生前就出现了。我个人认为,要区分涉及全球化未来走势决定过程中两类因素。一是经济因素,二是政治因素。

在经济因素层面,全球化在未来仍有发展壮大的巨大空间。从根本上说,经济全球化是各个生产要素在全球各地的流动和重新配置,而这种流动和重新配置的基本决定因素是各国经济发展的相对不平衡。显然,在未来,各国经济将继续处于不平衡的状态。因此,全球化没有走向完结的任何经济理由。

在政治因素层面,情况则有些复杂。疫情期间,不少国家都在倡议“加强自力更生”,减少对外部的依赖。如果这些说法真的上升为实际政策,那么,逆全球化就可能出现。但是,也要看到,反对全球化的呼声在各国社会素来就有、从未停过,这种声音要上升成为政治主流的可能性其实是不高的。这次疫情让逆全球化的声音“音量”有所升高,意味着全球化进程在未来将较多地受到政治因素的影响和干扰。但是,只要世界主要大国坚持支持全球化的政治担当,人们依然可以继续期待全球化发展。

记者:相关国家有关举动对中国会造成什么样的影响?

贺力平:上面提到的一些国家官方政策动向值得高度关注。中国拥有的产业链优势,是在过去多年改革开放格局中形成的,主要基于中国劳动成本优势、基础设施条件便利和国内外企业间的良性互动关系及在此背景下国内企业的技术不断进步,等等。现在,如果许多国外企业因各种原因离开中国内地,这不利于国内企业技术进步,不利于中外企业间的良性互动,当然也不利于中国继续保持产业链优势。

但从实际情况看,仍有一些美资企业继续在中国大量投资,开工上马大型新项目。

中国经济启示

从人民需要出发 “六保”就能实现

记者:中央最近提出“六保”战略思路,与“六稳”形成补充和呼应。您觉得现在提出“六保”的现实针对性何在?如何才能做到“六保”落到实处、取得成效?

贺力平:“六保”是针对疫情后期国内经济形势提出的任务,针对性很强,但不仅具有当前意义,也有长远意义。

疫情和抗疫措施使社会经济生活在很大程度上一度处于“停摆”状态,并由此引发一系列社会问题。比如,就就业而言,中国城镇就业80%以上在民营企业,其中许多是中小企业,以服务业居多。这些企业受到疫情和抗疫措施的严重影响,不少关门歇业,员工处于失业待业或半就业状态。这些员工收入减少,家庭生活也因此受到影响。可以说,保就业关系民生问题,关系市场主体问题,关系基层运转问题。

再比如,粮食问题。粮食安全较为复杂,既与国内农业生产有关,又与国际经贸形势有关。中国经济过去几十年之所以能快速增长,一定程度上得益于较好地利用国内国外积极因素解决了计划经济体制下的诸多问题,粮食供给就是其中之一。如果发生粮食安全问题,中国经济的良好前景也会受到不利影响。因此必须采取有力措施。

“六保”牵涉多个领域,需要许多具体措施。从根本上说,“六保”要求政府和人民具备基本经济信心,要求改革开放的政策方针保持稳定,防止在局部环节、局部地区发生供给短缺问题。政策为人民服务,政策从人民的基本需要出发,“六保”就一定能实现。

中国为全球减贫提供新成果

记者:今年可谓是中国脱贫攻坚与新冠肺炎疫情“遭遇战”,如果将中国脱贫攻坚放在全球减贫大视野中考量,中国应该怎样在这种特殊背景下对冲、化解危机,对全球减贫事业做出中国贡献、提供中国经验?

贺力平:从全球角度看,疫情的意外发生和扩散,不仅会妨碍脱贫事业的进展,而且可能让贫困发生率回升。IMF4月中旬预测2020年全球经济将衰退3%。如果这个预测变成现实,世界多个国家——包括发达经济体和发展中国家在内——都会出现贫穷人口的增多。

2020年是中国脱贫攻坚战的“最后一年”,按照既定规划,全国主要贫困区域的贫困人口都要在年底如期脱贫。疫情给完成这项任务带来严峻挑战。正是在这个背景下,中央从政策上加大了对脱贫攻坚工作的重视,并组织协调社会资源对脱贫相关事项给予积极支持。

通过疫情期间的努力,中国对全球减贫事业的新贡献将不仅表现在数字指标上,即中国数百万贫困人口摆脱了贫困,而且还会体现在对脱贫经验的总结概括上。减贫事业需要更强的支持力度,需要社会高度关注,需要在改革开放的大方针下积极利用社会各方面资源给贫困家庭和贫困人口提供可持续的帮扶和就业出路。这些新成果也是国际社会迫切需要的。

统筹/广州日报全媒体记者汤新颖、王晨阳

文/广州日报全媒体记者徐锋、谭敏

2020年第一季度手机安全状况报告出炉 五大关键词揭秘手机安全风险

近日,360正式发布了《2020年第一季度中国手机安全状况报告》(以下简称报告),从恶意程序、钓鱼网站、骚扰电话、垃圾短信、网络诈骗等关键词对2020年第一季度手机安全状况进行了系统的梳理,提醒公众注意防范网络诈骗,同时对移动安全重点趋势进行了分析。

在万物互联时代,每一台智能移动设备都在实时产生联网数据,个人隐私受到威胁。由于年初受到新冠肺炎疫情影响,在线教育、网络支付等大部分网络应用的用户规模呈现较大幅度增长的同时,也给不法分子提供了利用疫情话题传播不法内容及实施诈骗的可乘之机。

恶意程序中资费消耗占比最多 钓鱼网站层出不穷

恶意程序是未明确提示用户或未经用户许可的情况下,在用户计算机或其他终端上安装运行侵犯用户合法权益的应用程序。据报告显示,2020 年第一季度,360 安全大脑共截获移动端新增恶意程序样本约 39.2 万个,恶意程序类型以资费消耗类为主,并呈现持续直线涨幅态势,可见移动端恶意程序“攻坚战”将再一次打响。

2020年第一季度手机安全状况报告出炉 五大关键词揭秘手机安全风险

从地区上来看,遭受手机恶意程序攻击最多的地区为河南省,其次为山东、广东、江苏、河北,此外四川、安徽、浙江的恶意程序拦截量也名列前茅。

2020年第一季度手机安全状况报告出炉 五大关键词揭秘手机安全风险

钓鱼网站是不法分子利用各种手段,仿冒真实网站的URL地址以及页面内容,以此来骗取用户银行或信用卡账号、密码等私人资料。手机如果误入钓鱼网站,除了可能导致重要个人信息的泄露外,还有可能使手机误装恶意程序,导致更大的损失。

综合PC端与手机端的数据看,2020年第一季度,360安全大脑共为全国用户拦截钓鱼网站攻击约206.4亿次。其中,移动端拦截钓鱼网站类型主要为境外彩票,占比高达 71.9%;其次为假药(11.5%)、虚假购物(7.9%)、虚假中奖(3.2%)、金融证券(2.5%)、网站被黑(2.0%)等。

2020年第一季度手机安全状况报告出炉 五大关键词揭秘手机安全风险

骚扰电话狼奔豕突 垃圾短信成快速上升趋势

骚扰电话、垃圾短信一直是骚扰手机用户的社会毒瘤。2020年第一季度,360安全大脑收获用户主动标记各类骚扰号码(包括 360 手机卫士自动检出的响一声电话)约 400.8 万个。

从骚扰电话标记类型中看,响一声以 67.3%的比例位居首位;其次为广告推销(9.9%)、骚扰电话(7.2%)、疑似欺诈(5.9%)、房产中介(3.9%)、保险理财(3.6%)、招聘猎头(1.9%)与诈骗电话(0.2%)。

2020年第一季度手机安全状况报告出炉 五大关键词揭秘手机安全风险

移动短信从日常沟通发展至身份验证、支付校验的重要方式,出现了质的转变同时也成为传播不法信息的载体之一。

2020年第一季度,在 360 安全大脑的支撑下,360 手机卫士共为全国用户拦截各类垃圾短信约 34.4 亿条,垃圾短信数量与2019年同期相比整体呈现快速上升的趋势。垃圾短信的类型分布中广告推销短信最多,占比为 92.2%;其次为诈骗短信和违法短信。

2020年第一季度手机安全状况报告出炉 五大关键词揭秘手机安全风险

网络诈骗风起云涌 受骗者人均损失8218 元

报告显示,2020 年第一季度 360 手机先赔共接到手机诈骗举报856 起,涉案总金额高达 340.2 万元,人均损失 8218 元。

在所有诈骗申请中,金融理财(30.2%)占比最高,其次是虚假兼职(15.9%)、赌博博彩(14.3%)、虚假购物(8.7%)、网游交易(8.7%)等。从涉案总金额来看,同样是金融理财类诈骗总金额最高。

2020年第一季度手机安全状况报告出炉 五大关键词揭秘手机安全风险

此外,报告还对2020年第一季度典型诈骗案例和热门安全事件进行了盘点分析,并附上了360安全专家的防骗建议。

CoreDNS解析异常记录

CoreDNS解析异常记录 

异常情况:集群是用kubespray部署的4个worknode,coredns默认部署2个deployment。今天发现部署了coredns的node上的pod正常解析内部域名,而另外2个未运行coredns的node却无法解析。

 配置文件:

 下图中我们看到coredns2个pod分别在node1与node2上,只要分配到这2节点上的deployment都可以正常解析。

其他节点无法解析:

 处理过程:

正常来说所有的pod都是通过coredns来进行集群内域名解析的,我也搞不清楚为啥其他两个node没有跑coredns则就无法解析后面再研究。所以我临时的解决方法是扩容coredns让每个node都跑。

1、修改 ConfigMap 中的 dns-autoscaler(coredns自动扩容保证高可用)

kubectl edit configmap dns-autoscaler --namespace=kube-system

2、修改key:linear

  • coresPerReplica: 按照核心数目来计算副本集(replicas = cores / coresPerReplica)
  • nodesPerReplica:按照节点数目来计算副本集(replicas = nodes / nodesPerReplica)
  • min:最小副本数(默认为2,我先有4个节点改为4)
  • max:最大副本数
  • preventSinglePointFailure:防止单点故障

公式

replicas = max( ceil( cores × 1/coresPerReplica ) , ceil( nodes × 1/nodesPerReplica ) )

 

 

 

[Abp vNext 入坑分享] – 2.简化项目结构

一、简要说明

本篇文章根据我自己的需要对项目结果进行简化,让项目结构更符合我自己的要求,同时让项目跑起来。仅供参考

二、具体步骤

2.1卸载掉对我来说目前使用不上的项目,identityserver,mongodb,httpapi.client,以及对应的test项目

 

 

 

 

2.2删除掉下图红框中的包与类文件,由于我后期会创建一个独立的项目来做migrations,所以不需要在HttpApi.Host里面直接使用EF相关的操作,而且个人认为这样会模糊掉abpvnext的层级,混乱了层级的职责。

 

 

 

上图的报错都是由于我删除了相关的包引起的,因此跳转到相关文件中,把所有的报错行,全部删除。同时由于我没有启用redis的服务,所以要把下图的redis服务也先行注释掉。

2.3将启动模式修改成:如下图,同时把原来输出日志到文件的模式修改成:console(),以便在控制台时能很直观的看到Log。调试项目,则可以启动成功了。

 

 

 

 

 

2.4在src下面增加DbMigrations类库,注意:此处只能选择.netcore类型的类库,不能是只属于netstandard这样会导致无法使用。创建后的样子如下,这样就可以使用此项目进行migration操作了,且不会影响主线代码。

 

 

 

1.关于DbM_LearnDbContext这个类,如果你能保证整个项目的所有开发人员都只能使用codefirst进行开发的话,可以直接继承主的LearnDbContext,这样LearnDbContext的所有DbSet都会得到继承,则不需要再重复写dbset。

2.若是codefirstdbfirst混用的情况,则不要继承

3.单纯dbfirst的话,此项目可以去掉

Unity ML-agents 一、初次尝试

前言

曾在高二寒假的时候,跟表哥在外面玩,当时他问我有没有想过以后要做什么,我愣了一下,回答不上来。是的,从没想过以后要做什么,只是一直在完成学校、老师安排的任务,于是那之后半年,我一直在思考,大学要学什么。在大二下期中之后,我觉得自己还是对游戏更感兴趣,便想到以后想做游戏。于是,高考后填志愿,填的都是计算机专业。在大一的时候,自学了一段时间的 Unity,到大二在实验室接触强化学习之后,就想着用 RL 来做游戏 AI,但后来一直在做数据挖掘相关的内容,基本上以参加比赛为主。直到去年参加上海的谷歌开发者节,了解到 ML-agents 之后,就十分的想尝试。

然后由于疫情,直到现在还在家里咸鱼,前段时间一边咸鱼一边投简历,奈何自己水平太低又偏偏想投算法岗,直到现在也没有几次面试机会 orz。最近就想继续当年未完成的 Unity 的学习,顺便学习 ML-agents,回到原点,重新出发。

初试 ML-agents

环境配置

既然要尝试,肯定免不了环境配置
目前我的环境为:

  1. Win10
  2. Tensorflow 2.0
  3. ML-agents 0.15.0
  4. Unity 2019.3.1f1
    关于 Tensorflow 2.0 的安装,参考我之前的博客,Unity 的安装,推荐先下载 Unity Hub,通过 Unity Hub 可以管理不同版本的 Unity,下载戳这里

ML-agents 的安装有两种方式
一是直接 pip

pip install mlagents

二是从官方 github 中 clone 整个项目,然后 cd 到目录中

pip install -e ./ml-agents-envs
pip install -e ./ml-agents

到这里,环境配置就算完成了

跑个 Demo 先吧

在 Unity Hub 中导入刚刚从 github 上 clone 的项目

选择 Unity 版本之后打开

然后打开 3DBall 这个场景

点击运行的话可以直接看到效果

接着,开始尝试自己训练,打开命令行,进入到之前 clone 下来的项目目录中,并在目录中创建一个名为 summaries 的文件夹

然后输入

mlagents-learn config/trainer_config.yaml --run-id=test --train

在出现图标之后,切换到 Unity 运行项目,就可以看见开始训练了

可以看出来一开的效果是很差的,完全控制不好,这次训练大概训练 40w+ 步,到后面就很稳了

注:项目目录中尽量不要出现中文,下午在尝试的时候一直报错,后来更改目录之后发现成功了,不清楚是不是路径中有中文的原因
报错内容

 "The Unity environment took too long to respond. Make sure that :\n"
mlagents_envs.exception.UnityTimeOutException: The Unity environment took too long to respond. Make sure that :
         The environment does not need user interaction to launch
         The Agents are linked to the appropriate Brains
         The environment and the Python interface have compatible versions.

训练完成后,我们可以在 models 目录下看到刚刚训练好的模型,重命名一下,然后把模型拖到 TFModel 目录中

接着打开 prefabs 中的 3DBall,点击其中的 agent,然后将 Behavior 改成我们刚刚拖到 TFModel 目录中的模型

点击运行,发现控制的十分稳定,跟一开始差不多。至此,初试完毕。

小节

这里我们安装配置了 ML-agnets 的相关环境,并运行了个 Demo 来熟悉了遍流程,后面将开始尝试自己搭建环境,训练 AI,也不知道能不能捣鼓出来,23333。

kafka消息分区机制原理

背景

kafka如何支撑海量消息的集中写入?

答案就是消息分区。

核心思想是:负载均衡,采用合适的分区策略把消息写到不同的broker上的分区中;

其它的产品中有类似的思想。

比如monogodb, es 里面叫做 shard;   hbase叫region,  cassdra叫vnode;

消息的三层结构

如下图:

即  topic -> partition -> message ;

topic是逻辑上的消息容器;

partition实际承载消息,分布在不同的kafka的broke上;

message即具体的消息。

分区策略

round-robin轮询

消息按照分区挨个的写。

randomness随机分区

随机的找一个分区写入,代码如下:

List<PartitionInfo> partitions = cluster.partitionsForTopic(topic);
return ThreadLocalRandom.current().nextInt(partitions.size());

key

相同的key的消息写到固定的分区中

自定义分区

必须完成两步:

1,自定义分区实现类,需要实现org.apache.kafka.clients.producer.Partitioner接口。

主要是实现下面的方法:

int partition(String topic, Object key, byte[] keyBytes, 
              Object value, byte[] valueBytes, Cluster cluster);

比如按照区域分区。

List<PartitionInfo> partitions = cluster.partitionsForTopic(topic);
return partitions.stream().filter(p -> isSouth(p.leader().host()))
    .map(PartitionInfo::partition).findAny().get();

2,显示配置生产者端的参数partitioner.class为具体的类

系统默认:如果消息有key,按照key分区策略,否则按照轮询策略。

小结

kafka的分区实现消息的高吞吐量的主要依托,主要是实现了写的负载均衡。可以指定各种负载均衡算法。
负载均衡算法非常重要,需要极力避免消息分区不均的情况,可能给消费者带来性能瓶颈。

小结如下:

原创不易,点赞关注支持一下吧!转载请注明出处,让我们互通有无,共同进步,欢迎沟通交流。
我会持续分享Java软件编程知识和程序员发展职业之路,欢迎关注,我整理了这些年编程学习的各种资源,关注公众号‘李福春持续输出’,发送’学习资料’分享给你!

每个优秀程序员都应遵循的代码原则和规范

本文由葡萄城技术团队原创并首发

转载请注明出处:葡萄城官网,葡萄城为开发者提供专业的开发工具、解决方案和服务,赋能开发者。

 

什么是优秀的程序员?

首先我们会先提出这个问题,如果你向10个人问这个问题,尽管可能答案不同,但是少有一点应该是一致的。而对我个人而言,一个优秀的程序员应该是一个能够充分理解需求,并能提出可行性解决方案通过团队协作向最终用户展示成果。而说到团队协作,就涉及到代码的可维护性,那么你该如何管理庞大的代码库?如果放任团队成员提交随意的代码,那么在项目中无论在bug修复还是新增功能,都将很难完成。

如果想要实现可维护这个目标,那么团队中的每个成员都应该保证提交整洁且可维护的代码。那么您应该让你的团队成员遵守一定的编码原则。遵守这些原则,可以使你和其他人的协作变得更容易。所以团队成员应该遵循什么样的规则呢?

童子军原则

童子军是美国社会针对未成年人的一种教育实践制度,加入童子军的小朋友都要学习并遵守一些规则,然后获得各种各样的勋章。其中一条规则是离开宿营地前进行清扫活动的原则,简洁明了:

Leave the campground cleaner than you found it.

假设某个小朋友来到某个宿营地,不幸发现地上有两处垃圾,然后他自己在接下来的日常活动中也制造了一处垃圾。那么当他离开时,不仅要清理掉自己的垃圾,还有处理早先小朋友留下的两处垃圾。而不是去寻找是谁丢的。应把注意力放在为下一个露营者创造更好的环境。

这个原则放到软件生产中则意味着让check in比check out时更整洁,至少不要让代码变得更糟糕。

(图片来源于网络)

避免重复

尽量在项目的开发过程中减少产出重复的代码、方法和类,多数的设计模式根本目的是为了减少代码重复,尽可能将重复使用的代码抽象封装,是提高代码的可重用性和可维护性的最佳方式之一。

功能独立

这里功能独立的意思是指,函数或方法尽可能简单,功能尽可能独立。

换句话来讲就是,一个方法最好只做一件事,如果你觉得你的代码过于复杂,该怎么做?抽方法。

初级程序员最常犯的错误就是在一个方法中包含了很多种要做的工作,这可能会在软件的生命周期带来灾难。

简单易懂的代码比“聪明“的代码更好

程序员作为社会中最聪明的群体之一,往往在写代码时也会产出一些炫技的代码块,这部分代码块过段时间再去看,就像谜一样存在于程序中,虽然很简洁,但并不易读。

例如:有些人在程序中喜欢使用三目运算而非if-else,虽然本身使用三目运算符没有问题,但存在嵌套情况时,那么对于后面的维护者就是一场噩梦,例如如下代码:

(A>B?(A>C?A:C):(B>C?B:C))

其实上面的代码等同于,显然下面的格式更易懂

if(A>B){
    (A>C?A:C)
}else{
    (B>C?B:C)
}

迪米特法则

迪米特法则是1987年秋天由lan holland在美国东北大学一个叫做迪米特的项目设计提出的,它要求一个对象应该对其他对象有最少的了解,所以迪米特法则又叫做最少知识原则。它的意义旨在降低类和类之间的耦合,避免发生由于耦合度过大造成的因为一个类发生变化,而对另一个类造成影响。

YAGNI

YAGNI原则是指在开发时只需要将应用程序必需的功能包含进来,而不要试图添加任何其他你认为可能需要的功能。开发过程中为了应对将来可能的提出的需求,提前开发一些功能进去,我们通常会花不少时间成本在这些过度设计的功能开发上,但可能未来的两三年内这个设计根本没有用到。应把更多的精力花在更重要的功能开发上,适度假设未来需求的规划,加速后期功能迭代和代码维护。

总结

虽然上面提了很多原则和规范,但这些规范需要在长期在工作中的实践才能有更深的理解的。希望您能从本文中了解一些基础,最后,希望大家都能写出优美、规范的代码。

 

Golang 性能测试 (3) 跟踪刨析 golang trace

简介

对于绝大部分服务,跟踪刨析是用不到的。但是如果遇到了下面问题,可以不妨一试:

  • 怀疑哪个协程慢了
  • 系统调用有问题
  • 协程调度问题 (chan 交互、互斥锁、信号量等)
  • 怀疑是 gc (Garbage-Collect) 影响了服务性能
  • 网络阻塞
  • 等等

坦白的讲,通过跟踪刨析可以看到每个协程在某一时刻在干什么。

做跟踪刨析,首先需要获取trace 数据。可以通过代码中插入trace, 或者上节提到的通过pprof 下载即可。

Example

Code

下面通过代码直接插入的方式来获取trace. 内容会涉及到网络请求,涉及协程异步执行等。

package main

import (
	"io/ioutil"
	"math/rand"
	"net/http"
	"os"
	"runtime/trace"
	"strconv"
	"sync"
	"time"
)


var wg sync.WaitGroup
var httpClient = &http.Client{Timeout: 30 * time.Second}

func SleepSomeTime() time.Duration{
	return time.Microsecond * time.Duration(rand.Int()%1000)
}

func create(readChan chan int) {
	defer wg.Done()
	for i := 0; i < 500; i++ {
		readChan <- getBodySize()
		SleepSomeTime()
	}
	close(readChan)
}

func convert(readChan chan int, output chan string) {
	defer wg.Done()
	for readChan := range readChan {
		output <- strconv.Itoa(readChan)
		SleepSomeTime()
	}
	close(output)
}

func outputStr(output chan string) {
	defer wg.Done()
	for _ = range output {
		// do nothing
		SleepSomeTime()
	}
}

// 获取taobao 页面大小
func getBodySize() int {
	resp, _ := httpClient.Get("https://taobao.com")
	res, _ := ioutil.ReadAll(resp.Body)
	_ = resp.Body.Close()
	return len(res)
}

func run() {
	readChan, output := make(chan int), make(chan string)
	wg.Add(3)
	go create(readChan)
	go convert(readChan, output)
	go outputStr(output)
}

func main() {
	f, _ := os.Create("trace.out")
	defer f.Close()
	_ = trace.Start(f)
	defer trace.Stop()
	run()
	wg.Wait()
}

编译,并执行,然后启动trace;

[~/blog]$ go build trace_example.go 
[~/blog]$ ./trace_example
[~/blog]$ go tool trace -http=":8000" trace_example trace.out 
2020/04/15 17:34:48 Parsing trace...
2020/04/15 17:34:50 Splitting trace...
2020/04/15 17:34:51 Opening browser. Trace viewer is listening on http://0.0.0.0:8000

然后打开浏览器,访问8000 端口即可。

Trace 功能

其中:
View trace:查看跟踪 (按照时间分段,上面我的例子时间比较短,所以没有分段)
Goroutine analysis:Goroutine 分析
Network blocking profile:网络阻塞概况
Synchronization blocking profile:同步阻塞概况
Syscall blocking profile:系统调用阻塞概况
Scheduler latency profile:调度延迟概况
User defined tasks:用户自定义任务
User defined regions:用户自定义区域
Minimum mutator utilization:最低 Mutator 利用率 (主要是GC 的评价标准, 暂时没搞懂)

goroutine 调度分析

下图包含了两种事件:

  1. 网络相关 main.create 触发网络写的协程,网络写操作的协程 writeLoop,然后等待网络返回。
  2. GC 相关操作

下面是web请求到数据,从epoll 中触发,然后readLoop协程响应,直接触发main.create 的协程得到执行。

当然我们也可以筛选协程做具体分析,从 Goroutine analysis 进入,选择具体的协程进行分析:

我们选择对 main.create 的协程做分析(这个协程略复杂,可以分析的东西比较多)

可以从图中看出,network 唤醒 readLoop 协程,进而readLoop 又通知了main.create 协程。

当然,我们也可以选择 main.convert 协程。可以看出协程被main.create 唤醒了(由于给chan 提供了数据)

除了可以分析goroutine 调度之外,还可以做网络阻塞分析,异步阻塞分析,系统调度阻塞分析,协程调度阻塞分析(下图)

自定义 Task 和 Region

当然,还可以指定task 和 Region 做分析,下面是官方举的例子:

//filepath:  src/runtime/trace/trace.go
ctx, task := trace.NewTask(ctx, "makeCappuccino")
trace.Log(ctx, "orderID", orderID)

milk := make(chan bool)
espresso := make(chan bool)

go func() {
        trace.WithRegion(ctx, "steamMilk", steamMilk)
        milk <- true
}()
go func() {
        trace.WithRegion(ctx, "extractCoffee", extractCoffee)
        espresso <- true
}()
go func() {
        defer task.End() // When assemble is done, the order is complete.
        <-espresso
        <-milk
        trace.WithRegion(ctx, "mixMilkCoffee", mixMilkCoffee)
}()

MMU 图

除此之外,还提供了Minimum Mutator Utilization 图 (mmu 图 )

mmu 图,数轴是服务可以占用cpu的百分比 (其他时间为gc操作)

从图中可以看出,在2ms之后,可利用的cpu逐步上升,直到接近100%.所以gc 毫无压力。

重点提醒

  1. 必须用chrome,并且高版本不行。我使用的是76.
  2. trace 的文件都比较大,几分钟可能上百兆,所以网络一定要好,或者使用本机做验证。
  3. 造作是 w 放大, s 缩小, a 左移, d 右移
  4. gc 的mmu 图解释 (备注下,还没有来得及看)https://www.cs.cmu.edu/~guyb/papers/gc2001.pdf

臭名昭著的手机验证码功能是如何实现的

前言

现在基本上各种手机APP注册都会用到手机验证码,包括一些PC端网站也会使用手机号作为唯一标识验证!

恰巧,小明的老板,让其开发一个用户注册的功能,并且强制用户注册绑定手机,美其名曰为了提升安全性,呵呵哒,就是为了多撸一点用户信息。

案例

一般来说,发送手机验证码不能过于频繁,前端发送按钮点击后一般会有一个60秒倒计时的功能。也就是说,如果用户点击发送一直没有收到验证码,只能60秒之后才可以进行重发。

那么问题来了,如果用户绕过前端,直接向后台API发送短信请求,然后写个无限循环脚本,相信不久你的短信账户就会发来预警提示短信(一般来说大的短信商都有预警设置功能)。

其实很简单,你只需要F12,查看发送请求就可以查找出后台请求地址,然后你可以在控制台输入相关JS代码,执行个十万遍,是不是很爽?

这里以七牛云为测试案例,打开注册页面,F12进入调试模式,输入手机号,手动点击发送,获取其短信发送后台请求地址。下面是七牛云的一个短信发送请求,撸主测试了一下,显然没有达到撸主的预期,毕竟是大厂,防御措施还是做的很牛逼的。

以下是JS脚本,复制粘贴到控制台回车就可以执行:

var data = {"operation":1,"is_voice":false,"mobile_number":"17762018888","captcha_type":2};
for (var i = 0; i < 10; i++) {
    $.ajax({
        type: 'POST',
		contentType: 'application/json;charset=UTF-8',
        data:JSON.stringify(data),
        url: 'https://portal.qiniu.com/api/gaea/verification/sms/send',
        success: function(data) {
            console.log(data)
        }
    });
}

控制台返回以下信息,前三次请求成功,后面的就出现了验证码校验并进行了限流操作。

{"code":200,"message":""}
{"code":200,"message":""}
{"code":200,"message":""}
{"code": 7209,"message":"captcha required"}
{"code": 7209,"message":"captcha required"}
{"code": 429,"message":"too many requests"}
{"code": 429,"message":"too many requests"}
{"code": 429,"message":"too many requests"}
{"code": 429,"message":"too many requests"}
{"code": 7209,"message":"captcha required"}

撸主尝试刷新页面,随便输了一个手机号,再次点击发送,提示用户输入验证码,显然是加强了防备,触发了恶意请求认证拦截机制。

安全机制

对于开发者来说,他们不仅要考虑用户正常获取验证码的体验还要考虑短信接口的安全性,撸主总结了以下几点,希望对大家有所帮助。

  • 后台请求限流,对单位时间内发送频率做限制。
  • 验证码机制,切记不要一开始就限制验证码,体验及其不友好,触发限流以后开启验证码校验。
  • 监控日发送短信数量,触发一定的阈值做相应的处理,根据实际业务需求。
  • 验证码存储一定要保证key为手机号,切记不要以其它标识作为key,比如sessionId
  • 一定要设置验证码失效时间,比如五分钟,或者更短。
  • 验证码尽量保证短小精悍,四到六位即可。
  • 如果后台不做限制,切记前台一定要做个倒计时的限制,至少过滤一部分小白用户。

代码案例

给小伙伴分享一个简单的验证码生成、存储、失效代码案例:

import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;

import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;

public class Mobile {
    /**
     * 测试方便,这里设置了3秒失效
     */
    private static LoadingCache<String, String> caches = CacheBuilder.newBuilder()
            .maximumSize(1000)
            .expireAfterWrite(3, TimeUnit.SECONDS)
            .build(new CacheLoader<String, String>() {
                @Override
                public String load(String mobile) {
                    return "";
                }
            });

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        Integer code = (int)((Math.random()*9+1)*100000);
        caches.put("17762018888",code.toString());
        System.out.println(caches.get("17762018888"));
        Thread.sleep(4000);
        System.out.println("是不是没了:"+caches.get("17762018888"));
    }
}

小结

重要的功能必须进行前后端校验,必要的时候一定要做好限流、黑名单等骚操作!!!

  • 友情链接