关于服务端:程序员旅程中的思维与精神

本文作者:E、T、F最近碎片工夫有在看黑客与画家,看的过程中,有一个问题忽然冒了进去,一个程序员到底应该具备哪些思维,哪些精力才算领悟了真谛? 除了程序员,生存在咱们这个时代的每一个人又是否有借鉴之处呢?这里咱们先撇去技术层面的常识不谈,更宏观地看下这个问题。 陆奇曾在演讲中提到,入手去创造性地解决问题,代表了创造者一系列的外围行为和思维状态。 首先,肯定是要入手去做。在当今这个大数据生产时代,很多人仿佛“失去”了思考和学习的能力,被个性化举荐滋补投喂着“个人兴趣”,守着这一亩三分地再也没想着迈出去。 有些人通过浏览书籍,学了很多常识,听了很多情理,看了很多的世界,却仅止步于实践,将常识停留在记忆中,甚至缓缓消退。有时候,每当他人发表观点,忽然就好像唤醒了本人的记忆,说道:“诶?你不提我还真给忘了,这个我有印象,是那个啥啥啥吧,说的大略是balabala”。 再进一步的人,会在看的过程中,记录本人的笔记,就像当年学生时代很多人抄歌词一样,一是过后情绪到位了,让过后的本人大受触动;二是留个念想,待到多少年后一看,满是青春的回顾。但绝大多数人也仅仅停留在记录的这一道,没有更进一步。 然而,最难得的人呢,是那些看到这些常识内容后,会静下心来写出本人的想法,思考它在不同场景下是否依然实用,最终融汇到本人思维体系中的人,在这期间,同一份常识内容他们可能会重复回过头去细品确认,最终得出本人的见解并在后续的日常中付出实际。 当然,入手是须要勇气的,而且这往往要消耗大量的工夫,也须要咱们领有专一和急躁。尤其是在这个快生产时代,30分钟的干燥思考怎么抵得过30个欢快的短视频。 有时候就是这样,情理咱们都懂,但如果要付诸实践却困难重重,往往须要微小的信心和意志力。反过来看,那些真正能思考后付出实际,甚至养成习惯的人,就显得如许高大。 而后是创造性,咱们传统层面对翻新的了解始终是些高大上的货色,想着要从0到1发明创造个什么牛逼哄哄的货色。但创造性更多意味着不受解放,敢于摸索。从0到1是翻新,从1到1.1也是翻新。长于使用前人的智慧结晶才是小道。就像咱们感觉古人们都会作诗,但其实除了百里挑一的圣贤外,大多数也是因为他们过后“考试”要考这个,也是学习模拟名人名句,在某些场景下有感而发写出了一首首诗词歌赋。 另一方面,发明其实同设计和品尝是密不可分的。许多人其实都具备设计的能力,但真正有品尝的设计者却寥寥无几。设计作为需要和技术之间的桥梁,具备十分重要的位置。一个好的设计,能够一直满足需要,让技术施展更大的后劲。真正可能发明价值的人,就是那些真正有品尝的人,他们晓得什么是好的,明确什么是须要优化的,同时这些人往往很有态度,不做到卓越誓不罢休。 最初是要解决问题。解决问题不仅仅关乎技术层面,更关乎的是解决人的问题,满足人的需要。那如何能力挖掘和找到这些需要呢? 近些年比拟热的一个概念就是长于使用第一性原理。它最早是由古希腊哲学家亚里士多德提出,强调的是回归事物最根本的条件,将简单问题一直拆分进行因素解构剖析,从而找到实现目标最优门路的办法。那些最根本的事实或真谛是不须要再被推导、证实的,而其余的常识和实践都能够依据这些原理来构建和推导。 它能够帮忙咱们洞察事物的实质,更好地了解和挖掘需要,并促使人类一直演进和倒退。一个好的、更优的门路,能够让咱们瞻望更远的将来。 用一个可能不失当的例子,如果说“算法 + 数据结构 = 程序”。咱们看清了需要,能够认为找到了一种“解药”。但光有解决方案还不足以实现真正的改革,咱们还须要一种容器来承载和实现这个解决方案。这个容器就是发明的工具。 不同的时代,发明的工具有着显著的区别。随着人类社会的倒退和技术的提高,发明工具的模式和性能也在一直演变。 在现代,发明的工具次要是各种农业/手工艺工具。这些工具帮忙咱们进步了农作物的产量和效率,制作出精美的纺织品。 随着工业革命的到来,发明工具经验了革命性的变动。发电机、蒸汽机等工业设施的呈现,引领了新的工业时代。电力的使用使得生产力大幅晋升,机械化生产取代了手工劳动。这些发明工具极大地推动了工业化过程,并对社会产生了深远的影响。 而在当下这个时代,计算机、开发工具、编程语言等发明工具成为了重要的翻新驱动力。不论是在程序员开发的软件、Web利用、挪动利用中,还是最近大热的人工智能畛域,编程语言、开发框架、数据分析解决工具都施展着外围的作用。它们是当下创造者思考的基石,也是创造者进化和演变的外围环境。 驰名的心理学家、龙虾传授 乔丹·彼得森(Jordan Peterson)在之前的采访和演讲中也再三阐明了思考、写作、实际的重要性,甚至也强调了创作工具的位置。这种办法的底层逻辑其实也是在通知咱们:要思考,更要口头起来,用“正确的技术”去发现并解决问题。 实际上,不仅仅是对于黑客、程序员,对于画家,对于生存在这个时代的每一个人来说,都是相似的。当咱们的大脑进行思考时,命运的车轮也将停滞不前。如果咱们一味保持固化的观点和思维形式,终有一天也将变成那些咱们当初眼中的“老顽固”。 在这个大变革时代,咱们都须要敢于口头、长于思考,长于发现适宜本人的工具和办法,摸索翻新的边界。 本文公布自网易云音乐技术团队,文章未经受权禁止任何模式的转载。咱们长年招收各类技术岗位,如果你筹备换工作,又恰好喜爱云音乐,那就退出咱们 grp.music-fe(at)corp.netease.com!

September 25, 2023 · 1 min · jiezi

关于服务端:云音乐-GitOps-最佳实践

本文作者:kiloson近些年随着微服务、kubernetes 等技术的倒退,越来越多的厂商将单体架构的我的项目进行微服务化。然而随着原有我的项目的一直拆分,微服务的数量越来越多,部署的频率也越来越高,传统手工运维的劣势越发显著,效率低、部署品质没有保障。在云原生时代,是否有一种更加高效、稳固的部署形式,能够帮忙咱们改良部署和治理流程呢? 随着咱们对运维办法的调研,咱们发现 GitOps 可能很好的解决这些问题。GitOps 是一种合乎 DevOps 思维的运维形式,GitOps 以 Git 仓库作为惟一的事实起源,贮存申明式配置,并通过自动化工具实现环境和利用的自动化治理。Git 实现了版本控制、回滚、多人合作;申明式配置保障了配置的可读性和事务性;自动化部署打消了人为谬误,调高了部署效率和准确性,同时也保障了多环境的一致性。所以 GitOps + 申明式配置 可能很好的解决传统运维的痛点,进步部署效率,保障部署品质。 主机部署的缺点在传统的云主机部署模式下,通过工单创立运维申请,运维人员接管到工单后,通过 Ansible 等运维工具手动进行运维操作。这种形式在实际操作过程中遇到了许多问题,比方因为 Ansible 基于 SSH 下发文件,所以须要给每台机器配置 SSH;因为机器底层的异构,导致运维须要批改配置文件;或是因为脚本执行程序谬误,导致须要从新执行整个部署流程;手工操作,导致部署效率低,容易出错,无奈保障部署品质。 总的来说,云主机时代运维存在以下缺点: 环境不统一:须要step-by-step的编写脚本,构想指标环境中的各种状况,编写脚本时须要思考各种状况,比方机器是否曾经部署过,机器是否曾经配置过 SSH,机器是否曾经装置过依赖等等。并且脚本运行在不同环境中可能会有不同的后果。无事务保障:装置脚本不能被打断,如果中途遇到问题,服务可能处于不可用的中间状态。合作艰难:须要另行编写文档形容运维流程,如果多人同时保护一个脚本,合作往往十分艰难。回滚艰难:部署流程难以回滚,如果部署过程中呈现问题,须要手动执行逆向操作。权限管控与审核:通常运维须要指标主机的 root 权限,难以限度运维人员的权限,同时也难以对整个运维动作进行审核。云原生时代部署特点云原生的代表技术包含容器、服务网格、微服务、不可变基础设施和申明式API。云原生时代,微服务架构利用成为了支流。微服务架构的特点是将利用拆分成多个服务,每个服务都有本人的数据库和配置文件。每个微服务都是独立部署的,这大大提高了部署的频率,带来了新的挑战: 部署频繁:微服务利用被拆分成了多个服务,每个服务都须要独立部署,部署频率大大提高,须要更高的部署效率多正本:微服务通过扩容正本的形式来进步可用性,通常须要部署多正本,有时甚至须要部署数百个正本多环境:通常须要部署多个环境,比方开发环境、测试环境、预发环境和生产环境为满足以上需要,咱们须要一种全新的部署形式 其应该有较高的自动化程度,可能缩小人工参加,缩小出错,进步部署效率应该有良好的版本控制,不便回滚应该保障多环境统一,疾速在多个环境中拉起雷同的利用,不便测试和验证应该可能保障事务,防止部署过程中出错,导致服务不可用便于多人合作,进步部署效率什么是GitOps如果咱们须要本人实现一种满足需要的部署形式,咱们须要本人实现一个版本管理系统,这须要很大的工作量。然而事实上市面上曾经存在一个非常优良的版本管理系统,那就是 Git。能不能间接基于 Git 进行部署呢?咱们顺着这个思路持续调研基于 Git 的部署形式,最终发现了 GitOps,GitOps 可能很好的满足以上需要。那么到底什么是 GitOps 呢?GitOps 的要害是应用 Git 仓库贮存申明式配置,通过自动化工具将 Git 仓库中的配置利用到指标环境中。Git 仓库满足了对于版本治理、回滚、多人合作的需要,申明式配置满足了对于事务性、一致性的需要,而自动化工具进步了部署的自动化程度。所以 GitOps 可能很好的满足云原生时代的部署需要,是一种优良的部署形式。 Git仓库Git 仓库所有开发者都很相熟,它是一个分布式的版本控制系统,能够不便的进行版本治理和回滚。在 GitOps 中,Git 仓库作为惟一的事实起源,贮存所有的配置信息。应用 Git 仓库贮存配置,能够不便的进行版本治理和回滚,并且人造反对多人合作,同时批改配置文件。并且通过 Pull Request 提交批改,能够基于 Code Review 保障批改的正确性和品质。 申明式配置申明式配置应用配置文件间接形容零碎的冀望状态,使用者不须要思考执行流程和指标环境的差别,易于编写、了解、代码 review 和进行版本治理。并且申明式配置人造具备幂等性,能够反复利用而不会导致系统状态发生变化。具备事务性,要么全副利用胜利,要么什么都不做。以 Kubernetes 资源配置文件为例,使用者只须要指定 CPU 和 Memory 的大小,而不须要关怀底层执行细节和环境差别,保障了各个环境中部署统一。 ...

July 3, 2023 · 3 min · jiezi

关于服务端:云音乐-KubeCost-助力-FinOps-降本增效

本文作者:木心背景目前很多互联网公司都辞别了过来流量和业务迅猛增长的期间,进入了一个绝对稳固倒退的新阶段,业务增长可预期,老本管制成为了一个重要的议题。 在典型的互联网公司的老本组成中,IT 老本占比并不低,技术老本与人力老本的比例差不多在 1:2 ~ 1:2.5 左右, 升高 IT 老本显然能带来空谷传声的成果。 10 年来云计算、云原生、容器、Kubernetes、DevOps 等技术的高速倒退,使得 IT 老本的治理变得更加简单,也给老本的治理带来了更多的挑战。 目前大多数互联网公司,都基于 Kubernetes 实现资源的对立管控,实现对立的大池子,基于此的对立调度、调配、混合云等都是过来降本增效的重要伎俩。 在网易云音乐,咱们通过 2 年多的工夫实现了在线业务简直 100% 的容器化,通过超售、对立调度、混合云、混合部署等卓有成效的伎俩使得在线资源峰值利用率晋升到 50%+,每年为公司带来数千万的老本节俭。 然而,随着老本治理的深刻,咱们会发现,资源治理团队的压力会越来越大。因为研发一侧 DevOps 很容易获取资源,导致资源的增长也仍然十分地快,并且在流程上不足管控(因为实质上从 DevOps 角度心愿提效,传统的工单审批机制被摈弃)。 在云原生时代,随着资源池化之后,老本默认归属到了技术核心部门,业务部门对老本没有感知,同时不足无效的伎俩针将老本拆分到业务线,呈现了典型的 大账问题 ,导致无奈无效评估业务 ROI。 总结一下存在的变动与挑战: 去中心化:随着云和云原生利用的蓬勃发展,传统的集中式财务预算和 IT 管理模式在向以业务为导向的分布式决策转型动态变化:云上的动静环境和弹性能力导致费用随业务负载一直变动过剩节约:对资源和服务的即时拜访使翻新成为可能,但往往导致供给过剩这也就驱动了云音乐推动 FinOps 零碎建设,即通过数据驱动工程、财务、技术、业务团队合作,实现对老本的洞察、优化和经营,驱动建设更宽泛更多角色参加得经营责任制,帮助组织实现 ROI 的最大化。 云音乐的 FinOps 零碎目前还在外部应用,建设以及欠缺,后续咱们会择机开源进去,共享给社区。 在 FinOps 开源之前,咱们第一阶段先介绍下 "基于 Kubernetes 实现资源货币化,帮助推动大账拆分小账" 的组件 KubeCost。 KubeCostKubeCost 是一个基于 Kubernetes 的资源老本剖析工具,通过对 Kubernetes 集群资源的动态分析,将老本动静的调配到业务线,让业务线更加地关注老本,从而更好地利用资源,进步资源利用率,进步业务 ROI。 性能介绍1 反对多种计费计划比方包年包月、按量计费。 包年包月:目前大多数互联网企业都是依照包年包月的形式购买云资源,或者领有外部固定的专有资源池。在固定领有资源池的状况下,实质上企业须要依照业务峰值购买资源。天然须要依照业务峰值向业务摊派费用。按需计费:在固有资源池状况下,往往有很多低峰期的资源是较为节约的,为了进步资源利用率, 须要通过技术手段去充分利用低谷资源,比方在音乐场景,一些音频转码,音频特征分析等能够承受 T+1 的业务场景往往能够填补这些低谷。在这种场景下,须要依照业务理论应用的资源进行费用摊派,而不是依照常驻峰值。备注:SPOT 资源(比方为了疏导用户应用夜间资源,不同工夫点价格不同)临时不反对,后续会反对。 2 反对混合云多云计费除了应用外部固有资源,云音乐也在应用私有云资源,比方阿里云,AWS 等。针对这种混合云以及多云场景,须要反对不同环境资源采纳不同的计费单价。 ...

June 29, 2023 · 2 min · jiezi

关于服务端:云音乐-GitOps-最佳实践

作者:奇洛森近些年随着微服务、kubernetes 等技术的倒退,越来越多的厂商将单体架构的我的项目进行微服务化。然而随着原有我的项目的一直拆分,微服务的数量越来越多,部署的频率也越来越高,传统手工运维的劣势越发显著,效率低、部署品质没有保障。在云原生时代,是否有一种更加高效、稳固的部署形式,能够帮忙咱们改良部署和治理流程呢? 随着咱们对运维办法的调研,咱们发现 GitOps 可能很好的解决这些问题。GitOps 是一种合乎 DevOps 思维的运维形式,GitOps 以 Git 仓库作为惟一的事实起源,贮存申明式配置,并通过自动化工具实现环境和利用的自动化治理。Git 实现了版本控制、回滚、多人合作;申明式配置保障了配置的可读性和事务性;自动化部署打消了人为谬误,调高了部署效率和准确性,同时也保障了多环境的一致性。所以 GitOps + 申明式配置 可能很好的解决传统运维的痛点,进步部署效率,保障部署品质。 主机部署的缺点在传统的云主机部署模式下,通过工单创立运维申请,运维人员接管到工单后,通过 Ansible 等运维工具手动进行运维操作。这种形式在实际操作过程中遇到了许多问题,比方因为 Ansible 基于 SSH 下发文件,所以须要给每台机器配置 SSH;因为机器底层的异构,导致运维须要批改配置文件;或是因为脚本执行程序谬误,导致须要从新执行整个部署流程;手工操作,导致部署效率低,容易出错,无奈保障部署品质。 总的来说,云主机时代运维存在以下缺点: 环境不统一:须要step-by-step的编写脚本,构想指标环境中的各种状况,编写脚本时须要思考各种状况,比方机器是否曾经部署过,机器是否曾经配置过 SSH,机器是否曾经装置过依赖等等。并且脚本运行在不同环境中可能会有不同的后果。无事务保障:装置脚本不能被打断,如果中途遇到问题,服务可能处于不可用的中间状态。合作艰难:须要另行编写文档形容运维流程,如果多人同时保护一个脚本,合作往往十分艰难。回滚艰难:部署流程难以回滚,如果部署过程中呈现问题,须要手动执行逆向操作。权限管控与审核:通常运维须要指标主机的 root 权限,难以限度运维人员的权限,同时也难以对整个运维动作进行审核。云原生时代部署特点云原生的代表技术包含容器、服务网格、微服务、不可变基础设施和申明式API。云原生时代,微服务架构利用成为了支流。微服务架构的特点是将利用拆分成多个服务,每个服务都有本人的数据库和配置文件。每个微服务都是独立部署的,这大大提高了部署的频率,带来了新的挑战: 部署频繁:微服务利用被拆分成了多个服务,每个服务都须要独立部署,部署频率大大提高,须要更高的部署效率多正本:微服务通过扩容正本的形式来进步可用性,通常须要部署多正本,有时甚至须要部署数百个正本多环境:通常须要部署多个环境,比方开发环境、测试环境、预发环境和生产环境为满足以上需要,咱们须要一种全新的部署形式 其应该有较高的自动化程度,可能缩小人工参加,缩小出错,进步部署效率应该有良好的版本控制,不便回滚应该保障多环境统一,疾速在多个环境中拉起雷同的利用,不便测试和验证应该可能保障事务,防止部署过程中出错,导致服务不可用便于多人合作,进步部署效率什么是GitOps如果咱们须要本人实现一种满足需要的部署形式,咱们须要本人实现一个版本管理系统,这须要很大的工作量。然而事实上市面上曾经存在一个非常优良的版本管理系统,那就是 Git。能不能间接基于 Git 进行部署呢?咱们顺着这个思路持续调研基于 Git 的部署形式,最终发现了 GitOps,GitOps 可能很好的满足以上需要。那么到底什么是 GitOps 呢?GitOps 的要害是应用 Git 仓库贮存申明式配置,通过自动化工具将 Git 仓库中的配置利用到指标环境中。Git 仓库满足了对于版本治理、回滚、多人合作的需要,申明式配置满足了对于事务性、一致性的需要,而自动化工具进步了部署的自动化程度。所以 GitOps 可能很好的满足云原生时代的部署需要,是一种优良的部署形式。 Git仓库Git 仓库所有开发者都很相熟,它是一个分布式的版本控制系统,能够不便的进行版本治理和回滚。在 GitOps 中,Git 仓库作为惟一的事实起源,贮存所有的配置信息。应用 Git 仓库贮存配置,能够不便的进行版本治理和回滚,并且人造反对多人合作,同时批改配置文件。并且通过 Pull Request 提交批改,能够基于 Code Review 保障批改的正确性和品质。 申明式配置申明式配置应用配置文件间接形容零碎的冀望状态,使用者不须要思考执行流程和指标环境的差别,易于编写、了解、代码 review 和进行版本治理。并且申明式配置人造具备幂等性,能够反复利用而不会导致系统状态发生变化。具备事务性,要么全副利用胜利,要么什么都不做。以 Kubernetes 资源配置文件为例,使用者只须要指定 CPU 和 Memory 的大小,而不须要关怀底层执行细节和环境差别,保障了各个环境中部署统一。 ...

June 26, 2023 · 3 min · jiezi

关于服务端:百万在线大型游戏服务端开发用分布式扩能

课程简介本课程为机械工业出版社出版的图书《百万在线:大型游戏服务端开发》的电子版。 第一局部:学以致用(第1~4章),这部分介绍了Skynet引擎的应用办法及注意事项,以《球球大作战》的案例贯通其中,全面又详尽地分析了服务端结构设计、通信协议格局、数据表结构设计、断线重连等计划的核心技术。 第二局部:入木三分(第5~7章),这部分揭示了在多核时代采纳古代C++编写多线程TCP网络服务器的高效做法,以C++重写Skynet的案例贯通其中,应用大量图表,活泼翔实地形容Linux环境下的编程技术。 第三局部:各个击破(第8~11章),这部分列举了同步算法、热更新、防外挂等理论工程难题,并对其逐个击破,十分具备实用价值。只管本书以Skynet为例,但其同样实用于应用C++自研引擎的项目组,甚至是选用Erlang、Golang、Java的开发者。 关键词: C/C++/Lua | Socket、TCP/IP、Protobuf | Linux开发环境 | 多线程、数据库、分布式 | 高并发、内存透露、热更新 残缺版本,能够返回UWA学堂查看《百万在线:大型游戏服务端开发》。 第1.1节 咱们简略介绍了从玩家的角度来看,一款网络游戏大都会波及的流程,在此过程中,藏在幕后的服务端做了很多事件,那到底做了哪些?此服务端零碎又是如何开发的呢? 服务端程序要承载很多玩家,性能是必须要思考的问题。那么,1.2.4节的程序可能承载多少玩家同时在线呢? 1.3大节介绍服务端程序要承载很多玩家,性能是必须要思考的问题。 对于中大型商业游戏来说,往往呈现全服爆满的景象(如图1-12),1000多人的承载量远远不够。依据游戏厂商的新闻稿可知,2012年《梦幻西游》最高同时在线玩家达到了270多万人;2016年《王者光荣》的同时在线玩家超过了300万人。既然单个程序的承载量无限,最间接的方法就是开启多个程序来进步承载量。 图1-12 玩家爆满的游戏画面示意图 1.4.1 多个程序协同工作 图1-13展现了一种由多个程序独特合作的服务端模型,图中程序A和程序B别离解决客户端音讯,程序C作为中转站,负责程序A和程序B之间的通信。每个程序均独立运行,能够将其部署在不同的物理机上,造成人造的分布式系统。 图1-13 多过程服务端示意图 阐明:为对立术语,本书中“服务端”代表整个游戏服务端零碎;“程序”“过程”或“节点”代表一个操作系统过程;“物理机”代表服务器,涵盖了实体服务器和云服务器。 只管单个程序还是最多承载1000余人,然而只需开启1000个程序,并将其安排在数百台物理机上,实践上就能够撑持100万玩家,总承载量得以进步。 1.4.2 三个档次的交互 在分布式构造中,数据的交互被分成了三个档次,如表1-2所示。这就要求开发者能对游戏业务性能做出正当的切分。在游戏中,有些性能是强交互的,有些性能是弱交互的。以MMORPG为例,同一个场景的角色交互很强,每走一步都要让对方晓得,能够在同一个程序中解决同一个场景逻辑;不同场景的角色交互较弱,只有聊天、好友、公会这些性能须要交互,能够将同一个服务器的玩家都放在同一台物理机上解决;不同服务器的玩家交互很少,能够放到不同的物理机上。 表1-2 不同交互场景的区别 1.4.3 搭个简略的分布式服务端 实践归实践,实际出真知。实现1.2.4节的“走路”程序是场景服务器的一项次要性能,只管一个场景只能撑持数十人,只有多开几个场景就可能反对更多玩家。本节将实现图1-14所示的分布式程序,零碎中有两个“走路”程序,别离代表兽人村落和森林两个游戏场景,客户端间接连贯角色所在的场景,玩家只能看到所在场景的角色,不同场景角色能够全服聊天。该程序可分成三个步骤实现。 图1-14 简略的分布式系统 第一步,编写聊天服务器。聊天服务器其实是转发服务器,它治理着场景服务器发来的连贯(见代码1-5中的scenes),只有收到场景服务器的音讯,它就会播送给所有的场景服务器。聊天服务器会监听8010端口,期待场景服务器连贯。 代码1-5 聊天服务器(Node.js) (资源:Chapter1/3_chat_server.js) var net = require('net');var scenes = new Map();var server = net.createServer(function(socket){ scenes.set(socket, true) //新连贯 socket.on('data', function(data) { //收到数据 for (let s of scenes.keys()) { s.write(data); } });});server.listen(8010);第二步,让场景服务器(“走路”程序)连贯聊天服务器。场景服务器即是服务端又是客户端,对于玩家来说,它是服务端,对于聊天服务器来说,它又是客户端。在“走路”程序的根底上,让场景服务器连贯聊天服务器(见代码1-6中的net.connect),当场景服务器收到聊天服务器发来的数据时,就会把它一成不变地播送给客户端。 ...

June 11, 2022 · 1 min · jiezi

关于服务端:千亿级IM独立开发指南全球即时通讯全套代码4小时速成四

本文篇幅较长,共计6227字,预计浏览时长20-30min 这是《千亿级IM独立开发指南!寰球即时通讯全套代码4小时速成》的第四篇:《服务端搭建与总结》 系列文章可参考:《千亿级IM独立开发指南!寰球即时通讯全套代码4小时速成(一)》:Demo演示与IM设计《千亿级IM独立开发指南!寰球即时通讯全套代码4小时速成(二)》:UI设计与搭建《千亿级IM独立开发指南!寰球即时通讯全套代码4小时速成(三)》:APP 外部流程与逻辑 四、服务端搭建与总结这篇终于进入了最初的局部:服务端。随着这部分的实现,一个残缺的,可制撑持千亿级音讯的IM便白嫖实现!所以,咱们加一把劲,来看一下这最初的服务端局部。 1. 服务端选型服务端的开发,首当其冲,且也是最重要的,便是服务端的选型。依据前两篇的需要剖析和功能设计,咱们有三个突出的外围需要: 能与 RTM 服务端交互:这意味着云上曲率官网必须提供对应语言的Server 端 SDK反对 HTTP/HTTPS 以 GET 和 POST 的形式拜访能以简略且疾速的形式,开发咱们所需要的业务云上曲率 RTM 其实提供了很多不同的SDK用于客户与RTM,官网下面间接列出的有 Go、PHP、C++、Python、Java、C# 六种。其实还存在其余的暗藏款,比方 Node.js。 在这些SDK中,从简略和不便水平上而言,疾速开发有以下四个选项:● C++● Go● Python● Node.js 首先,因为Node.js SDK打算会有重大更新,以后 GitHub 上是较老版本,所以咱们暂不抉择。这也是Node.js SDK 成为暗藏款的外围起因。 而 Python 和 Go 对于 HTTP/HTTPS 来说,则算是经典候选。间接启动 HTTP 服务器,接入 RTM 对应语言的SDK,实现相干的业务代码即可。而咱们这里抉择C++。咱们抉择C++的起因有两点:一是在FPNN框架的加持下,C++开发者将不再须要去解决任何 HTTP/HTTPS 相干的反对,HTTP/HTTPS 的反对能够被齐全透明化。第二点就是,整个RTM服务零碎就是基于C++ FPNN的框架进行开发的,所以咱们能够更好地与RTM服务器进行交互。 尽管RTM服务端的C++ SDK是用 FPNN C++ SDK进行开发,但 FPNN C++ SDK 是FPNN 框架的特化子集,大部分状况下简直无需改变便可从FPNN C++ SDK改为由FPNN框架提供根底反对。这样咱们便可轻松实现开发需要。但接下来,咱们会采纳更加简略的操作! 2. FPNN 框架的配置首先从GitHub下面下载FPNN框架的最新发行版,目前是 1.1.3 版本。留神:FPNN 框架目前仅反对 CentOS、Ubuntu 和 MacOS 三个操作系统,WIndows 仅有 C++ Widnows SDK。C++ SDK 不含服务器和HTTP/HTTPS等性能反对。 ...

April 24, 2022 · 9 min · jiezi

关于服务端:服务API版本控制设计与实践

一、前言笔者曾负责vivo利用商店服务器开发,有幸见证利用商店从百万日活到几千万日活的倒退历程。利用商店客户端经验了大大小小上百个版本迭代后,服务端也在架构上实现了单体到服务集群、微服务降级。 上面次要聊一聊在业务疾速倒退过程中,产品一直迭代,服务端在兼容不同版本客户端的API遇到的问题的一些教训和心得。一方面让团队内童鞋对已有的一些设计思维有一个更彻底的了解,另一方面也是心愿能引起一些遇到相似场景同行的共鸣,提供解决思路。 二、通用解决方案利用商店客户端迭代十分频繁,公布新的APP版本的时候,势必导致呈现多版本,这样服务端就会导致多个不同的客户端申请。强制用户降级APP,可能会导致用户散失,因而采纳多版本共存就是必须的。以下是业界探讨过的的一些SOA服务API版本控制办法参考[1]。在理论开发中原则上离不开以下三个计划。 计划一:The Knot 无版本——即平台的API永远只有一个版本,所有的用户都必须应用最新的API,任何API的批改都会影响到平台所有的用户。(如下图1) 计划二:Point-to-Point——点对点,即平台的API版本自带版本号,用户依据本人的需要抉择应用对应的API,须要应用新的API个性,用户必须本人降级。(如下图2) 计划三:Compatible Versioning——兼容性版本控制,和The Knot一样,平台只有一个版本,然而最新版本须要兼容以前版本的API行为。(如下图3) (援用自:The Costs of Versioning an API) 简略剖析,The Knot只保护最新版本,对服务端而言保护有肯定简化了,然而要求服务使用者及时适配最新的版本,这种做法不太实用用户产品,目前外部服务比拟实用。Point-Point针对不同客户的版本提供独立的服务,当随着版本的减少开发和运维的保护老本会减少,这种在前面咱们面对“协定降级”的时候有应用。 计划三应该是最罕用的状况,服务端向后兼容。前面案例也次要采纳这种思维,具体的做法也是有很多种,会联合具体的业务场景应用不同策略,这个会是接下来探讨的重点。 三、具体业务场景面临的挑战和摸索3.1 The Knot 无版本和Point-to-Point模式的利用场景 上图是咱们利用商店迭代变动的一个缩影,业务倒退到肯定阶段面临以下挑战: 1)业务倒退后期,作为服务提供方,服务端不仅要撑持多个版本利用商店客户端,同时服务于软件侧的PC助手; 2)产品状态变动多样,服务端接口变更和保护面临多版本客户端兼容的挑战; 3)架构逻辑上,服务端采纳晚期传统架构,开发和保护老本比拟高;服务端与客户端进行交互的协定优化降级;以及服务拆分势在必行。 所以服务端协定、框架降级以及公共服务拆分是首要解决的方向。革新经验了两个过程: 阶段一新版本新的接口一律采纳新的JSON协定;已有性能接口进行兼容解决,依据客户端版本进行辨别,返回不同协定的格局内容。阶段二随着业务迭代,新的版本商店依赖的所有接口都实现了协定降级后,为了晋升服务的稳定性,旧的协定性能无奈显著晋升,一方面降级后端架构和框架,晋升开发效率和可维护性。同时拆分和独立新的工程,实现历史工程只提供给历史版本应用。咱们针对大流量高并发、以及根底服务场景比方首页、详情、下载进行独立服务独立拆分。同时也提取一些公共的外部RPC服务,比方获取利用详情、过滤服务等。 通过革新,服务端架构如上图所示。 1)至此Old-Service后续只用进行相应的保护工作即可,对应Point-to-Point版本。 2)外部的RPC服务因为只提供外部服务,服务端和客户端能够随时同步降级,只有保护最新的版本就能够,采纳The Knot模式。这里须要留神的是服务的降级须要留神放弃向下兼容,在扩大字段或者批改字段的时候须要特地小心,不然可能在服务降级的时候会引起客户端调用的异样。 3.2 Compatible Versioning:兼容性版本控制兼容性版本控制应该是最常见的版本控制形式,特地是在C/S架构当中,具体的兼容性版本不同的策略总结有API版本、客户端版本号、性能参数标记等。 场景一:API版本号管制 随着互联网倒退的,用户体验要求也是越来越高,产品模式也会随之每年有不一样的变动。除了防止审美疲劳外,也是在一直摸索如何晋升屏效、点击率和转化。就拿利用商店首页列表举例。 利用列表在状态上经验过繁多的利用双排 -> 单排  -\> 单排+交叉的布局。内容上也经验了不同商业化模式、人工排期到算法等演进。 每个版本接口外部逻辑变动是非常大的,有显著差别。如果只是简略在service层依据版本进行判断解决,会导致解决逻辑会变得异样简单,并且还可能导致对低版本产生影响。同时商店首页是非常重要的业务场景,联合危险思考,相似这样对场景,在接口URL上新增版本字段,不同对版本应用不同的值,在管制层依据不同的版本进行不同的解决逻辑会更加正当,简略无效。具体策略也有比方在URL上新增接口版本字段/{version}/index、申请头携带版本参数等。 场景二:客户端版本号管制 相似首页列表,商店的交叉Banner也经验了多个版本的迭代。如下图所示。这些交叉款式都是在不同版本下呈现的,在款式布局,反对跳转能力等方面各个版本的反对水平不一样,接口返回时须要进行相应的解决适配、过滤等解决。  这类场景如果采纳场景一的计划降级新的接口也可能解决,然而会存在大量反复代码,而且新增接口对于客户端接口革新、特地是一些接口门路会影响到大数据埋点统计,也是有比拟高的沟通和保护老本在外面。 为了晋升代码复用性。应用客户端版本号管制是首选思考策略。然而须要留神,如果只是简略的在代码层面依据客户端版本号进行判断,会存在以下问题须要思考: 1)代码层面会存在各种判断,造成的代码可读性差,有没有更加优雅的办法; 2)存在一个客观情况。那就是客户端的版本号是存在不确定性的。因为客户端采纳火车公布模式 参考[2],多版本并行开发,导致版本号存在变动、版本跳跃不间断的状况时有发生,也给服务端开发带来了不少困扰。 如何思考解决这些问题呢?其实对于不同的产品状态波及的一些资源或者产品模块自身呈现在不同的迭代周期,能够认为他们具备了版本或者工夫的属性。站在程序员视角,把某个资源反对对应的客户端版本作为这个资源对象的一个成员属性。每种资源具备这种属性后,也有相应的逻辑行为来对应成员办法---依据属性进行过滤。这样的设计赋予资源了属性和行为后,资源具备了对立的、灵便的过滤能力,而不再是简略的硬编码依据版本进行if-else判断。 有了计划后,施行起来就比拟容易了。开发分配资源ID,并且设置对应反对客户端版本范畴。过滤逻辑对立到资源对象。 代码层面能够将过滤逻辑对立封装到一个工具类(示例代码),在各个业务接口返回进行过滤。更加优雅的计划是建设对立的资源下层类,封装资源过滤办法,所有资源位的资源对象实现该下层类,对立在获取资源逻辑实现过滤能力。 场景三:新增性能标识参数 利用商店业务次要提供用户发现和下载新利用、更新手机已装置的利用。商店有增量更新能够减小更新包体积,因而也叫省流量更新,无效晋升用户体验。后期咱们应用开源的增量算法,然而发现该算法在局部机器合成拆分包会耗时很长,甚至引起crash。 于是项目组寻求更加高效拆分算法。相似在这些已有接口的进行性能加强的场景,除了提供新的API或者外部简略通过客户端版本判断进行扩大外,有没有更好的计划呢?因为除了这些计划已知的弊病外,须要从久远思考,比方后面提到的算法,后续还会不会存在降级的可能,下载接口会不会有更多能力的加强。 联合下面思考,在原来接口根底上新增标记参数字段,示意该申请收回的客户端反对的能力。为了后续扩大,字段类型为整数值,不只是简略的boolean,服务端通过位运算实现判断逻辑。客户端也解脱某个性能与版本的强一致性,不必去记录某个版本具备某种能力。 四、对于接口设计的更多思考最初补充一些踩过的坑和反思。服务端在提供接口时,不能仅仅关注接口的实现,更多的时候须要关注接口的应用方,他们应用的场景、调用机会等等。否则开发在对接口问题排查、保护破费的工夫会比理论开发的耗时要多上好几倍。 1)场景化:具体到什么是场景化呢,拿商店客户端的帮忙用户检测手机装置的利用版本是否最新的服务举例,检测机会是存在不同的场景的,比方用户启动、用户切换wlan环境、定时检测等。当须要进行精细化剖析,哪些申请是无效的,哪些会引起集中申请时,这个时候如果申请上没有场景辨别,那么剖析将无从下手。所以在与客户端沟通接口设计时,请带上场景这个因素。接口设计上可参考如/app/{scene}/upgrade,定义好各个场景名称,在门路上带上具体的场景,这样对线上不同起源申请量级、问题剖析都会有很大益处。 2)鉴权和服务隔离:除了场景须要思考外,接口调用在调配时做好记录和鉴权以及服务隔离。比方商店的局部接口服务不仅提供给客户端,同时也会提供给手机零碎利用调用。目前vivo上亿的存量用户体量,这里要非常小心,零碎利用的调用量管制不当,并发可比商店自身要大的多。首先后期与服务调用方评估沟通、做好设计,防止出问题。即便在出问题时,也要有机制可能疾速发现问题、可能剖析出问题的起源,升高问题带来的损失。 至此下面解决问题的思路,都与具体业务以及背景有肯定关系。随着技术一直迭代和倒退,在挪动端APP页面动态性,目前业界也有了更多高效的技术计划,比方谷歌的Flutter、Weex等。这些技术可能实现灵便扩大,多端对立,性能也可能靠近native。不仅缩小了客户端发版频次,也缩小了服务端兼容性解决老本。目前咱们vivo也有团队在应用和实际。 技术一直更迭,没有最好的计划,只有最适宜的计划。开发过程中不仅满足以后实现,更多的是思考到后续扩展性和可维护性。开发不能一味谋求高端技术,技术最终服务于业务,保持长期主义,效率至上。 五、参考资料1、The Costs of Versioning an API ...

November 29, 2021 · 1 min · jiezi

关于服务端:前端服务框架调研NextjsNuxtjsNestjsFastify

概述这次 Node.js 服务框架的调研将着点于各框架性能、申请流程的组织和染指形式,以对前端 Node.js 服务设计和对智联 Ada 架构改良提供参考,不过多关注具体实现。 最终选取了以下具备代表性的框架: Next.js、Nuxt.js:它们是别离与特定前端技术 React、Vue 绑定的前端利用开发框架,有肯定的相似性,能够放在一起进行调研比照。Nest.js:是“Angular 的服务端实现”,基于装璜器。能够应用任何兼容的 http 提供程序,如 Express、Fastify 替换底层内核。可用于 http、rpc、graphql 服务,对提供更多样的服务能力有肯定参考价值。Fastify:一个应用插件模式组织代码且反对并基于 schema 做了运行效率晋升的比拟纯正的偏底层的 web 框架。Next.js、Nuxt.js这两个框架的重心都在 Web 局部,对 UI 出现局部的代码的组织形式、服务器端渲染性能等提供了欠缺的反对。 Next.js:React Web 利用框架,调研版本为 12.0.x。Nuxt.js:Vue Web 利用框架,调研版本为 2.15.x。性能首先是路由局部: 页面路由: 雷同的是两者都遵循文件即路由的设计。默认以 pages 文件夹为入口,生成对应的路由构造,文件夹内的所有文件都会被当做路由入口文件,反对多层级,会依据层级生成路由地址。同时如果文件名为 index 则会被省略,即 /pages/users 和 /pages/users/index 文件对应的拜访地址都是 users。不同的是,依据依赖的前端框架的不同,生成的路由配置和实现不同: Next.js:因为 React 没有官网的路由实现,Next.js 做了本人的路由实现。Nuxt.js:基于 vue-router,在编译时会生成 vue-router 构造的路由配置,同时也反对子路由,路由文件同名的文件夹下的文件会变成子路由,如 article.js,article/a.js,article/b.js,a 和 b 就是 article 的子路由,可配合 <nuxt-child /> 组件进行子路由渲染。api 路由: Next.js:在 9.x 版本之后增加了此性能的反对,在 pages/api/ 文件夹下(为什么放在pages文件夹下有设计上的历史包袱)的文件会作为 api 失效,不会进入 React 前端路由中。命名规定雷同,pages/api/article/[id].js -> /api/article/123。其文件导出模块与页面路由导出不同,但不是重点。Nuxt.js:官网未提供反对,然而有其余实现路径,如应用框架的 serverMiddleware 能力。动静路由:两者都反对动静路由拜访,然而命名规定不同: ...

November 16, 2021 · 6 min · jiezi

关于服务端:论一个java服务端工程师的自我修养一编码篇

毕业以来也写过不少代码了,打算总结一下本人认为的"服务端工程师的自我涵养"爱护本人的身材哈哈哈哈,你认为我会讲什么,事实上这点是最重要的。毛主席讲: 身材是反动的成本,程序员们要学会爱护本人的身材啊。我之前在公司用的是笔记本,始终须要抬头,对本人的颈椎很不好,我很是放心本人得职业病,通过一番调研,我给本人搞了一个笔记本支架。我保温杯里早就泡上枸杞了。除此之外,还有久坐,久坐工夫长了,也对身材不好,我又给本人搞了一个手环(这里就不说是哪个手环了,省得人家说我打广告),揭示我久坐工夫长,站起来走一走。 除此之外就是锻炼身体了,毕业一年了,而后体重蹭蹭的往上涨,咱们以衰弱为美,尽管2020还都没过来,然而我的2021指标曾经定下来了,就是瘦回我一百三十斤的样。 URI和前后端协约、正文留神本文如不非凡阐明,均将API和URI视作同义语。URI应该怎么命名呢? 这是我刚开始学Java EE的第一个问题,那个时候命名大多还是遵循见名知义规定。命名大抵都是getXXinsert等等。起初理解到restful标准,就是用申请形式来表白对资源采取的动作,其实对资源的更新也就四种,也就是CRUD,新增对应post,R是读对应get,U是更新,D是删除。然而有了restful标准之后,在是微服务之后,咱们的接口大抵都是: /我的项目名/v1/表名/。而后一个典型的场景就是表名上面一个单词表白不了这个接口的作用该怎么办,再往下一层,有的时候这样会让URL很长,还是驼峰命名,还是下划线命名? /我的项目名/v1/表名/a/b/我的项目名/v1/表名/a_b/我的项目名/v1/表名/aB该如何抉择呢? 我感觉这个问题是通用的,于是就去找了Alibaba出品的《Java开发手册》嵩山版,嵩山版是目前最新的,有前后端API的协定。Alibaba出品的《Java开发手册》嵩山版这么形容: 【强制】前后端交互的 API,须要明确协定、域名、门路、申请办法、申请内容、状态码、响应体。 阐明: 1 协定:生产环境必须应用 HTTPS。 2 门路:每一个 API 需对应一个门路,示意 API 具体的申请地址: a 代表一种资源,只能为名词,举荐应用复数,不能为动词,申请办法曾经表白动作意义。 b URL 门路不能应用大写,单词如果须要分隔,对立应用下划线。 c 门路禁止携带示意申请内容类型的后缀,比方".json",".xml",通过 accept 头表白即可。 3 申请办法:对具体操作的定义,常见的申请办法如下: a GET:从服务器取出资源。 b POST:在服务器新建一个资源。 c PUT:在服务器更新资源。 d DELETE:从服务器删除资源。 咱们的问题解决了,抉择应该是/我的项目名/v1/表名/A_B,那我还是有问题: 为什么/我的项目名/v1/表名/aB被否决?为什么不是中划线、上划线?驼峰式的被否决的一个起因是在输出时要求输出大小写,减少输出难度,也容易输错,URL还对大小写敏感。那下划线还要用shift呢?惟一来说摈弃驼峰命名法的起因就是行业内不成文的常规,习惯上全用小写。URL门路有三种命名计划: 驼峰(行业内采纳的不多)下划线宰割(也称蛇形命名法,淘宝系采纳比拟多)中划线命名法(脊柱命名法, github,stackOverFlow采纳)我看知乎是既有脊柱命名也有蛇形命名,脊柱命名。每种命名代表不同的不同的含意吗? 是中划线,还是下划线,我感觉团队内对立就好,该当尽量避免太长。 API中的版本号如果你留心的话,会发现有的网站的API会带v1或v2。比方掘金: 如果你留心响应的话,咱们还能够从响应头中看出该网站应用的web服务器是哪一个。比方掘金: 可能你对一些出名的WEB服务器比方: Tomcat、Nginx,比拟相熟了。 那这个Tengine是什么鬼? Tengine是Nginx的改装版,齐全兼容Nginx。顺便提一下,Tengine有Nginx的教程,有趣味的同学能够看下。 那么问题来了,为什么API中要有版本号呢? 这是一种扩展性和复用性设计,假如你写了一个接口供他人调用,而后你实现了接口的设计,对外裸露进来,而后很快需要变更来了,你须要改变你的接口,然而又不想影响之前的调用者,这个是时候通常有两种计划: 向前兼容从新写一个个别状况下,程序员大多都会抉择本人从新写一个,毕竟一直的向前兼容会导致代码一直的收缩,不不便保护。从新写一个,那URI的命名呢,事实上我只改变了上一个接口的某个流程,从应用含意上他们能够是一个,这也就是引出了版本号的概念。咱们再举一个场景,就以地图类程序为例吧,高德地图公布了一些接口,许多程序也调用了,那么随着技术的倒退,高德地图发现有些接口能够更优雅,速度更快。那这个时候怎么办,间接降级旧的接口?到时候如果导致应用高德地图的零碎出了问题,那些零碎的设计者预计也是要骂娘的,事实上也无奈保障百分之百齐全兼容,要做到百分之兼容最好就是不改变,那我重写的借口呢? 你就别重名了,加个版本号吧。 简略而又实惠。 那如何优雅的加版本号又跟RestFul标准兼容呢? 一般来说有以下几种形式: ...

December 5, 2020 · 1 min · jiezi

关于服务端:活动回顾WebRTC服务端工程实践和优化探索

11月7日,即构和上海GDG技术社区联结举办了实时音视频技术云上技术分享专场,来自即构科技和Bilibili的资深技术专家进行了深度分享。大会吸引了泛滥开发人员交换、观看,并在流动过程中与分享嘉宾进行了热烈互动,上面咱们整顿了嘉宾们分享的核心内容,错过流动直播的小伙伴能够持续观看学习。 本文是即构科技黄开宁带来的主题为《WebRTC服务端工程实际和优化摸索》的技术分享。以下为次要的分享内容: 大家下午好,我是来自即构科技的黄开宁,目前在即构科技负责音视频、媒体服务器以及网关的研发和开发,次要是架构的设计和开发,心愿本次分享能让大家在WebRTC服务端实现或者我的项目选型时能带来一些思考。 接下来进入主题,明天的分享次要分为三个局部: 第一,WebRTC服务器架构介绍及设计思路; 第二,咱们开发一个服务器所须要的技术和面临的难点; 第三,QoS服务质量的实现及优化。 一、WebRTC服务器架构介绍和设计思路 咱们首先要想一下,为什么须要WebRTC服务器?WebRTC服务器它的作用是什么?在大家的认知外面,WebRTC是谷歌开发的一个我的项目或者是协定,是当初大家比拟相熟的一个点对点通信计划。点对点计划是指单方浏览器之间是间接互联的,如果咱们在多方会议的多方通话的状况下,咱们各个通话者之间都是直连的,没有通过第三方。 上面来大略看一下它的优劣势: 劣势 第一,简略。这个模型非常简单,点对点,没有通过两头的一些服务器。 第二,提早小。既然是直连的,咱们可能天经地义地认为两头除了这些路由节点之外,就没有其余中央会减少延时了。然而我前面加了一个问号,也就是说未必是这样的。相熟咱们国内运营商网络状况的都晓得,联通,挪动,电信之间的通信可能是不对称的,如果我是联通,你是挪动,咱们直连的话,提早未必是小的,这个就是我加了一个问号的起因。 第三,端对端带宽适应。这个指的是WebRTC能够依据会话者之间的网络状况、带宽状况进行适应。比方当你的接管带宽不够时,我能够升高上行编码码率来适应你,从而达到一个更好的通话成果。 劣势 第一,连通性能差。点对点之间,因为所有的网络不是在一个防火墙后,咱们可能须要打洞,甚至有一些防火墙十分严格的话,咱们连打洞都没方法实现,这会极大的影响服务的连通性。咱们首先要发现对方,而后要打洞,如果打洞不胜利,还须要通过直达服务器来进行媒体的传输,这个过程可能会快则几秒钟,慢则几分钟。也就是说咱们从会话开始到单方建设通信,整个过程是非常复杂、消耗十分长的工夫。 第二,带宽占用高。所有的与会者是直连的,带来的一个问题是,如果我要看到其余所有人的视频,那么每个人都须要推一路流给我。同样的,其他人也是须要接管除他以外的所有流,这时候我的上行带宽占用是十分高的。在视频会议场景下,少则十几多则二十几个人,当初几百个人的会议也是很常见的。依照咱们现行的带宽,是达不到的。 第三,编解码压力大。既然每个人的流要独自发送给其余与会者,那么也要独自编解码,要发送N路就要编N路,并且编解码压力是十分大的,不仅挪动端没方法接受,甚至咱们的PC端也是没方法接受的,这是它很大的一个劣势。 在咱们理论的利用场景上,如果没有服务器,那么咱们也没方法进行录制,无奈实现视频回播、鉴黄以及CDN散发等性能。综合思考,咱们就会发现点对点计划可能并没有很好的满足咱们以后理论的利用需要。 所以这里就要引入一个服务器计划架构,依据方才提到的点对点三大劣势,咱们来重点看看新计划是如何解决的。 连通性 通常咱们的服务器都会架构在公网上,所以各个会话者是间接跟咱们在公网上的服务器建设连贯,省掉了打洞,间接一步到位。 网络带宽占用高 假如以后咱们这个会议有四方会话,那我的与会者有三路,我只需发一路到服务器上,通过服务器把我这一路转发给其余三路的与会者就能够了,不须要再去多发两路,这样我的上行带宽就从本来的三路变成了一路了;而接收端,引入MCU的概念,为了节俭上行带宽,咱们能够将这三路混流,再转发给我,那么我的上行也只有一路。 编解码压力小 通过优化架构带宽,编解码从原来的N路变成一路,也同步缓解了编解码压力。 既然服务器能更好的满足咱们的理论利用,那么WebRTC服务器应该怎么进行架构设计呢?开发WebRTC服务器须要哪些技术以及可能会面临哪些难点?WebRTC服务端QoS(服务质量)的实现及优化有哪些重点要留神的? 篇幅关系,对于《WebRTC服务端工程实际和优化摸索》的残缺内容,大家能够通过咱们的流动材料包获取,材料包中还有视频回放、演讲PPT等材料。申请流动材料包链接https://www.wjx.top/m/9757900...。

November 19, 2020 · 1 min · jiezi

前后端开发数据大小限制

背景编程过程中在存储用户数据的时候,会遇到数据存储大小的限制。经常遇到的限制可以分为:用户侧、服务端、数据库三个方面,按照流程可以划分为5个阶段,如图所示。作为开发人员,需要了解这些限制,避免撞墙。 第一道墙-client:浏览器限制用户通过http请求提交数据,http请求本身是没有数据大小的限制,但是浏览器对URI的长度进行了限制。 浏览器限制的是URI长度,而不是你的请求参数浏览器限制大小(字符)IE2083Chrome8182curl8167汉字字符:在utf-8编码格式中,3个字节,在gbk编码中,2个字节,英文就一个字符一个字节超过限制长度就会返回错误码414 第二道墙-server:服务端限制服务端对于数据的处理能力不同,对于提交的数据限制能力也不同,不同服务器对请求的限制不同,会存在两个方面的限制: URI长度限制(以Node为例)数据包大小限制(以post请求为例)NodeNode对URI的大小有一定的大小限制, 最大值8kb(8 * 1024),一般情况下,不会触发这个限制,如果程序想单独限制一个大小,通过中间件限制下就行了 req.on('data', function(chunk){ received += chunk.length; if (received > bytes) req.destroy();});如果想修改最大的大小,只能去改变源码文件 http_parser.h 了 POST服务器限制大小(字符)apache8192IIS16384nginx8kb附加:get请求是幂等操作,所以可以用缓存来处理,post请求不是幂等的,所以无法应用缓存 第二道墙-数据库代理:DBProxy线上环境会部署几个数据库,通常情况下,会使用DBProxy进行代理,实现负载均衡、IP地址过滤、数据库分表等操作。常见的数据库代理mycat/mybuh/dbproxy等。不同的数据库代理默认的数据大小不同,比如有的公司,DBProxy的代理设置大小最大为150kb。 第三道墙-max_allowed_packet在实际读写数据库的时候,数据库本身会有容量限制,mysql中max_allow_packet,就是第三道墙。max_allow_pocket是数据库对于单个数据包的大小限制。 参数大小默认大小64M(v >= 8.0.3)/4M最大值1G第四道墙-数据库本身大小限制每一条数据在数据库中都有对应的字段对应,而每一个字段会有对应的大小限制,所以在写入数据库的时候就有对应的大小限制。下面以mysql数据库为例说明一下:mysql的数据库类型分为五类:数字类型、日期类型、字符串类型,特殊类型、JSON类型 数字类型类型存储(位)无符号范围有符号范围默认值TINYINT1-128~1270~255SMALLINT2-32768~327670~65535MEDIUMINT3-8388608~83886070~16777215INT4-2147483648~21474836470~4294967295BIGINT8-2的63方~2的63方-10~2的64方-1注意⚠️:超过范围怎么处理? 在严格模式下,会直接报错在非严格模式下,会显示范围的边界,比如要存储9223372036854775808的值,会显示9223372036854775807,因为有符号整数最大值为9223372036854775807假如就是想显示这样的值怎么办? 将值变为有符号的,或者使用字符串。其他基本的数据类型和大小,在这里就不赘述了查看详情 JSON类型对于JSON数据类型,可以通过JSON_STORAGE_SIZE,获取可以存储的JSON数据的大小 总结本文目的不是让你记住这些限制,而是让你知道哪里有数据存储的限制,当出现问题的时候,知道去哪里排查。 参考文献JSON MERGE FUNCTION 对GET和POST的理解很形象 url长度限制 如何选择合适的数据库代理 美团点评的DBProxy 常见的Mysql数据库类型 长度限制 推荐一个面试 JSON_STORAGE_SIZE()

October 15, 2019 · 1 min · jiezi

MySQL单表数据不要超过500万行是经验数值还是黄金铁律

原文地址:梁桂钊的博客博客地址:http://blog.720ui.com 欢迎关注公众号:「服务端思维」。一群同频者,一起成长,一起精进,打破认知的局限性。 今天,探讨一个有趣的话题:MySQL 单表数据达到多少时才需要考虑分库分表?有人说 2000 万行,也有人说 500 万行。那么,你觉得这个数值多少才合适呢? 曾经在中国互联网技术圈广为流传着这么一个说法:MySQL 单表数据量大于 2000 万行,性能会明显下降。事实上,这个传闻据说最早起源于百度。具体情况大概是这样的,当年的 DBA 测试 MySQL性能时发现,当单表的量在 2000 万行量级的时候,SQL 操作的性能急剧下降,因此,结论由此而来。然后又据说百度的工程师流动到业界的其它公司,也带去了这个信息,所以,就在业界流传开这么一个说法。 再后来,阿里巴巴《Java 开发手册》提出单表行数超过 500 万行或者单表容量超过 2GB,才推荐进行分库分表。对此,有阿里的黄金铁律支撑,所以,很多人设计大数据存储时,多会以此为标准,进行分表操作。 那么,你觉得这个数值多少才合适呢?为什么不是 300 万行,或者是 800 万行,而是 500 万行?也许你会说这个可能就是阿里的最佳实战的数值吧?那么,问题又来了,这个数值是如何评估出来的呢?稍等片刻,请你小小思考一会儿。 事实上,这个数值和实际记录的条数无关,而与 MySQL 的配置以及机器的硬件有关。因为,MySQL 为了提高性能,会将表的索引装载到内存中。InnoDB buffer size 足够的情况下,其能完成全加载进内存,查询不会有问题。但是,当单表数据库到达某个量级的上限时,导致内存无法存储其索引,使得之后的 SQL 查询会产生磁盘 IO,从而导致性能下降。当然,这个还有具体的表结构的设计有关,最终导致的问题都是内存限制。这里,增加硬件配置,可能会带来立竿见影的性能提升哈。 那么,我对于分库分表的观点是,需要结合实际需求,不宜过度设计,在项目一开始不采用分库与分表设计,而是随着业务的增长,在无法继续优化的情况下,再考虑分库与分表提高系统的性能。对此,阿里巴巴《Java 开发手册》补充到:如果预计三年后的数据量根本达不到这个级别,请不要在创建表时就分库分表。那么,回到一开始的问题,你觉得这个数值多少才合适呢?我的建议是,根据自身的机器的情况综合评估,如果心里没有标准,那么暂时以 500 万行作为一个统一的标准,相对而言算是一个比较折中的数值。 写在末尾【服务端思维】:我们一起聊聊服务端核心技术,探讨一线互联网的项目架构与实战经验。让所有孤军奋战的研发人员都找到属于自己的圈子,一起交流、探讨。在这里,我们可以认知升级,连接顶级的技术大牛,连接优秀的思维方式,连接解决问题的最短路径,连接一切优秀的方法,打破认知的局限。 更多精彩文章,尽在「服务端思维」!

June 21, 2019 · 1 min · jiezi

老代码多=过度耦合=if else?阿里巴巴工程师这样捋直老代码

简介在业务开发的过程中,往往存在平台代码和业务代码耦合严重难以分离、业务和业务之间代码交织缺少拆解的现象。平台和业务代码交织导致不易修改,不同业务的代码交织增加了不同负责团队之间的协同成本。因此不论从代码质量,还是从团队协作的角度来看都严重地影响了开发团队之间的协同效率和开发效率,最终影响到了用户体验和业务发展。在闲鱼,商品发布和编辑功能也是如此。本文将以闲鱼商品发布和编辑功能的改造为例,向大家展示闲鱼是如何解决此类问题,从而更有效地协同更多团队更快更稳定地支撑各种业务的。发布编辑功能的升级改造为了实现上述目标,针对发布和编辑功能,进行了两轮升级。第一轮的目标在于“平台和业务分离、业务和业务隔离”;而第二轮将更进一步,目标在于“系统之间的解耦合,提升团队协同效率”。1.平台和业务分离,业务和业务隔离第一轮改造中,闲鱼将原先的商品发布和编辑功能从老应用中抽取到了新应用item。为了实现“平台和业务分离、业务和业务隔离”的目标,闲鱼自研了一套技术框架SWAK,具体请参考文章《业务代码解构利器–SWAK》,该文介绍了其设计思想和实现原理。接入SWAK框架后,平台逻辑和业务逻辑得到了分离,各个业务(如租房业务、免费送业务)之间的逻辑也不再耦合,而是变成package隔离(当然也是可以做成jar包隔离)。看一看改造后的应用情况示意图:我们根据发布和编辑的主干流程,抽象了17个SWAK扩展点。发布和编辑的主干流程主要就是对这些扩展点的编排。主干流程的编写并不需要考虑业务上怎么实现这些扩展点的。我们根据不同的业务(在SWAK里面更准确的表述是tag)对这些扩展点进行了各自的实现。根据这样的开发方式,我们可以把开发同学分成如下的两种角色:各业务开发人员。各业务开发人员主要是负责各个业务相关的代码。在item应用里面,业务同学需要维护其业务中和发布编辑相关的个性化业务逻辑。主干开发人员。主干的人员只需要维护主干的代码,尤其是扩展点的抽象。随着不同业务的不断接入,原先的扩展点也需要随之调整。如在之前的《业务代码解构利器–SWAK》一文中指出的一样,经过SWAK改造后,获得了如下的几个优点:代码逻辑清晰,可变和不可变一目了然。代码复用度变高。可变逻辑按照标签进行隔离,单个标签的实现不会影响到其他标签的实现,降低开发和测试成本。无论是按照“类型”分还是按照类目分,对应的开发和测试同学只需要关注对应的逻辑即可。新接手的开发人员能够快速理解,轻松上手。2.系统之间的解耦合,提升团队协同效率以租房为例——租房业务的同学需要在item应用中维护一套租房发布编辑相关的逻辑(如校验地小区数据、地铁数据真实性等);租房业务的同学还需要在详情应用的逻辑中维护一套和租房详情相关的逻辑(如展示地图,展示内部设施标签);租房业务的同学还需要在交易应用的逻辑中维护一套和租房交易相关的逻辑(如预约看房)等等。租房的同学不仅仅需要着手于自己的代码逻辑,还需要修改发布和编辑应用item、还需要修改详情应用,还需要修改交易应用……这种体验是非常糟糕的,有极大的可能性接手一个简单业务就需要修改和发布四五个应用。另一方面,从主干开发人员的角度来说,其应用不仅仅由自己或自己的小团队来维护,还有很多业务开发人员也在修改和发布此应用,且频率会远远超过主干开发任务的发布和部署频次(否则就是主干扩展点逻辑抽取得不好了)。这不利于整个应用的稳定性。A业务服务挂了,应该只影响A业务,而不应该影响主干。依此逻辑,最好能做到JVM隔离。本质上来说,第一轮改造完成了业务之间的解耦合,而第二轮则是系统之间的解耦合。康威定律告诉我们:Any organization that designs a system (defined more broadly here than just information systems) will inevitably produce a design whose structure is a copy of the organization’s communication structure.简而言之就是人员组织结构和系统结构之间的一致性。而完成系统之间的解耦合又恰恰是符合康威定律的。这一轮的改造,我们称之为“业务服务化”。业务服务化改造方案首先,我们把租房业务给单独抽取出来。原先的帖子和拍卖业务暂时没有独立的团队来予以维护(但也基本上没有什么新需求)因此暂时仍然放在主干应用中,时机合适将会和租房应用一样迁移出去。其次,租房业务通过远程服务的方式给主干应用提供服务。接口即是主干业务的提供的扩展点。由于现在是优先使用远程服务来连接主干应用和垂直应用,考虑到性能问题和安全问题,我们在扩展点的定义上也做了一些特殊的改动,后文会有针对性的详述。最后,SWAK框架做了一些改变以注册和调用远程服务。相对于本地服务,远程服务一般都是有超时、连接异常等问题。然而不同接口对于这些异常情况其处理策略也是截然不同的,后文“SWAK框架的针对性改进”会详述这些改动。通过这种方式,我们将主干应用和各业务应用彻底分离了。仍然以租房业务为例,租房团队负责开发和维护租房业务的独立应用rent。租房个性化的发布和编辑需求只需要开发和部署rent应用,而不必修改主干应用。主干应用只由主干团队的同学负责维护,不会被其他业务团队的同学所开发和部署,稳定性更加能得以保障。各业务系统独立开发、独立部署。这些都大幅地减少了不必要的沟通成本、提升协同效率。主干应用和业务应用是通过薄薄的一层接口所联系起来的,这层薄薄的接口都是“声明”:Interface定义、DO的定义和扩展点的默认Reduce策略定义。SWAK框架的针对性改进在之前的《业务代码解构利器–SWAK》一文中指出了,SWAK框架在应用启动的时候会通过各种注册器(registery)注册框架所需的信息。其中最重要的信息就是——业务tag及其对应的SWAK接口的实现类类名或者类实例instance。大多RPC框架都会在client端提供一个代理,代理掉内部的服务发现、保活、序列化、网络通信、反序列化等一系列操作。实际上,SWAK为了支持远程服务调用,只需要将业务tag,以及这些RPC的client的instance的对应关系注册进去就可以了。在闲鱼,RPC使用的是阿里通用的HSF框架(其类似的一个开源框架是Dubbo),这里的RPC的client就是HSF中的ConsumerBean。上文还提到了RPC调用会引入服务超时、连接异常的概念。为何要限制超时?是因为不能被单个应用的超时占据了主干应用的服务资源而引起其他服务和整个应用系统受到影响(如大多数线程阻塞在超时调用上)。无论是超时异常还是连接异常,在业务上也有对应的处理策略。在这里,我们定义了三种异常处理策略,通过在配置上设置相应的注解,SWAK框架会自动按照策略来处理异常。这三种策略是:IGNORE。 即,直接向上层抛出异常。SKIP。对于一个接口有多个tag执行的时候,本tag下该扩展点将跳过,继续执行其他tag下该扩展点的实现。DEFAULT_VALUE。返回默认值。默认值通过spel表达式进行设置。减少扩展点数量众所周知,RPC调用相对于本地调用会增加一部分的网络传输和序列化开销。对于单次调用来说,增加若干ms并没有什么问题,但对于调用10次、20次或更多,这笔开销就相当可观而应该引起重视了。为此,如何降低RPC开销,是一个必须要考虑的问题。最可靠的方法就是降低RPC的次数。在实践中我们发现,很多扩展点实际上都是获取业务配置。如在闲鱼业务中,“是否支持多库存”就是一种配置,如租房不支持多库存。这些业务配置项是由其业务形态所决定的,基本不会变动。因此可以将一组配置项打包一起调用,并且可以缓存下来,也可以直接由主干应用进行维护。在item应用里,这些配置项关系到主干的通用存储过程,目前由各业务方委托主干开发人员进行维护,目前配置在主干环境。可以通过阿里的动态配置平台(如Switch、Diamond)进行动态修改。另外我们对部分邻接的扩展点进行了合并。这些相邻扩展点之间的逻辑比较简单,且不会中断主流程。通过“配置型接口”和“邻接扩展点合并”这两种操作,我们将扩展点数量降低由17个降低到了6个。要注意的是,扩展点并不是越少越好。扩展点越少,越意味着“过度拟合”,可能会对后续业务变更无法适应导致主干需要大幅改动,因此需要在数量和扩展性之间找到一个平衡。另外值得一提的是,SWAK为配置型扩展点做了相应的小改造,并提供了查看当前配置型扩展点返回值的可视化界面。开发人员可以直观地了解当前各个业务的配置值。接口对象定义和细节设计在闲鱼,各种业务所需要存储的东西大同小异,从闲鱼的发布界面上来看就不难发现这一点,都是在基础对象(如标题、描述、图片)之外添加一些业务相关的数据,如拍卖业务中指定拍卖的开拍时间等信息,免费送业务中设置兑换币值,图书业务上设置条形码。即对一本图书进行拍卖当然也是允许的,这就出现了拍卖业务和图书业务叠加起来的复合型业务。对于主干应用开发人员来说,应该提供单个接口以支持所有业务类型,这样不用每次修改或者新增业务时都需要提供新接口。从稳定性的角度考虑,这样的要求很合理。既然是单个接口,那么DO的定义也应该统一。以商品DO为例,有以下三种方式:第一种是继承型结构,该结构不适用于业务叠加的情况。另外主干需要知晓各个业务的DO,每次业务修改或新增,主干都需要做变动。第二种是组合型结构,适用于业务叠加的情况,但同上一种一样,主干需要知晓各个业务的DO,每次业务修改或新增,主干也需要随之变动。第三种使用了Map类型类承载各个业务(biz)的定义类型。主干完全不知道、也不需要知道各个业务DO是如何组成的。这种方式具有最好的扩展性(有点无边界的扩展),也分离了主干应用和业务应用,最接近主干和业务分离的期望。最终我们选择了这一种。使用第三种的对象模型,以新加一种业务为例,其开发流程是:新业务服务端开发人员和客户端开发人员约定各业务的DO,这些DO会存储到bizMap字段。主干应用开发人员不需要了解这些约定。主干应用新增一份新业务的配置,实际上是新业务的识别信息和路由信息。新业务应用实现主干扩展点。联调、测试和上线。业务应用在扩展点返回值中设置需要更新的数据,由主干应用合并。业务应用不应该也不可以直接修改ItemDO,避免影响其他业务的处理逻辑。对于发布和编辑这种需要持久化存储的逻辑来说,必须要强控各业务对ItemDO的修改,否则理论上来说,各业务都有可能将所有的关键字段修改得面目全非。前面提到的“配置型接口”中,就有这样的配置——该业务是否可以修改属性字段、该业务是否可以修改描述字段等配置。总结闲鱼的商品发布和编辑功能基于SWAK框架经过了两次改造升级,第一次升级完成了平台和业务之间的解耦合以及业务和业务之间的解耦合,第二次升级通过平台和业务间使用RPC调用完成了系统和系统之间的解耦合。改造之后,能更有效地协同更多团队更快更稳定地支撑各种业务。SWAK框架依然在继续演进,如部分扩展点原则上可以通过并行处理或异步化处理来提升性能,但暂时还没有提供支持。在这两次改造中, 我们还在测试用例的采集、回放、监控告警等方面也有很多积累,敬请期待后续的文章分享。本文作者:闲鱼技术-紫思阅读原文本文为云栖社区原创内容,未经允许不得转载。

January 18, 2019 · 1 min · jiezi

由一个需求(广告每天弹一次)引发……

需求:用户每天第一次打开网页时弹出一条广告,并且可以选择关闭(默认当天不再弹出)和近期不再弹出。如何从头开始实现?弹出框这里用alert代替了,可以用插件如https://v3.bootcss.com/javascript/#popovers、http://element-cn.eleme.io/#/zh-CN/component/dialog等实现。Cookie前端设置方法document.cookie = “date="+new Date(); // 创建一条cookie,浏览器关闭后就清理document.cookie = “user=mine;expires=” + new Date().setDate(time.getDate() + 7); // 再创建一条cookie,7天后会自动清理console.log(document.cookie); // user=mine; date=Thu Dec 20 2018 15:26:45 GMT+0800 (中国标准时间) /自行封装setCookie、getCookie、removeCookiefunction setCookie(name, value, expires){ document.cookie = ${name}=${value};expires=${expires};}function getCookie(name){ let cookies = document.cookie.split(”; “); let values = []; for(var i=0; i<cookies.length; i++){ values = cookies[i].split("=”); if(values[0] === name){ return values[1]; } } return null;}function removeCookie(name){ setCookie(name, “”, “-1”);}服务端设置方法Http无状态协议,只能在同一个网站(包括多个页面)下获取,存储在客户端本地的一段信息,帮助我们存储信息获取信息。但是同样有风险:我们自己在浏览器上可以操作或者设置Cookie。const express = require(’express’)const cookieParser = require(‘cookie-parser’)const app = express()app.use(cookieParser())app.get(’/’, (req,res)=>{ res.send(‘欢迎’ + req.cookies.username); // 如果有username cookie则显示username,否则显示undefined})app.get(’/login’, (req,res)=>{ let username = req.query.username; res.cookie(‘username’,username,{maxAge:99999, httpOnly:true}); // maxAge:cookie的有效期;httpOnly设置为true,可以防止XSS攻击,只能被web serve访问,不能通过document.cookie获取 res.send(‘登录成功’);})app.listen(80);至此,需求的思路就可以实现// 选择关闭(默认当天不再弹出)if(!getCookie(“isAlert”)){ alert(“我是弹出层”); let now = new Date(); setCookie(“isAlert”, “不要弹出了”, new Date(now.getFullYear(), now.getMonth(), now.getDate(), “23”, “59”, “59”));}// 选择近期(7天)不再弹出if(!getCookie(“isAlert”)){ alert(“我是弹出层”); let now = new Date(); setCookie(“isAlert”, “不要弹出了”, new Date(now.getFullYear(), now.getMonth(), now.getDate()+7, “23”, “59”, “59”));}cookie的学习同一网站共享一套cookie,它的数量和大小有限,有过期时间,JS中可以用document.cookie设置和访问。实现一个记住用户名(30天)和密码(7天)的需求// html code<form action="#" id=“form”> <input type=“text” id=“user”> <input type=“password” id=“psd”> <input type=“submit” value=“提交”> <input type=“button” id=“clear” value=“清除”></form>// js code// setCookie getCookie removeCookie 前面以封装var user = document.getElementById(“user”);var psd = document.getElementById(“psd”);var clear = document.getElementById(“clear”);form.onsubmit = function(){ var userTime = new Date(); userTime.setDate(userTime.getDate() + 30); var psdTime = new Date(); psdTime.setDate(psdTime.getDate() + 7); setCookie(“user”, user.value, userTime); setCookie(“psd”, psd.value, psdTime);} user.value = getCookie(‘user’); psd.value = getCookie(‘psd’);clear.onclick = function () { removeCookie(‘user’); removeCookie(“psd”); user.value = “”; psd.value = “”;};jquery-cookie https://cdn.bootcss.com/jquery-cookie/1.4.0/jquery.cookie.min.js获取:$.cookie(“name”),不存在就返回undefined,不管你看到的是什么,它都是字符串设置、修改:$.cookie(“name”, “value”) 有效期至当前会话关闭$.cookie(“name”, “value”, {expires: 7, path: “/”}) 有效期7天,有效路径是"/“删除:$.cookie(“name”, null); $.cookie(“name”, “”, {expires: -1})小技巧怎么获取当天最后一秒的时间戳let now = new Date();let resDate = new Date(now.getFullYear(), now.getMonth(), now.getDate(), “23”, “59”, “59”).getTime();怎么获取N天后的此时function N(N){ let now = new Date(); now.setDate(now.getDate() + N); return now;}怎么获取本周最后一秒let now = new Date();let day = now.getDay() || 7;/ 隐藏知识点:星期天返回的是0,typeof(now.getDay()) == “number” ,0 == false。 实质是这段代码 day = now.getDay() === 0 ? 7 : now.getDay();*/let weekLastDate = now.getDate()+(7-day); // 如果以周六为最后一天,这里就是用6减let resWeek = new Date(now.getFullYear(), now.getMonth(), weekLastDate, “23”, “59”, “59”);获取年和月的最后一秒就很简单了。 ...

December 25, 2018 · 2 min · jiezi