系统架构

一次商业web网站搭建的取舍过程

月盾
最近为公司官网重构搭建项目,把遇到的问题总结一下。此处的“商业”并没有多神秘,说的有点夸张而已,不过是为了区分公司项目与个人项目罢了。在这之前,我自己搭建过的网站也不下于10个,其中有个人网站也有公司网站,那时候搭建的网站也能上线运行,也没有过多的条件限制,所以不会有什么纠结的地方。 所以搭建一个网站并不复杂,复杂的是让其满足很多要求。有业务需求,有领导喜好,有同事对技术的接受度。业务说网站要支持SEO,支持IE浏览器,领导说我们要前后端分离,同事说我想使用主流新技术。最后经过几轮商讨下来自然是业务第一,领导第二,同事第三的优先级进行选择了。 要支持SEO和IE浏览器,只能是服务端渲染,可选的技术就只有SSR和模板引擎。SSR能选择的也就同事熟悉的Vue技术栈nuxtjs,但是其只能首屏渲染,并不能完全满足整站的SEO需求,而且开发体验并不怎么好,编译时间长,调试难,占用内存高等缺点。最后只能选择一把刷技术jQuery和node模板引擎。 选择了jQuery和模板引擎还不够,前端的模块化怎么做?目前前端模块化方案还是少的可怜,但并不是没有好的方案,只是在技术潮流下显得有点暗淡失色。比如requirejs,seajs,fis等都可以做模块化,~~最后在内心斗争一番后选择了layui自带的模块化(主要是使用了这一套UI)。layui本身是一套UI框架,为了尽量减少引入第三方js就直接使用其提供的模块化。~~原网站使用的是fis3也很好,但是如果继续使用的话等于又回去了,而且fis3也不再维护了。好在改造难度不大,只需要重新包装一下即可,其实fis3最后生成的代码也是类似于AMD/CMD规范。 技术方案确定后就剩开发环境工程问题了,由于一些老项目的缘故,前端同事都习惯了使用less开发css,也需要引入。然后是公司项目不同于个人项目具有服务器完全管理权限,通常使用NGINX代理,这样会对前端文件进行缓存,而网站发布频率较大,前端文件变化了还有缓存,所以又需要对前端文件进行哈希处理,这样就有了编译过程,同时还有node服务需要同时运行,所以使用了gulp工作流。后续补充:layui在开发过程中没啥问题,但是要上线时对静态文件哈希处理不好,最终也放弃了,回归了最原始的开发方式。 这样一顿操作下来也耗时一周才完成,远比搭建个人项目一天内费事多了。

Consul 入门教程

月盾
一、什么是服务发现 二、consul 简介 三、consul的几个概念 四、安装 Consul 五、运行 Consul Agent 六、集群成员 七、停止 Agent 八、注册服务 九、Consul 集群 十、健康检查 十一、KV Data 十二、Consul Web UI 十三、Docker下安装consul 作者:菲宇 来源:CSDN 原文:https://blog.csdn.net/bbwangj/article/details/81116505

服务发现:Zookeeper vs etcd vs Consul

月盾
【编者的话】本文对比了Zookeeper、etcd和Consul三种服务发现工具,探讨了最佳的服务发现解决方案,仅供参考。 如果使用预定义的端口,服务越多,发生冲突的可能性越大,毕竟,不可能有两个服务监听同一个端口。管理一个拥挤的比方说被几百个服务所使用的所有端口的列表,本身就是一个挑战,添加到该列表后,这些服务需要的数据库和数量会日益增多。因此我们应该部署无需指定端口的服务,并且让Docker为我们分配一个随机的端口。唯一的问题是我们需要发现端口号,并且让别人知道。 当我们开始在一个分布式系统上部署服务到其中一台服务器上时,事情会变得更加复杂,我们可以选择预先定义哪台服务器运行哪个服务的方式,但这会导致很多问题。我们应该尽我们所能尽量利用服务器资源,但是如果预先定义每个服务的部署位置,那么要实现尽量利用服务器资源是几乎不可能的。另一个问题是服务的自动伸缩将会非常困难,更不用说自动恢复了,比方说服务器故障。另一方面,如果我们将服务部署到某台只有最少数量的容器在运行的服务器上,我们需要添加IP地址到数据列表中,这些数据需要可以被发现并存储在某处。 当我们需要存储和发现一些与正在工作的服务相关的信息时,还有很多其他的例子。 为了能够定位服务,我们需要至少接下来的两个有用的步骤。 服务注册——该步骤存储的信息至少包括正在运行的服务的主机和端口信息 服务发现——该步骤允许其他用户可以发现在服务注册阶段存储的信息。 除了上述的步骤,我们还需要考虑其他方面。如果一个服务停止工作并部署/注册了一个新的服务实例,那么该服务是否应该注销呢?当有相同服务的多个副本时咋办?我们该如何做负载均衡呢?如果一个服务器宕机了咋办?所有这些问题都与注册和发现阶段紧密关联。现在,我们限定只在服务发现的范围里(常见的名字,围绕上述步骤)以及用于服务发现任务的工具,它们中的大多数采用了高可用的分布式键/值存储。 服务发现工具 服务发现工具的主要目标是用来服务查找和相互对话,为此该工具需要知道每个服务,这不是一个新概念,在Docker之前就已经存在很多类似的工具了,然而,容器带给了这些工具一个全新水平的需求。 服务发现背后的基本思想是对于服务的每一个新实例(或应用程序),能够识别当前环境和存储相关信息。存储的注册表信息本身通常采用键/值对的格式,由于服务发现经常用于分布式系统,所以要求这些信息可伸缩、支持容错和分布式集群中的所有节点。这种存储的主要用途是给所有感兴趣的各方提供最起码诸如服务IP地址和端口这样的信息,用于它们之间的相互通讯,这些数据还经常扩展到其它类型的信息服务发现工具倾向于提供某种形式的API,用于服务自身的注册以及服务信息的查找。 比方说我们有两个服务,一个是提供方,另一个是第一个服务的消费者,一旦部署了服务提供方,就需要在服务发现注册表中存储其信息。接着,当消费者试图访问服务提供者时,它首先查询服务注册表,使用获取到的IP地址和端口来调用服务提供者。为了与注册表中的服务提供方的具体实现解耦,我们常常采用某种代理服务。这样消费者总是向固定IP地址的代理请求信息,代理再依次使用服务发现来查找服务提供方信息并重定向请求,在本文中我们稍后通过反向代理来实现。现在重要的是要理解基于三种角色(服务消费者、提供者和代理)的服务发现流程。 服务发现工具要查找的是数据,至少我们应该能够找出服务在哪里?服务是否健康和可用?配置是什么样的?既然我们正在多台服务器上构建一个分布式系统,那么该工具需要足够健壮,保证其中一个节点的宕机不会危及数据,同时,每个节点应该有完全相同的数据副本,进一步地,我们希望能够以任何顺序启动服务、杀死服务或者替换服务的新版本,我们还应该能够重新配置服务并且查看到数据相应的变化。 让我们看一下一些常用的选项来完成我们上面设定的目标。 手动配置 大多数服务仍然是需要手动管理的,我们预先决定在何处部署服务、如何配置和希望不管什么原因,服务都将继续正常工作,直到天荒地老。这样的目标不是可以轻易达到的。部署第二个服务实例意味着我们需要启动全程的手动处理,我们需要引入一台新的服务器,或者找出哪一台服务器资源利用率较低,然后创建一个新的配置集并启动服务。情况或许会变得越来越复杂,比方说,硬件故障导致的手动管理下的反应时间变得很慢。可见性是另外一个痛点,我们知道什么是静态配置,毕竟是我们预先准备好的,然而,大多数的服务有很多动态生成的信息,这些信息不是轻易可见的,也没有一个单独的地方供我们在需要时参考这些数据。 反应时间会不可避免的变慢,鉴于存在许多需要手动处理的移动组件,故障恢复和监控也会变得非常难以管理。 尽管在过去或者当服务/服务器数量很少的时候有借口不做这项工作,随着服务发现工具的出现,这个借口已经不存在了。 Zookeeper Zookeeper是这种类型的项目中历史最悠久的之一,它起源于Hadoop,帮助在Hadoop集群中维护各种组件。它非常成熟、可靠,被许多大公司(YouTube、eBay、雅虎等)使用。其数据存储的格式类似于文件系统,如果运行在一个服务器集群中,Zookeper将跨所有节点共享配置状态,每个集群选举一个领袖,客户端可以连接到任何一台服务器获取数据。 Zookeeper的主要优势是其成熟、健壮以及丰富的特性,然而,它也有自己的缺点,其中采用Java开发以及复杂性是罪魁祸首。尽管Java在许多方面非常伟大,然后对于这种类型的工作还是太沉重了,Zookeeper使用Java以及相当数量的依赖使其对于资源竞争非常饥渴。因为上述的这些问题,Zookeeper变得非常复杂,维护它需要比我们期望从这种类型的应用程序中获得的收益更多的知识。这部分地是由于丰富的特性反而将其从优势转变为累赘。应用程序的特性功能越多,就会有越大的可能性不需要这些特性,因此,我们最终将会为这些不需要的特性付出复杂度方面的代价。 Zookeeper为其他项目相当大的改进铺平了道路,“大数据玩家“在使用它,因为没有更好的选择。今天,Zookeeper已经老态龙钟了,我们有了更好的选择。 etcd etcd是一个采用HTTP协议的健/值对存储系统,它是一个分布式和功能层次配置系统,可用于构建服务发现系统。其很容易部署、安装和使用,提供了可靠的数据持久化特性。它是安全的并且文档也十分齐全。 etcd比Zookeeper是比更好的选择,因为它很简单,然而,它需要搭配一些第三方工具才可以提供服务发现功能。 现在,我们有一个地方来存储服务相关信息,我们还需要一个工具可以自动发送信息给etcd。但在这之后,为什么我们还需要手动把数据发送给etcd呢?即使我们希望手动将信息发送给etcd,我们通常情况下也不会知道是什么信息。记住这一点,服务可能会被部署到一台运行最少数量容器的服务器上,并且随机分配一个端口。理想情况下,这个工具应该监视所有节点上的Docker容器,并且每当有新容器运行或者现有的一个容器停止的时候更新etcd,其中的一个可以帮助我们达成目标的工具就是Registrator。 Registrator Registrator通过检查容器在线或者停止运行状态自动注册和去注册服务,它目前支持etcd、Consul和SkyDNS 2。 Registrator与etcd是一个简单但是功能强大的组合,可以运行很多先进的技术。每当我们打开一个容器,所有数据将被存储在etcd并传播到集群中的所有节点。我们将决定什么信息是我们的。 上述的拼图游戏还缺少一块,我们需要一种方法来创建配置文件,与数据都存储在etcd,通过运行一些命令来创建这些配置文件。 Confd Confd是一个轻量级的配置管理工具,常见的用法是通过使用存储在etcd、consul和其他一些数据登记处的数据保持配置文件的最新状态,它也可以用来在配置文件改变时重新加载应用程序。换句话说,我们可以用存储在etcd(或者其他注册中心)的信息来重新配置所有服务。 对于etcd、Registrator和Confd组合的最后的思考 当etcd、Registrator和Confd结合时,可以获得一个简单而强大的方法来自动化操作我们所有的服务发现和需要的配置。这个组合还展示了“小”工具正确组合的有效性,这三个小东西可以如我们所愿正好完成我们需要达到的目标,若范围稍微小一些,我们将无法完成我们面前的目标,而另一方面如果他们设计时考虑到更大的范围,我们将引入不必要的复杂性和服务器资源开销。 在我们做出最后的判决之前,让我们看看另一个有相同目标的工具组合,毕竟,我们不应该满足于一些没有可替代方案的选择。 Consul Consul是强一致性的数据存储,使用gossip形成动态集群。它提供分级键/值存储方式,不仅可以存储数据,而且可以用于注册器件事各种任务,从发送数据改变通知到运行健康检查和自定义命令,具体如何取决于它们的输出。 与Zookeeper和etcd不一样,Consul内嵌实现了服务发现系统,所以这样就不需要构建自己的系统或使用第三方系统。这一发现系统除了上述提到的特性之外,还包括节点健康检查和运行在其上的服务。 Zookeeper和etcd只提供原始的键/值队存储,要求应用程序开发人员构建他们自己的系统提供服务发现功能。而Consul提供了一个内置的服务发现的框架。客户只需要注册服务并通过DNS或HTTP接口执行服务发现。其他两个工具需要一个亲手制作的解决方案或借助于第三方工具。 Consul为多种数据中心提供了开箱即用的原生支持,其中的gossip系统不仅可以工作在同一集群内部的各个节点,而且还可以跨数据中心工作。 Consul还有另一个不错的区别于其他工具的功能,它不仅可以用来发现已部署的服务以及其驻留的节点信息,还通过HTTP请求、TTLs(time-to-live)和自定义命令提供了易于扩展的健康检查特性。 Registrator Registrator有两个Consul协议,其中consulkv协议产生类似于etcd协议的结果。 除了通常的IP和端口存储在etcd或consulkv协议中之外,Registrator consul协议存储了更多的信息,我们可以得到服务运行节点的信息,以及服务ID和名称。我们也可以借助于一些额外的环境变量按照一定的标记存储额外的信息。 Consul-template confd可以像和etce搭配一样用于Consul,不过Consul有自己的模板服务,其更适配Consul。 通过从Consul获得的信息,Consul-template是一个非常方便的创建文件的途径,还有一个额外的好处就是在文件更新后可以运行任意命令,正如confd,Consul-template也可以使用 Go模板格式。 Consul健康检查、Web界面和数据中心 监控集群节点和服务的健康状态与测试和部署它们一样的重要。虽然我们应该向着拥有从来没有故障的稳定的环境努力,但我们也应该承认,随时会有意想不到的故障发生,时刻准备着采取相应的措施。例如我们可以监控内存使用情况,如果达到一定的阈值,那么迁移一些服务到集群中的另外一个节点,这将是在发生“灾难”前执行的一个预防措施。另一方面,并不是所有潜在的故障都可以被及时检测到并采取措施。单个服务可能会齿白,一个完整的节点也可能由于硬件故障而停止工作。在这种情况下我们应该准备尽快行动,例如一个节点替换为一个新的并迁移失败的服务。Consul有一个简单的、优雅的但功能强大的方式进行健康检查,当健康阀值达到一定数目时,帮助用户定义应该执行的操作。 如果用户Google搜索“etcd ui”或者“etec dashboard”时,用户可能看到只有几个可用的解决方案,可能会问为什么我们还没有介绍给用户,这个原因很简单,etcd只是键/值对存储,仅此而已。通过一个UI呈现数据没有太多的用处,因为我们可以很容易地通过etcdctl获得这些数据。这并不意味着etcd UI是无用的,但鉴于其有限的使用范围,它不会产生多大影响。 Consu不仅仅是一个简单的键/值对存储,正如我们已经看到的,除了存储简单的键/值对,它还有一个服务的概念以及所属的数据。它还可以执行健康检查,因此成为一个好的候选dashboard,在上面可以看到我们的节点的状态和运行的服务。最后,它支持了多数据中心的概念。所有这些特性的结合让我们从不同的角度看到引入dashboard的必要性。 通过Consul Web界面,用户可以查看所有的服务和节点、监控健康检查状态以及通过切换数据中心读取设置键/值对数据。 对于Consul、Registrator、Template、健康检查和Web UI的最终思考 Consul以及上述我们一起探讨的工具在很多情况下提供了比etcd更好的解决方案。这是从内心深处为了服务架构和发现而设计的方案,简单而强大。它提供了一个完整的同时不失简洁的解决方案,在许多情况下,这是最佳的服务发现以及满足健康检查需求的工具。 结论 所有这些工具都是基于相似的原则和架构,它们在节点上运行,需要仲裁来运行,并且都是强一致性的,都提供某种形式的键/值对存储。 Zookeeper是其中最老态龙钟的一个,使用年限显示出了其复杂性、资源利用和尽力达成的目标,它是为了与我们评估的其他工具所处的不同时代而设计的(即使它不是老得太多)。 etcd、Registrator和Confd是一个非常简单但非常强大的组合,可以解决大部分问题,如果不是全部满足服务发现需要的话。它还展示了我们可以通过组合非常简单和特定的工具来获得强大的服务发现能力,它们中的每一个都执行一个非常具体的任务,通过精心设计的API进行通讯,具备相对自治工作的能力,从架构和功能途径方面都是微服务方式。 Consul的不同之处在于无需第三方工具就可以原生支持多数据中心和健康检查,这并不意味着使用第三方工具不好。实际上,在这篇博客里我们通过选择那些表现更佳同时不会引入不必要的功能的的工具,尽力组合不同的工具。使用正确的工具可以获得最好的结果。如果工具引入了工作不需要的特性,那么工作效率反而会下降,另一方面,如果工具没有提供工作所需要的特性也是没有用的。Consul很好地权衡了权重,用尽量少的东西很好的达成了目标。 Consul使用gossip来传播集群信息的方式,使其比etcd更易于搭建,特别是对于大的数据中心。将存储数据作为服务的能力使其比etcd仅仅只有健/值对存储的特性更加完整、更有用(即使Consul也有该选项)。虽然我们可以在etcd中通过插入多个键来达成相同的目标,Consul的服务实现了一个更紧凑的结果,通常只需要一次查询就可以获得与服务相关的所有数据。除此之外,Registrator很好地实现了Consul的两个协议,使其合二为一,特别是添加Consul-template到了拼图中。Consul的Web UI更是锦上添花般地提供了服务和健康检查的可视化途径。 我不能说Consul是一个明确的赢家,而是与etcd相比其有一个轻微的优势。服务发现作为一个概念,以及作为工具都很新,我们可以期待在这一领域会有许多的变化。秉承开放的心态,大家可以对本文的建议持保留态度,尝试不同的工具然后做出自己的结论。

nodejs-go内存占比

月盾
同一台服务器上部署了两个功能差不多的服务,但是内存占比差距有点大。 go占14.7M nodejs占122.2M

gRPC负载均衡

月盾
gRPC是谷歌开发的跨语言(C, C++, Python, PHP, Nodejs, C#, Objective-C、Golang、Java)RPC框架,跨语言是指可以使用gRPC进行个语言之间的通信,例如:PHP可以对java进行远程调用。 在系统架构中,我们会把多个系统公共的模块拆分出来做成单独的服务,可以提供RESTful接口,也可以为了低延迟快速响应而提供RPC接口。如果选择的是gRPC,上线后发现多个系统都请求这个RPC服务提供者,而且流量很大的时候负载过高导致崩溃。为了降低负载和提高可用性,理所当然的要做集群,用nginx作为代理服务器,幸运的是nginx版本为1.13及以上支持了gRPC的负载均衡。那么请看以下配置: upstream grpcservice { server localhost:50051; server localhost:50052; } server { listen 8080 http2;#需要加http2 server_name localhost; location / { grpc_pass grpc://grpcservice;#以grpc为前缀 } grpc_connect_timeout 10; } 配置好nginx以后,客户端需要连接到localhost:8080来调用远程服务。 效果图: 可以看到,一次任务的多个请求两个RPC服务器都有输出,证明请求被分配到了两台服务器上。 虽然我们使用了两台服务器来保证性能和可用性,但是当其中一台服务器挂掉以后发现部分请求响应非常慢。 原因是服务器虽然宕机,但是请求还会发送到挂掉的服务器上,然后等待超时(默认1分钟),超时后再请求另外的服务器,重新请求以后可能还会再次分配到这台宕机的服务器。为了能加快响应,配置了grpc_connect_timeout选项,把时间设为5秒,再次测试,大概5秒后就能返回。如果设置更小的时间响应时间会更短。

过早的优化是万恶之源

月盾
“过早的优化是万恶之源”,这句话或多或少在哪听过,不过为什么优化也会带来问题,恐怕只有经历过的人才能理解其中的意义。 关于程序优化,产品优化这些词在开发工作中一定有经历过。某位程序员做事一丝不苟,对程序开发特别注重性能问题,花大量时间来优化某段代码。某位产品在提出需求的时候总是有一些目前用不到的功能,说是为了方便将来扩展。 那么实际工作中这种优化到底起到了什么作用?个人认为弊多于利。 问题一:过早引入新技术 甲同学在做一个员工日常工作内容列表的接口时,认为该接口会产生性能问题,将来数据增多的时候会有性能瓶颈,于是利用了某项缓存技术,觉得缓存一定比直接查数据库速度快,于是就引入了缓存数据库。把数据拉到缓存中,先从缓存中读取数据,没有数据的时候从数据库中读取放到缓存中。这个思路看似挺好,不过为了更新数据就设置过期时间为1天。上线后发现很多员工的日常工作内容一天内会有变化,就设置过期时间为半天,结果半天过期时间还是会有部分员工工作内容更新频繁。这时候就有些纠结了,到底是再降低过期时间还是单独更新某个员工的数据?如果选择降低过期时间会导致所有数据都要从数据库重新拉取,选择单独更新又要对各个更新几口进行修改来更新缓存。这期间不免要折腾几回来适应业务需求,而且容易造成各个业务过度依赖缓存,为了保持缓存数据一致性需要做很多工作,然而很多的工作目的并没有提高系统可用性。 问题二:过早优化数据库 有些同学在设计数据库的时候总喜欢多加些字段,为了方便未来使用,知道索引能加速查询,就使劲加索引,这基本属于不够成熟的思想,试问:等真正需要字段的时候加会晚吗?现在提前加了后面还能知道这个字段当初是准备怎么用来的吗?别的同学要加的时候发现已经有了一个类似的,这个字段到底有没有在用,不敢删又不敢用。索引加了一大堆本以为有积极作用,可不知道索引会占用空间,插入修改却慢了下来。 问题三:过早进行防范准备 在没有真实QPS数据和准确预估的情况,开发同学生生怕线上出现故障,要求多部署几台服务器做负载均衡,反正服务器多了也不会有问题。但是过多的服务器会带来其他方面的问题: 1、运维难度增加 2、企业成本增加 3、线上故障排查难度增加 针对性优化 在避免过度设计的情况下才进行针对性优化。性能问题的出现并不是经常性的,而是在某个访问高峰期出现,这时候影响范围还不是很大,但是该考虑进行优化了,如果是经常性突发并发数增加可以考虑缓存数据库。如果是日常单机承载能力高可以进行一定压力测试,评估并发压力增加合适的服务器。随着企业发展,数据量不断累积,此时数据库成为主要压力,此时对数据库索引,SQL进行优化,往往能有立竿见影的效果。 总结:没有针对性的性能优化,只是按照假象场景来设计,最后不但不能起到优化作用反而为后期优化带来累赘。

消息队列中参数的传递和存储

月盾
消息队列(MQ)在系统架构中发挥了重要作用,其主要作用有系统解耦,流量削峰,异步消息存储,分布式系统最终一致性等。 本文介绍的是消息系统中消息发布者和订阅者间参数如何约定和传递?实际应用场景中,一种消息的发布者和订阅者都有可能是多个,也就是多对多的关系,这样就形成了消息参数传递的复杂性,就算一开始参数有约定,大家都按照最初约定来开发,但不免开发过程中各端需求变化带来的修改。例如最开始为了实现系统解耦而引进了消息队列,此时消息参与者较少,只有一个发布者和一个订阅者,这种情况最简单(其实最简单还是直接调接口),双方简单约定了需要传递的参数。 { userId:123, userName:"阿离", age:23 } 后来订阅方又需要性别,地址,工作等信息,要求发布方加参数,这种要求也不过分,那就加好了。 { userId:123, userName:"阿离", age:23, gender:"女", address:"上海", job:"测试" } 再后来又有一个订阅者参与进了消息系统,要求在上述参数中再加“工作年限”参数,那么先不说什么了,加呗。 { userId:123, userName:"阿离", age:23, gender:"女", address:"上海", job:"测试", workingLife:4 } 再后来又有不同的订阅者参与进消息系统,每个订阅者都可能有自己的参数要求,参数类型不同,随着系统的发展,连发布者也有多个。这时最初的文档或约定已经不奏效了,总会有人不能及时更新文档导致约定不能成为约束,各自为政,比如“学历”参数有的人要求叫“硕士”,有人要叫“研究生”,总之是很难统一。如果要继续修改发布参数就会有很多冗余出现,参数类型不统一出现系统故障。 这时消息系统已经不是当初简单的两个发布者订阅者了,而是一群人在参数,所谓的众口难调。此时弊端已现,无论哪一方有变化都势必牵连所有人。所以看出的出这种消息参数传递有其不合理的地方,那么怎么传递更合理?此处的MQ最开始已经说了,是为了解耦而引进,说明该MQ是多个系统的衔接者,而多个系统终究还是系统,不是简单的前端和后端接口调用,例如某个前端A也是由自己的接口提供服务系统的,MQ不是直接为前端A提供参数的。应该是由前端A自己的服务端A订阅消息,前端A需要什么参数就有服务A查询需要的参数即可,前端B需要什么参数由服务B查询提供。而发布者A,发布者B等只需要传递关键参数userId即可,其他姓名,性别,年龄什么的都不需要传。 此时有人喜欢拿性能来说事,觉得应该由发布者一次性查出来传递并(作为日志)存储,订阅者不用每次都查询那么多相同参数,这是没理解MQ的意义,MQ应该是负责告诉其他人发布者做了什么,而不应该由订阅者决定发布者和MQ应该怎么做。因为既然是解耦系统,那么各个系统有不同需求,也可能有自己的数据库,就算是要记录日志也是由各系统自己负责存储,不应该由MQ来存储,如果所有参数都由发布者来查询那是不是会降低发布者的性能?就像上面的情况,MQ的参数随着各端要求不断增减,类型变化,最后存储的参数会变得乱七八糟,根本无法使用。 总结:消息队列应该只传递和存储关键信息,如ID就足够了,如果传递多余信息而造成不一致也会出现扯皮的事。各个订阅方自己负责其他参数查询和日志存储,否则就不是解耦了。

在docker中运行nodejs

月盾
首先看项目目录: 再看Dockerfile文件内容: # 以最新的node为基础镜像 FROM hub.c.163.com/library/node:latest # 工作目录为app WORKDIR /app # 拷贝当前所在项目根目录到app目录 COPY . /app # 全局安装pm2 RUN npm install pm2 -g EXPOSE 8081 #使用pm2启动nodejs,如果没有--no-daemon参数docker启动后就退出 CMD ["pm2-runtime", "dest/server.js", "--no-daemon"] # ENTRYPOINT ["node", "server.js"] 或者在Dockerfile中不添加CMD命令,可以在启动docker时执行命令: docker run --name ks -ti -p 8081:8081 kser:pm2 pm2-runtime dest/server.js 如果是后台运行的docker: docker run --name ks -d -p 8081:8081 kser:pm2 pm2-runtime dest/server.js -d选项是后台运行 需要进入到docker查看pm2运行情况 ,可以通过docker exec -ti ks /bin/sh查看运行的容器内部情况 要不要在docker中使用pm2运行nodejs pm2可以监控nodejs进程,如果进程挂了,可以自动重启 pm2可以设置启动的nodejs进程个数,提高服务性能 pm2可以设置日志记录 pm2可以设置端口,避免端口冲突 docker已经提供了自动重启的功能,可以这样启动nodejs服务: docker run --name ks -d --restart=always -p 8081:8081 kser:pm2 pm2-runtime dest/server.
为什么需要RPC,而不是简单的HTTP接口

为什么需要RPC,而不是简单的HTTP接口

月盾
目前有很多Java的RPC框架,有基于Json的,有基于XML,也有基于二进制对象的。 论复杂度,RPC框架肯定是高于简单的HTTP接口的。但毋庸置疑,HTTP接口由于受限于HTTP协议,需要带HTTP请求头,导致传输起来效率或者说安全性不如RPC。 现在问题是,遇到怎样的瓶颈了才需要或者说更适合用RPC(比如像阿里这么大的请求并发量,简单的HTTP肯定达不到预期),但问题是大家所在的公司,要有像阿里这么大的量是比较少的,甚至说1/1000的量可能都没有,那我们还需要使用RPC吗? 技术应该不是为了使用新技术而去使用,而应该是旧技术存在某些瓶颈,存在难以支撑或者扩展性越老越差等问题暴露出来之后,用新技术来进行解决。 那RPC最大的优点,或者说它相比简单的HTTP接口,它的优势、更适合它的业务场景是怎样呢?简单的HTTP又哪里不足,哪些场景明显不太适合呢? RPC=Remote Produce Call 是一种技术的概念名词. HTTP是一种协议,RPC可以通过HTTP来实现,也可以通过Socket自己实现一套协议来实现.所以楼主可以换一个问法,为何RPC还有除HTTP 之外的实现法,有何必要.毕竟除了HTTP实现外,私有协议不具备通用性.那么我想唯一的答案就在于HTTP不能满足其业务场景的地方,所以这个就要具体 案例具体分析了. http接口是在接口不多、系统与系统交互较少的情况下,解决信息孤岛初期常使用的一种通信手段;优点就是简单、直接、开发方便。利用现成的http协议 进行传输。但是如果是一个大型的网站,内部子系统较多、接口非常多的情况下,RPC框架的好处就显示出来了,首先就是长链接,不必每次通信都要像http 一样去3次握手什么的,减少了网络开销;其次就是RPC框架一般都有注册中心,有丰富的监控管理;发布、下线接口、动态扩展等,对调用方来说是无感知、统 一化的操作。第三个来说就是安全性。最后就是最近流行的服务化架构、服务化治理,RPC框架是一个强力的支撑。 rpc是一种概念,http也是rpc实现的一种方式。论复杂度,dubbo/hessian用起来是超级简单的。最近用dubbo和hessian比较多,http的几乎都被废弃了。 至于为什么用,其实很简单,业务场景不一样。我最早的单位所有的代码都在一个工程里,一次要发布几百m的代码。这种架构是非常有利于小程序的。但是我们为什么要应用rpc层呢,一个功能,一套代码下来不就解决了么?我觉得有几个好处: 1 灵活部署 2 解耦 至于为什么,当你用到的时候,你会体会。 系统做大了,肯定是需要做微服务的。 现在我们做电商就是这样,单独有一个订单系统,支付系统,商品系统,用户系统。都是分开部署,单独上线的。 但我们交互是用HTTP接口来交互的,我想转用RPC,但问题是我现在还没发现为什么需要用RPC,我还没能理解它的作用和意义。 用http交互其实就已经属于rpc了。 RPC:远程过程调用。RPC的核心并不在于使用什么协议。RPC的目的是让你在本地调用远程的方法,而对你来说这个调用是透明的,你并不知道这个调用的方法是部署哪里。通过RPC能解耦服务,这才是使用RPC的真正目的。RPC的原理主要用到了动态代理模式,至于http协议,只是传输协议而已。简单的实现可以参考spring remoting,复杂的实现可以参考dubbo。 RPC是一个软件结构概念,是构建分布式应用的理论基础。就好比为啥你家可以用到发电厂发出来的电?是因为电是可以传输的。至于用铜线还是用铁丝还是其他 种类的导线,也就是用http还是用其他协议的问题了。这个要看什么场景,对性能要求怎么样。比如在java中的最基本的就是RMI技术,它是java原 生的应用层分布式技术。我们可以肯定的是在传输性能方面,RMI的性能是优于HTTP的。那为啥很少用到这个技术?那是因为用这个有很多局限性,首先它要 保证传输的两端都要要用java实现,且两边需要有相同的对象类型和代理接口,不需要容器,但是加大了编程的难度,在应用内部的各个子系统之间还是会看到 他的身影,比如EJB就是基于rmi技术的。这就与目前的bs架构的软件大相径庭。用http必须要服务端位于http容器里面,这样减少了网络传输方面 的开发,只需要关注业务开发即可。所以在架构一个软件的时候,不能一定根据需求选定技术。 转自:https://www.cnblogs.com/winner-0715/p/5847638.html