博客

  • 语法糖

    1. 什么是语法糖?‌

    语法糖(Syntactic Sugar)是由英国计算机科学家彼得·约翰·兰达提出的术语,指编程语言中添加的某种语法,这种语法对语言的功能没有影响,但更方便程序员使用。它通过简化代码结构,使代码更易读、更符合人类的思维习惯。

    2. 语法糖的作用

    • 提高可读性:简化代码结构,使代码更直观,更容易被其他开发者理解。
    • 减少错误:由于语法糖通常让代码更简洁,因此可以减少因复杂代码而导致的错误。
    • 提升效率:开发人员能够更快地写出正确的代码,从而提高编码效率。

    3. 语法糖的示例

    • C语言:用 a[i] 表示 *(a+i),用 a[i][j] 表示 *(*(a+i)+j)
    • Java:自动装箱/拆箱、增强的 for 循环、泛型以及Lambda表达式。
    • Python:列表推导式、字典推导式、集合推导式、生成器表达式。
    • VUE:v-bind:src=>:src v-on:click => @click

    4. 语法糖的意义

    语法糖不仅是一种便捷的写法,编译器会帮我们做转换,而且可以提高开发编码的效率,在性能上也不会带来损失。它与其他编程思想一样重要,如duck type、人本接口、最小接口、约定优于配置等,广义来讲都是一些思想上的“语法糖”。

    5. 语法糖的争议

    尽管语法糖带来了诸多便利,但也有反对的声音。例如,图灵奖的第一个获得者Alan Perlis曾对此提出质疑。然而,大多数开发者认为,语法糖是一种让编程语言更加用户友好、更具表现力的方式。

    通过以上分析,我们可以看到,语法糖在编程语言中扮演着重要角色,它不仅简化了代码,还提高了开发效率和代码的可读性。

  • 混沌工程(Chaos Engineering)

    最近在看SLA,看到里面一个词叫混沌工程,故整理一下。

    定义:混沌工程是一门对系统进行实验的学科,旨在了解系统对应生产环境的各种混乱状况的能力,建立对系统的信心。所有系统的用户都希望系统具备可靠性,但影响可靠性的因素有很多。混沌工程师能找到证据,指明那些异常但不可回避的状况下系统的应变情况。

    简单来说:混沌工程是在分布式系统上进行实验的学科,目的是建立对该系统能够承受生产环境的动荡的信心。

    我们的用户将 TiDB 运行在国内某云厂商的机器上面,然后跟我们反映,读延迟会不定期的增长,我们看了看监控,发现唯一的异常指标就是 Cached 的 memory 那段时间会突然下降。当时真的就懵逼了,完全不知道是为啥,最终发现,云厂商的运维监控脚本里面有个 bug,会不定期的将磁盘热拔插,并且将现有的 page cache 刷到磁盘,所以那段时间 TiDB 的 read 操作很多是从磁盘重新读取数据的。

    可以看到,分布式系统真的是一个非常复杂的系统,故障无处不在,那么我们如何在这么复杂的分布式系统的世界里面生存下去呢?现在,一个很好的答案就是 – Chaos Engineering,中文里面叫做混沌工程。

    Netflix工程师创建了Chaos Monkey,使用该工具可以在整个系统中在随机位置引发故障。正如GitHub上的工具维护者所说,“Chaos Monkey会随机终止在生产环境中运行的虚拟机实例和容器。”通过Chaos Monkey,工程师可以快速了解他们正在构建的服务是否健壮,是否可以弹性扩容,是否可以处理计划外的故障。
    2012年,Netflix开源了Chaos Monkey。今天,许多公司(包括谷歌,亚马逊,IBM,耐克等),都采用某种形式的混沌工程来提高现代架构的可靠性。 Netflix甚至将其混沌工程工具集扩展到包括整个“Simian Army(中文可以译为猿军)”,用它攻击自己的系统。

    混沌工程

    相比于我们成天担惊受怕系统会出现什么样的问题,还不如提前就模拟线上环境可能出现的各种情况,来看我们的系统是否能做到容错,仍然能继续对外提供服务。当然,我们并不是简单的就在线上环境上面,把机器给断电,或者把网线给拔掉,在混沌工程领域,有一套指导原则,以及标准的实验步骤,具体的可以参考 PRINCIPLES OF CHAOS ENGINEERING 

    简单来说,要做一次混沌实验,我们只需要做到如下的 4 个步骤:

    1. 定义系统的稳态,这个稳态就是系统在正常运行的时候一些指标,譬如当前请求的 QPS,latency 这些。
    2. 将系统分为实验组以及对照组,做出一个假设,譬如我在实验组引入一个故障,这个稳态仍然能在实验组保持。
    3. 执行试验,给实验组引入现实世界中的故障,譬如拔掉网卡。
    4. 验证第 2 步的假设是否成立,如果实验组的稳态跟对照组不一样了,证明我们的系统在第 3 步的故障中不能很好的容错,所以我们需要改进。

    可以看到,上面的步骤非常的简单,但要在实际从很好的做混沌试验,还是有一些困难的,主要在以下几点:

    1. 自动化,我们需要有一套自动化的系统帮我们进行故障注入,进行假设对比等。
    2. 尽可能多的引入不同故障。现实环境中可能会出现非常多的故障,仅仅不是拔网线这么简单,所以引入的故障越多越好。
    3. 业务方无感知。如果我们每次做混沌试验,都要业务系统去配合,譬如在业务里面写一些混沌相关的代码,让混沌试验调用,或者更改系统的部署逻辑,跟混沌试验配合,这种的就属于紧耦合的。

    你好,ChaosMesh!!!

    所以,为了让大家更好的做混沌试验,我们开发了 ChaosMesh,ChaosMesh 是一套基于 Kubernetes 的云原生混沌工程平台。ChaosMesh 的架构如下:

    相比于其他混沌平台,ChaosMesh 有如下优势:

    1. 基于 K8s,只要你的系统能跑在 K8s 上面,那么就可以无缝的集成 ChaosMesh,而且不用修改任何业务代码,真正是被测系统无感知。
    2. 多种多样的故障注入。ChaosMesh 能全方位的帮你对网络,磁盘,文件系统,操作系统等进行故障注入。我们后面也会提供对 K8s,或者云服务自身进行 chaos 的能力。
    3. 易于使用,你无需关注 ChaosMesh 的底层实现细节,只需用 YAML 配置好混沌试验,就可以实施,后面所有的实验是全自动化的。我们也提供了 Dashboard 能让你在网页上就轻松的进行试验。
    4. 可观测性,ChaosMesh 的 Dashboard 能很方便的让你观测系统,知道什么时候进行了什么试验,知道你自己的系统当前的运行情况,当然,这里需要一点配置,你需要告诉 ChaosMesh 如何去获取你系统的稳态指标,譬如你的系统使用 Prometheus,那么就可以告诉 ChaosMesh 如何去 Prometheus 查询相关的监控指标。
    5. 强大的开源社区支持,ChaosMesh 的社区成长的非常迅速,我们非常高兴的看到大部分的功能已经由社区支持,并且也有很多用户。你无需担心遇到问题不知道如何解决,当然,你可能要担心下 ChaosMesh 做实验的时候把你的数据给完全干掉,所以做实验的时候一定要控制好实验半径,这个也是混沌工程的一条原则。

    来一次 Chaos 实验?

    在我们开始一次 Chaos 实验之前,你首先需要满足两个条件:

    1. 你自己的业务是跑在 K8s 上面的
    2. 在 K8s 上面安装了 ChaosMesh

    另外,在开始实验之前,这里我还是要强调一下 Chaos 实验的一些注意事项,可能你觉得我这个大叔很啰嗦,但小心驶得万年船,因为稍微一不注意,你可能就丢了数据了。

    1. 如果你刚准备将你的系统应用 ChaosMesh,一定要保证首先在测试环境中使用。你的系统应该还非常的脆弱,如果在线上进行试验,会非常的危险。
    2. 在生产系统中,一定要控制好试验的爆炸半径,控制好影响范围,譬如我们可以先对某一个街道的用户进行干扰,然后在扩大到某一个区域,或者某一个城市,如果我们一开始的影响半径就很大,一个稍微不留意,你的 boss 就可能让你第二天滚蛋了。
    3. 做混沌实验一定不是随机的瞎做实验,我们是带有目的的,是需要规划好的,与其漫无目的的对系统随机进行故障注入,我们还不如先问自己一个问题『为了对系统在混乱状况下的表现更有信心,在哪里做混沌实验最有价值?』也就是我们要熟悉了解我们的系统,做高杠杆价值的混沌实验。

    好了,现在你已经完全准备好了,现在就可以踏上混沌之旅了,因为 ChaosMesh 的使用是如此简单,你只需要参考 用户指南 就能上手使用,所以我就不过多介绍了,如果你仍然遇到了问题,欢迎给 ChaosMesh 提 issue,相信我,ChaosMesh 社区会很热情的帮你解决问题的。

    总结

    随着 ServiceMesh,Serverless 等理念的兴起,我们的系统真的趋向于越来越分布式,这样虽然简化了我们单个模块的实现,但整体来看,也可能会导致我们的系统因为过于分布式而变得复杂,那么如何在这种复杂的环境下仍然让我们有信心能保证系统能正常稳定运行,混沌工程可以算是一个很不错的选择。

    现在市面上面,支持混沌工程的平台已经有很多了,但我这里仍然推荐 ChaosMesh,毕竟使用它能让你极大提升你对系统的信心。

    该咋做混沌工程?

    在讨论咋做混沌工程之前,让我们先回答下面5个问题。

    什么是混沌工程?

    先说一个能说出点名堂的我个人对混沌工程的理解,**混沌工程,是Netflix公司当面对具有不可预知的“暗债”的复杂系统时,在“目标一致,关系宽松”的企业文化下,“逼上梁山”的结果**。

    什么是“暗债”?这个词来源于2017年发表的一篇名为[STELLA](https://snafucatchers.github.io/)的报告。这份报告由一群韧性工程专家在聚会后所撰写。就在他们聚会的那几天,这群专家赶上了一场极具破坏性的暴风雪。而那场暴风雪的名字,就是 STELLA。

    **暗债**,指当复杂系统内部子系统间相互作用时,所**必然存在**的**不可预知**的漏洞,最终会由此引发系统的意外故障。

    再说说上面那个“除了‘实验’貌似啥也没说”的定义。

    2015年,Netflix将混沌工程正规化,主持起草了[混沌工程原则](https://principlesofchaos.org/?lang=ENcontent),并给混沌工程下了定义。

    混沌工程是在分布式系统上进行实验的学科,目的是建立对该系统能够承受生产环境的动荡的信心。

    “貌似啥也没说”的背后,其实这个定义是大有深意的。

    • 分布式系统就是一种复杂系统,其活动规律是**不可预知和非线性的**。详情参见我之前撰写的[“不可能构建第二个云环境去做测试”](“不可能构建第二个云环境去做测试”——为复杂混沌的微服务生产环境设计韧性系统 v0.11)和[“混沌工程与系统稳定性设计模式”](https://myslide.cn/slides/22341)
    • 生产环境的动荡,来源于复杂系统内部**所固有的“暗债”**。见与不见,暗债就在那里,不增不减
    • 具有“可证伪性”的科学实验,只关注所定义的稳态是否被证伪,而对于**具体采取哪种方法保持稳态,不做要求**,悉听尊便,这就孕育了混沌猴
    • 要建立对系统能够承受生产环境的动荡的信心,需要**针对生产环境“丰富多彩”的暗债,设计同样“丰富多彩”的防范手段**。依据是控制论学者艾什比的[必要多样性法则(Law of Requisite Variety)](艾什比定律_百度百科)——要实现控制,控制系统能够执行的行为的多样性,必须不低于需要应对的环境动荡的多样性
    • 一个不断演化的分布式系统的复杂性,只会增加,而不会减少。依据是著有《人月神话》的那位大神Frederick Brooks的一篇文章中所谈到的两类复杂性(偶然复杂性与本质复杂性),都不会减少,甚至有一类还会增加。

    其中,偶然复杂性,是在资源有限的条件下,对相互冲突的限制条件作出权衡后的必然结果。

    不存在已知的可持续方法,能减少偶然复杂性,因为资源总是有限的,权衡总是要做出的,暗债总是要欠下的。

    而本质复杂性,是满足不断增加的新需求的必然结果。一个不断演化的分布式系统,新需求能少得了吗?

    混沌工程和测试有什么区别?

    两者的运行环境有区别。

    测试一般运行在**测试环境**上,而混沌猴一般运行在**生产环境**上。因为生产环境必然存在不可预知且与测试环境不同的暗债,所以对测试环境所建立的信心,并不能用在生产环境上。

    两者的侧重点也有区别。

    测试一般只关注**已知**的断言是否通过,而混沌工程会更关注发现更多**未知**的暗债。

    混沌工程和故障演练啥区别?

    两者的侧重点有区别。

    故障演练侧重操练**已知**的故障应对过程,而混沌工程侧重通过实验发现**未知**的暗债。

    生产环境是不允许引入任何风险的。如果混沌工程是在生产环境上做实验,那风险多大呀。领导会答应吗?

    前面提到,暗债是生产系统这个复杂系统所固有且不可预知的。那么即使不人为地引入风险,生产环境也是遍布暗债的。不在生产环境进行最小化爆炸半径的实验,来发现暗债,那么**只能任凭暗债在最不希望发生的时刻爆发**。

    该咋做混沌工程?

    借鉴Netflix的实例,可以从“摆正心态、人员主动和试点业务”三方面入手,来启动混沌工程。

    ### 摆正心态

    承认暗债为复杂系统所固有,而不是一味要求工程师[“不能也不该出现失误”](6月27日阿里云故障说明-阿里云开发者社区)。否则在故障面前,大家就只会花大量时间相互甩锅,耽误了发现更多暗债和防范措施。

    ### 人员主动

    前面说过,根据必要多样性法则,要建立对系统能够承受生产环境的动荡的信心,需要针对生产环境“丰富多彩”的暗债,设计同样“丰富多彩”的防范手段。而技术骨干一个人,是发现不了那么多暗债,并找到那么多的防范手段的。所以,就需要发挥各位工程师的主动性。此时,领导者要创造能调动工程师主动性和创造性的企业文化,来促进工程师更安全地发现与修复更多“花样”的暗债。在修复暗债的过程中,就可以使用文章[【分布式系统稳定性设计入门】如果不想总是半夜爬起来抢修生产事故……《发布!》第2版解读](【分布式系统稳定性设计入门】如果不想总是半夜爬起来抢修生产事故……《发布!》第2版解读 v0.2)所介绍的“分布式系统稳定性设计关键清单”。

    ### 试点业务

    • 选择一个出现生产事故频率较高的业务系统,尝试混沌工程。因为事故的反复,出现会让发现与解决暗债的动力更大
    • 基于能反映用户体验的业务稳态行为建立假设,而不是先聚焦于在系统内寻找弱点。因为这样能更利于进行全局优化,让成效更大
    • 为了让暗债浮现出来,设计引入足够多样化的现实世界可能发生的事件,而不是设计那些易于生成但在现实中不大可能出现的事件,以便切中要害。针对每一个所引入的事件,参考上述“分布式系统稳定性设计关键清单”,来进行稳定性设计
    • 可以先从准生产环境入手进行混沌实验,等条件成熟后,再逐渐过渡到生产环境
    • 自动化地持续进行混沌实验,以起到回归实验的效果,持续发现并解决暗债,避免系统随着时间的推移,在韧性方面逐渐“掉队”
    • 设计更安全的实验方式,以最小化爆炸半径,让实验所导致的业务损失降到最低,而不是明知故障难以控制,还要贸然进行实验。如果实验的假设被证伪,那么就遇到了发现新的暗债的好机会。在寻找暗债的过程中,可以参考上述“分布式系统稳定性设计关键清单”,来启发寻找漏洞及修复

    混沌工程的唯一目标就是证明系统存在缺陷。通过开展混沌工程方面的科学实验,你可以测试系统是否存在缺陷,从而了解系统在混乱的类生产环境条件下如何表现。

    混沌工程属于一门新兴的技术学科,行业认知和实践积累比较少,大多数IT团队对它的理解还没有上升到一个领域概念。阿里电商域在2010年左右开始尝试故障注入测试的工作,希望解决微服务架构带来的强弱依赖问题。

    参考来源1:https://zhuanlan.zhihu.com/p/149599011
    参考来源2:https://zhuanlan.zhihu.com/p/149419512

  • 微信小程序分享朋友圈和转发朋友

    onShareAppMessage: function() {
    	wx.showShareMenu({
    	      withShareTicket: true,
    	      menus: ['shareAppMessage', 'shareTimeline']
          })
          return {
            title: '帮我选车',
            path: ''
    	    }
    	},
    	//用户点击右上角分享朋友圈
    	onShareTimeline: function () {
    		return {
    	      title: '帮我选车',
    	      query: {
    	        key: ''
            },
    	      imageUrl: ''
    	    }
    	},

    体验版已支持iOS和android,只是微信官方文档还未做更新

  • 观《乐队的夏天》有感

    周末两天在手机端看马东的《乐队的夏天》第一季。以前没怎么了解过摇滚乐,或者说对于音乐听歌就没有怎么痴迷过。因为总觉得听歌会放大自己的情绪,尤其是一些悲伤的歌儿。让稳定的情绪都受到感染变得低落和流泪。听说这种人属于客场型人,容易受氛围的影响,和比如对方打哈欠,更容易打哈欠的一类人。

    在看《乐队的夏天》这个综艺的时候,有的地方也哭了起来。比如九连真人的唢呐响起来的时候,主唱的眼睛里在喷火,小民在用客家话碎碎念的要不要出去闯荡的时候,当《莫欺少年穷》歌名撞出来的时候。当新裤子乐队的改编的汪峰的《花火》唱到“所以我变了”的时候和他们自己的歌曲《生活因你而火热》,当刺猬乐队的《白日梦蓝》的响起来的时候,没想到据采访被队友总是吐槽不洗澡缺点多如星星的子健,一开口就跪了,清澈辽远的嗓音,就像未经社会历练的少年。跟他做程序猿邋遢的头发胖胖的样子形成了巨大的反差。打鼓的石璐真帅,女生的打鼓真帅。斯斯与帆的声音好干净,她俩在台上紧张的手抖,弹不了吉他的样子。当歌词出来的时候就好动人,好干净,太干净了。又是唱的对于外婆外公的改编自儿歌的,哎呀我又流泪了。还有痛仰乐队回来《西湖》。

    尤其是新裤子乐队的《生活因你而火热》这首,我想忍住(主要是旁边有人),轻轻的吐着气,但是眼泪它自己就跑出来。哈,搞我很不好意思啊,不过我还是忍不住。

    “我倒下后

    不敢回头

    不能再见的朋友

    有人堕落

    有人疯了

    有人随着风去了

    那些昙花一现的灿烂

    是爆炸的烟火”

    他们好厉害,他们做喜欢的乐队,也有中断坚持不下去,有队友离开,有生活所迫,去做广告去做程序员去做等等,而后又回到梦想出发的地方。《海龟先生》的歌曲很有哲学的意义,我觉得最后乐队比拼的不仅仅是个人情感的宣泄,而是社会层面的,和人生的了。尤其是海龟先生说的,为什么离去的人不是我,那些离去的人是不是更有价值?突然就大批的人在你面前消失。就已经达到了伤害后的“幸存者内疚症”

    他们的歌曲有延伸感,扩展到了更辽阔的高度。

    这是31支乐队的比拼,是比赛。

    刚开始感觉新裤子乐队 彭磊,看样子真不像玩乐队的,长得更像一个教书文弱先生,不过每次开场都要蹦一蹦哈哈

    九连真人,刚开始听到名字的时候觉得这个莫不是95后看玄幻小说毒害的,起了这个名字

    有瞬间灵感的神作,也更有日复一日的长期的坚持的爆发力。

    通过看《乐队的夏天》得到的经验是

    业务技术要强(坚持到最后都是实力的比拼,而不是最初的反差和手段)

    舞台表演要完整,而不是仅仅靠偶然的灵光(需要多多的经验积累,舞台演出经验、痛仰乐队、海龟先生、斯斯与帆)

    热情,表演的时候要自信要热情,享受舞台(新裤子乐队、click#15 乐队态度很重要)

  • 天道酬勤和蚂蚁搬家

    昨天和牡丹下山,在逛了n个地方后,我们找了一块靠近松月湖的凉快的小树林休息。我们坐着边聊边看风景,后来我注意到有一只蚂蚁扛着一只比它自身大四五倍的大虫子飞快的走动着。

    不一会儿走到了一根树枝前方,它拖动着虫子艰难的想翻过去。可是怎么也翻不过去,如果它把它的食物扔掉它就能很快的爬过去,可是拖动着虫子总是被绊住,它尝试了七八次就在那个小树枝的范围,无论怎样努力也拖动不过去。牡丹看着说:“我们就是上帝视角“,想到蚂蚁可以换个方向来个曲线绕过去,可是蚂蚁不知道,它继续尝试,终于决定稍稍绕一点弯,可是树枝相对于它来说还是有长,它还是需要翻过树枝,还是失败了。

    牡丹不忍心就轻轻的把拦在它面前的树枝给拿掉了。蚂蚁顺利的拖着食物过去了。它会感慨什么吗?

    我在想,天道酬勤是不是就是老天看我们就像蚂蚁,我们持之以恒的撞南墙撞了好多次,失败了好多次的继续撞南墙,最后老天也不忍心看下去了,就轻轻的把拦在我们面前的障碍给拿掉了。我们就恍若如神助直达目标。就像稻盛和夫在《活法》里面写的自己,绞尽脑汁的做实验,百思不得其解找不到合适的材料,终于某天他又思考着进实验室,突然被某个容器绊了一下,下意识一看脚下,发现了松香。他立即拿松香做起了实验,那么令人头痛的难题居然一下子就解决了!他就感慨道“看到我那么拼命的工作,那样苦苦思索,神都看不过去了,神可怜我,赋予了我智慧。我想事情只能这样来解释”。

    现在疫情很严重,我们都戴口罩😷,有的时候我觉得可能老天会看到我们戴着口罩,是不是就像我们看到仓鼠🐹可可爱爱的戴着口罩,严谨的戴着口罩,也许老天会放我们一条生路。当然我们的医生更伟大,全心全意,专心致志的研究疫苗,是不是老天也可以给他们启示呢?

    做事情就要全力以赴,认真的工作也会锤炼自己的性格。

  • 我为嘲笑17岁而抱歉

    上周六抄小道步行3.7公里下山去买洗发水牙膏,上山的时候爬不上来了。绕大路就需要6公里了。找了家水饺店。在微信群帮同事订了四份水饺,然后让老板娘帮我找了人,花了20块雇了一辆四座小面包车把我送上山,提溜着包装好的四盒水饺问了下司机大叔放在了后排座的中间。这时候遇到了你,你拎着大箱子放在了车厢内后方。上了车也坐在后排,你就自顾自的倒豆子似的讲话了。

    你对司机大叔说你打车打了俩小时都没打上车,才通过同学的电话联系到了大叔。大叔说可以坐公交车,你说从不坐公交车,都是打车,说五莲火车站到莒县是7块钱,坐大客车是15块钱。老家是莒县,现在住日照东港。是艺考生,刚从南京回来。

    司机大叔问:你为什么来松柏镇啊?你说有同学在这里。你后面回去济南考试。我拎着四盒水饺问现在疫情还可以考试吗?你说不是现场考试,你讲自己如果不是因为疫情就会在3月份出国了,你拿到了几个国家的音乐的证书,有东京大学的,有俄罗斯师范大学的等等。你又讲自己心情状态不好,感觉迷茫,也许10月份才能出国。司机大叔说现在疫情,国外特别严重现在都是留学的回国的。你没有接话,继续说你谈了个对象,但是又分手了,感觉心里空落落的。你说自己在唱歌完去后台的时候,有个女生一直问你要微信,要了五次,你终于同意给出了自己的微信号,某天,你和她走在小公园,她对你说:“你做我男朋友吧”然后你就答应了。可是好了一周,那个女生就告诉你不想玩了。“分手吧”,你很难受。再次觉得心里空落落的,觉得人生很无常,怎么会这样。隔着四份水饺的我搭话问你多大了,你说你是02年出生的,那个女生是97年的。然后看到窗外的山上,说自己喜欢在山上。不喜欢人群太吵闹。你去国外也觉得国外是幽静的。当然你还是觉得中国也挺好的。我和大叔盯着窗外忍住笑看着窗外。人和人的悲喜并不相通。司机大叔和我都在沉默着,我拍了拍司机的椅背说,大叔你不安慰安慰啊,司机大叔说不用安慰。好吧,司机大叔比我成熟,我说时间久了就好了,而且你和她谈了一周,这一周占你一年的多少时间,又占你一生的多少时间呢?时间会稀释掉一切的。下了车我就去酒店了,不知道司机会不会跟你聊些什么。

    后来回到我跟三个同事讲你的故事,高声的大笑,弯腰狠狠的嘲笑着,我在嘲笑02年出生的你所谓好了一周的爱情你的伤春悲秋,喜欢幽静的小山,就像嘲笑我的17岁,就像自己没有那么傻过自卑过暗恋一个没有说过话的人一样。也像嘲笑这个住了3个月的酒店周边3公里内都没有超市吧。就像你打车打了俩小时还打不到车。

    虽然这些你都不会知道,嘲笑完后,但17岁知道。

    17岁的我想着要出一趟远门,自己也去跑到济南去找姐姐。一个人独自出远门第一次坐火车。也和同一排的一个姐姐聊了一路,当时还把自己买的零食给周围的人吃,当然他们都没吃。当时那个在威海上学,济南转火车的姐姐还担心我被骗,让我下了火车赶紧和自己的姐姐联系,不要乱跟别人讲话和走。

    想必未来你也会游历四方,祝你远行顺利。

    我好像是为了背叛自己的17岁而深深的嘲笑忧伤的你。

    每个人的17岁都是哲学家。不去思考还能做什么呢?时而能上天入地,无所不能,时而颓废沮丧,无地自容

    我为嘲笑17岁而抱歉。

    小道景色
    山路小道
    风景如画

  • 如何理解多租户架构?(转)

      1.什么是多租户架构?
      2.多租户架构的优缺点?
      3.多租户架构的适用场景?

      让我们带着这几个问题进入下面的阅读。

    一、对多租户的理解

      多租户定义:多租户技术或称多重租赁技术,简称SaaS,是一种软件架构技术,是实现如何在多用户环境下(此处的多用户一般是面向企业用户)共用相同的系统或程序组件,并且可确保各用户间数据的隔离性。简单讲:在一台服务器上运行单个应用实例,它为多个租户(客户)提供服务。从定义中我们可以理解:多租户是一种架构,目的是为了让多用户环境下使用同一套程序,且保证用户间数据隔离。那么重点就很浅显易懂了,多租户的重点就是同一套程序下实现多用户数据的隔离。对于实现方式,我们下面会讨论到。

      在了解详细一点:在一个多租户的结构下,应用都是运行在同样的或者是一组服务器下,这种结构被称为“单实例”架构(Single Instance),单实例多租户。多个租户的数据是保存在相同位置,依靠对数据库分区来实现隔离操作。既然用户都在运行相同的应用实例,服务运行在服务供应商的服务器上,用户无法去进行定制化的操作,所以这对于对该产品有特殊需要定制化的客户就无法适用,所以多租户适合通用类需求的客户。那么缺点来了,多租户下无法实现用户的定制化操作。

      在翻阅多租户的资料时,还有一个名词与之相对应,那就是单租户SaaS架构(也被称作多实例架构(Multiple Instance))。单租户架构与多租户的区别在于,单租户是为每个客户单独创建各自的软件应用和支撑环境。单租户SaaS被广泛引用在客户需要支持定制化的应用场合,而这种定制或者是因为地域,抑或是他们需要更高的安全控制。通过单租户的模式,每个客户都有一份分别放在独立的服务器上的数据库和操作系统,或者使用强的安全措施进行隔离的虚拟网络环境中。因为本篇主要是讨论多租户,所以单租户的相关知识就简单了解一下,不做过多的阐述了。

    二、多租户数据隔离的三种方案

      在当下云计算时代,多租户技术在共用的数据中心以单一系统架构与服务提供多数客户端相同甚至可定制化的服务,并且仍可以保障客户的数据隔离。目前各种各样的云计算服务就是这类技术范畴,例如阿里云数据库服务(RDS)、阿里云服务器等等。

      多租户在数据存储上存在三种主要的方案,分别是:

      1. 独立数据库

      这是第一种方案,即一个租户一个数据库,这种方案的用户数据隔离级别最高,安全性最好,但成本较高。 
      优点: 
        为不同的租户提供独立的数据库,有助于简化数据模型的扩展设计,满足不同租户的独特需求;如果出现故障,恢复数据比较简单。 
      缺点: 
        增多了数据库的安装数量,随之带来维护成本和购置成本的增加。 
      这种方案与传统的一个客户、一套数据、一套部署类似,差别只在于软件统一部署在运营商那里。如果面对的是银行、医院等需要非常高数据隔离级别的租户,可以选择这种模式,提高租用的定价。如果定价较低,产品走低价路线,这种方案一般对运营商来说是无法承受的。

      2. 共享数据库,独立 Schema 
      这是第二种方案,即多个或所有租户共享Database,但是每个租户一个Schema(也可叫做一个user)。底层库比如是:DB2、ORACLE等,一个数据库下可以有多个SCHEMA 
      优点: 
        为安全性要求较高的租户提供了一定程度的逻辑数据隔离,并不是完全隔离;每个数据库可支持更多的租户数量。
      缺点: 
        如果出现故障,数据恢复比较困难,因为恢复数据库将牵涉到其他租户的数据; 
      如果需要跨租户统计数据,存在一定困难。

      3. 共享数据库,共享 Schema,共享数据表
      这是第三种方案,即租户共享同一个Database、同一个Schema,但在表中增加TenantID多租户的数据字段。这是共享程度最高、隔离级别最低的模式。 
      即每插入一条数据时都需要有一个客户的标识。这样才能在同一张表中区分出不同客户的数据。
      优点: 
        三种方案比较,第三种方案的维护和购置成本最低,允许每个数据库支持的租户数量最多。 
      缺点: 
        隔离级别最低,安全性最低,需要在设计开发时加大对安全的开发量; 数据备份和恢复最困难,需要逐表逐条备份和还原。

      如果希望以最少的服务器为最多的租户提供服务,并且租户接受牺牲隔离级别换取降低成本,这种方案最适合。 
        
      在SaaS实施过程中,有一个显著的考量点,就是如何对应用数据进行设计,以支持多租户,而这种设计的思路,是要在数据的共享安全隔离性能间取得平衡。

      因为我们用的底层库是MySQL,且要保证数据的完全隔离,所以用的方案属于第一种。独立数据库。因为MySQL下SCHEMA就是他的数据库名。所以每多服务一个用户,都需要新建一个数据库。如果是DB2或者是ORACLE的话,一个数据库下,可以采用独立的SCHEMA来进行数据隔离,这样会相对节省成本,且数据隔离的强度高。

    三、选择合理的实现模式 
      衡量三种模式主要考虑的因素是隔离还是共享

    成本角度因素 

        隔离性越好,设计和实现的难度和成本越高,初始成本越高。共享性越好,同一运营成本下支持的用户越多,运营成本越低。

      安全因素 

        要考虑业务和客户的安全方面的要求。安全性要求越高,越要倾向于隔离。

      从租户数量上考虑
        主要考虑下面一些因素 
        系统要支持多少租户?上百?上千还是上万?可能的租户越多,越倾向于共享。 
        平均每个租户要存储数据需要的空间大小。存贮的数据越多,越倾向于隔离。 
        每个租户的同时访问系统的最终用户数量。需要支持的越多,越倾向于隔离。 
        是否想针对每一租户提供附加的服务,例如数据的备份和恢复等。这方面的需求越多, 越倾向于隔离

      技术储备 
        共享性越高,对技术的要求越高。

      以上三部分内容分别针对开头的三个问题做了概要的阐述,文章中部分内容也是摘录自查阅的资料,实乃他人总结的非常好,所以就直接把轮子拿过来用了,旨在让你我更加了解多租户这种架构,还望勿喷!


    查阅资料如下:

       多租户和单租户SaaS的架构对比 http://blog.sina.com.cn/s/blog_a5ed66830102wddk.html
       数据层的多租户浅谈 https://www.ibm.com/developerworks/cn/java/j-lo-dataMultitenant/
       SaaS多租户数据隔离的三种方案 http://blog.csdn.net/yown/article/details/51288549

    转自:https://www.cnblogs.com/pingfan21/p/7478242.html

  • 大屏设计中echart 各种图形元素记录

     

    注:如果需要百度地图,需要百度账号生成apikey调用百度地图链接 

    下面列出的是利用echart开发数据大屏和管理驾驶舱所遇到的和值得记录下来的点。包含飞行运动轨迹,GPS百度地图和柱状图边距,文本倾斜显示,饼状图,异型图,世界地图,中国地图下钻地图,折线图,雷达图,云标签图,自动轮播效果等等

    0.Echart 数据

    X轴标题倾斜

    axisLabel:{

    Rotate:60 //倾斜角度

    }

    1、柱状体刚开始的距离

    xAxis: [{

        // boundaryGap: false,

    2、横向柱状图和纵向柱状图的区别,在于 纵向树状图

    yAxis:【type: ‘value’,】

    xAxis:【type: ‘category’,】 

    3、给X轴Y轴,加单位

    echarts柱状图的XY轴加单位的写法

    yAxis : [

            {

                type : ‘value’,

                axisLabel:{formatter:'{value} %’}

            }

    ],

    如果想控制百分比最大到100% 可添加

    yAxis : [

            {

                type : ‘value’,

                max:100,//Y轴最大值 不写的话自动调节

                axisLabel:{formatter:'{value} %’}

            }

        ],

    > max:100,//Y轴最大值 不写的话自动

    4、修改legend字体颜色

    修改legend字体颜色:

     legend: {

                    y:’55%’,

                    textStyle:{

                                fontSize: 18,//字体大小

                                color: ‘#ffffff’//字体颜色

                            },

                    data: []

                }

    修改x轴字体颜色:

    xAxis : [

              {

                      type : ‘category’,

                      data : [],

                      axisLabel: {

                                show: true,

                                textStyle: {

                                    color: ‘#ffffff’

                                }

                            }

                        }

                    ]

    修改y轴字体颜色:

    yAxis : [

                {

                       type : ‘value’,

                       name : ”,

                       axisLabel : {

                                textStyle: {

                                    color: ‘#ffffff’

                                }

                            }

                   }

            ]

    5、echart设置柱子之间的宽度,和柱子本身的宽度

            series : 

                  {

                     name:”,

                     type:’bar’,

                     barWidth:20,

                     barGap:’80%’,/*多个并排柱子设置柱子之间的间距*/

                     barCategoryGap:’50%’,/*多个并排柱子设置柱子之间的间距*/

                     data:[],

                     itemStyle: {

                         normal: {

                         barBorderRadius: false,

                             color: ‘#1E9FFF’,

                         }

                     }

                 }

    6、鼠标点击出现圆点放大

    7、柱体上有数据

    var labelOption = {

        normal: {

            show: true,

            position: ‘top’,

            align: ‘center’,

            formatter: ‘{c}’,

            fontSize: ‘100%’,

            rich: {

                // name: {

                // textBorderColor: ‘#fff’

                // }

            }

        }

    };

    orientation: portrait;/

    强制竖屏

    http://localhost:8080/cabin_portal_war_exploded/a/module/exclusive/showJspfl?dateStamp=201908&busType=%E5%85%A8%E9%99%A9%E7%B1%BB

    如何多个数据进行,ffarmat排序进行

    //数据进行push出来整个

    success: function (result) {

        $.each(result, function (index, item) {

            qddat1.push(item.channelName);

            qddat2.push(item.premiumBudget);

    // 拼接出新的数据,进行移除隐藏问题

            qddat3.push({

                “name”:item.channelName,

                “value”:item.premiumY,

                “premiumYRate”:item.premiumYRate,

                “premiumBudgetComplete”:item.premiumBudgetComplete

            });

        });

        var qddat4 = [];

        var qddat5 = [];

        var qddat6 = [], qdata7 = [], qdata8 = [];

        for (var i = qddat1.length – 1; i >= 0; i–) {

            qddat4.push(qddat1[i]);

            qddat5.push(qddat2[i]);

            qddat6.push(qddat3[i]);

           /* qdata7.push(qtbzf[i]);

            qdata8.push(qysdc[i]);*/

        }

        chart2(qddat4, qddat5, qddat6, qdata7, qdata8);

    },

    formatter: function (params) {

        var htmlStr = “”;

        for (var i = 0; i < params.length; i++) {

            if (params[i].seriesName == ‘实际’ ) {

                htmlStr += “同比增幅” + “:” + params[i].data.premiumYRate + “%” + “</br>”;

                htmlStr += “预算达成” + “:” + params[i].data.premiumBudgetComplete + “%” + “</br>”;

            }

        }

        console.log(htmlStr);

        return htmlStr;

    }

    8、设置网格背景 x轴和y轴内

    splitLine: {

    show: true,

    lineStyle: {

    color: ‘#1e2c41’, // 网格颜色

    width: 1, //网格线宽

    type: ‘solid’, //网格borderstyle

    shadowColor: ‘rgba(255, 255, 255, 0.5)’,

    shadowBlur: 10,

    shadowOffsetX:2,

    shadowOffsetY:1

    },

    },

    9.echart 设置yAxis.min y轴的数据

    min: function(value) {

    return value.min – 100;

    },

    max: function(value) {

        return parseInt(value.max +100);

    }

    10、去除指示线

    echarts中如何去除(修改)指示线

    tooltip:{

    axisPointer :{

    type: (‘line’ | ‘cross’ | ‘shadow’ | ‘none'(无)) ,

    lineStyle ->color: (填颜色值) ,

    type: (‘solid’ | ‘dotted’ | ‘dashed’, 树图还可以选:’curve’ | ‘broken’) ,

    width: (指示线宽) ,

    shadowColor : (指示线阴影颜色) ,

    shadowBlur: (大约0的数) ,

    shadowOffsetX : (横向偏移正右负左) ,

    shadowOffsetY : (纵向偏移正上负下)

    }

    }

    11、x轴y轴颜色

    xAxis: [{

    type: ‘category’,

    axisLine: { //x轴颜色

    lineStyle: {

    color: ‘#1e2c41’

    }

    },

    splitLine: { //网格颜色

    interval: 0,

    show: true,

    lineStyle: {

    color: ‘#1e2c41’,

    width: 1,

    type: ‘solid’,

    shadowColor: ‘rgba(255, 255, 255, 0.5)’,

    },

    },

    boundaryGap: 10,

    data: dataX

    // data: [‘2015’, ‘2016’, ‘2017’, ‘2018’, ‘2019’]

    }],

    12、tip总是显示

    13扩展效果

    圈层颜色修改

    color:’blue’,

    series: [{

    type: ‘effectScatter’,

    coordinateSystem: ‘geo’,

    zlevel: 2,

    rippleEffect: { //涟漪特效

    color:’white’,

    period: 4, //动画时间,值越小速度越快

    brushType: ‘stroke’, //波纹绘制方式 stroke, fill

    scale: 20, //波纹圆环最大限制,值越大波纹越大

    },

    label: {

    normal: {

    show: true,

    position: ‘right’, //显示位置

    offset: [5, 0], //偏移设置

    formatter: function(params) { //圆环显示文字

    return params.data.name;

    },

    fontSize: 13,

    },

    emphasis: {

    show: false

    }

    },

    // symbol: ‘circle’,

    showSymbol: false,

    hoverAnimation: true,

    itemStyle: {

    normal: {

    color: ‘#ec8000’, //设置图例颜色cricle边框

    borderWidth: 2,

    show: false,

    }

    },

    // symbol: ‘circle’, //折点设定为实心点

    symbolSize: function(val) {

    return 8; //圆环大小

    },

    data: res11

    },

    14、echart legend 用自定义图片

    当折线图时,legend默认时rect形式,如果需要改图例形状,可以自己设置legend的icon属性

    legend: {

        icon:’stack’

    },

    15、自定义每个图例样式:为data的每个对象修改icon属性

    legend:{

        show:true,

        orient:’horizontal’,

        borderColor:’#df3434′,

        borderWidth:2,

        data:[

            {

                name:’蒸发量’,

                textStyle:{

                    fontSize:12,

                    fontWeight:’bolder’,

                    color:’#cccccc’

                },

                icon:’stack’

            },

            {

                name:’降水量’,

                textStyle:{

                    fontSize:12,

                    fontWeight:’bolder’,

                    color:’#df3434′

                },

                icon:’pie’

            }

        ]

    }

    2、修改图例的图标为自定义图片

      首先我找了如下两张图片放在根目录下的images文件夹下

    legend:{

        show:true,

        orient:’horizontal’,

        borderColor:’#df3434′,

        borderWidth:2,

        data:[

            {

                name:’蒸发量’,

                textStyle:{

                    fontSize:12,

                    fontWeight:’bolder’,

                    color:’#cccccc’

                },

                icon:’image://./images/icon1.png’//格式为’image://+icon文件地址’,其中image::后的//不能省略

            },

            {

                name:’降水量’,

                textStyle:{

                    fontSize:12,

                    fontWeight:’bolder’,

                    icon:’image://./images/icon2.png’//格式为’image://+icon文件地址’,其中image::后的//不能省略

                },

                icon:’pie’

            }

        ]

    }

    legend:{

    itemWidth: 10 , //设置图片宽度为10

    itemHeight: 10 //设置图片高度为10

    }

    15、html页面地图图层,display:none; display:block

    type: ‘scatter’,

    coordinateSystem: ‘geo’, 出现数据被隐藏的情况。

    可以把地图的areaColor设置为有色进行检查

    itemStyle: {

    normal: {

    areaColor: ‘none’,

    borderWidth: ‘0px’,

    borderColor: ‘none’

    },

    emphasis: {

    areaColor: ‘none’

    }

    }

    数组状的字符串,转成对象数组

    eval(“(“+data[i].carLine+”)”);

    Ajax出现进入到error,解决方案是空白和json对象的属性值key值是没有双引号

    16、饼状图 指引线

        series : [

            {

                type: ‘pie’,

                radius : ‘65%’,

                center: [‘50%’, ‘50%’],

                selectedMode: ‘single’,

                data:[

                    {value:535, name: ‘荆州’},

                    {value:510, name: ‘兖州’},

                    {value:634, name: ‘益州’},

                    {value:735, name: ‘西凉’}

                ],

                itemStyle: {

                    emphasis: {

                        shadowBlur: 10,

                        shadowOffsetX: 0,

                        shadowColor: ‘rgba(0, 0, 0, 0.5)’

                    }

                },

                 label: {

                    normal: {

                        show:true,//标签隐藏

                        // position: ‘center’

                    },

                    emphasis: {

                        show: true,

                        textStyle: {

                            fontSize: ’30’,

                            fontWeight: ‘bold’

                        }

                    }

                },

                labelLine:{//指示线

                    show:true

                }

            }

        ]

    17、116.404, 39.915 百度地图设置中心点不起作用 echart

     缺少 Cannot read property ‘0’ of undefined

        at e.getLineCoords (echarts-3.8.5.min.js:22)

    地图的中心点在左上角

    只要先去show

    然后再生成

     Math.max.apply

    取出数组中最大数据

     Math.max.apply(null, [‘1′,’2′,’3.1′,’3.2’])

    < 3.2

     

    17、百度地图和echart结合,出现个个性地图设置

    地图版本要用v3.0 样式

    var bmap = myChart.getModel().getComponent(‘bmap’).getBMap();

    bmap.setMapStyleV2({

    styleId: ‘7479f0ec695598ad21b6ddfb3367d34f’

    });

    map.setViewport(pointsView)

    var points = [point1, point2,point3];

    var view = map.getViewport(eval(points));

    var mapZoom = view.zoom; 

    var centerPoint = view.center; 

    map.centerAndZoom(centerPoint,mapZoom);

    //异型图的加载,和边距。边距barCategoryGap和barWidth不能同时设置,且x轴的和数据个数要一致

    option = {

        xAxis: {

            data: [‘a’, ‘b’, ‘c’, ‘d’,’3′,’3′,’3′,’9′,’9′],

            axisTick: {show: false},

            axisLabel: {

                formatter: ‘barGap: \’-100%\”

            }

        },

        yAxis: {

            splitLine: {show: false}

        },

        animationDurationUpdate: 1200,

        series: [{

            type: ‘bar’,

            itemStyle: {

                normal: {

                    color: ‘#ddd’

                }

            },

            silent: true,

            // barWidth: 40,

            barGap: ‘-100%’, // Make series be overlap

            data: [60, 60, 60, 60, 60, 60, 60, 60],

            barCategoryGap:’20%’

        }, {

            type: ‘bar’,

            // barWidth: 40,

            z: 10,

            data: [45, 60, 13, 25, 60, 60, 60, 60],

            barCategoryGap:’20%’

        }]

    };

    var barGaps = [‘30%’, ‘-100%’];

    var loopIndex = 0;

    // setInterval(function () {

    //     var barGap = barGaps[loopIndex];

    //     myChart.setOption({

    //         xAxis: {

    //             axisLabel: {

    //                 formatter: ‘barGap: \” + barGap + ‘\”

    //             }

    //         },

    //         series: [{

    //             barGap: barGap

    //         }]

    //     });

    //     loopIndex = (loopIndex + 1) % barGaps.length;

    // }, 2000);

    18、多个设置轮播图 后台控制tooltip的时候会出现,多个tooltip直接删除div即可(利用打印来调试程序)

    19.echart运动线轨迹飞行图 3.2.2版本以上

    function convertDataLines(data) {

    var res = [];

    var toCoord = [‘111.461338’, ‘40.752298’];

    for (var i = 0; i < data.length; i++) {

    var dataItem = data[i];

    res.push(

    {

    coords: [

        dataItem.value,  // 起点

        toCoord   // 终点

    ]

    }

    );

    }

    return res;

    };

  • https页面引用外部http文件出现“Mixed Content”

    Mixed Content: The page at ‘https://www.XXXX.com/’ was loaded over HTTPS, but requested an insecure script ‘http://libs.baidu.com/jquery/1.4.2/jquery.min.js’. This request has been blocked; the content must be served over HTTPS.

    刚刚在看小说的时候,发现某小说网站控制台报了俩错误,查看了一下发现是因为,https安全机制页面,引入了baidu的jQuery的文件使用的是http导致的。
    http:超文本传输协议
    https:添加了加密及认证机制的http成为https,https要比http慢2-100倍

    解决方式:

    1、可以把外部资源下载到自己服务器上,统一使用https(如果使用的是外部分享邮箱之类的,这种能方法不可取)
    2、可以在页面头部加上

    会把http请求转化为https请求

    扩展

    Content-Security-Policy(CSP 内容安全政策)



    default-src 'self'; img-src https://*; child-src 'none';

    • 作用
    1. 使用白名单的方式告诉客户端(浏览器)允许加载和不允许加载的资源。
    2. 内容安全策略   (CSP) 是一个额外的安全层,用于检测并削弱某些特定类型的攻击,包括跨站脚本 (XSS) 和数据注入攻击等。无论是数据盗取、网站内容污染还是散发恶意软件,这些攻击都是主要的手段

    content 内部代码

    upgrade-insecure-requests: 指示 User Agent 将 HTTP 更改为 HTTPS,重写网址架构。 该指令适用于具有大量旧网址(需要重写)的网站。
    base-uri: 用于限制可在页面的 <base> 元素中显示的网址。
    child-src: 用于列出适用于工作线程和嵌入的帧内容的网址。例如:child-src https://youtube.com 将启用来自 YouTube(而非其他来源)的嵌入视频。 使用此指令替代已弃用的 frame-src 指令。
    connect-src: 用于限制可(通过 XHR、WebSockets 和 EventSource)连接的来源。
    font-src: 用于指定可提供网页字体的来源。Google 的网页字体可通过 font-src https://themes.googleusercontent.com 启用。
    form-action: 用于列出可从 <form> 标记提交的有效端点。
    frame-ancestors: 用于指定可嵌入当前页面的来源。此指令适用于 <frame>、<iframe>、<embed> 和 <applet> 标记。此指令不能在 <meta> 标记中使用,并仅适用于非 HTML 资源。
    frame-src: 已弃用。请改用 child-src。
    img-src: 用于定义可从中加载图像的来源。
    media-src: 用于限制允许传输视频和音频的来源。
    object-src: 可对 Flash 和其他插件进行控制。
    plugin-types: 用于限制页面可以调用的插件种类。
    report-uri: 用于指定在违反内容安全政策时浏览器向其发送报告的网址。此指令不能用于 <meta> 标记
    style-src: 是 script-src 版的样式表

    参考文档:
    https://developer.mozilla.org/zh-CN/docs/Web/HTTP/CSP