首页

网页中这10种字体的运用方式,不会让人觉得Low

涛涛

对于设计师而言,在日常的平面和 UI设计中,给字体增加一直都是一件恼人的事情。客户提出的浮雕或者大阴影的需求,但是直接按照要求来设计可能会毁掉整个设计。更多时候,你需要的是一些相对优雅但是又足够吸引人的字体效果,让整个设计项目的走向更加合理。
字体非常多,有目的地选取合理的是让它们发挥效果的诀窍所在。好的字体排版是不需要辅助就能被识别的,否则这个设计是失败的。
值得一提的是,最好的字体往往是润物细无声的,近乎无形,但是对于整个设计在视觉和质感上都有所提升。

1. 有目的地运用阴影效果


无论你使用什么软件做设计,都不要使用默认的阴影效果,这个经验里面包含了太多血的教训。
正如前文所说,好的阴影有着较高的融入度,几乎是「隐形」的。在部署阴影的时候,不要为了创建而创建,而是要借助阴影来构建前景文字和背景之间的层次感,这种对比恰到好处即可。
这种「隐形」的阴影设计对于设计师而言通常是不难识别出来的,不过普通用户通常不会太注意到它们。这些柔和的阴影,功能只是用来营造对比。
相对较为硬朗的阴影,会给人以更加复古的感觉,在较粗的、笔触平整的字体背后使用这样的阴影效果会比较好。

2. 使用双重曝光效果


双重曝光效果在网页设计和平面设计当中是非常流行的设计技巧。在文本字体中使用双重曝光效果能够让它看起来复杂而有趣,尤其是在双重曝光的图片选取得比较精妙的时候,效果看起来会非常惊艳。

3. 描边


对于较粗的字体使用描边,往往能够让字体的轮廓更加清晰,也增加了整体复古的感觉。在上面的案例当中,设计师就借助霓虹色字体和描边创造出了独特的氛围。

4. 使用多彩字体


多彩字体本身就包含有多样的色彩属性,甚至含有阴影、渐变、透明度甚至纹理。你可以使用多彩字体来让文本拥有远超传统字体的时髦值。
当大量的色彩共同来构成一套字体的时候,字体本身的视觉吸引力就已经达到了。现如今明亮大胆的字体是一种设计趋势,这样的配色本身并不会冒犯用户,因为用户正在越来越适应这样的设计。
当然,在色彩的搭配上需要协调且有目的性。

5. 适当地融入一些动效


从来都没有规定文本必须是静止的,在网页的文本中加入动效能够提升它的视觉吸引力。
不过,在为文本添加动效的时候,尤其要注意保持文本字体的可读性:
  • 运动轨迹应该是有意识地设计的;
  • 字母的运动不应该太快;
  • 滚动或者自动播放的文本应该可以被停止;
  • 无论屏幕大小,文本内容应该始终保持可读。

6. 模仿一些标志性的元素和特征


这两年的 Netflix 的热门美剧《怪奇物语》中,就模仿80年代经典的电影,融入了大量当时的元素,创造出让许多影迷共鸣的设计。
最典型的就是霓虹色的运用,充满80年代风情的 LOGO 成为了该剧最具识别度的元素。这种模仿的基础在于近年来80年代复古元素的疯狂流行,以及霓虹色等设计风格的回潮。
在模仿这些标志性的风格和元素的时候,度的把握很重要,恰到好处的模仿让人觉得亲切,而拙劣的复制则会显得很 Low。

7. 引入图形


引入图形或者其他的多媒体元素,在文本中加入一些额外的东西,也是不错的手法。使用图形或者其他的元素来替代一个或者多个字母,这样的设计还是很抓人眼球的。
这种技法的诀窍在于,图形的外观要和字母的风格、形状相匹配。很明显,如果不这么做的话,会让内容难以阅读。
在上面的 Kasra Design 的网页当中,视频的触发按钮和图标很好地融合了起来。

8. 增加纹理


有些字体风格本身就显得复古、粗糙,设计师能够通过自定义增加纹理来强化这种感觉。纹理本身能够让文本更加突出一些,也能够强化文本的质感,营造出独特的氛围。
在上面的案例当中,设计师通过两种不同的方式来赋予文本以纹理:
  • 通过切割出来的细节来赋予文本以纹理;
  • 通过半透明的效果让字体透出背景,从而拥有纹理。

9. 创造自定义的文本字体


在进行品牌 LOGO 设计的时候,自定义的文本字体是最常见的元素之一。基于特定的字体来进行自定义设计,通过标志性的细节来营造令人难忘的视觉体验,是自定义字体的主要目标之一。
这并不是一件容易实现的事情,自定义文本字体不仅需要足够扎实的技术,而且需要在具体设计的时候,足够小心谨慎。在绝大多数时候,最好是要同专业的字体设计师合作,以达到最好的设计效果。

10. 让字体本身发挥效果


有的时候,最好的文本效果,就是不要加其他任何。在形状、大小和色彩具有足够对比度的情况下,文本元素和背景会自然地构成前后景的对比,自然分离。
缺少其他效果的加持,设计师需要精心地控制所有的辅助性的元素,确保所有的元素能够完美的协同工作。加粗字体,深浅对比,是比较合理的组合方式。
The University of Essex 这个网站就在较暗的背景上采用了加粗的白色字体,视觉上足够突出,也足够清晰。

结语

文字的使用还需要特别注意设计趋势的存在,过于突出的可能会显得过犹不及,而趋势的流行周期也是设计师需要尤为注意的问题。微妙的设计总归是拥有更加持久生命力的。 

设计!

蓝蓝设计的小编

如果您想订阅本博客内容,每天自动发到您的邮箱中, 请点这里

版式设计中的简约设计
设计!

设计!

设计!

设计!

设计!

设计!

设计!

设计!

设计!

设计!

设计!

设计!

设计!

设计!

设计!

设计!

设计!

设计!

设计!

设计!

设计!

设计!

设计!

设计!

设计!

设计!

设计!

设计!

设计!

设计!

设计!

设计!

设计!

设计!

设计!

设计!

设计!

设计!

设计!

设计!

设计!

设计!

设计!

设计!

设计!

设计!

设计!

设计!

设计!

设计!

设计!

设计!

设计!

设计!

设计!

设计!

设计!

设计!

设计!

设计!

设计!

设计!

设计!

设计!

设计!

设计!

设计!

设计!

设计!

设计!

设计!

设计!

设计!

设计!

设计!

设计!

设计!

设计!

设计!

设计!


蓝蓝设计www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 平面设计服务

零基础学习UI设计到底需要学些什么?

蓝蓝设计的小编

在进入一个未知的范畴前,一定要先梳理这个范畴的架构,待有了对比全部认知后再深挖。学习UI规划也是相同,假如有条件,能够尝试了解一个新的互联网商品出炉的作业流程。

微交互|只要关注这6个点,交互设计师也能做好竞品分析!

涛涛

今天我们来聊聊竞品分析,它并不是像人们认为的那样——有统一的模板,因为针对不同的岗位,做的竞品分析是不同的。所以本文聊的是:交互设计师如何做竞品分析。
竞品分析是对产品、交互从业人员最基本的技能要求之一,很多刚入行的产品汪、交互喵首先要做的都是竞品分析,一来可以考考你的底子,二来可以锻炼你的逻辑思维。虽然它是基本技能,但是它的作用却非常大。
那有什么作用呢?当你设计了一个功能,别人问你为什么这么设计时,你的答案要非常专业,而不是说“我觉得……”,这时候竞品分析就派上用场了。
做竞品分析,可以避免相关设计人员站在自己的角度去思考问题,在评审的时候容易通过且能够获得大家的认同,而不会受到来自各方的质疑,这也是那么多人做竞品分析的原因之一。
当然,站在产品和运营的角度来说,做竞品分析还能开拓市场、优化产品、制定策略、确定战略等等,但是这些在我看来并不是交互设计师需要关心的事情(除了优化产品)。

怎么做竞品分析

大家在网上能看到很多竞品分析文档,会发现里面的内容非常多,而且很多都看不懂。告诉你三个字:不用看。
这些文档看起来好像很专业,但是当中涉及的数据内容、商业分析、产品战略等大部分都是笔者自己 YY 的,这个不仅对做竞品分析没什么帮助,还会使自己在做的过程中特别容易跑偏。所以你只需要关注以下六个点来做或看竞品分析文档。
  1. 找到商业需求
  2. 用户操作流程
  3. 产品功能分析
  4. 交互逻辑思考
  5. 用户使用评价
  6. 得到设计需求

01. 找到商业需求

商业需求这个点,不仅仅适用在竞品分析的开头,我们做交互文档、需求文档都要把商业需求放在首位。只有商业需求的目标明确了,才好进行下一步操作。那什么是商业需求呢?
给大家举个简单的例子:
今天接到一个产品需求:即优化产品的搜索功能。可能很多人看到这个需求就马上开始看看别人的搜索都是怎么做的,然后抄一下,改一下就好了。这样设计出来的东西,只能说是一个具体的设计任务,而不是解决实际问题的方法。
我们要先找到商业需求,为什么要优化产品的搜索功能呢?有些资深的产品经理会在需求文档中写出,而有的并不能想到这一层,仅仅只是觉得不好用所以让你去优化。所以当你的产品经理属于后者的时候,你就要提前参与到前期的工作中,给自己提问题,告诉自己为什么要去优化,以及它能带来什么效益?
当你的工作做到位的时候,并且了解的足够多的话,你很轻易的就会发现,我优化这个搜索功能的原因有两个,也就是商业需求:一是提升平台成交率,二是获取用户数据。

02. 用户操作流程

得到商业需求,我们就要做具体操作,就是找到合适的竞品。这里我扩展一个话题,就是找什么竞品。
通常,我把竞品分为三大类,分别是核心竞品、潜在竞品(类竞品)、交互参考竞品,这三类具体指的是什么,有兴趣的小伙伴可以自己去研究了解。
找到这三类竞品后,要做的就是把它们所有关于搜索功能模块的界面做一个仔细操作,并截图单独存放在一个文件夹中做深入分析。
比如这个功能涉及到的页面、动效、视觉等所有信息都进行详细观察,然后将其做成一份流程图,将所有的竞品都这样做完后,进行对比分析,你就会发现当中的差异,然后就可以知道哪种操作路径是最好或最适合你的产品的。

这图是我为了写文随便搭的,就是个demo,具体的大家还是要自己去操作。

03. 产品功能分析

当你列出所有流程操作图后,下面就可以对搜索的功能进行分析。
这块操作起来比较简单,首先建一张表,罗列出相应的支持功能,然后对支持的竞品类目打上勾,不支持的就不做处理,如下图:

这图也是我为了写文随便搭的,就是个demo,具体的大家还是要自己去操作。
做完以上操作,接下来再分析每个竞品的搜索导航是属于什么类型,这种类型对搜索有什么好处等等。包括搜索功能模块的其他信息,如展示形式、关键词、筛选字段等等,以此推导出其中的差异。当然,做其他功能也是一样,我只是拿搜索做个例子。

04. 交互逻辑思考

由这层开始,要分析功能交互的问题。在每个流程图的边上写下相关的交互逻辑,然后通过自身的行业知识来拆解竞品当中的交互信息,如:
  • 搜索之后页面的跳转的层级
  • 搜索结果展示
  • 页面布局的合理性
  • 图片比例规则
  • 按钮热区
  • 表单展示形式
  • 等等
如果你是一个资深的交互设计师,看到的信息还会更多,这块跟自身能力有关,拆解的产品、分析的交互逻辑越多,这块的梳理能力就会越强,看产品的本质也会越深。那么你分析竞品所能得到的信息也是一般交互和产品不能发掘的。(关于这块的产品拆解我后续会有文章单独说明)

05. 用户使用评价

这块工作看着好像跟竞品分析不搭边,但却是不可缺少的一环。因为即使你做了再多的分析和拆解,看了再多的偏好数据(更何况有些公司拿到的数据并不全面),都没有看用户使用评价来的更加直观。所以看用户的使用评价变得极其重要,只有真实了解用户内心,你才能真正设计出好的产品。
我们可以通过各个渠道去了解用户对一款产品的评价,包括对某个功能的看法,当然我之前也说过,我们不能听用户的一面之词,所以需要去提炼当中的关键信息,帮助自己更好的去完善产品。
这块其实没什么好说的,在竞品分析文档中,这块内容其实不需要做过多的展示,只要拿到你的关键信息并做个大概说明,然后说出你从中得到的设计思路就可以了,我们最后还是要看输出总结,即通过做竞品分析得到的设计需求。

06. 总结输出

当我们按照上面的流程做完所有步骤之后,你就会得到你的设计需求,如:
  • 关键词搜索
  • 搜索建议
  • 条件过滤
  • 搜索历史
  • 查找相似商品
  • 让用户快速识别搜索入口
  • 字段排序
等等。
这些所有子功能都是通过做竞品分析得到的,当然你也可以通过用户调研等方式去得到设计需求。
说这么多,就是告诉他家我们做一个产品时,不是自己去YY要做什么,而是通过这一系列工作流去找到应该做的事情。这就是你在这个岗位必须做到的事情,不要以为产品或交互的工作很简单,上面的每个步骤都是需要大量时间的练习才能做好的。

小结

我们通过竞品分析来提高我们产品自身的核心竞争力,并不是为了求同,也不是为了模仿,而是为了突出自身的产品价值,正所谓知己知彼,百战不殆,竞品分析的目的并不是为了抄袭,而是为了超越竞品。
不过,竞品分析还是会有一定的局限性,比如说我们做竞品分析的时候往往容易将产品和企业文化、产品商业战略等信息剥离开来,但是对于很多产品来说,这些是很重要的东西。所以也就很容易忽视这其中的相关性,分析的时候就有可能导致片面或者出现误差。
所以我们就要不断地改进我们的竞品分析报告,学会从整体上去把握产品的脉络,才能更好地摆脱竞品分析的局限性。 

四大分析法打造你的产品说服力

涛涛

开篇明义,这四大分析法就是:市场分析、竞品分析、用户分析、需求分析。从这四个角度深入分析,就能证明你产品方案的正确性。
其实干了多年的产品老手,一眼就能看出我说的都是「废话」,谁都知道这四类分析法是做产品的基本功,做好了当然能把产品做好。是的,我写这篇文章还有一个目的:就是让大家重新重视这些「基本功」,心态归零。
很多时候,产品经理都被各业务方需求压得喘不过气,更多时间在写文档、画原型、跟项目、处理 bug 反馈中度过。各位正在看本文的产品经理可以回忆下,有多久没认真做过分析了?

话说回来,所谓「认真分析」,也是有法可依、有据可循的。今天就给大家复盘下,身为产品经理,最需要掌握的四大分析法,都如何来做。 

一、市场分析

市场分析的官方定义:
对市场容量、市场规模及市场特性等相关内容进行实事求是的经济分析及预测 。
包括三大范畴:
  • 从行业角度,要看行业有没有发展,市场规模大不大,政策好不好;
  • 从用户角度,要看市场中的用户习惯、用户构成、用户期望;
  • 从自身角度,要认清在市场中自己的优势劣势,遇到的挑战等。
如果要用一句话描述做市场分析的目的,就是看你要做的这个产品,能不能赚钱。是的,虽然很残酷,但一款不赚钱的产品,无论用户体验多好,设计多精美,技术多先进,仍旧是无法持续的。
当然,除了能不能挣钱外,还要进一步研究为什么能挣钱,怎么挣钱,怎么挣到更多钱,能挣多少钱等等。
具体的分析方法,包括:
  • 搜集相关资料,包括宏观经济、行业竞争、技术趋势、市场阶段、市场规模等;
  • 分析市场用户基本情况;
  • 分析自身基本情况。
可能会用到的一些分析模型包括:PEST、SWOT、波特五力等等,这里不再展开,大家可以按关键词搜索更多。

二、竞品分析

竞品分析和市场分析是相辅相成的,有市场就有竞争,很少有一家独大的情况,因此就需要你思考如何在激烈的竞争中脱颖而出。
竞品分析的目的:一方面是了解市场格局,判断是否有机会切入;另一方面是为了制定有利于自身的竞争策略。这个策略,不仅体现在交互设计、使用流程、用户体验上,还要考虑运营、营销、推广策略,甚至还有资本运作方式等。
因此,要求你做竞品分析时,要先定义清楚你分析的目的是什么,然后自顶向下地进行,从行业格局到功能细节,都要有所涉猎。

三、用户分析

用户分析的目的是为产品的立项或优化提供定量或定性支持 ,常见方法包括:观察用户行为、听取用户意见、收集用户数据。对于新产品,比较好用的分析方法是做用户调研。
在用户调研过程中,最需要注意的就是调查问卷的撰写,总结下我觉得需要注意的几点:
  • 避免出现诱导用户选择的选项,比如:如果给你提供一个XX功能,你会不会用。
  • 避免出现无法理解的专业术语,比如:你是否希望我们的产品采用个性化推荐算法分发内容。
  • 避免出现容易引起歧义的模糊词语,比如:你使用社交电商产品频率是多少。
  • 避免出现需要让用户思考的问题,比如:你每周共花多少钱买我们的产品。
  • 避免直接出现产品名称,比如:你觉得像喜马拉雅、得到这样的知识付费产品能解决你的问题么。
还有一点想说的是:设计每道题的每个回答项时,都要明确每个选项你希望带来的结论是什么,这样才会促使你不断完善自己的问卷。 

四、需求分析

需求分析是我觉得四大分析里最难的,也是产品经理的必备课题,因为这背后体现的是对心理的洞察,而「人心」其实是最难猜的,抓住了人心,你的产品自然会成功。
需求分析的过程,要求产品经理具备一双敏锐的眼睛发现需求,一颗好奇心挖掘需求。日常工作中,你所面对的需求包括:客观需求和主观需求。
客观需求:是指通过行为数据、市场趋势分析、竞品调研、用户研究、体验问题等渠道收集的需求,通常要求产品经理时刻保持对行业、对数据的观察和思考。
主观需求:是明确有人向产品经理提出的需求,你的需求方可能包括老板、客户、用户、内部团队。日常工作中最复杂的情况也就是处理主观需求,因为「说服」是个非常耗时耗力的过程,但也是体现你产品能力的时候。
具体如何分析需求,其实已很多方法论,比如威格斯法、KANO模型、Y模型、四象限法等。
建议在每次分析需求时,都用如下句式对需求定义:
什么人,在什么场景下,为了达到什么目的,在遇到什么问题的情况下,希望采用什么方法来解决。
以上句式,说明了:用户角色、使用场景、目标定义、任务说明、问题描述。几乎囊括了描述一个需求的所有要素。
此外,需求分析最重要的还是如何把用户需求转化成产品方案,这一过程要求产品经理同时具备用户思维和产品思维,具体做法在此不再赘述。
最后还想再和大家强调下,分析不是目的,最重要的是通过分析得出对工作有帮助的结论 ,与你共勉。

Java跨域问题的解决方案及axios的跨域请求方法封装

seo达人

如果您想订阅本博客内容,每天自动发到您的邮箱中, 请点这里

原因

出于安全考虑,浏览器有一个同源策略。浏览器中,异步请求的地址与目标地址的协议、域名和端口号三者与当前有不同,就属于跨域请求。

限制跨域访问是浏览器的一个安全策略,因为如果没有这个策略,那么就有被跨站攻击的危险。比如,攻击者在自己的网站A放置一个表单,这个表单发起DELETE请求,删除某个用户在B网站上的个人资料。如果没有同源策略保护,那么在同一个浏览器内,如果用户已经登录了B网站,这个删除的请求就会被接受,导致在用户不知情的情况下自己在B网站中的资料被删除。

解决方式

浏览器的同源策略提升了安全性,但是给需要在不同域名下开发的开发者带来了跨域问题。

解决跨域的问题主要有: 
jsonp和cors。jsonp是利用 script 标签可以跨域加载的特性而创造出来的一种非正式的跨域解决方案。在实际开发中,推荐使用cors,即在服务端返回时加入允许跨域的请求头,允许指定域名的跨域访问。

千万要小心!这种直接加 * 号的做法是相当危险的,千万别这么做!

response.addHeader("Access-Control-Allow-Origin", "*"); 
  • 1

正确的做法:

1. 创建一个 Filter 类

/**
 * 使用Filter的方式解决跨域问题
 */ public class CorsFilter implements Filter { private static final List<String> ALLOW_ORIGINS = Config.getListString("allowOrigins", ","); private static final String REQUEST_OPTIONS = "OPTIONS"; @Override public void init(FilterConfig filterConfig) throws ServletException {
    } @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;
        String orgHeader = request.getHeader(HttpHeaders.ORIGIN); if (orgHeader != null && ALLOW_ORIGINS.contains(orgHeader)) { // 允许的跨域的域名 response.addHeader("Access-Control-Allow-Origin", orgHeader); // 允许携带 cookies 等认证信息 response.addHeader("Access-Control-Allow-Credentials", "true"); // 允许跨域的方法 response.addHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE, PATCH, PUT, HEAD"); // 允许跨域请求携带的请求头 response.addHeader("Access-Control-Allow-Headers", "Content-Type, Content-Length, Authorization, Accept, X-Requested-With"); // 返回结果可以用于缓存的最长时间,单位是秒。-1表示禁用 response.addHeader("Access-Control-Max-Age", "3600"); // 跨域预检请求,直接返回 if (REQUEST_OPTIONS.equalsIgnoreCase(request.getMethod())) { return;
            }
        }
        filterChain.doFilter(request, response);
    } @Override public void destroy() {

    }
} 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39

2. 在 web.xml 的最前面注册这个 Filter

<filter> <filter-name>corsfilter</filter-name> <filter-class>com.bj58.crm.plus.filter.CorsFilter</filter-class> </filter> <filter-mapping> <filter-name>corsfilter</filter-name> <url-pattern>/*</url-pattern> <dispatcher>REQUEST</dispatcher> </filter-mapping> 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

前端使用 axios 可以先进行封装

http-util.js

let axios = require("axios"); let qs = require("qs");
axios.defaults.withCredentials = true;
axios.defaults.headers.post["Content-Type"] = "application/x-www-form-urlencoded"; function post(url, param) { return axios.post(url, qs.stringify(param))
} function get(url, param) { axios.get(url, {params: param})
}

export default {
  get,
  post
};

蓝蓝设计www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 平面设计服务




转载设计反模式之架构设计

博博

背景

 

下图所示线上故障,你的产品线是否曾经中招或者正在中招?同样的问题总是在不同产品线甚至相同产品线不同系统重复上演,这些故障有个共同特点,就是线下常规测试很难发现,即便线上验证也不易暴露。但是总是在“无变更安全日”悄然爆发,严重影响系统稳定性指标。



面对这些看似并无规律的故障,Case by case的分析无疑是低效而且不系统的,无法全面扫除稳定性测试盲区,也无法阻止悲剧在其他产品线再一次发生。为此笔者把问题聚类,根据问题特点寻求通用测试手段,并在产品线各个系统落地验证,效果显著,现把个人经验融合前辈经验产出,供大家参考,有则改之,无则加勉。

首先,为了让大家更好了解这些故障对业务系统稳定性的影响程度,需了解下何为稳定性,衡量指标就是系统可用性= MTBF / (MTBF + MTTR) , 其中MTBF, Mean Time Between Failure, 是平均无故障时间, 而MTTR, Mean Time To Repair,是平均修复时间,参考下表更加直观。

从如上数字看,5个9的故障时间月故障时间只有25s,3个9的可用性月故障时间也只有40多分钟,回想我们平时处理过的线上问题,开发和测试质量把控不过关,然后再把期望寄托在半人肉处理故障的运维团队,显然无法达到线上产品稳定性要求。

为了保障系统稳定性,提前消除风险势在必行。产品质量风险类型很多,产品研发流程的各个阶段都可能引入和存在风险,每个阶段的风险的类型和发现手段都不尽相同,为此产出如下风险模型。按照风险发生的阶段及原因,风险类型可分为:架构设计风险、编码风险、安全风险、流程规范风险、运维风险和监控风险。


本文主要讲解架构设计风险,接下来介绍的每个风险都会说明风险定义,影响,以及通过什么技术手段来进行风险识别,最后总结风险消除方案。另外每个风险都会有具体的例子来讲解,这些例子都是发生在百度内部的真实故事。


架构设计风险


架构设计风险是QA最容易忽略的,该类风险出现在研发阶段的早期,我们都知道缺陷越早的暴露后期研发的维护成本越低,而且一旦架构设计上出现了问题,影响面是涉及整个模块甚至系统的,修复代价必然非常高,因此对于架构设计的风险更要提前了解和避免。

根据既往经验,架构设计风险大概可以分为以下几个维度:交互、依赖、耦合。

交互类常见风险:重复交互、高频交互、冗余/无用交互、接口不可重用、超时重试设置不合理、IP直连、跨机房等。

依赖类常见风险:不合理强弱依赖、无效依赖、忽略第三方依赖、缓存依赖失效等。

耦合类常见风险:架构耦合不合理、缓存耦合不合理等。


一、重复交互

1、风险定义

在一次业务请求中,系统内部发起了多次完全相同的网络交互,即存在重复交互风险。从交互层级和上下游来说,重复交互有两类,整个业务请求范围内的重复和同层重复,其中同层重复交互的上下游也是相同的,本文更多关注的是整个业务请求范围内的重复交互。通常在一次业务请求中,为了提升性能和负载,尽量避免或者降低重复交互次数。

2、风险影响

重复交互增加接口耗时,降低接口性能,当重复的是跨机房交互会使得性能急剧下降影响系统稳定性,增加对下游服务的压力(模块压力增加一倍,下游服务压力增加几倍)。

3、风险识别

如果两个交互具有完全相同的请求服务对象(尤其是mysql、redis、memcache这类数据存储服务)、请求数据、返回数据,那么这两个交互就判定为重复交互;对于获取不到交互数据时也可以通过数据包size进行初判。这里可以借助开源trace系统,采集业务测试时的调用链信息,根据上面的判断规则进行风险自动识别。

4、风险消除

在对实时性要求可控的前提下,将第一次查询信息缓存下来。


  • 真实案例一:系统间重复交互。11次重复请求session,对于前端一次请求就要对session模块产生几十倍的流量冲击,所有这些交互都是完全重复的,极大的降低的了接口性能和session的负载能力。


  • 真实案例二:mysql/redis重复交互。mysql/redis作为系统中性能瓶颈,这样的重复请求无疑加速了其性能瓶颈的到达。


二、高频交互

1、风险定义

一次用户发起的请求,如果在模块之间的交互次数完全依赖于后端返回的数据条数,会给下游造成极大压力的同时,也降低了系统的稳定性。相同业务请求的模块交互次数多少不一,原因通常是代码中循环操作内部存在网络交互,总交互次数受到循环迭代的次数影响。这样的情况在模块上线初期,可能因为数据量比较小、pv比较小很容易被人忽视,当某天上线一些大数据、大客户,将会给予致命一击。

2、风险影响

循环请求次数过多会导致下游压力倍增(前端pv增加一倍,后端pv增加几十倍),接口性能不稳定,降低系统处理能力。系统稳定性完全依赖于数据的代码逻辑非常脆弱,当遇到某一个大数据时将会出现模块假死、系统雪崩、功能失败。

3、风险识别

基于上游传来的数据或某个子请求返回的数据量(通常是一个数组),针对每个数组元素进行网络请求,遍历并没有错,但是要对这个遍历的数组元素个数有限制,否则循环遍历的次数就完全依赖于数据。这里也可以借助开源trace系统,采集业务测试时的调用链信息,根据上面的判断规则进行风险自动识别。

4、风险消除

数据量要可控,结合产品业务需求,比如请求返回结果要有上限;批量请求替代逐个请求。


  • 真实案例:查询某商户物料详情,当该商户拥有大量物料,就出现了如下场景,用户的一次查询就造成服务与db之间156次交互,那该接口的性能就可想而知了,平均耗时都在3s+,用户体验极差。



三、冗余/无用交互

1、风险定义

交互依赖的数据已出现异常,还继续执行后续交互,使得后续的交互是没有任何意义的冗余交互。这些依赖的数据,可能是上游传递而来,也可能是与下游模块请求得来。

2、风险影响

冗余交互会占用系统资源,降低接口性能,从而影响系统稳定性和性能。

3、风险识别

如果交互A依赖数据B(比如交互A的请求数据中需要传入B),在B异常(比如数据为空、null、false等)情况下,还是发生了交互A,那么就认为A是冗余交互;如果操作A依赖于操作B的成功执行,当B异常时,还是发生了操作A,那么A也认为是冗余交互。可以借助开源trace系统,采集业务测试时的调用链信息,根据上面的判断规则进行风险自动识别。

4、风险消除

代码中增加异常逻辑判断:当交互依赖的数据异常时不进行该交互。


  • 真实案例:如下调用链正常场景是先查询团单list,然后用团单list去查询每个团单的优惠。但是当查询团单列表为空时,就没有必要再调用marketing查询团单的优惠信息了,应该立即返回错误码。这里增加无效交互无疑降低了接口性能。



四、接口不可重入

1、风险定义

相同请求发给模块再次处理,不能保证结果一致,符合预期。

2、风险识别

相同请求,模块返回结果不一致亦或重复写操作产生脏数据。这里可以利用录制工具,重放请求,验证结果正确性。

3、风险消除

对于防重入可总结三点,前端加入防重复点击设置,接口层加入锁机制,db层需要加入唯一键设置。



  • 真实案例

在商家会员卡充值购买的流程中,nmq故障情况下,购买结果页显示充值失败,但是卡中余额却一直在直线增加,原因是充值接口没有做到可重入,这个case幸好在线下及时发现,否则后果不堪设想。

商家会员卡涉及到的购买流程如右下图所示:



用户提交订单并且钱包处理完成后,钱包回调交易模块的payresult接口,交易模块验证通过之后,会调用商家会员卡的rechargemoney接口给商家会员卡充值。为了提高充值接口的可用性,与交易模块有个约定了一个机制:若调用rechargemoney返回的errno不为0 ,则投入nmq重试三分钟,三分钟之内的重试均没有成功,才触发自动退款。商家会员卡模块的充值接口rechargemoney的流程图如下图所示:



在rechargemoney接口处理过程中,有一个防频繁重入的判定redis锁过程,expireTime设置时间为10s,10s内会拦截过来的重复请求,直接返回。

上述过程可以看到,前端是有无限重试策略的,因此可以认为前端无防重入,那么看接口层锁机制,重试时间3min明显大于锁有效时间10s,因此相同请求10s后锁机制也失效,再看db层,插入order_id和其他营销信息,数据库中并没有设置order_id为唯一键,因此该接口彻底失守,没有做到可重入,相同订单可以重复插入成功,从而导致业务表现为同一订单多次重复充值。

对于该案例,改进方案是首先将锁有效时间设置大于一切来源的重试时间,其次在db充值记录表中将orderid设置为主键,双重保护该接口做到可重入。


五、超时设置不合理

1、风险定义

顾名思义,就是超时并没有根据系统真实表现科学的设置。

2、风险影响

就像下图化学反应一样,不合理的超时实际设置并不会产生真正影响,但是遇到网络故障,依赖超时时,后果不堪设想。



模块交互必设超时,这是基本要求,但是超时设置过长、过短可能会适得其反。不合理超时设置主要表现为①交互超时时间设置过长,比如5s甚至10s的超时②下游超时时间大于上游超时时间。

交互超时重试时间过长,在下游偶尔出现网络抖动时连接被hang住,接口耗时增加,并且降级模块处理能力。下游超时>上游超时,上游超时后断开连接引发重试,下游还在继续上次运算(此时已经没有意义),下游负载增加N倍(取决于重试次数设置和发生重试的层数),使得系统性能急剧下降甚至雪崩。

3、风险识别

①超时时间设置过长(比如数据库connect超时1s,模块读写超时5s)

②下游超时时间大于上游超时时间。

4、风险消除

从系统整体考虑,并且结合重试和本模块计算时间的影响。下游超时<上游超时;超时时间不宜过长,根据下游接口性能设置;对于弱依赖的服务交互,超时时间更不能过长,以免弱依赖阻塞主流程。


  • 真实案例:如下图,该接口调用redis超时时间超过2s,然而Redis性能极好,单线程阻塞性server,这种长耗时会阻塞其他请求,很容易引起系统雪崩,应该把redis连接超时时间修改适当小。



六、重置不合理

1、风险定义

顾名思义,就是重试并没有根据系统真实表现科学的设置。

2、风险影响

任何网络交互都可能失败,为了保证最终交互成功,通常交互失败/超时、数据错误后再次与该模块交互,即发生了重试。重试的次数设置不当,轻者交互成功率不达标,业务失败率增高,严重者引发系统雪崩。

3、风险识别

查看框架配置文件中重试次数配置,是否简单粗暴的经验值设定重试次数,比如一律重试3次,查看代码中逻辑控制的重试限制(这种很隐蔽)。

4、风险消除

相对于固定的重试序列,随机重试序列也可能给系统带来风险,例如可能会降低下游模块的cache命中率,降低系统性能,甚至引起雪崩。

评估重试机制:

1) 真的需要在每一层都努力重试吗?

2) 真的需要这么多次重试吗?

3) 真的需要在连接,写,读这三者失败后都重试吗?

  • 按照业务需求和模块性能设置重试次数

  • 弱依赖不用重试也可以

  • 下游模块性能好,基本不会超时,也可以不重试

  • 大部分情况下,重试次数为1已经足够


  • 真实案例

如图为某产品线的架构,整个系统中,上游模块对下游模块所有的交互,重试次数都是设成3次,交互失败包括连接失败,写失败,读失败这三种情形。如果是写和读失败,那么要关闭当前连接,再重新发起连接。



如果一台bs假死,到该bs的请求会超时。(注意区分模块假死和真死,假死情况下,模块端口打开,能够接收上游连接,但是由于各种原因(如连接队列满,工作线程耗尽,陷入死循环等),不会返回任何应答,上游模块必须等待超时才知道失败,连接超时,写超时和读超时都有可能。而在真死情况下,模块端口关闭,或者干脆程序退出,上游模块连接它会很快得到失败返回码,这个返回码由下游模块的操作系统协议栈返回的,如ECONNREFUSED错误码代表端口不存在,连接被拒绝。) 

那么as有1/3的概率需要重试,as重试的过程中,ui可能早就认为as已经超时了,所以ui也开始重试,ui重试的过程中,webserver可能认为ui已经超时了,所以webserver也开始重试……就这样,整个系统的负载急剧增加,到达bs的qps会是平时的27倍,直到系统崩溃为止。


七、IP直连服务方式

1、风险定义

A,B两个系统交互,B系统分布式部署,A-B连接是通过配置B系统所有IP方式。

2、风险影响

当B系统分布式服务中某一台挂掉时,不能做到failover,导致故障影响扩大。

3、风险消除

通过bns或者组的方式进行连接。


  • 真实案例

某产品线依赖服务redis调用均采用ip列表的方式,如果redis proxy出现单机故障,需要人工介入进行切流量止损。单机发单重启修复周期有时会达小时级别,因此线上服务在故障期间会长时间处于切流量状态,高峰期单机房容量会存在风险。如同时有其他机房服务异常,则无法执行既定预案止损。并且如想下掉故障proxy,只能采用发上线单修改线上配置的方式。止损操作复杂,周期长,效率低下,具体case如下:

(1)用户中心redisproxy单机故障,人工切流量止损,恢复服务花费2小时,期间线上处于切流量状态。

(2)商品中心redis proxy单机故障,会存在扣除库存失败的风险。恢复服务花费半小时,后续又再次发生宕机,发单下掉故障proxy。

如上对应前面讲的故障时间,该服务sla月可用性已不足3个9。


八、跨机房请求

1、风险定义

交互的两个模块分别部署在不同机房。

2、风险影响

跨机房交互由于存在网络延时,严重影响接口性能、请求成功率,极大的降低了系统稳定性。

3、风险识别

①配置错误(ODP框架)ral-service中配置的服务后端IP的Tag不能为空(在ral中,会将Tag为空的也认为是本机房)②上游传入idc错误,Idc是完全匹配,nj和nj02就不相同,因此如果上游传入nj02,当前模块的idc是nj,就会找不到对应的Tag而只能使用default。

4、风险消除

主要关注配置是否合理,由于线上配置很难在线下验证正确性,肉眼排查难免遗漏,因此可通过线上机房流量切换演练验证。


九、不合理强/弱依赖

1、风险定义

所谓强依赖就是,请求链路中某个服务失败/结果异常/无结果后,核心逻辑必失败,否则就认为是弱依赖。不合理的强弱依赖有两类,本应该是弱依赖的设置为强依赖,本应该是强依赖的设置为弱依赖。

2、风险影响

系统稳定性取决于调用链中所有依赖稳定性最差的依赖,如果将稳定性较差的服务作为强依赖将严重影响稳定性

3、风险识别

强弱依赖的合理性是需要结合业务判断的,如果业务返回结果不可或缺该依赖,那么就该设置强依赖;如何判断该依赖是否为强依赖可以通过故障模拟验证,如果模拟该依赖异常时导致调用异常,则判断其为强依赖。

4、风险消除

①调整不合理的强弱依赖关系,将业务非强依赖服务降级;②通过系统优化及运维优化等手段提高强依赖的稳定性。③对强依赖结果进行全面校验,保证强依赖故障能够及时被发现。


  • 真实案例

用户下单请求到trade模块,是通过消息队列nmq保证下单后的商户通知功能,通知商户是借助公共服务云推送,这里云推送被实现成了强依赖,也就是当云推送如果失败,返回给本次请求失败。

某次下单高峰期时,云推送出现故障,无法给ios用户推送消息,nmq收到请求失败后,会持续不断的重发,nmq的通道堵塞之后也影响了trade模块向nmq的请求故障不断往上层蔓延,最后用户无法下单。



对于如上案例,工程师最后去掉对云推送强依赖代码,服务才慢慢恢复,但已造成非常大的损失。


十、无效依赖干扰

1、风险定义

服务启动流程中与该依赖建立了连接,但是整个逻辑处理过程中无需依赖该服务,无任何业务关联性。

2、风险影响

其实该风险是不合理依赖的一个特例,无业务关联性的依赖应该及时去除,否则会影响整体服务稳定性。

3、风险识别

与依赖服务只有一次链接交互,无其他交互,就可以初步判断该依赖为无效依赖,为了准确评估可再结合代码排查。


  • 真实案例

某产品线由于配置管理较乱,有个服务每次启动都会判断多个与业务完全不依赖的服务启动情况,这几个依赖服务处于无人维护状态,非常不稳定,从而导致该服务启动失败率非常高。


十一、第三方依赖

1、风险定义

请求的完成,需要依赖产品外的其他服务,都称之为第三方(tp)依赖,按照公司又分为公司外第三方,比如糯米酒店依赖携程服务;公司内第三方,比如passport相对于手百。

2、风险影响

第三方服务的性能,正确性,稳定性直接影响自身服务,尤其是第三方强依赖,当第三方依赖出现异常,很可能导致自身产品受到损失;公司外第三方依赖有些是小型公司,技术和运维能力有限,其服务的性能,正确性、稳定性不是很高。

3、风险识别

第三方依赖的可靠性是不可控的也是我们系统建设中不可避免的,那么只能尽量降低第三方依赖不稳定对自身的影响。

4、风险消除:

  • 尽量避免第三方强依赖;

  • 超时设置,重试设置结合第三方容量,平均响应时间,部署情况;

  • 增加第三方依赖挂掉,假死,接口变更的校验及容错降级处理,从架构和云微商做到各个TP方与自身业务的解耦;

  • 运维上,提高第三方依赖可靠性,使用内网bns,vip请求,且避免跨机房交互。


  • 真实案例

某产品线依赖A,B,C三个tp方数据进行汇总展示,每次都需要调用三方都有结果时再进行聚合,否则认为整个流程失败,而三个tp方稳定性不尽相同,其中B是个小公司,经常出现故障,导致自身服务经常故障。

对此工程师对各个TP方加上了全面校验,当验证故障后自动调用降级操作,去掉该tp依赖。从此服务稳定性大大提升。


十二、缓存穿透

1、风险定义

前端请求一个肯定不存在的key,导致每次请求都会请求后端原始数据,使得缓存被“穿透”,当该类请求高并发时,那么后端压力凸显。

2、风险影响

缓存穿透后,每个请求都会到达后端服务,对后端服务压力突增;当缓存穿透的并发较高(尤其是恶意攻击),后端服务很可能被压垮,导致整个系统瘫痪。

3、风险原因

一种可能是对于主从分离系统,缓存失效时间小于主从延迟时间,尤其是跨机房的主从分离,主从延迟在某些时候会达到数秒甚至数十秒,这是如果缓存时间设置过小,就会导致所有缓存读写记过均为失效结果,进而请求后端服务获取新的数据。另一种可能是查询结果为空的情况。

4、风险消除

  • 对于查询结果为空的情况也进行缓存,缓存时间设置短一点,或者该key对应的数据insert了之后清理缓存;

  • 对于一定不存在的key进行过滤,把这些key放到一个大的bitmap上;

  • 设计的时候考虑,当缓存失效时,系统服务的情况及应对措施。


十三、缓存失效/缓存雪崩

1、风险定义

大量缓存同时过期失效,前端请求同时到达后端服务。

2、风险影响

当并发量足够大(比如秒杀,抢购),后端服务很可能被压垮,导致整个系统雪崩。

3、风险识别

缓存设置时间相同,失效周期也相同,导致多个缓存同时失效。

4、风险消除

  • 不同的key,设置不同的过期时间,让缓存失效的时间点尽量散列均匀;

  • 在缓存试下后,通过加锁或者队列来控制读数据库读写缓存的线程数量(比如对某个key只允许一个线程查询和写缓存,其他线程等待);

  • 做二级缓存,A为原始缓存,A2位拷贝缓存,A1失效时,可以访问A2A1缓存失效设置为较短,A2设置为长期。


  • 真实案例

某产品线监控发现机器A机器的8688端口挂掉了,经追查发现一个广告配置下发的接口(/api/v1/ipid)挂掉了,据统计,前一天23点到当日9点之间,该接口被访问了400+次,正常来讲,这种广告配置下发的接口一天最多几百个请求量。

经查,客户端有一个零点定时触发策略,零点会同时启动很多服务,平时并发请求会命中缓存,不会造成太大压力,可是当时正赶上缓存时间到期,大量请求将服务接口压死,端口挂掉。

对此临时方案是在接入层nginx配置文件中加入了流量控制机制,用lua脚本来将零点的请求屏蔽掉,长期方案是避免这种缓存集体失效的情况。


十四、 架构耦合不合理

1、风险定义

系统架构和设计上存在着耦合,包括模块耦合、接口耦合、消息队列耦合。具体体现在,主次不分的功能在一个模块或者接口中实现,nmq中不同重要性的命令耦合在同一个module中。

2、风险影响

整个系统稳定性<最不稳定的功能稳定性,不重要的功能可能拖垮重要功能

3、风险消除

整体思路就是,重要与不重要拆分,实时与非实时拆分,在线与离线拆分,根本上解决就是架构解耦,但是系统发展到一定阶段再拆分代码成本很高,这里可以通过运维方法控制解耦,具体见如下案例。


  • 真实案例

某产品线的一级服务和二级服务共同依赖一个基础服务,由于二级服务的一个bug拖垮基础服务,从而导致一级服务不可用,对此解决方案是通过运维将不同上游流量分开。



十五、缓存耦合不合理

思想同2.1.14这里不再赘述。


总结


本文给出了常见的15种架构设计风险,希望大家能够在实际工作中参考审视自己系统是否也存在同样的风险,尽早消除,提高稳定性!



转载各大团队校招笔试题集锦

博博

UCDCHINA上海群友们这两年收集整理的校招面试题,包含目前国内几家顶尖互联网企业。适用于产品及设计岗的各位小伙伴参考学习。如果有任何想法,也欢迎在群里踊跃发言。反正说的不好也不罚钱╮(╯▽╰)╭


阿里的面试题

 


请系好安全带,有一大波阿里面试题正在向你涌来。。。



报告,我感觉我和阿里的面试题八字不合,可以看看其他公司的面试题吗?

腾讯的面试题


其他公司的面试题


 


是不是感觉很难?是不是感觉无从下手?多多参与群内讨论,众多大佬给你指点迷津!




 


好了~最后的压轴面试题来了,大家可以踊跃发表感想。答出来的可以找大佬要棒棒糖当奖励



日历

链接

个人资料

蓝蓝设计的小编 http://www.lanlanwork.com

存档