• 关于

    处理语言如何看配置

    的搜索结果

回答

之前,我是把说明信息,放到了数据库中保存,在服务启动时,将配置表中的数据读取出来,然后在页面显示的时候使用。 其实这个数据,就是一个映射数据,怎么保存都可以,只要在启动时加载就行。 1、数据库保存 2、保存为.CSV文件,txt文件 3、XML 4、JSON也可以 ######一般我碰这种事就直接上spring,省事######回复 @feifeiguo : 例子没有,不过我一般就把这所有的配置做成一个bean,然后spring里把这个bean配成singleton,参数写好,就像写配置一样。######用Spring怎么管理这些?有没有例子什么的?######可以使用JSON啊,JSON存取也很方便啊,javascript和大部分开发语言都支持。######你看下面我给你的回复###### 引用来自“Adairs”的评论可以使用JSON啊,JSON存取也很方便啊,javascript和大部分开发语言都支持。 我刚刚补充了一下我的问题,我的意思是这样的,比如我在页面上新增一个用户的话,那么这个用户的性别肯定是在页面上选择为男或女,而在数据库中可能分别对应0或1,我的问题就是如何配置这些对应关系,当然,这个性别对应关系我肯定是知道的,但是我现在处理的问题是一个很泛的,也就是我在页面上呈现的时候我并不知道数据库中的char中的值在页面上如何呈现出来,那么就需要有一个配置文件来给我指明,如果用到了这个类中的这个属性,我就知道如何在页面上呈现这个类型的值。######xml可以写xsd文件,做xml的验证吧######yaml ,或者直接groovy 
kun坤 2020-06-09 11:56:04 0 浏览量 回答数 0

问题

Windows如何环境配置求前辈帮帮忙啊

刚申请了个试用 服务器 , Windows Server 2003 标准中文版 SP2 32位 己加固激活   1核处理器      内存1G       带宽3M    磁盘50G 我以为官方可以给试用云服务器作环境配置和...
3g210 2019-12-01 21:07:50 9717 浏览量 回答数 4

问题

基础语言百问-Python

基础语言百问-Python 软件界最近非常流行一句话“人生苦短,快用Python”,这就展示出了Python的特点,那就是快,当然这个快并不是指的Python运行快,毕竟是脚本语言,再怎样也快不过C语言和C++这样的底层语言,这里的快指的是...
薯条酱 2019-12-01 20:12:27 56807 浏览量 回答数 30

问题

[精品问答]Java一百问第一期

java之父高斯林,Java的缔造者。 而Java发展至今,使用者已占领市场七成。 动心者仍在观望,使用者“爱恨交加” 以下是为每一个java使用者整理的灵魂百问,大部分都是踩坑经验...
问问小秘 2019-12-01 21:51:20 791 浏览量 回答数 1

问题

Nginx性能为什么如此吊

Nginx性能为什么如此吊,Nginx性能为什么如此吊,Nginx性能为什么如此吊 (重要的事情说三遍)的性能为什么如此吊!!!         最近几年,web架构拥抱解耦的...
小柒2012 2019-12-01 21:20:47 15038 浏览量 回答数 3

问题

2018python技术问答集锦,希望能给喜欢python的同学一些帮助

小编发现问答专区中有很多人在问关于python的问题,小编把这些问题汇总一下,希望能给喜欢python的大家一些启示和帮助 本帖不定期更新,喜欢的可以收藏哦 python可能替代Java吗?感觉现在很多Java程序员都跑去学python。h...
技术小能手 2019-12-01 19:31:10 2040 浏览量 回答数 2

问题

【精品问答】Java技术1000问(1)

为了方便Java开发者快速找到相关技术问题和答案,开发者社区策划了Java技术1000问内容,包含最基础的如何学Java、实践中遇到的技术问题、RocketMQ面试、Java容器部署实践等维度内容。 我们会以每...
问问小秘 2019-12-01 21:57:43 46087 浏览量 回答数 16

问题

荆门开诊断证明-scc

(微)电〗【186-6605-3854〗号【精品问答】Java技术1000问(1) 问问小秘 2019-11-15 11:24:15 9099 为了方便Java开发者快速找到相关技术问题和答案,开发...
游客5k2abgdj3m2ti 2019-12-01 22:09:00 1 浏览量 回答数 0

问题

【阿里云产品公测】以开发者角度看ACE服务『ACE应用构建指南』

评测介绍 评测产品: 云引擎ACE服务开发语言: PHP评测人: mr_wid评测时间: 2014年10月13日-19日 评测概要 非常有幸能够申请到ACE的公测资格, 在本篇评测中, 笔者将以一个开发者的角度来对云引擎...
mr_wid 2019-12-01 21:10:06 20092 浏览量 回答数 6

回答

微服务 (MicroServices) 架构是当前互联网业界的一个技术热点,圈里有不少同行朋友当前有计划在各自公司开展微服务化体系建设,他们都有相同的疑问:一个微服务架构有哪些技术关注点 (technical concerns)?需要哪些基础框架或组件来支持微服务架构?这些框架或组件该如何选型?笔者之前在两家大型互联网公司参与和主导过大型服务化体系和框架建设,同时在这块也投入了很多时间去学习和研究,有一些经验和学习心得,可以和大家一起分享。 服务注册、发现、负载均衡和健康检查和单块 (Monolithic) 架构不同,微服务架构是由一系列职责单一的细粒度服务构成的分布式网状结构,服务之间通过轻量机制进行通信,这时候必然引入一个服务注册发现问题,也就是说服务提供方要注册通告服务地址,服务的调用方要能发现目标服务,同时服务提供方一般以集群方式提供服务,也就引入了负载均衡和健康检查问题。根据负载均衡 LB 所在位置的不同,目前主要的服务注册、发现和负载均衡方案有三种: 第一种是集中式 LB 方案,如下图 Fig 1,在服务消费者和服务提供者之间有一个独立的 LB,LB 通常是专门的硬件设备如 F5,或者基于软件如 LVS,HAproxy 等实现。LB 上有所有服务的地址映射表,通常由运维配置注册,当服务消费方调用某个目标服务时,它向 LB 发起请求,由 LB 以某种策略(比如 Round-Robin)做负载均衡后将请求转发到目标服务。LB 一般具备健康检查能力,能自动摘除不健康的服务实例。服务消费方如何发现 LB 呢?通常的做法是通过 DNS,运维人员为服务配置一个 DNS 域名,这个域名指向 LB。 Fig 1, 集中式 LB 方案 集中式 LB 方案实现简单,在 LB 上也容易做集中式的访问控制,这一方案目前还是业界主流。集中式 LB 的主要问题是单点问题,所有服务调用流量都经过 LB,当服务数量和调用量大的时候,LB 容易成为瓶颈,且一旦 LB 发生故障对整个系统的影响是灾难性的。另外,LB 在服务消费方和服务提供方之间增加了一跳 (hop),有一定性能开销。 第二种是进程内 LB 方案,针对集中式 LB 的不足,进程内 LB 方案将 LB 的功能以库的形式集成到服务消费方进程里头,该方案也被称为软负载 (Soft Load Balancing) 或者客户端负载方案,下图 Fig 2 展示了这种方案的工作原理。这一方案需要一个服务注册表 (Service Registry) 配合支持服务自注册和自发现,服务提供方启动时,首先将服务地址注册到服务注册表(同时定期报心跳到服务注册表以表明服务的存活状态,相当于健康检查),服务消费方要访问某个服务时,它通过内置的 LB 组件向服务注册表查询(同时缓存并定期刷新)目标服务地址列表,然后以某种负载均衡策略选择一个目标服务地址,最后向目标服务发起请求。这一方案对服务注册表的可用性 (Availability) 要求很高,一般采用能满足高可用分布式一致的组件(例如 Zookeeper, Consul, Etcd 等)来实现。 Fig 2, 进程内 LB 方案 进程内 LB 方案是一种分布式方案,LB 和服务发现能力被分散到每一个服务消费者的进程内部,同时服务消费方和服务提供方之间是直接调用,没有额外开销,性能比较好。但是,该方案以客户库 (Client Library) 的方式集成到服务调用方进程里头,如果企业内有多种不同的语言栈,就要配合开发多种不同的客户端,有一定的研发和维护成本。另外,一旦客户端跟随服务调用方发布到生产环境中,后续如果要对客户库进行升级,势必要求服务调用方修改代码并重新发布,所以该方案的升级推广有不小的阻力。 进程内 LB 的案例是 Netflix 的开源服务框架,对应的组件分别是:Eureka 服务注册表,Karyon 服务端框架支持服务自注册和健康检查,Ribbon 客户端框架支持服务自发现和软路由。另外,阿里开源的服务框架 Dubbo 也是采用类似机制。 第三种是主机独立 LB 进程方案,该方案是针对第二种方案的不足而提出的一种折中方案,原理和第二种方案基本类似,不同之处是,他将 LB 和服务发现功能从进程内移出来,变成主机上的一个独立进程,主机上的一个或者多个服务要访问目标服务时,他们都通过同一主机上的独立 LB 进程做服务发现和负载均衡,见下图 Fig 3。 Fig 3 主机独立 LB 进程方案 该方案也是一种分布式方案,没有单点问题,一个 LB 进程挂了只影响该主机上的服务调用方,服务调用方和 LB 之间是进程内调用,性能好,同时,该方案还简化了服务调用方,不需要为不同语言开发客户库,LB 的升级不需要服务调用方改代码。该方案的不足是部署较复杂,环节多,出错调试排查问题不方便。 该方案的典型案例是 Airbnb 的 SmartStack 服务发现框架,对应组件分别是:Zookeeper 作为服务注册表,Nerve 独立进程负责服务注册和健康检查,Synapse/HAproxy 独立进程负责服务发现和负载均衡。Google 最新推出的基于容器的 PaaS 平台 Kubernetes,其内部服务发现采用类似的机制。 服务前端路由微服务除了内部相互之间调用和通信之外,最终要以某种方式暴露出去,才能让外界系统(例如客户的浏览器、移动设备等等)访问到,这就涉及服务的前端路由,对应的组件是服务网关 (Service Gateway),见图 Fig 4,网关是连接企业内部和外部系统的一道门,有如下关键作用: 服务反向路由,网关要负责将外部请求反向路由到内部具体的微服务,这样虽然企业内部是复杂的分布式微服务结构,但是外部系统从网关上看到的就像是一个统一的完整服务,网关屏蔽了后台服务的复杂性,同时也屏蔽了后台服务的升级和变化。安全认证和防爬虫,所有外部请求必须经过网关,网关可以集中对访问进行安全控制,比如用户认证和授权,同时还可以分析访问模式实现防爬虫功能,网关是连接企业内外系统的安全之门。限流和容错,在流量高峰期,网关可以限制流量,保护后台系统不被大流量冲垮,在内部系统出现故障时,网关可以集中做容错,保持外部良好的用户体验。监控,网关可以集中监控访问量,调用延迟,错误计数和访问模式,为后端的性能优化或者扩容提供数据支持。日志,网关可以收集所有的访问日志,进入后台系统做进一步分析。 Fig 4, 服务网关 除以上基本能力外,网关还可以实现线上引流,线上压测,线上调试 (Surgical debugging),金丝雀测试 (Canary Testing),数据中心双活 (Active-Active HA) 等高级功能。 网关通常工作在 7 层,有一定的计算逻辑,一般以集群方式部署,前置 LB 进行负载均衡。 开源的网关组件有 Netflix 的 Zuul,特点是动态可热部署的过滤器 (filter) 机制,其它如 HAproxy,Nginx 等都可以扩展作为网关使用。 在介绍过服务注册表和网关等组件之后,我们可以通过一个简化的微服务架构图 (Fig 5) 来更加直观地展示整个微服务体系内的服务注册发现和路由机制,该图假定采用进程内 LB 服务发现和负载均衡机制。在下图 Fig 5 的微服务架构中,服务简化为两层,后端通用服务(也称中间层服务 Middle Tier Service)和前端服务(也称边缘服务 Edge Service,前端服务的作用是对后端服务做必要的聚合和裁剪后暴露给外部不同的设备,如 PC,Pad 或者 Phone)。后端服务启动时会将地址信息注册到服务注册表,前端服务通过查询服务注册表就可以发现然后调用后端服务;前端服务启动时也会将地址信息注册到服务注册表,这样网关通过查询服务注册表就可以将请求路由到目标前端服务,这样整个微服务体系的服务自注册自发现和软路由就通过服务注册表和网关串联起来了。如果以面向对象设计模式的视角来看,网关类似 Proxy 代理或者 Façade 门面模式,而服务注册表和服务自注册自发现类似 IoC 依赖注入模式,微服务可以理解为基于网关代理和注册表 IoC 构建的分布式系统。 Fig 5, 简化的微服务架构图 服务容错当企业微服务化以后,服务之间会有错综复杂的依赖关系,例如,一个前端请求一般会依赖于多个后端服务,技术上称为 1 -> N 扇出 (见图 Fig 6)。在实际生产环境中,服务往往不是百分百可靠,服务可能会出错或者产生延迟,如果一个应用不能对其依赖的故障进行容错和隔离,那么该应用本身就处在被拖垮的风险中。在一个高流量的网站中,某个单一后端一旦发生延迟,可能在数秒内导致所有应用资源 (线程,队列等) 被耗尽,造成所谓的雪崩效应 (Cascading Failure,见图 Fig 7),严重时可致整个网站瘫痪。 Fig 6, 服务依赖 Fig 7, 高峰期单个服务延迟致雪崩效应 经过多年的探索和实践,业界在分布式服务容错一块探索出了一套有效的容错模式和最佳实践,主要包括: Fig 8, 弹性电路保护状态图 电路熔断器模式 (Circuit Breaker Patten), 该模式的原理类似于家里的电路熔断器,如果家里的电路发生短路,熔断器能够主动熔断电路,以避免灾难性损失。在分布式系统中应用电路熔断器模式后,当目标服务慢或者大量超时,调用方能够主动熔断,以防止服务被进一步拖垮;如果情况又好转了,电路又能自动恢复,这就是所谓的弹性容错,系统有自恢复能力。下图 Fig 8 是一个典型的具备弹性恢复能力的电路保护器状态图,正常状态下,电路处于关闭状态 (Closed),如果调用持续出错或者超时,电路被打开进入熔断状态 (Open),后续一段时间内的所有调用都会被拒绝 (Fail Fast),一段时间以后,保护器会尝试进入半熔断状态 (Half-Open),允许少量请求进来尝试,如果调用仍然失败,则回到熔断状态,如果调用成功,则回到电路闭合状态。舱壁隔离模式 (Bulkhead Isolation Pattern),顾名思义,该模式像舱壁一样对资源或失败单元进行隔离,如果一个船舱破了进水,只损失一个船舱,其它船舱可以不受影响 。线程隔离 (Thread Isolation) 就是舱壁隔离模式的一个例子,假定一个应用程序 A 调用了 Svc1/Svc2/Svc3 三个服务,且部署 A 的容器一共有 120 个工作线程,采用线程隔离机制,可以给对 Svc1/Svc2/Svc3 的调用各分配 40 个线程,当 Svc2 慢了,给 Svc2 分配的 40 个线程因慢而阻塞并最终耗尽,线程隔离可以保证给 Svc1/Svc3 分配的 80 个线程可以不受影响,如果没有这种隔离机制,当 Svc2 慢的时候,120 个工作线程会很快全部被对 Svc2 的调用吃光,整个应用程序会全部慢下来。限流 (Rate Limiting/Load Shedder),服务总有容量限制,没有限流机制的服务很容易在突发流量 (秒杀,双十一) 时被冲垮。限流通常指对服务限定并发访问量,比如单位时间只允许 100 个并发调用,对超过这个限制的请求要拒绝并回退。回退 (fallback),在熔断或者限流发生的时候,应用程序的后续处理逻辑是什么?回退是系统的弹性恢复能力,常见的处理策略有,直接抛出异常,也称快速失败 (Fail Fast),也可以返回空值或缺省值,还可以返回备份数据,如果主服务熔断了,可以从备份服务获取数据。Netflix 将上述容错模式和最佳实践集成到一个称为 Hystrix 的开源组件中,凡是需要容错的依赖点 (服务,缓存,数据库访问等),开发人员只需要将调用封装在 Hystrix Command 里头,则相关调用就自动置于 Hystrix 的弹性容错保护之下。Hystrix 组件已经在 Netflix 经过多年运维验证,是 Netflix 微服务平台稳定性和弹性的基石,正逐渐被社区接受为标准容错组件。 服务框架微服务化以后,为了让业务开发人员专注于业务逻辑实现,避免冗余和重复劳动,规范研发提升效率,必然要将一些公共关注点推到框架层面。服务框架 (Fig 9) 主要封装公共关注点逻辑,包括: Fig 9, 服务框架 服务注册、发现、负载均衡和健康检查,假定采用进程内 LB 方案,那么服务自注册一般统一做在服务器端框架中,健康检查逻辑由具体业务服务定制,框架层提供调用健康检查逻辑的机制,服务发现和负载均衡则集成在服务客户端框架中。监控日志,框架一方面要记录重要的框架层日志、metrics 和调用链数据,还要将日志、metrics 等接口暴露出来,让业务层能根据需要记录业务日志数据。在运行环境中,所有日志数据一般集中落地到企业后台日志系统,做进一步分析和处理。REST/RPC 和序列化,框架层要支持将业务逻辑以 HTTP/REST 或者 RPC 方式暴露出来,HTTP/REST 是当前主流 API 暴露方式,在性能要求高的场合则可采用 Binary/RPC 方式。针对当前多样化的设备类型 (浏览器、普通 PC、无线设备等),框架层要支持可定制的序列化机制,例如,对浏览器,框架支持输出 Ajax 友好的 JSON 消息格式,而对无线设备上的 Native App,框架支持输出性能高的 Binary 消息格式。配置,除了支持普通配置文件方式的配置,框架层还可集成动态运行时配置,能够在运行时针对不同环境动态调整服务的参数和配置。限流和容错,框架集成限流容错组件,能够在运行时自动限流和容错,保护服务,如果进一步和动态配置相结合,还可以实现动态限流和熔断。管理接口,框架集成管理接口,一方面可以在线查看框架和服务内部状态,同时还可以动态调整内部状态,对调试、监控和管理能提供快速反馈。Spring Boot 微框架的 Actuator 模块就是一个强大的管理接口。统一错误处理,对于框架层和服务的内部异常,如果框架层能够统一处理并记录日志,对服务监控和快速问题定位有很大帮助。安全,安全和访问控制逻辑可以在框架层统一进行封装,可做成插件形式,具体业务服务根据需要加载相关安全插件。文档自动生成,文档的书写和同步一直是一个痛点,框架层如果能支持文档的自动生成和同步,会给使用 API 的开发和测试人员带来极大便利。Swagger 是一种流行 Restful API 的文档方案。当前业界比较成熟的微服务框架有 Netflix 的 Karyon/Ribbon,Spring 的 Spring Boot/Cloud,阿里的 Dubbo 等。 运行期配置管理服务一般有很多依赖配置,例如访问数据库有连接字符串配置,连接池大小和连接超时配置,这些配置在不同环境 (开发 / 测试 / 生产) 一般不同,比如生产环境需要配连接池,而开发测试环境可能不配,另外有些参数配置在运行期可能还要动态调整,例如,运行时根据流量状况动态调整限流和熔断阀值。目前比较常见的做法是搭建一个运行时配置中心支持微服务的动态配置,简化架构如下图 (Fig 10): Fig 10, 服务配置中心 动态配置存放在集中的配置服务器上,用户通过管理界面配置和调整服务配置,具体服务通过定期拉 (Scheduled Pull) 的方式或者服务器推 (Server-side Push) 的方式更新动态配置,拉方式比较可靠,但会有延迟同时有无效网络开销 (假设配置不常更新),服务器推方式能及时更新配置,但是实现较复杂,一般在服务和配置服务器之间要建立长连接。配置中心还要解决配置的版本控制和审计问题,对于大规模服务化环境,配置中心还要考虑分布式和高可用问题。 配置中心比较成熟的开源方案有百度的 Disconf,360 的 QConf,Spring 的 Cloud Config 和阿里的 Diamond 等。 Netflix 的微服务框架Netflix 是一家成功实践微服务架构的互联网公司,几年前,Netflix 就把它的几乎整个微服务框架栈开源贡献给了社区,这些框架和组件包括: Eureka: 服务注册发现框架Zuul: 服务网关Karyon: 服务端框架Ribbon: 客户端框架Hystrix: 服务容错组件Archaius: 服务配置组件Servo: Metrics 组件Blitz4j: 日志组件下图 Fig 11 展示了基于这些组件构建的一个微服务框架体系,来自 recipes-rss。 Fig 11, 基于 Netflix 开源组件的微服务框架 Netflix 的开源框架组件已经在 Netflix 的大规模分布式微服务环境中经过多年的生产实战验证,正逐步被社区接受为构造微服务框架的标准组件。Pivotal 去年推出的 Spring Cloud 开源产品,主要是基于对 Netflix 开源组件的进一步封装,方便 Spring 开发人员构建微服务基础框架。对于一些打算构建微服务框架体系的公司来说,充分利用或参考借鉴 Netflix 的开源微服务组件 (或 Spring Cloud),在此基础上进行必要的企业定制,无疑是通向微服务架构的捷径。 原文地址:https://www.infoq.cn/article/basis-frameworkto-implement-micro-service#anch130564%20%EF%BC%8C
auto_answer 2019-12-02 01:55:22 0 浏览量 回答数 0

问题

极光推送一个朋友,三四天的Rails学习之路? 报错

极光推送一个朋友,三四天的Rails学习之路? 400 报错   最近因为一位极光推送朋友,我开始了大概三四天的Rails学习之路,最终达到的水平是可以比较轻松地做出大部分功能,然...
优选2 2020-06-04 21:19:39 3 浏览量 回答数 1

问题

极光推送一个朋友,三四天的Rails学习之路? 400 报错

极光推送一个朋友,三四天的Rails学习之路? 400 报错   最近因为一位极光推送朋友,我开始了大概三四天的Rails学习之路,最终达到的水平是可以比较轻松地做出大部分功能,然...
爱吃鱼的程序员 2020-05-29 19:26:23 0 浏览量 回答数 1

问题

极光推送一个朋友,三四天的Rails学习之路? 400 报错

极光推送一个朋友,三四天的Rails学习之路? 400 报错   最近因为一位极光推送朋友,我开始了大概三四天的Rails学习之路,最终达到的水平是可以比较轻松地做出大部分功能,然...
爱吃鱼的程序员 2020-06-02 13:32:16 0 浏览量 回答数 1

问题

如何用 70 行 Go 语言代码击败了 C 语言?

《用80行Haskell击败C:wc》一文在互联网是引起热议,掀起了一场用不用语言尝试打败wc的游戏。 下面我们就来看看GO语言如何用70行代码击败C语言。 基准和比较 我们将使用GNU time实用程序来...
珍宝珠 2020-02-10 16:01:47 35 浏览量 回答数 0

回答

1:JFinal 是支持注解映射Action的,可以使用@ActionKey来做。另外有朋友做了自动路由映射的扩展:http://www.oschina.net/p/jfinal-ext。另外路由映射还可以写在配置文件之中,然后通过几行代码将其加载至Routes对象中去。另外还可以使用Handler来自定义路由规则,总之方法非常之多,JFinal手册中给的路由方式只是常见形式。 2:render方法仅仅只是 new 了一个XxxRender 并放入Controller之中,在所有interceptor执行完成以后,再调用的render。 3:redirect需要指定一个正确的资源,而非空串“” ###### @JFinal 看了源码,确实许多地方处理的很好, 整个请求链式操作,设计的很精武精巧,这样做到了各个组件之间的低藕合,而且能给开发者很大的自动发挥空间. 对于使用惯传统框架的思维来讲,确实显得有些固化了 要改变自己的想法.此贴只是想最大限度的解决实际中遇到的问题,快速完成一个应用. 谢谢波波的热心解答.(ps:貌似我的1.3中没有此actionKey注解 哈哈)###### @JFinal  看了源码,确实许多地方处理的很好, 整个请求链式操作,设计的很精武精巧,这样做到了各个组件之间的低藕合,而且能给开发者很大的自动发挥空间. 对于使用惯传统框架的思维来讲,确实显得有些固化了 要改变自己的想法.此贴只是想最大限度的解决实际中遇到的问题,快速完成一个应用. 谢谢波波的热心解答.(ps:貌似我的1.3中没有此actionKey注解 哈哈) ###### 引用来自“java_cmm”的答案 @JFinal  看了源码,确实许多地方处理的很好, 整个请求链式操作,设计的很精武精巧,这样做到了各个组件之间的低藕合,而且能给开发者很大的自动发挥空间. 对于使用惯传统框架的思维来讲,确实显得有些固化了 要改变自己的想法.此贴只是想最大限度的解决实际中遇到的问题,快速完成一个应用. 谢谢波波的热心解答.(ps:貌似我的1.3中没有此actionKey注解 哈哈)     JFinal 的几大核心部件全部都是为扩展设计的,这些部件为:Controller、Model、Render、Interceptor、Handler、Plugin。这些部件构成了一个微内核 + 全方位扩展型架构。这样就为开发者提供了充分发挥的空间。     JFinal在很多方面与传统开发是不同的,而更偏向于动态语言世界的模式,只有这样才能最大化开发者生产力,让开发成为一件轻松愉快的事情。传统的零入侵、IOC等等之类很多时候只会拖累开发者。     升级到 JFinal 1.1.5 吧,谢谢你的支持 :) ###### @JFinal 请问下,如果我的bean不继承自model类时,操作需要使用dbKit,但这个接口返回的对象为Record对象,需要手工转换成实际对象?######在你的bean 里面写个方法转一下就行,如 Bean.from(Record)或者做个构造方法 Bean(Record)###### @JFinal 请教  jfinal 如何将spring applicationContext容器对象引用拿到 springplug中的app对象只有包访问权限..###### @JFinal 可以考虑在springplug中添加接口方法让子类实现###### @JFinal 不好意思,打扰了   没注意看源码,已经有一个构造方法是预留了  ###### 引用来自“java_cmm”的答案 @JFinal 不好意思,打扰了   没注意看源码,已经有一个构造方法是预留了  谢谢支持,多来提建议哈 :)
爱吃鱼的程序员 2020-06-03 16:41:30 0 浏览量 回答数 0

问题

Salesforce爱因斯坦聊天机器人介绍

今年Dreamforce,爱因斯坦又迎来了一波更新,其中就包括了让许多客户期待已久的 爱因斯坦聊天机器人! 爱因斯坦机器人可以向客户问好,回答他们的问题,甚至可以进入...
赛思salesnow 2019-12-01 21:59:04 2144 浏览量 回答数 0

回答

初识 MyBatis MyBatis 是第一个支持自定义 SQL、存储过程和高级映射的类持久框架。MyBatis 消除了大部分 JDBC 的样板代码、手动设置参数以及检索结果。MyBatis 能够支持简单的 XML 和注解配置规则。使 Map 接口和 POJO 类映射到数据库字段和记录。 MyBatis 的特点 那么 MyBatis 具有什么特点呢?或许我们可以从如下几个方面来描述 MyBatis 中的 SQL 语句和主要业务代码分离,我们一般会把 MyBatis 中的 SQL 语句统一放在 XML 配置文件中,便于统一维护。 解除 SQL 与程序代码的耦合,通过提供 DAO 层,将业务逻辑和数据访问逻辑分离,使系统的设计更清晰,更易维护,更易单元测试。SQL 和代码的分离,提高了可维护性。 MyBatis 比较简单和轻量 本身就很小且简单。没有任何第三方依赖,只要通过配置 jar 包,或者如果你使用 Maven 项目的话只需要配置 Maven 以来就可以。易于使用,通过文档和源代码,可以比较完全的掌握它的设计思路和实现。 屏蔽样板代码 MyBatis 回屏蔽原始的 JDBC 样板代码,让你把更多的精力专注于 SQL 的书写和属性-字段映射上。 编写原生 SQL,支持多表关联 MyBatis 最主要的特点就是你可以手动编写 SQL 语句,能够支持多表关联查询。 提供映射标签,支持对象与数据库的 ORM 字段关系映射 ORM 是什么?对象关系映射(Object Relational Mapping,简称ORM) ,是通过使用描述对象和数据库之间映射的元数据,将面向对象语言程序中的对象自动持久化到关系数据库中。本质上就是将数据从一种形式转换到另外一种形式。 提供 XML 标签,支持编写动态 SQL。 你可以使用 MyBatis XML 标签,起到 SQL 模版的效果,减少繁杂的 SQL 语句,便于维护。 MyBatis 整体架构 MyBatis 最上面是接口层,接口层就是开发人员在 Mapper 或者是 Dao 接口中的接口定义,是查询、新增、更新还是删除操作;中间层是数据处理层,主要是配置 Mapper -> XML 层级之间的参数映射,SQL 解析,SQL 执行,结果映射的过程。上述两种流程都由基础支持层来提供功能支撑,基础支持层包括连接管理,事务管理,配置加载,缓存处理等。 接口层 在不与Spring 集成的情况下,使用 MyBatis 执行数据库的操作主要如下: InputStream is = Resources.getResourceAsStream("myBatis-config.xml"); SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder(); SqlSessionFactory factory = builder.build(is); sqlSession = factory.openSession(); 其中的SqlSessionFactory,SqlSession是 MyBatis 接口的核心类,尤其是 SqlSession,这个接口是MyBatis 中最重要的接口,这个接口能够让你执行命令,获取映射,管理事务。 数据处理层 配置解析 在 Mybatis 初始化过程中,会加载 mybatis-config.xml 配置文件、映射配置文件以及 Mapper 接口中的注解信息,解析后的配置信息会形成相应的对象并保存到 Configration 对象中。之后,根据该对象创建SqlSessionFactory 对象。待 Mybatis 初始化完成后,可以通过 SqlSessionFactory 创建 SqlSession 对象并开始数据库操作。 SQL 解析与 scripting 模块 Mybatis 实现的动态 SQL 语句,几乎可以编写出所有满足需要的 SQL。 Mybatis 中 scripting 模块会根据用户传入的参数,解析映射文件中定义的动态 SQL 节点,形成数据库能执行的SQL 语句。 SQL 执行 SQL 语句的执行涉及多个组件,包括 MyBatis 的四大核心,它们是: Executor、StatementHandler、ParameterHandler、ResultSetHandler。SQL 的执行过程可以用下面这幅图来表示 MyBatis 层级结构各个组件的介绍(这里只是简单介绍,具体介绍在后面): SqlSession: ,它是 MyBatis 核心 API,主要用来执行命令,获取映射,管理事务。接收开发人员提供 Statement Id 和参数。并返回操作结果。Executor :执行器,是 MyBatis 调度的核心,负责 SQL 语句的生成以及查询缓存的维护。StatementHandler : 封装了JDBC Statement 操作,负责对 JDBC Statement 的操作,如设置参数、将Statement 结果集转换成 List 集合。ParameterHandler : 负责对用户传递的参数转换成 JDBC Statement 所需要的参数。ResultSetHandler : 负责将 JDBC 返回的 ResultSet 结果集对象转换成 List 类型的集合。TypeHandler : 用于 Java 类型和 JDBC 类型之间的转换。MappedStatement : 动态 SQL 的封装SqlSource : 表示从 XML 文件或注释读取的映射语句的内容,它创建将从用户接收的输入参数传递给数据库的 SQL。Configuration: MyBatis 所有的配置信息都维持在 Configuration 对象之中。 基础支持层 反射模块 Mybatis 中的反射模块,对 Java 反射进行了很好的封装,提供了简易的 API,方便上层调用,并且对反射操作进行了一系列的优化,比如,缓存了类的 元数据(MetaClass)和对象的元数据(MetaObject),提高了反射操作的性能。 类型转换模块 Mybatis 的别名机制,能够简化配置文件,该机制是类型转换模块的主要功能之一。类型转换模块的另一个功能是实现 JDBC 类型与 Java 类型的转换。在 SQL 语句绑定参数时,会将数据由 Java 类型转换成 JDBC 类型;在映射结果集时,会将数据由 JDBC 类型转换成 Java 类型。 日志模块 在 Java 中,有很多优秀的日志框架,如 Log4j、Log4j2、slf4j 等。Mybatis 除了提供了详细的日志输出信息,还能够集成多种日志框架,其日志模块的主要功能就是集成第三方日志框架。 资源加载模块 该模块主要封装了类加载器,确定了类加载器的使用顺序,并提供了加载类文件和其它资源文件的功能。 解析器模块 该模块有两个主要功能:一个是封装了 XPath,为 Mybatis 初始化时解析 mybatis-config.xml配置文件以及映射配置文件提供支持;另一个为处理动态 SQL 语句中的占位符提供支持。 数据源模块 Mybatis 自身提供了相应的数据源实现,也提供了与第三方数据源集成的接口。数据源是开发中的常用组件之一,很多开源的数据源都提供了丰富的功能,如连接池、检测连接状态等,选择性能优秀的数据源组件,对于提供ORM 框架以及整个应用的性能都是非常重要的。 事务管理模块 一般地,Mybatis 与 Spring 框架集成,由 Spring 框架管理事务。但 Mybatis 自身对数据库事务进行了抽象,提供了相应的事务接口和简单实现。 缓存模块 Mybatis 中有一级缓存和二级缓存,这两级缓存都依赖于缓存模块中的实现。但是需要注意,这两级缓存与Mybatis 以及整个应用是运行在同一个 JVM 中的,共享同一块内存,如果这两级缓存中的数据量较大,则可能影响系统中其它功能,所以需要缓存大量数据时,优先考虑使用 Redis、Memcache 等缓存产品。 Binding 模块 在调用 SqlSession 相应方法执行数据库操作时,需要制定映射文件中定义的 SQL 节点,如果 SQL 中出现了拼写错误,那就只能在运行时才能发现。为了能尽早发现这种错误,Mybatis 通过 Binding 模块将用户自定义的Mapper 接口与映射文件关联起来,系统可以通过调用自定义 Mapper 接口中的方法执行相应的 SQL 语句完成数据库操作,从而避免上述问题。注意,在开发中,我们只是创建了 Mapper 接口,而并没有编写实现类,这是因为 Mybatis 自动为 Mapper 接口创建了动态代理对象。 MyBatis 核心组件 在认识了 MyBatis 并了解其基础架构之后,下面我们来看一下 MyBatis 的核心组件,就是这些组件实现了从 SQL 语句到映射到 JDBC 再到数据库字段之间的转换,执行 SQL 语句并输出结果集。首先来认识 MyBatis 的第一个核心组件 SqlSessionFactory 对于任何框架而言,在使用该框架之前都要经历过一系列的初始化流程,MyBatis 也不例外。MyBatis 的初始化流程如下 String resource = "org/mybatis/example/mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); sqlSessionFactory.openSession(); 上述流程中比较重要的一个对象就是SqlSessionFactory,SqlSessionFactory 是 MyBatis 框架中的一个接口,它主要负责的是 MyBatis 框架初始化操作 为开发人员提供SqlSession 对象 SqlSessionFactory 有两个实现类,一个是 SqlSessionManager 类,一个是 DefaultSqlSessionFactory 类 DefaultSqlSessionFactory : SqlSessionFactory 的默认实现类,是真正生产会话的工厂类,这个类的实例的生命周期是全局的,它只会在首次调用时生成一个实例(单例模式),就一直存在直到服务器关闭。 SqlSessionManager : 已被废弃,原因大概是: SqlSessionManager 中需要维护一个自己的线程池,而使用MyBatis 更多的是要与 Spring 进行集成,并不会单独使用,所以维护自己的 ThreadLocal 并没有什么意义,所以 SqlSessionManager 已经不再使用。 ####SqlSessionFactory 的执行流程 下面来对 SqlSessionFactory 的执行流程来做一个分析 首先第一步是 SqlSessionFactory 的创建 SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); 1 从这行代码入手,首先创建了一个 SqlSessionFactoryBuilder 工厂,这是一个建造者模式的设计思想,由 builder 建造者来创建 SqlSessionFactory 工厂 然后调用 SqlSessionFactoryBuilder 中的 build 方法传递一个InputStream 输入流,Inputstream 输入流中就是你传过来的配置文件 mybatis-config.xml,SqlSessionFactoryBuilder 根据传入的 InputStream 输入流和environment、properties属性创建一个XMLConfigBuilder对象。SqlSessionFactoryBuilder 对象调用XMLConfigBuilder 的parse()方法,流程如下。 XMLConfigBuilder 会解析/configuration标签,configuration 是 MyBatis 中最重要的一个标签,下面流程会介绍 Configuration 标签。 MyBatis 默认使用 XPath 来解析标签,关于 XPath 的使用,参见 https://www.w3school.com.cn/xpath/index.asp 在 parseConfiguration 方法中,会对各个在 /configuration 中的标签进行解析 重要配置 说一下这些标签都是什么意思吧 properties,外部属性,这些属性都是可外部配置且可动态替换的,既可以在典型的 Java 属性文件中配置,亦可通过 properties 元素的子元素来传递。 <properties> <property name="driver" value="com.mysql.jdbc.Driver" /> <property name="url" value="jdbc:mysql://localhost:3306/test" /> <property name="username" value="root" /> <property name="password" value="root" /> </properties> 一般用来给 environment 标签中的 dataSource 赋值 <environment id="development"> <transactionManager type="JDBC" /> <dataSource type="POOLED"> <property name="driver" value="${driver}" /> <property name="url" value="${url}" /> <property name="username" value="${username}" /> <property name="password" value="${password}" /> </dataSource> </environment> 还可以通过外部属性进行配置,但是我们这篇文章以原理为主,不会介绍太多应用层面的操作。 settings ,MyBatis 中极其重要的配置,它们会改变 MyBatis 的运行时行为。 settings 中配置有很多,具体可以参考 https://mybatis.org/mybatis-3/zh/configuration.html#settings 详细了解。这里介绍几个平常使用过程中比较重要的配置 一般使用如下配置 <settings> <setting name="cacheEnabled" value="true"/> <setting name="lazyLoadingEnabled" value="true"/> </settings> typeAliases,类型别名,类型别名是为 Java 类型设置的一个名字。 它只和 XML 配置有关。 <typeAliases> <typeAlias alias="Blog" type="domain.blog.Blog"/> </typeAliases> 当这样配置时,Blog 可以用在任何使用 domain.blog.Blog 的地方。 typeHandlers,类型处理器,无论是 MyBatis 在预处理语句(PreparedStatement)中设置一个参数时,还是从结果集中取出一个值时, 都会用类型处理器将获取的值以合适的方式转换成 Java 类型。 在 org.apache.ibatis.type 包下有很多已经实现好的 TypeHandler,可以参考如下 你可以重写类型处理器或创建你自己的类型处理器来处理不支持的或非标准的类型。 具体做法为:实现 org.apache.ibatis.type.TypeHandler 接口, 或继承一个很方便的类 org.apache.ibatis.type.BaseTypeHandler, 然后可以选择性地将它映射到一个 JDBC 类型。 objectFactory,对象工厂,MyBatis 每次创建结果对象的新实例时,它都会使用一个对象工厂(ObjectFactory)实例来完成。默认的对象工厂需要做的仅仅是实例化目标类,要么通过默认构造方法,要么在参数映射存在的时候通过参数构造方法来实例化。如果想覆盖对象工厂的默认行为,则可以通过创建自己的对象工厂来实现。 public class ExampleObjectFactory extends DefaultObjectFactory { public Object create(Class type) { return super.create(type); } public Object create(Class type, List constructorArgTypes, List constructorArgs) { return super.create(type, constructorArgTypes, constructorArgs); } public void setProperties(Properties properties) { super.setProperties(properties); } public boolean isCollection(Class type) { return Collection.class.isAssignableFrom(type); } } 然后需要在 XML 中配置此对象工厂 <objectFactory type="org.mybatis.example.ExampleObjectFactory"> <property name="someProperty" value="100"/> </objectFactory> plugins,插件开发,插件开发是 MyBatis 设计人员给开发人员留给自行开发的接口,MyBatis 允许你在已映射语句执行过程中的某一点进行拦截调用。MyBatis 允许使用插件来拦截的方法调用包括:Executor、ParameterHandler、ResultSetHandler、StatementHandler 接口,这几个接口也是 MyBatis 中非常重要的接口,我们下面会详细介绍这几个接口。 environments,MyBatis 环境配置,MyBatis 可以配置成适应多种环境,这种机制有助于将 SQL 映射应用于多种数据库之中。例如,开发、测试和生产环境需要有不同的配置;或者想在具有相同 Schema 的多个生产数据库中 使用相同的 SQL 映射。 这里注意一点,虽然 environments 可以指定多个环境,但是 SqlSessionFactory 只能有一个,为了指定创建哪种环境,只要将它作为可选的参数传递给 SqlSessionFactoryBuilder 即可。 SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader, environment); SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader, environment, properties); databaseIdProvider ,数据库厂商标示,MyBatis 可以根据不同的数据库厂商执行不同的语句,这种多厂商的支持是基于映射语句中的 databaseId 属性。 <databaseIdProvider type="DB_VENDOR"> <property name="SQL Server" value="sqlserver"/> <property name="DB2" value="db2"/> <property name="Oracle" value="oracle" /> </databaseIdProvider> mappers,映射器,这是告诉 MyBatis 去哪里找到这些 SQL 语句,mappers 映射配置有四种方式 上面的一个个属性都对应着一个解析方法,都是使用 XPath 把标签进行解析,解析完成后返回一个 DefaultSqlSessionFactory 对象,它是 SqlSessionFactory 的默认实现类。这就是 SqlSessionFactoryBuilder 的初始化流程,通过流程我们可以看到,初始化流程就是对一个个 /configuration 标签下子标签的解析过程。 SqlSession 在 MyBatis 初始化流程结束,也就是 SqlSessionFactoryBuilder -> SqlSessionFactory 的获取流程后,我们就可以通过 SqlSessionFactory 对象得到 SqlSession 然后执行 SQL 语句了。具体来看一下这个过程‘ 在 SqlSessionFactory.openSession 过程中我们可以看到,会调用到 DefaultSqlSessionFactory 中的 openSessionFromDataSource 方法,这个方法主要创建了两个与我们分析执行流程重要的对象,一个是 Executor 执行器对象,一个是 SqlSession 对象。执行器我们下面会说,现在来说一下 SqlSession 对象 SqlSession 对象是 MyBatis 中最重要的一个对象,这个接口能够让你执行命令,获取映射,管理事务。SqlSession 中定义了一系列模版方法,让你能够执行简单的 CRUD 操作,也可以通过 getMapper 获取 Mapper 层,执行自定义 SQL 语句,因为 SqlSession 在执行 SQL 语句之前是需要先开启一个会话,涉及到事务操作,所以还会有 commit、 rollback、close 等方法。这也是模版设计模式的一种应用。 MapperProxy MapperProxy 是 Mapper 映射 SQL 语句的关键对象,我们写的 Dao 层或者 Mapper 层都是通过 MapperProxy 来和对应的 SQL 语句进行绑定的。下面我们就来解释一下绑定过程 这就是 MyBatis 的核心绑定流程,我们可以看到 SqlSession 首先调用 getMapper 方法,我们刚才说到 SqlSession 是大哥级别的人物,只定义标准(有一句话是怎么说的来着,一流的企业做标准,二流的企业做品牌,三流的企业做产品)。 SqlSession 不愿意做的事情交给 Configuration 这个手下去做,但是 Configuration 也是有小弟的,它不愿意做的事情直接甩给小弟去做,这个小弟是谁呢?它就是 MapperRegistry,马上就到核心部分了。MapperRegistry 相当于项目经理,项目经理只从大面上把握项目进度,不需要知道手下的小弟是如何工作的,把任务完成了就好。最终真正干活的还是 MapperProxyFactory。看到这段代码 Proxy.newProxyInstance ,你是不是有一种恍然大悟的感觉,如果你没有的话,建议查阅一下动态代理的文章,这里推荐一篇 (https://www.jianshu.com/p/95970b089360) 也就是说,MyBatis 中 Mapper 和 SQL 语句的绑定正是通过动态代理来完成的。 通过动态代理,我们就可以方便的在 Dao 层或者 Mapper 层定义接口,实现自定义的增删改查操作了。那么具体的执行过程是怎么样呢?上面只是绑定过程,别着急,下面就来探讨一下 SQL 语句的执行过程。 MapperProxyFactory 会生成代理对象,这个对象就是 MapperProxy,最终会调用到 mapperMethod.execute 方法,execute 方法比较长,其实逻辑比较简单,就是判断是 插入、更新、删除 还是 查询 语句,其中如果是查询的话,还会判断返回值的类型,我们可以点进去看一下都是怎么设计的。 很多代码其实可以忽略,只看我标出来的重点就好了,我们可以看到,不管你前面经过多少道关卡处理,最终都逃不过 SqlSession 这个老大制定的标准。 我们以 selectList 为例,来看一下下面的执行过程。 这是 DefaultSqlSession 中 selectList 的代码,我们可以看到出现了 executor,这是什么呢?我们下面来解释。 Executor 还记得我们之前的流程中提到了 Executor(执行器) 这个概念吗?我们来回顾一下它第一次出现的位置。 由 Configuration 对象创建了一个 Executor 对象,这个 Executor 是干嘛的呢?下面我们就来认识一下 Executor 的继承结构 每一个 SqlSession 都会拥有一个 Executor 对象,这个对象负责增删改查的具体操作,我们可以简单的将它理解为 JDBC 中 Statement 的封装版。 也可以理解为 SQL 的执行引擎,要干活总得有一个发起人吧,可以把 Executor 理解为发起人的角色。 首先先从 Executor 的继承体系来认识一下 如上图所示,位于继承体系最顶层的是 Executor 执行器,它有两个实现类,分别是BaseExecutor和 CachingExecutor。 BaseExecutor 是一个抽象类,这种通过抽象的实现接口的方式是适配器设计模式之接口适配 的体现,是Executor 的默认实现,实现了大部分 Executor 接口定义的功能,降低了接口实现的难度。BaseExecutor 的子类有三个,分别是 SimpleExecutor、ReuseExecutor 和 BatchExecutor。 SimpleExecutor : 简单执行器,是 MyBatis 中默认使用的执行器,每执行一次 update 或 select,就开启一个Statement 对象,用完就直接关闭 Statement 对象(可以是 Statement 或者是 PreparedStatment 对象) ReuseExecutor : 可重用执行器,这里的重用指的是重复使用 Statement,它会在内部使用一个 Map 把创建的Statement 都缓存起来,每次执行 SQL 命令的时候,都会去判断是否存在基于该 SQL 的 Statement 对象,如果存在 Statement 对象并且对应的 connection 还没有关闭的情况下就继续使用之前的 Statement 对象,并将其缓存起来。因为每一个 SqlSession 都有一个新的 Executor 对象,所以我们缓存在 ReuseExecutor 上的 Statement作用域是同一个 SqlSession。 BatchExecutor : 批处理执行器,用于将多个 SQL 一次性输出到数据库 CachingExecutor: 缓存执行器,先从缓存中查询结果,如果存在就返回之前的结果;如果不存在,再委托给Executor delegate 去数据库中取,delegate 可以是上面任何一个执行器。 Executor 的创建和选择 我们上面提到 Executor 是由 Configuration 创建的,Configuration 会根据执行器的类型创建,如下 这一步就是执行器的创建过程,根据传入的 ExecutorType 类型来判断是哪种执行器,如果不指定 ExecutorType ,默认创建的是简单执行器。它的赋值可以通过两个地方进行赋值: 可以通过 标签来设置当前工程中所有的 SqlSession 对象使用默认的 Executor <settings> <!--取值范围 SIMPLE, REUSE, BATCH --> <setting name="defaultExecutorType" value="SIMPLE"/> </settings> 另外一种直接通过Java对方法赋值的方式 session = factory.openSession(ExecutorType.BATCH); Executor 的具体执行过程 Executor 中的大部分方法的调用链其实是差不多的,下面是深入源码分析执行过程,如果你没有时间或者暂时不想深入研究的话,给你下面的执行流程图作为参考。 我们紧跟着上面的 selectList 继续分析,它会调用到 executor.query 方法。 当有一个查询请求访问的时候,首先会经过 Executor 的实现类 CachingExecutor ,先从缓存中查询 SQL 是否是第一次执行,如果是第一次执行的话,那么就直接执行 SQL 语句,并创建缓存,如果第二次访问相同的 SQL 语句的话,那么就会直接从缓存中提取。 上面这段代码是从 selectList -> 从缓存中 query 的具体过程。可能你看到这里有些觉得类都是什么东西,我想鼓励你一下,把握重点,不用每段代码都看,从找到 SQL 的调用链路,其他代码想看的时候在看,看源码就是很容易发蒙,容易烦躁,但是切记一点,把握重点。 上面代码会判断缓存中是否有这条 SQL 语句的执行结果,如果没有的话,就再重新创建 Executor 执行器执行 SQL 语句,注意, list = doQuery 是真正执行 SQL 语句的过程,这个过程中会创建我们上面提到的三种执行器,这里我们使用的是简单执行器。 到这里,执行器所做的工作就完事了,Executor 会把后续的工作交给 StatementHandler 继续执行。下面我们来认识一下 StatementHandler 上面代码会判断缓存中是否有这条 SQL 语句的执行结果,如果没有的话,就再重新创建 Executor 执行器执行 SQL 语句,注意, list = doQuery 是真正执行 SQL 语句的过程,这个过程中会创建我们上面提到的三种执行器,这里我们使用的是简单执行器。 到这里,执行器所做的工作就完事了,Executor 会把后续的工作交给 StatementHandler 继续执行。下面我们来认识一下 StatementHandler StatementHandler 的继承结构 有没有感觉和 Executor 的继承体系很相似呢?最顶级接口是四大组件对象,分别有两个实现类 BaseStatementHandler 和 RoutingStatementHandler,BaseStatementHandler 有三个实现类, 他们分别是 SimpleStatementHandler、PreparedStatementHandler 和 CallableStatementHandler。 RoutingStatementHandler : RoutingStatementHandler 并没有对 Statement 对象进行使用,只是根据StatementType 来创建一个代理,代理的就是对应Handler的三种实现类。在MyBatis工作时,使用的StatementHandler 接口对象实际上就是 RoutingStatementHandler 对象。 BaseStatementHandler : 是 StatementHandler 接口的另一个实现类,它本身是一个抽象类,用于简化StatementHandler 接口实现的难度,属于适配器设计模式体现,它主要有三个实现类 SimpleStatementHandler: 管理 Statement 对象并向数据库中推送不需要预编译的SQL语句。PreparedStatementHandler: 管理 Statement 对象并向数据中推送需要预编译的SQL语句。CallableStatementHandler:管理 Statement 对象并调用数据库中的存储过程。 StatementHandler 的创建和源码分析 我们继续来分析上面 query 的调用链路,StatementHandler 的创建过程如下 MyBatis 会根据 SQL 语句的类型进行对应 StatementHandler 的创建。我们以预处理 StatementHandler 为例来讲解一下 执行器不仅掌管着 StatementHandler 的创建,还掌管着创建 Statement 对象,设置参数等,在创建完 PreparedStatement 之后,我们需要对参数进行处理了。 如 如果用一副图来表示一下这个执行流程的话我想是这样 这里我们先暂停一下,来认识一下第三个核心组件 ParameterHandler ParameterHandler - ParameterHandler 介绍 ParameterHandler 相比于其他的组件就简单很多了,ParameterHandler 译为参数处理器,负责为 PreparedStatement 的 sql 语句参数动态赋值,这个接口很简单只有两个方法 ParameterHandler 只有一个实现类 DefaultParameterHandler , 它实现了这两个方法。 getParameterObject: 用于读取参数setParameters: 用于对 PreparedStatement 的参数赋值ParameterHandler 的解析过程 上面我们讨论过了 ParameterHandler 的创建过程,下面我们继续上面 parameterSize 流程 这就是具体参数的解析过程了,下面我们来描述一下 下面用一个流程图表示一下 ParameterHandler 的解析过程,以简单执行器为例 我们在完成 ParameterHandler 对 SQL 参数的预处理后,回到 SimpleExecutor 中的 doQuery 方法 上面又引出来了一个重要的组件那就是 ResultSetHandler,下面我们来认识一下这个组件 ResultSetHandler - ResultSetHandler 简介 ResultSetHandler 也是一个非常简单的接口 ResultSetHandler 是一个接口,它只有一个默认的实现类,像是 ParameterHandler 一样,它的默认实现类是DefaultResultSetHandler ResultSetHandler 解析过程 MyBatis 只有一个默认的实现类就是 DefaultResultSetHandler,DefaultResultSetHandler 主要负责处理两件事 处理 Statement 执行后产生的结果集,生成结果列表 处理存储过程执行后的输出参数 按照 Mapper 文件中配置的 ResultType 或 ResultMap 来封装成对应的对象,最后将封装的对象返回即可。 其中涉及的主要对象有: ResultSetWrapper : 结果集的包装器,主要针对结果集进行的一层包装,它的主要属性有 ResultSet : Java JDBC ResultSet 接口表示数据库查询的结果。 有关查询的文本显示了如何将查询结果作为java.sql.ResultSet 返回。 然后迭代此ResultSet以检查结果。 TypeHandlerRegistry: 类型注册器,TypeHandlerRegistry 在初始化的时候会把所有的 Java类型和类型转换器进行注册。 ColumnNames: 字段的名称,也就是查询操作需要返回的字段名称 ClassNames: 字段的类型名称,也就是 ColumnNames 每个字段名称的类型 JdbcTypes: JDBC 的类型,也就是 java.sql.Types 类型 ResultMap: 负责处理更复杂的映射关系 在 DefaultResultSetHandler 中处理完结果映射,并把上述结构返回给调用的客户端,从而执行完成一条完整的SQL语句。 内容转载自:CSDN博主:cxuann 原文链接:https://blog.csdn.net/qq_36894974/article/details/104132876?depth_1-utm_source=distribute.pc_feed.none-task&request_id=&utm_source=distribute.pc_feed.none-task
问问小秘 2020-03-05 15:44:27 0 浏览量 回答数 0

问题

开发者论坛一周精粹(第四十一期) 雅虎邮箱迁移 物联网链接

开发者论坛每周选取精华内容总结,精选论坛优质贴,每周更新一期,方便大家阅读! OSS同步工具,首发,用于本地磁盘或目录同到阿里云OSS 作者...
福利达人 2019-12-01 22:04:23 2113 浏览量 回答数 0

问题

wttr.in 一个 Python 实现的命令行查看天气工具

wttr.in是面向控制台的天气预报服务,它支持各种信息表示方法,例如用于控制台HTTP客户端(curl,httpie或wget)的面向终端的ANSI序列,...
huc_逆天 2020-05-21 19:12:17 19 浏览量 回答数 1

问题

Spark,一种快速数据分析替代方案:报错

虽然 Hadoop 在分布式数据分析方面备受关注,但是仍有一些替代产品提供了优于典型 Hadoop 平台的令人关注的优势。Spark 是一种可扩展的数据分析平台,它整合了内存计算的基元,因此...
kun坤 2020-06-06 11:49:13 0 浏览量 回答数 1

回答

先说结论: 不要对接!不要对接!不要对接! 开个玩笑,以上仅代表个人观点,大家也知道这种“三体式警告”根本没有用的,我自己也研究如何对接,说不定做完后就觉得“真香”了。 为什么要对接? 首先讨论一下为什么要把 Flutter 对接到 Web 生态。 Flutter 现在是一个炙手可热的跨平台技术,能够一套代码运行在 Android、iOS、PC、IoT 以及浏览器上,被认为是下一代跨平台技术。相比于 Weex 和 React Native 可以很好地解决多平台一致性问题,原生渲染性能相近,上层没有 JS 那么厚的封装层次,整体性能会略好一些。 但是大部分兴冲冲去学 Flutter 的人疑惑的第一个问题就是:为什么 Flutter 要用 Dart?一个全新的语言意味着新的学习成本,难道 JS 不香吗?JS 不香不是还有 TypeScript 吗!事实上 Flutter 抛弃的岂止是 JS 这门语言,也抛弃了 HTML 和 CSS,设计了一套解耦得更好的 Widget 体系,Flutter 抛弃的是整个 Web,致力于打造一个新的生态,但是这个生态无法复用 Web 生态的代码和解决方案。尤其是之前所有跨平台方案 Hybrid、React Native、Weex 都是对接 Web 生态的,这让 Flutter 显得有些格格不入,也让大部分前端开发者望而却步。 下面是我整理出来的,前端开发者使用 Flutter 的各方面成本: 因为 Flutter 的开发模式和前端框架比较像(可以说就是抄的 React),所以框架的学习成本并不高,稍微高一些的是 Dart 语言的学习成本,另外还要学习如何用 Widget 组装 UI,虽然很多布局 Widget 设计得和 CSS 很像,灵活度还是差了很多。要想在真实项目中用起来,还要改造整个工具链,以“Native First”的视角做开发,开发 Flutter 和开发原生应用的链路是比较像的,和开发前端页面有较大差异。最高的还是生态成本,前端生态的积累无论是代码还是技术方案都很难复用,这是最痛的一点,生态也是 Flutter 最弱的一环。 无论是为了先进的技术理念还是出于商业私心,先不管 Flutter 为什么抛弃 Web 生态,现实问题是最大的 UI 开发者群体是前端,最丰富的生态是 Web 生态,我觉得 Web 技术也是开发 UI 最高效的方式。如果能在上层使用 Web 技术栈开发,在底层使用 Flutter 实现跨平台渲染,不是可以很好的兼顾开发效率、性能和跨平台一致性吗?还能复用 Web 技术栈大量的技术积累。 可能这些理由也不够充分,暂且先照着这个假设继续分析,最后再重新讨论到底该不该对接。 关于 Flutter 和 Web 生态的对接涉及两个方面: 从 Web 到 Flutter。就是使用 Web 技术栈来开发,然后对接到 Flutter 上实现跨平台渲染。对 Web 来说是解决性能和跨平台一致性问题,对 Flutter 来说是解决生态复用问题。从 Flutter 到 Web。就是官方已经实现的 Web support for Flutter,把已经用 Dart 开发好的 App 编译成 HTML/JS/CSS 然后运行在浏览器上,可以用于降级和外投场景。 如何实现“从 Web 到 Flutter”? 首先分析一下 Flutter 的架构图,看看可以从哪里下手。 Flutter 可以分为 Framework 和 Engine 两部分,Engine 部分比较底层也比较稳定了,最好不要动,需要改的是用 Dart 实现的 Framework。要想对接 Web 生态的话,JS 引擎肯定是要引入的,至于是否保留 Dart VM 有待讨论。图中最上面 Material 和 Cupertino 两个 UI 库前端是不需要的,前端有自己的。关键是 Widget 这部分,是替换成 HTML/CSS 的方式写 UI,还是继续保留 Widget 但是把语言换成 JS,不同方案给出的解法也不一样。 有不少方案可以实现对接,业界有挺多尝试的,我总结了下面三种方式: - TS 魔改:用 JS 引擎替换掉 Dart VM,用 JS/TS 重新实现 Flutter Framework(或者直接 dart2js 编译过来)。 - JS 对接:引入 JS 引擎同时保留 Dart VM,用前端框架对接 Flutter Framework。 - C++ 魔改:用 JS 引擎替换掉 Dart VM,用 C++ 重新实现 Flutter Framework。 TS 魔改 TS 魔改就是完全抛弃掉 Dart VM,用 TypeScript 重新实现一遍用 Dart 写的 Flutter Framework。 为啥是 TS 而不是 JS?这不是因为 TS 是个大热门嘛,而且向下兼容 JS,现在几乎所有时髦的框架都要用 TS 重写了。 这种方案的出发点是“如果能把 Flutter 的 Dart 换成 JS 就好了”,最容易想到的路就是把 Dart 翻译成 TS,或者直接用 dart2js 把代码编译成 js,但是编译出来的代码包含很多 dart:ui 之类的库的封装,生成的包也挺大的,也比较难定制需要导出的接口,不如干脆用 TS 重写一遍,工具链更熟悉一些,还可以加一些定制。 理论上讲翻译之后 Flutter 绝大部分功能都依然支持,可以复用各种 npm 包,还可以动态化,但是丧失了 AOT 能力,JS 语言的执行性能应该是不如 Dart 的。而且所有节点的布局运算都发生在 JS,底层只需要提供基础的图形能力就好了,就好像是基于 Canvas API 写了一套 UI 框架,性能未必有现存前端框架的性能高。 此外最大的问题是如何与官方 Flutter 保持一致,假如现在是从 v1.13 版本翻译过来的,以后官方升级到了 v1.15 要不要同步更新?这个过程没啥技术含量,而且需要持续投入,做起来比较恶心。 另外还需要考虑上层是用 Widget 的方式写 UI,还是用前端熟悉的 HTML+CSS。如果依然用 Widget 的话,那大部分前端组件还是用不了的,UI 还是得重写一遍。反正要重写的话,成本也没降下来,那就用 Dart 重写呗…… 直接用官方原版 Flutter 也避免每次更新都要翻译一遍 Dart 代码。所以既然选择了对接前端生态,那就要对接 CSS,不然就没有足够的价值。然而 CSS 和 Widget 的对接也是很繁琐的过程,而且存在完备性问题。 JS 对接 翻译代码的方式不够优雅,那就保留 Dart,把 JS/CSS 对接到 Widget 上面不就好了? 当然可以,这种方式是仅把 Flutter 当做了底层的渲染引擎,上层保持前端框架的写法,仅把渲染部分对接到 Flutter。现存的很多前端框架都把底层渲染能力做了抽象,可以对接到不同渲染引擎上,如 Vue/Rax 同时支持浏览器和 Weex,用同样的方式,可以再支持一个 Flutter。 这种方式对前端框架的兼容性比较好,但是链路太长了,业务代码调用前端框架接口做渲染,一顿操作之后发出了渲染指令,这个渲染指令要基于通信的方式传给 Flutter Framework,这中间涉及一次 JS 到 C++ 再到 Dart 的跨语言转换,然后再接收到渲染指令之后还要转成相应的 Widget 树,从 CSS 到 Widget 的转换依然很繁琐。而且 Widget 本身是可以带有状态的,本身就是响应式更新的,在更新时会重新生成 widget 并 diff,如果在前端更新 UI 的话,前端框架在 js 里 diff 一次 vdom,传到 Flutter 之后又 diff 一次 widget。 如果要绕过 Widget 直接对接图中的 Rendering 这一层,可以绕过 widget diff 但是得改 Flutter Framework 的渲染链路,既然要改 Flutter Framework 那为什么不直接用 TS 魔改呢,还绕过了 JS 到 Dart 的通信,又回到了第一种方案。 总结来说,这个方案的优点是:实现简单、能最大化保留前端开发体验,缺点是:渲染链路长、通信成本高、响应式逻辑冲突、CSS 转 Widget 不完备等。 C++ 魔改 想要干掉 Dart VM,就需要用其他语言重新实现用 Dart 开发的 Framework,用 JS/TS 可以,用 C++ 当然可以,最硬核的方式就是用 C++ 重新实现 Flutter 的 Framework,然后接入 JS 引擎,通过 binding 把 C++ 接口透出到 JS 环境,上层应用还是用 JS 做开发。 把 Framework 层下沉到 C++ 之后,不仅会有更好的性能,也能支持更多语言。原本 Flutter Framework 是在 Dart VM 之上的,必须依赖 Dart VM 才能运行,所以对 Dart 有强依赖;用 C++ 重新实现之后,JS 引擎是在 C++ 版 Framework 之上的,框架本身并不依赖 JS 引擎,还可以对接其他各种语言,如对接了 JVM 之后可以支持 Java 和 Kotlin,对接回 Dart VM 可以继续支持 Dart。 这个方案可以增强性能,也能保持和 Flutter 的一致性,但是改造成本和维护成本都相当高。C++ 的开发效率肯定不如 Dart,当 Flutter 快速迭代之后如何跟进是很大的问题,如果跟进不及时或者实现不一致那很可能就分化了。从 CSS 到 Widget 的转换也是不得不面对的问题。 几种方案对比 把上面几种方案画在同一张图里是这个样子的: 图中实线部分表示了跨语言的通信,太过频繁会影响性能,虚线部分表示了其他对接可能性。 从下到上,Flutter Engine 是不需要动的,这一层是跨平台的关键。Framework 则有三种语言版本,JS/TS、Dart、C++,性能是 C++ 版本最好,成本是 Dart 版本最低。然后还需要向上处理 HTML/CSS 和 Widget 的问题,可以直接对接一个前端框架,也可以直接在 C++ 层实现(不然需要透出的 binding 接口就太多了,用通信的方式也太过频繁了)。 如何实现“从 Flutter 到 Web”? 这个功能官方已经实现了,可以把使用 Dart 开发的 App 编译成 Web App 运行在浏览器上,官方文档以介绍用法和 API 为主,我这里简单分析一下内部具体的实现方案。 实现原理 结合 Flutter 的架构图来看,要实现 Web 到 Flutter 需要改造的是上层 Framework,要实现 Flutter 到 Web 需要改造的则是底层 Engine。 Framework 对 Engine 的核心依赖是 dart:ui,这是库是在 Engine 里实现的,抽象出了绘制 UI 图层的接口,底层对接 skia 的实现,向上透出 Dart 语言的接口。这样来看,对接方式就比较简单了: 使用 dart2js 把 Framework 编译成 JS 代码。基于浏览器的 API 重新实现 dart:ui,即 dart:web_ui。 把 Dart 编译成 JS 没什么问题,性能可能会有一点影响,功能都是可以完全保留的,关键是 dart:web_ui 的实现。在原生 Engine 中,dart:ui 依赖 skia 透出的 SkCanvas 实现绘制,这是一套很底层的图形接口,只定义了画线、画多边形、贴图之类的底层能力,用浏览器接口实现这一套接口还是很有挑战的。上图可以看到 Web 版 Engine 是基于 DOM 和 Canvas 实现的,底层定义了 DomCanvas 和 BitmapCanvas 两种图形接口,会把传来的 layer tree 渲染成浏览器的 Element tree,但是节点上仅包含了 position, transform, opacity 之类的样式,只用到 CSS 很小的一个子集,一些更复杂的绘制直接用 2D canvas 实现。 存在的问题 我编译了一个还算复杂的 demo 试了一下,性能很不理想,滑动不流畅,有时候图片还会闪动。生成出来的 js 代码有 1.1MB (minify 之后,未 gzip),节点层次也比较深,我评估这个页面用前端写不会超过 300KB,节点数可以少一半以上。 另外再看一下 Flutter 仓库的 issue,过滤出 platfrom-web 相关的,可以看到大量:文字编辑失效、找不到光标、ListView 在 ios 上不可滚动、checkbox/button 行为不正常、安卓滚动卡顿图片闪烁、字体失效、某些机型视频无法播放、文字选中后无法复制、无法调试…… 感觉 flutter for web 已经陷入泥潭,让人回想起前端当年处理各种浏览器兼容性的噩梦。 这些性能和兼容性问题,核心原因是浏览器未暴露足够的底层能力,以及浏览器处理手势、用户输入和方式和 Flutter 差异巨大。 实现 Flutter Engine 需要的是底层的图形接口和系统能力,虽然canvas 提供了相似的图形接口,如果全部用 canvas 实现的话很难处理可访问性、文本选择、手势、表单等问题,也会存在很多兼容性问题。所以真实方案里用的是 Canvas + DOM 混合的方式,封装层次太高了,渲染链路太长。就好像 Flutter Framework 里进行了一顿猛如虎的操作之后,节点生成好了、布局算好了、绘制属性也处理好了,就差一个画布画出来了,然后交到浏览器手里,又生成一遍 Element,再算一遍布局,在处理一遍绘制,最终才交给了底层的图形库画出来。 再比如长页面的滚动,浏览器里只要一条 CSS (overflow:scroll) 就可以让元素可滚动,手势的监听以及页面的滚动以及滚动动画都是浏览器原生实现的,不需要与 JS 交互,甚至不需要重新 layout 和 paint,只需要 compositing。如上图所示,在 Flutter 中 Animation 和 Gesture 是用 Dart 实现的,编译过来就是 JS 实现的,浏览器本身并不知道这个元素是否可滚,只是不断派发 touchmove 事件,JS 根据事件属性计算节点偏移,然后运算动画,然后把 transform 或者新的 position 作用到节点上,然后浏览器再来一遍完整的渲染流程…… 优化方案 性能和兼容性的问题还是要解决的,短期内先把 issue 解掉,长线的优化方案,官方有两种尝试: 使用 CSS Painting API 做绘制。 a, 这是还处于提案状态的新标准,可以用 JS 实现一些绘制功能,自定义 CSS 属性。 b. 目前还未实现,需要等浏览器先把 CSS Houdini 支持好。 使用 WebAssembly 版本的 Skia 做绘制 https://skia.org/user/modules/canvaskit a, 这样可以发挥 wasm 的性能优势,并且保持 skia 功能的一致。但是目前 wasm 在浏览器环境里未必有性能优势,这里不展开讨论了。 b. 已经部分实现,参考这里的配置启用功能: https://github.com/flutter/flutter/issues/41062#issuecomment-533952994 这两个方案都是想更多的利用到浏览器的底层能力,只有浏览器暴露了更多底层能力,才能更好的实现 Flutter 的 Web Engine。不过这个要等挺久的时间,我们也参与不了,现阶段想要使用 flutter for web,还是得保持现有架构,一起参与进去把 issue 解决掉,优先保障功能,其次优化性能。 一种适应性更好的架构 如果理想化一点,能不能从架构角度让 Flutter 和 Web 生态融合的更好一些呢? 回顾文章最开始的官方架构图,上面是 Framework(Dart),下面是 Engine(C++),切分在 Foundation 这一层,双方之间的交互是几何图形信息。如果还保持这个架构,把切分层次划分的更靠上一些,如下图所示,划分在 Widgets 和 Rendering 这一层,理论上讲对 Flutter 的开发者来说是无感知的,因为上层的开发语言和 Widget 接口都是不变的。 切分在这一层,Framework 和 Engine 之间的交互就不再是几何图形而是节点信息,Widget 的组合、setState 响应式更新、Widget diff 都还在 Dart 中,展开后的 RenderObject 的布局、绘制、裁剪、动画全都在 C++ 中,不仅有更好的性能,还可以与 Engine 有更好的结合。 或者说,还原本保留 Engine 的设计,把下沉的这部分逻辑上划分成 Renderer,就有了如下三层的结构: 这样划分出来的每一层都有明确的定位: Framework: 开发框架。为开发者提供可编程 API,实现响应式的开发模式,提供细粒度 Widget 供开发者自由封装和组合。Renderer: 渲染引擎。专门实现布局、绘制、动画、手势的的处理,这部分功能相对独立,是可以与开发框架解耦的,也不必与特定语言绑定。Engine: 图形引擎。实现跨平台一致的图形接口,合成输入的层并绘制到屏幕上,处理好平台力的接入和适配。 这样切分除了有性能优势以外,也使得渲染引擎摆脱了对 Dart 的依赖,能够支持多种语言,也能支持多种开发模式。对接到 Dart VM 就可以用 Dart 写代码,对接到 JS 引擎就可以用 JS 写代码,对接到 JVM 还可以写 Java,但是无论怎么写,底层的渲染能力是一样的,一套统一的布局算法,动画和手势的处理行为也是一致的。 在这样的架构下,对接 Web 生态就更容易了。Dart 和 Widget 是前端不想要的,希望能换成 JS 和 CSS,但是又想要底层的跨平台一致渲染引擎,那从 Renderer 层开始对接就好了,绕过了所有不想要的,也保留了所有想要的。 要实现 Flutter for Web 也更简单了一些。在 Engine 层做对接,一直苦于浏览器透出的底层能力不够,如果是在 Renderer 之上做对接就更容易一些,基于 JS/CSS/DOM/Canvas 的能力封装出一套 Rendering 接口,供 Widget 调用就好了,这样可以使渲染链路更短一些,但是依然要处理 Widget 和 DOM/CSS 之间的兼容性问题。 再讨论一遍:为什么要对接? 技术上已经分析完了,要想搞定 Flutter 生态和 Web 生态的对接,需要投入很大的成本,所以真正决定做之前,要先讨论清楚为什么要做对接?到底要不要做对接? 首先 Google 官方对 Flutter 的定位就是个问题。Flutter 设计之初就是不考虑 Web 生态的,甚至在刻意回避,倡导的是更贴近原生的开发方式。我之所以在开头说不要对接,原因也很简单:两种技术设计理念不同,不是朝着一个方向发展的,生态不通,技术方案不通,强行融合很可能让彼此都丧失了优势。但是业界又有很多团队在做这种尝试,说明需求是存在的,如果 Google 抵制这个方向,那就不好做了。不过现在官方已经支持了 Flutter for Web,已经向 Web 生态迈了一步,未来是否进一步与 Web 融合,也是有可能的。 另外就是跨平台技术本身的问题,浏览器发展了二三十年,已经是个很强大的跨平台产品了,几乎是 Web 的代名词了,这一点无人能敌。但是也臃肿不堪,有大量历史包袱,性能和体验不够好,和 Native 的结合度差,尤其在移动和 IoT 平台。虽然硬件性能在不断提升,但这是所有软件共享的,浏览器的性能和体验总会比 Native 差一些,差的这一些很可能就是新业务和新场景的发挥空间。观察一下近几年新诞生的业务场景,很多都是利用到了 Native 新提供的能力才火爆起来的,如 AI/AR/ 视频 / 直播 等,有因为新的 Web API 而孵化生出来的商业模式吗? 原文链接: https://mp.weixin.qq.com/s?__biz=MzAxNDEwNjk5OQ==&mid=2650405725&idx=1&sn=0b7476f7c7c01df7fdafda578f9ceb98&chksm=83953345b4e2ba53917ac30b709c07be15bd1c2fd5ae2a8ecfbb129b3813f771621b8fac95ca&scene=27#wechat_redirect
剑曼红尘 2020-03-10 09:54:40 0 浏览量 回答数 0

问题

搞懂了这几点,你就学会了Web编程

做了那么多年Web编程,仔细想想,其实本质上就那点事儿,你抓住了几个重点问题,学起来一点都不难。 1.理解浏览器/服务器结构(B/S) B/S是从90年代的客户端/服务器端...
技术小菜鸟 2019-12-01 21:20:38 2373 浏览量 回答数 1

问题

深入理解Magento - 第二章 - Magento请求分发与控制器 400 请求报错 

深入理解Magento 作者: Alan Storm 翻译: zhlmmc 第二章 - Magento请求分发与控制器 Model-View-Controller (MVC) ,模型-视图-控制器...
kun坤 2020-05-28 16:31:47 81 浏览量 回答数 0

回答

浅谈Flutter框架原理及其生态圈 Flutter的锋芒 跨平台高性能的渲染引擎逐渐成为移动端、大前端领域的一个热点,作为其中的明星框架Flutter,经过近几年来的迅速发展,由极大的可能成为下一代跨端终端解决方案。自从2017 年 5 月,谷歌公司发布的了 Alpha 版本的 Flutter; 2018 年底 Flutter Live 发布的 1.0 版本;2019年7月发布1.5版本,截止今日(2020年2月)已经发布了v1.14.6 Beta版本。 在Flutter诞生之前,已经有许多跨平台UI框架的方案如Cordova、ReactNative、weex、uni-app、Hippy等,常见的需要处理兼容的终端平台也包括android、ios、web、Iot等,但是在大前端的浪潮下,对于企业和开发者来说开发效率和使用体验都十分重要,传统的做法莫过于分不同的团队开发不同的终端项目,如果还要继续向其他平台,拓展的话,我们需要付出的成本和时间将成倍增长。正因为如此,在这样的背景下,Flutter等跨端框架的兴起,从本质上讲,帮助开发者增加业务代码的复用率,减少因为要适配多个平台带来的工作量,从而降低开发成本、提高开发效率。 纵观已有的跨端方案,可以分为三类:Web 容器、泛 Web 容器、自绘引擎框架。 基于web容器即基于浏览器的跨平台也做得越来越好,自然管线也越来越短,与native的一些技术手段来实现性能上的相互补充。比如Egret、Cocos、Laya这些游戏引擎,它们在跨平台方面的做法多以Typescript编写,在iOS和安卓平台的各种浏览器中轻松的运行HTML5游戏,并在不同平台浏览器里提供近乎一致的用户体验,比如Egret还会提供高效的 JS-C Binding 编译机制,以满足游戏编译为原生格式的需求,不过大多数HTML游戏引擎也属于web容器这个范畴内。web容器框架也有一个明显的致命(在对体验&性能有较高要求的情况下)的缺点,那就是WebView的渲染效率和JavaScript执行性能太差。再加上Android各个系统版本和设备厂商的定制,很难保证所在所有设备上都能提供一致的体验。 泛 Web 容器框架比如ReactNative和Weex,即上层通过面向前端友好的UI,下层通过native的渲染形式,虽然同样使用类HTML+JS的UI构建逻辑,但是最终会生成对应的自定义原生控件,以充分利用原生控件相对于WebView的较高的绘制效率,同时H5与native相互补充来达到更好的用户体验,这也是一种很好的解决方案。缺陷也很明显,随着系统版本变化和API的变化,开发者可能也需要处理不同平台的差异,甚至有些特性只能在部分平台上实现,这样框架的跨平台特性就会大打折扣。 自绘引擎框架这里专指Flutter框架,从底层就承担跨端的任务和渲染方式,从目前来看,从技术的实现和方案的成熟度、产品的性能方面比较,Flutter有很大可能成为下一代主流跨平台框架。 Flutter与其他跨端框架的不同点之一就是自带渲染引擎,Flutter渲染引擎依靠跨平台的Skia图形库来实现,Skia引擎会将使用Dart语言构建的抽象的视图结构数据加工成GPU数据,交由 OpenGL 最终提供给 GPU 渲染,至此完成渲染闭环,因此可以在最大程度上保证一款应用在不同平台、不同设备上的体验一致性。 而开发语言选用的是同时支持 JIT和 AOT的 Dart语言,Dart本身提供了三种运行方式,应对web环境,用Dart2js编译成JavaScript代码,运行在常规浏览器中;使用DartVM直接在命令行中运行Dart代码;AOT方式编译成机器码,例如Flutter App框架。而且Dart 避免了抢占式调度和共享内存,可以在没有锁的情况下进行对象分配和垃圾回收,在性能方面表现相当不错,不仅保证了开发效率,代码性能和用户体验也更卓越。因此,Flutter在各类跨平台移动开发方案中脱颖而出。同时在去年2019的Google IO大会上,备受关注的Fuchsia系统虽然并没有发布,但是宣布了 Flutter除了支持开发 Android 和 iOS 程序之外,现在还支持开发Web程序了,在 I/O 大会上,谷歌发布了 Web 版 Flutter 的首个技术预览版,宣布 Flutter 将为包括 Google Home Hub 在内的 Google Smart Display 平台提供技术支持,并迈出利用 Chrome 操作系统支持桌面级应用的第一步。 很多JS开发者会思考Google Flutter团队至于为啥选择Dart而不是JS,其实Google 公司给出的原因很简单也很直接:Dart 语言开发组就在隔壁,对于 Flutter 需要的一些语言新特性,能够快速在语法层面落地实现;而如果选择了 JavaScript,就必须经过各种委员会(TC39等)和浏览器提供商漫长的决议。 Flutter绘制原理 在计算机系统中,图像的显示需要 CPU、GPU 和显示器一起配合完成:CPU 负责图像数据计算,GPU 负责图像数据渲染,而显示器则负责最终图像显示。 CPU 把计算好的、需要显示的内容交给 GPU,由 GPU 完成渲染后放入帧缓冲区,随后视频控制器根据垂直同步信号(VSync)以每秒 60 次的速度,从帧缓冲区读取帧数据交由显示器完成图像显示。 操作系统在呈现图像时遵循了这种机制,而 Flutter 作为跨平台开发框架也采用了这种底层方案。下面有一张更为详尽的示意图来解释 Flutter 的绘制原理。可以看到,Flutter 关注如何尽可能快地在两个硬件时钟的 VSync 信号之间计算并合成视图数据,然后通过 Skia 交给 GPU 渲染:UI 线程使用 Dart 来构建视图结构数据,这些数据会在 GPU 线程进行图层合成,随后交给 Skia 引擎加工成 GPU 数据,而这些数据会通过 OpenGL 最终提供给 GPU 渲染。 Skia原理 Skia 是一款用由C++ 开发的2D 图像绘制引擎。在2005 年被 Google 公司收购后被广泛应用在 Android和其他等核心产品上,Skia 目前是Android 官方的图像渲染引擎,因此 Flutter Android SDK 无需内嵌 Skia 引擎就可以获得天然的 Skia 支持;而对于 iOS 平台来说,由于 Skia 是跨平台的,因此它作为 Flutter iOS 渲染引擎被嵌入到 Flutter 的 iOS SDK 中,替代了 iOS 闭源的 Core Graphics/Core Animation/Core Text,这也正是 Flutter iOS SDK 打包的 App 包体积比 Android 要大一些的原因。 底层渲染能力统一了,上层开发接口和功能体验也就随即统一了,开发者再也不用操心平台相关的渲染特性了。也就是说,Skia 保证了同一套代码调用在 Android 和 iOS 平台上的渲染效果是完全一致的。 Flutter架构 Framework底层是Flutter引擎,引擎主要负责图形绘制(Skia)、文字排版(libtxt)和提供Dart运行时,引擎全部使用C++实现,Framework层使我们可以用Dart语言调用引擎的强大能力。Flutter 架构采用分层设计,从下到上分为三层,依次为:Embedder、Engine、Framework。 Embedder 是操作系统适配层,实现了渲染 Surface 设置,线程设置,以及平台插件等平台相关特性的适配。从这里我们可以看到,Flutter 平台相关特性并不多,这就使得从框架层面保持跨端一致性的成本相对较低。 Engine 层主要包含 Skia、Dart 和 Text,实现了 Flutter 的渲染引擎、文字排版、事件处理和 Dart 运行时等功能。Skia 和 Text 为上层接口提供了调用底层渲染和排版的能力,Dart 则为 Flutter 提供了运行时调用 Dart 和渲染引擎的能力。而 Engine 层的作用,则是将它们组合起来,从它们生成的数据中实现视图渲染。 Framework 层则是一个用 Dart 实现的 UI SDK,包含了动画、图形绘制和手势识别等功能。为了在绘制控件等固定样式的图形时提供更直观、更方便的接口,Flutter 还基于这些基础能力,根据 Material 和 Cupertino 两种视觉设计风格封装了一套 UI 组件库,开发者可以直接使用这些组件库。 Flutter运行流程 页面中的各界面元素(Widget)以树的形式组织,即控件树。Flutter 通过控件树中的每个控件创建不同类型的渲染对象,组成渲染对象树。在Flutter界面渲染过程分为三个阶段:布局、绘制、合成,布局和绘制在Flutter框架中完成,合成则交由引擎负责。 Flutter 采用深度优先机制遍历渲染对象树,决定渲染对象树中各渲染对象在屏幕上的位置和尺寸。在布局过程中,渲染对象树中的每个渲染对象都会接收父对象的布局约束参数,决定自己的大小,然后父对象按照控件逻辑决定各个子对象的位置,最终完成布局过程。这里只需要注意一点,无论布局还是绘制,都是父子间的遍历关系:父Widget的布局需要依赖子Widget的布局结果;而绘制则反过来(子Widget需要盖在父Widget上),布局是后续遍历,绘制是前序遍历,他们都是深度优先遍历。 Flutter生命周期 可以看到,Flutter中State 的生命周期可以分为 3 个阶段:创建(插入视图树)、更新(在视图树中存在)、销毁(从视图树中移除)。接下来,我们一起看看每一个阶段的具体流程。 第一步创建 State 初始化时会依次执行 :构造方法 -> initState -> didChangeDependencies -> build,随后完成页面渲染。构造方法是 State 生命周期的起点,Flutter 会通过调用StatefulWidget.createState() 来创建一个 State。我们可以通过构造方法,来接收父 Widget 传递的初始化 UI 配置数据。这些配置数据,决定了 Widget 最初的呈现效果。 initState,会在 State 对象被插入视图树的时候调用。这个函数在 State 的生命周期中只会被调用一次,所以我们可以在这里做一些初始化工作,比如为状态变量设定默认值。 didChangeDependencies 则用来专门处理 State 对象依赖关系变化,会在 initState() 调用结束后,被 Flutter 调用。 build,作用是构建视图。经过以上步骤,Framework 认为 State 已经准备好了,于是调用 build。我们需要在这个函数中,根据父 Widget 传递过来的初始化配置数据,以及 State 的当前状态,创建一个 Widget 然后返回。 第二步更新 Widget 的状态更新,主要由个方法触发:setState、didchangeDependencies、didUpdateWidget。 setState:我们最熟悉的方法之一。当状态数据发生变化时,我们总是通过调用这个方法告诉 Flutter:“我这儿的数据变啦,请使用更新后的数据重建 UI!” didChangeDependencies:State 对象的依赖关系发生变化后,Flutter 会回调这个方法,随后触发组件构建。哪些情况下 State 对象的依赖关系会发生变化呢?典型的场景是,系统语言 Locale 或应用主题改变时,系统会通知 State 执行 didChangeDependencies 回调方法。 didUpdateWidget:当 Widget 的配置发生变化时,比如,父 Widget 触发重建(即父 Widget 的状态发生变化时),热重载时,系统会调用这个函数。一旦这三个方法被调用,Flutter 随后就会销毁老 Widget,并调用 build 方法重建 Widget。 第三步销毁 比如组件被移除,或是页面销毁的时候,系统会调用 deactivate 和 dispose 这两个方法,来移除或销毁组件。 Flutter生态圈及其常用框架 一项技术一个框架是否流行,最直观的体现就是它的生态圈是否活跃,下面列举了一些Flutter开发中常用的库工具。 参考文献 1、[Flutter原理与实践](https://tech.meituan.com/2018/08/09/waimai-flutter-practice.html) 少杰 2、[Flutter框架技术概览](https://flutter.dev/docs/resources/technical-overview) 3、[Flutter中文官网](https://pub.dartlang.org/flutter/) 4、[Flutter插件仓库](https://pub.dev/flutter/packages)
罗思雨 2020-02-27 11:47:50 0 浏览量 回答数 0

回答

“程序设计 = 算法 + 数据结构”是瑞士计算机科学家Niklaus Wirth于1976年出版的一本书的书名,很快就成了在计算机工作者之间流传的一句名言。斗转星移,尽管新技术方法不断涌现,这句名言依然焕发着无限的生命力,它借助面向对象知识的普及,使数据结构技术更加完善和易于使用。由此,也说明了数据结构在计算机学科中的地位和不可替代的独特作用。 然而,在可视化程序设计的今天,借助于集成开发环境我们可以很方便、快捷地开发部署应用程序,程序设计似乎不再只是计算机专业的人员的专利,很多人以为,只要掌握了几种开发工具就可以成为编程高手了,其实这是一个误区。纵然,我们可以很熟练地掌握一门程序设计语言、熟练地运用各种IDE开发应用程序,但是我们写出的代码是否是优良的。我们的设计是否合理。代码执行是否是高效的。代码风格是否是有美感的。更甚的说我们所写出代码的是否是艺术。 在长达几年的时间内,我总是陷在了一个误区里面:即认为工程能力和算法能力是不相干的两回事,我们似乎可以很轻松地完成一个工程项目,至少我在做一些MIS系统的时候一直都是这么认为的,甚至觉得根本不需要所谓的算法或数据结构。当时一直想不通的是为什么Google、百度这样牛的公司却对ACMer们如此青睐,对于这种招聘的标准感到疑惑不解。为什么他们不在技术(多线程、网络编程、分布式系统等)上做要求,却偏偏只关注这么一小块的算法设计。 我曾经反复地告诉自己“程序设计 = 算法 + 数据结构”在70年代提出是受限于计算机硬件,当时的内存不足、计算能力不强,程序需要设计足够精巧细致。再看当前主流的计算机配置,比70年代的大型机运算能力还要强大,我们好像完全不用担心算法设计的问题。报着这样的想法,我向来都不太重视算法,而且工程中对算法的需求并不多。 只是有一天,我突然发现我只是片面地关注其中一个方面,硬件能力是提升了,但同时人们所面对的信息、数据、运算任务的规模也是极大的膨胀了,而且膨胀的规模比硬件本身运算能力提升的规模还要大很多。算法和数据结构不仅没有贬值,反而比之前那个时代显得更为重要。试想,在互联网迅猛发展的今天,一个中等规模的企业每天所产生的数据量能达到GB级甚至TB级。要处理这样的海量数据不是说单纯的硬件运算能力上来就解决了的,设计优良的算法和数据结构设计能够在1分钟之内完成任务,而一个糟糕的设计则可能需要1个小时的运行。 一般认为,一个数据结构是由数据元素依据某种逻辑联系组织起来的,这种对数据元素间逻辑关系的描述称为数据结构。许多大型系统的构造经验表明,系统实现的困难程度和系统构造的质量都严重的依赖于是否选择了最优的数据结构。许多时候,确定了数据结构后,算法就容易得到了。当然,有些情况下事情也会反过来,我们根据特定算法来选择数据结构与之适应。算法则可以理解为有基本运算及规定的运算顺序所构成的完整的解题步骤,或者看成按照要求设计好的有限的确切的计算序列,并且这样的步骤和序列可以解决一类问题。 总的来说,数据结构和算法并不是一门教你编程的课,它们可以脱离任何的计算机程序设计语言,而只需要从抽象意义上去概括描述。说的简单一点,数据结构是一门告诉你数据在计算机里如何组织的课程,而算法是一门告诉你数据在计算机里如何运算的课程,前者是结构学、后者是数学。程序设计就像盖房子,数据结构是砖、瓦,而算法则是设计图纸。你若想盖房子首先必须要有原材料(数据结构),但这些原材料并不能自动地盖起你想要的房子,你必须按照设计图纸(算法)一砖一瓦地去砌,这样你才能拥有你想要的房子。数据结构是程序设计这座大厦的基础,没有基础,无论设计有多么高明,这座大厦不可能建造起来。算法则是程序设计之灵魂,它是程序设计的思想所在,没有灵魂没有思想那不叫程序,只是一堆杂乱无章的符号而已。在程序设计中,数据结构就像物质,而算法则是意识,这在哲学上可以理解为:意识是依赖与物质而存在的,物质是由意识而发展的。双方相互依赖,缺一不可。 当然最经典的数据结构是有限的,包括线性表、栈、队列、串、数组、二叉树、树、图、查找表等,而算法则是琳琅满目的,多种多样的。就好像数据结构是人体的各种组织、器官,算法则是人的思想。你可以用自己的思想去支配你的身体各个可以运动的器官随意运动。如果你想吃苹果,你可以削皮吃,可以带皮吃,只要你愿意,甚至你可以不洗就吃。但无论如何,你的器官还是你的器官,就那么几样,目的只有一个就是吃苹果,而方式却是随心所欲的。这就是算法的灵活性、不固定性。因此可以这样说:数据结构是死的,而算法是活的。 我花了四年时间才走出这个误区,值得庆幸的是不算太晚,而我的梦想是要做一名优秀的架构师,缺乏数据结构和算法的深厚功底,很难设计出高水平的具有专业水准的架构和应用,数据结构和算法则是我实现梦想最坚实的基石。现在,也正是我需要开始沉淀的时刻。程序设计这项伟大的工程,教授于我的将不仅仅是技术这么简单,我期待它能给我以更深的思考与感悟,激发我对生命的热爱,对理想的执着,对卓越的追求。
琴瑟 2019-12-02 01:22:02 0 浏览量 回答数 0

回答

Java Java核心技术·卷 I(原书第10版)| Core Java Volume 讲的很全面,书中的代码示例都很好,很适合Java入门。 但是作者不太厚道的是把现在没人用的GUI编程放在了第一卷,基本上10~13章是可以不用读的。 Java性能权威指南|Java Performance: The Definitive Guide 市面上介绍Java的书有很多,但专注于Java性能的并不多,能游刃有余地展示Java性能优化难点的更是凤毛麟角,本书即是其中之一。 通过使用JVM和Java平台,以及Java语言和应用程序接口,本书详尽讲解了Java性能调优的相关知识,帮助读者深入理解Java平台性能的各个方面,最终使程序如虎添翼。 实战Java高并发程序设计|葛一鸣 由部分段落的行文来看,搬了官方文档。 也有一些第一人称的叙述和思考,也能看出作者也是花了一点心思的。胜在比较基础,涉及到的知识点也还很全面(讲到了流水线计算和并发模型这些边边角角的),但是由于是编著,全书整体上不够统一和深入,适合作为学习高并发的第一本工具书。 Java 8实战 对Java8的新特性讲解的十分到位,尤其是lamdba表达式和流的操作。 再者对于Java8并发处理很有独到见解。对于并行数据处理和组合式异步编程还需要更深的思考才能更加掌握。 推荐给再用java8但没有去真正了解的人看,有很多你不知道的细节、原理和类库设计者的用心良苦在里面、内容没有很难,抽出几个小时就能看完,花费的时间和收获相比,性价比很高。 Java并发编程实战 先不谈本书的内容如何,光书名就足够吸引不少目光。“并发”这个词在Java世界里往往和“高级、核心”等字眼相联系起来,就冲着这两个字,都将勾起软件工程师们埋藏在心底那种对技术的探索欲和对高级API的驾驭感。 程序员嘛,多少都有点职业病。其实Java对“并发”优化从未停止过,从5.0到7.0,几乎每个版本的新特性里,都会针对前一版本在“并发”上有所改进。这种改进包括提供更丰富的API接口、JVM底层性能优化等诸多方面。 Thinking in Java 很美味的一本书,不仅有icecreamm,sundae,sandwich,还有burrito!真是越看越饿啊~ Effective Java中文版(第3版)|Effective Java Third Edition Java 高阶书籍,小白劝退。介绍了关于Java 编程的90个经验技巧。 作者功力非常强悍,导致这本书有时知识面迁移很广。总之,非常适合有一定Java开发经验的人阅读提升。 深入理解Java虚拟机(第3版)| 周志明 浅显易懂。最重要的是开启一扇理解虚拟机的大门。 内存管理机制与Java内存模型、高效并发这三章是特别实用的。 Java虚拟机规范(Java SE 8版)|爱飞翔、周志明 整本书就觉得第二章的方法字节码执行流程,第四章的前8节和第五章能看懂一些。其他的过于细致和琐碎了。 把Java字节码讲的很清楚了,本质上Java虚拟机就是通过字节码来构建的一套体系罢了。所以字节码说的非常细致深入。 数据&大数据 数据结构与算法分析|Data Structures and Algorithm Analysis in Java 数据结构是计算机的核心,这部书以java语言为基础,详细的介绍了基本数据结构、图、以及相关的排序、最短路径、最小生成树等问题。 但是有一些高级的数据结构并没有介绍,可以通过《数据结构与算法分析——C语言描述》来增加对这方面的了解。 MySQL必知必会 《MySQL必知必会》MySQL是世界上最受欢迎的数据库管理系统之一。 书中从介绍简单的数据检索开始,逐步深入一些复杂的内容,包括联结的使用、子查询、正则表达式和基于全文本的搜索、存储过程、游标、触发器、表约束,等等。通过重点突出的章节,条理清晰、系统而扼要地讲述了读者应该掌握的知识,使他们不经意间立刻功力大增。 数据库系统概念|Datebase System Concepts(Fifth Edition) 从大学读到现在,每次拿起都有新的收获。而且这本书还是对各个数据相关领域的概览,不仅仅是数据库本身。 高性能MySQL 对于想要了解MySQL性能提升的人来说,这是一本不可多得的书。 书中没有各种提升性能的秘籍,而是深入问题的核心,详细的解释了每种提升性能的原理,从而可以使你四两拨千斤。授之于鱼不如授之于渔,这本书做到了。 高可用MySQL 很实用的书籍,只可惜公司现有的业务和数据量还没有达到需要实践书中知识的地步。 利用Python进行数据分析|唐学韬 内容还是跟不上库的发展速度,建议结合里面讲的库的文档来看。 内容安排上我觉得还不错,作者是pandas的作者,所以对pandas的讲解和设计思路都讲得很清楚。除此以外,作者也是干过金融数据分析的,所以后面专门讲了时间序列和金融数据的分析。 HBase 看完影印版第一遍,开始以为会是大量讲API,实际上除了没有将HBase源代码,该讲的都讲了,CH8,9章留到最后看的,确实有点顿悟的感觉,接下来需要系统的看一遍Client API,然后深入代码,Come ON! Programming Hive Hive工具书,Hive高级特性。 Hadoop in Practice| Alex Holmes 感觉比action那本要强 像是cookbook类型的 整个过完以后hadoop生态圈的各种都接触到了 这本书适合当参考手册用。 Hadoop技术内幕|董西成 其实国人能写这样的书,感觉还是不错的,不过感觉很多东西不太深入,感觉在深入之前,和先有整体,带着整体做深入会更好一点, jobclient,jobtracer,tasktracer之间的关系最好能系统化 Learning Spark 很不错,core的原理部分和api用途解释得很清楚,以前看文档和代码理解不了的地方豁然开朗。 不足的地方是后几章比较弱,mllib方面没有深入讲实现原理。graphx也没有涉及 ODPS权威指南 基本上还算一本不错的入门,虽然细节方面谈的不多,底层也不够深入,但毕竟是少有的ODPS书籍,且覆盖面很全,例子也还行。 数据之巅|徐子沛 从一个新的视角(数据)切入,写美国历史,统计学的发展贯穿其中,草蛇灰线,伏脉千里,读起来波澜壮阔。 消息队列&Redis RabbitMQ实战 很多年前的书了,书中的例子现在已经不适用了,推荐官方教程。 一些基础还是适用,网上也没有太多讲rab的书籍,将就看下也行,我没用过所以…. Apache Kafka源码剖析|徐郡明 虽然还没看,但知道应该不差。我是看了作者的mybatis源码分析,再来看这本的,相信作者。 作者怎么有这么多时间,把框架研究的这么透彻,佩服,佩服。 深入理解Kafka:核心设计与实践原理|朱忠华 通俗易懂,图文并茂,用了很多图和示例讲解kafka的架构,从宏观入手,再讲到细节,比较好,值得推荐。 深入理解Kafka是市面上讲解Kafka核心原理最透彻的,全书都是挑了kafka最核心的细节在讲比如分区副本选举、分区从分配、kafka数据存储结构、时间轮、我认为是目前kafka相关书籍里最好的一本。 Kafka 认真刷了 kafka internal 那章,看了个talk,算是入了个门。 系统设计真是门艺术。 RocketMQ实战与原理解析|杨开元 对RocketMQ的脉络做了一个大概的说明吧,深入细节的东西还是需要自己看代码 Redis设计与实现|黄健宏 部分内容写得比较啰嗦,当然往好了说是对新手友好,不厌其烦地分析细节,但也让整本书变厚了,个人以为精炼语言可以减少20%的内容。 对于有心一窥redis实现原理的读者来说,本书展露了足够丰富的内容和细节,却不至于让冗长的实现代码吓跑读者——伪代码的意义在此。下一步是真正读源码了。 Redis 深度历险:核心原理与应用实践|钱文品 真心不错,数据结构原理+实际应用+单线程模型+集群(sentinel, codis, redis cluster), 分布式锁等等讲的都十分透彻。 一本书的作用不就是系统性梳理,为读者打开一扇窗,读者想了解更多,可以自己通过这扇窗去Google。这本书的一个瑕疵是最后一章吧,写的仓促了。不过瑕不掩瑜。 技术综合 TCP/IP详解 卷1:协议 读专业性书籍是一件很枯燥的事,我的建议就是把它作为一本手册,先浏览一遍,遇到问题再去详细查,高效。 Netty in Action 涉及到很多专业名词新概念看英文原版顺畅得多,第十五章 Choosing the right thread model 真是写得太好了。另外结合Ron Hitchens 写的《JAVA NIO》一起看对理解JAVA NIO和Netty还是很有帮助的 ZooKeeper 值得使用zookeeper的人员阅读, 对于zookeeper的内部机制及api进行了很详细的讲解, 后半部分深入地讲解了zookeeper中ensemble互相协作的流程, 及group等高级配置, 对zookeeper的高级应用及其它类似系统的设计都很有借鉴意义. 从Paxos到Zookeeper|倪超 分布式入门鼻祖,开始部分深入阐述cap和base理论,所有的分布式框架都是围绕这个理论的做平衡和取舍,中间 zk的原理、特性、实战也讲的非常清晰,同时讲cap理论在zk中是如何体现,更加深你对cap的理解. 深入理解Nginx(第2版)|陶辉 云里雾里的快速读了一遍,主要是读不懂,读完后的感受是设计的真好。 原本是抱着了解原理进而优化性能的想法来读的,却发现书中的内容都是讲源码,作者对源码的注释超级详细,非常适合开发者,但不适合使用者,给个五星好评是因为不想因为我这种菜鸡而埋没了高质量内容。 另外别人的代码写的真好看,即便是过程式语言程序也吊打我写的面向对象语言程序。 作者是zookeeper的活跃贡献者,而且是很资深的研究员,内容比较严谨而且较好的把握住了zk的精髓。书很薄,但是没有废话,选题是经过深思熟虑的。 深入剖析Tomcat 本书深入剖析Tomcat 4和Tomcat 5中的每个组件,并揭示其内部工作原理。通过学习本书,你将可以自行开发Tomcat组件,或者扩展已有的组件。 Tomcat是目前比较流行的Web服务器之一。作为一个开源和小型的轻量级应用服务器,Tomcat 易于使用,便于部署,但Tomcat本身是一个非常复杂的系统,包含了很多功能模块。这些功能模块构成了Tomcat的核心结构。本书从最基本的HTTP请求开始,直至使用JMX技术管理Tomcat中的应用程序,逐一剖析Tomcat的基本功能模块,并配以示例代码,使读者可以逐步实现自己的Web服务器。 深入理解计算机系统 | 布莱恩特 无论是内容还是纸张印刷,都是满分。计算机学科的集大成之作。引导你如何练内功的,算是高配版本的计算机导论,目的是釜底抽薪引出来操作系统、组成原理这些专业核心的课程。帮助我们按图索骥,点亮一个一个技能树。 架构探险分布式服务框架 | 李业兵 刚看前几章的时候,心里满脑子想得都是这特么贴一整页pom文件代码上来干鸡毛,又是骗稿费的,买亏了买亏了,后来到序列化那章开始,诶?还有那么点意思啊。 到服务注册中心和服务通讯,60块钱的书钱已经赚回来了。 知识是无价的,如果能花几十块钱帮你扫了几个盲区,那就是赚了。 深入分析JavaWeb技术内幕 | 许令波 与这本书相识大概是四年前是在老家的北方图书城里,当时看到目录的感觉是真的惊艳,对当时刚入行的自己来说,这简直就是为我量身定做的扫盲科普集啊。 但是可惜的是,这本书在后来却一直没机会读上。然后经过四年的打怪升级之后,这次的阅读体验依旧很好。 其中,java编译原理、 Servlet工作原理、 Tomcat、spring和iBatis这几章的收获很大。 前端 jQuery 技术内幕| 高云 非常棒的一本书,大大降低了阅读jquery源码的难度(虽然还是非常难)。 Head First HTML与CSS(第2版) 翻了非常久的时间 断断续续 其实从头翻到尾 才发现一点都不难。 可我被自己的懒惰和畏难情绪给拖累了 简单说 我成了自己往前探索的负担。网页基础的语法基本都涵盖了 限于文本形态 知识点都没法像做题一样被反复地运用和复习到。通俗易懂 这不知算是多高的评价? 作为入门真心算不错了 如果更有耐心 在翻完 HTML 后 对 CSS 部分最好是可以迅速过一遍 找案例练习估计更好 纸上得来终觉浅 总是这样。 JavaScript高级程序设计(第3版) JavaScript最基础的书籍,要看认真,慢慢地看,累计接近1000小时吧。而且对象与继承,性能优化,HTML5 api由于没有实践或缺乏代码阅读量导致看的很糊涂,不过以后可以遇到时再翻翻,或者看更专业的书。 深入理解ES6 Zakas的又一部杰作,他的作品最优秀的地方在于只是阐述,很少评价,这在帮助我们夯实基础时十分有意义,我也喜欢这种风格。 我是中英文参照阅读的,译本后半部分有一些文字上的纰漏,但是总体来说忠实原文,水平还是相当不错,希望再版时可以修复这些文字问题。 高性能JavaScript 还是挺不错的。尤其是对初学者。总结了好多程序方面的好习惯。 不过对于老手来说,这些常识已经深入骨髓了。 深入浅出Node.js|朴灵 本书是我看到现在对Node.JS技术原理和应用实践阐述的最深入,也最全面的一本书。鉴于作者也是淘宝的一位工程师,在技术总是国外好的大环境下,没有理由不给本书五颗星。 作者秉着授人于鱼不如授人于渔的精神,细致入微的从V8虚拟机,内存管理,字符串与Buffer的应用,异步编程的思路和原理这些基础的角度来解释Node.JS是如何工作的,比起市面上众多教你如何安装node,用几个包编写一些示例来比,本书绝对让人受益匪浅。 认真看完本书,几乎可以让你从一个Node的外行进阶到专家的水平。赞! 总结 其实我觉得在我们现在这个浮躁的社会,大家闲暇时间都是刷抖音,逛淘宝,微博……他们都在一点点吞噬你的碎片时间,如果你尝试着去用碎片的时间看看书,我想时间久了你自然能体会这样的好处。 美团技术团队甚至会奖励读完一些书本的人,很多公司都有自己的小图书馆,我觉得挺好的。 文章来自:敖丙
剑曼红尘 2020-03-20 14:52:22 0 浏览量 回答数 0

回答

本文总结了常见的 Linux 内核参数及相关问题。修改内核参数前,您需要: 从实际需要出发,最好有相关数据的支撑,若您的业务没有受到影响不建议调整内核参数。 了解每一个参数的具体作用,并且同类型或版本操作系统下内核参数可能有所不同。 备份 ECS 实例中的重要数据。参阅文档 创建快照。 Linux 常用内核网络参数 参数 描述 net.core.rmem_default 默认的 TCP 数据接收窗口大小(字节)。 net.core.rmem_max 最大的 TCP 数据接收窗口(字节)。 net.core.wmem_default 默认的 TCP 数据发送窗口大小(字节)。 net.core.wmem_max 最大的 TCP 数据发送窗口(字节)。 net.core.netdev_max_backlog 在每个网络接口接收数据包的速率比内核处理这些包的速率快时,允许送到队列的数据包的最大数目。 net.core.somaxconn 定义了系统中每一个端口最大的监听队列的长度,这是个全局的参数。 net.core.optmem_max 表示每个套接字所允许的最大缓冲区的大小。 net.ipv4.tcp_mem 确定 TCP 栈应该如何反映内存使用,每个值的单位都是内存页(通常是 4KB)第一个值是内存使用的下限;第二个值是内存压力模式开始对缓冲区使用应用压力的上限;第三个值是内存使用的上限。在这个层次上可以将报文丢弃,从而减少对内存的使用。对于较大的 BDP 可以增大这些值(注意:其单位是内存页而不是字节)。 net.ipv4.tcp_rmem 为自动调优定义 socket 使用的内存。第一个值是为 socket 接收缓冲区分配的最少字节数;第二个值是默认值(该值会被 rmem_default 覆盖),缓冲区在系统负载不重的情况下可以增长到这个值;第三个值是接收缓冲区空间的最大字节数(该值会被 rmem_max 覆盖)。 net.ipv4.tcp_wmem 为自动调优定义 socket 使用的内存。第一个值是为 socket 发送缓冲区分配的最少字节数;第二个值是默认值(该值会被 wmem_default 覆盖),缓冲区在系统负载不重的情况下可以增长到这个值;第三个值是发送缓冲区空间的最大字节数(该值会被 wmem_max 覆盖)。 net.ipv4.tcp_keepalive_time TCP 发送 keepalive 探测消息的间隔时间(秒),用于确认 TCP 连接是否有效。 net.ipv4.tcp_keepalive_intvl 探测消息未获得响应时,重发该消息的间隔时间(秒)。 net.ipv4.tcp_keepalive_probes 在认定 TCP 连接失效之前,最多发送多少个 keepalive 探测消息。 net.ipv4.tcp_sack 启用有选择的应答(1 表示启用),通过有选择地应答乱序接收到的报文来提高性能,让发送者只发送丢失的报文段,(对于广域网通信来说)这个选项应该启用,但是会增加对 CPU 的占用。 net.ipv4.tcp_fack 启用转发应答,可以进行有选择应答(SACK)从而减少拥塞情况的发生,这个选项也应该启用。 net.ipv4.tcp_timestamps TCP 时间戳(会在 TCP 包头增加 12 B),以一种比重发超时更精确的方法(参考 RFC 1323)来启用对 RTT 的计算,为实现更好的性能应该启用这个选项。 net.ipv4.tcp_window_scaling 启用 RFC 1323 定义的 window scaling,要支持超过 64KB 的 TCP 窗口,必须启用该值(1 表示启用),TCP 窗口最大至 1GB,TCP 连接双方都启用时才生效。 net.ipv4.tcp_syncookies 表示是否打开 TCP 同步标签(syncookie),内核必须打开了 CONFIG_SYN_COOKIES 项进行编译,同步标签可以防止一个套接字在有过多试图连接到达时引起过载。默认值 0 表示关闭。 net.ipv4.tcp_tw_reuse 表示是否允许将处于 TIME-WAIT 状态的 socket (TIME-WAIT 的端口)用于新的 TCP 连接。 net.ipv4.tcp_tw_recycle 能够更快地回收 TIME-WAIT 套接字。 net.ipv4.tcp_fin_timeout 对于本端断开的 socket 连接,TCP 保持在 FIN-WAIT-2 状态的时间(秒)。对方可能会断开连接或一直不结束连接或不可预料的进程死亡。 net.ipv4.ip_local_port_range 表示 TCP/UDP 协议允许使用的本地端口号。 net.ipv4.tcp_max_syn_backlog 对于还未获得对方确认的连接请求,可保存在队列中的最大数目。如果服务器经常出现过载,可以尝试增加这个数字。默认为 1024。 net.ipv4.tcp_low_latency 允许 TCP/IP 栈适应在高吞吐量情况下低延时的情况,这个选项应该禁用。 net.ipv4.tcp_westwood 启用发送者端的拥塞控制算法,它可以维护对吞吐量的评估,并试图对带宽的整体利用情况进行优化,对于 WAN 通信来说应该启用这个选项。 net.ipv4.tcp_bic 为快速长距离网络启用 Binary Increase Congestion,这样可以更好地利用以 GB 速度进行操作的链接,对于 WAN 通信应该启用这个选项。 net.ipv4.tcp_max_tw_buckets 该参数设置系统的 TIME_WAIT 的数量,如果超过默认值则会被立即清除。默认为 180000。 net.ipv4.tcp_synack_retries 指明了处于 SYN_RECV 状态时重传 SYN+ACK 包的次数。 net.ipv4.tcp_abort_on_overflow 设置改参数为 1 时,当系统在短时间内收到了大量的请求,而相关的应用程序未能处理时,就会发送 Reset 包直接终止这些链接。建议通过优化应用程序的效率来提高处理能力,而不是简单地 Reset。默认值: 0 net.ipv4.route.max_size 内核所允许的最大路由数目。 net.ipv4.ip_forward 接口间转发报文。 net.ipv4.ip_default_ttl 报文可以经过的最大跳数。 net.netfilter.nf_conntrack_tcp_timeout_established 让 iptables 对于已建立的连接,在设置时间内若没有活动,那么则清除掉。 net.netfilter.nf_conntrack_max 哈希表项最大值。 查看和修改 Linux 实例内核参数 方法一、通过 /proc/sys/ 目录 /proc/sys/ 目录是 Linux 内核在启动后生成的伪目录,其目录下的 net 文件夹中存放了当前系统中生效的所有内核参数、目录树结构与参数的完整名称相关,如 net.ipv4.tcp_tw_recycle,它对应的文件是 /proc/sys/net/ipv4/tcp_tw_recycle,文件的内容就是参数值。 查看内核参数:使用 cat 查看对应文件的内容,例如执行命令 cat /proc/sys/net/ipv4/tcp_tw_recycle 查看 net.ipv4.tcp_tw_recycle 的值。 修改内核参数:使用 echo 修改内核参数对应的文件,例如执行命令 echo "0" > /proc/sys/net/ipv4/tcp_tw_recycle 将 net.ipv4.tcp_tw_recycle 的值修改为 0。 注意:方法一修改的参数值仅在当次运行中生效,系统重启后会回滚历史值,一般用于临时性的验证修改的效果。若需要永久性的修改,请参阅方法二。 方法二、通过 sysctl.conf 文件 查看内核参数:执行命令 sysctl -a 查看当前系统中生效的所有参数,如下所示: net.ipv4.tcp_app_win = 31 net.ipv4.tcp_adv_win_scale = 2 net.ipv4.tcp_tw_reuse = 0 net.ipv4.tcp_frto = 2 net.ipv4.tcp_frto_response = 0 net.ipv4.tcp_low_latency = 0 net.ipv4.tcp_no_metrics_save = 0 net.ipv4.tcp_moderate_rcvbuf = 1 net.ipv4.tcp_tso_win_divisor = 3 net.ipv4.tcp_congestion_control = cubic net.ipv4.tcp_abc = 0 net.ipv4.tcp_mtu_probing = 0 net.ipv4.tcp_base_mss = 512 net.ipv4.tcp_workaround_signed_windows = 0 net.ipv4.tcp_challenge_ack_limit = 1000 net.ipv4.tcp_limit_output_bytes = 262144 net.ipv4.tcp_dma_copybreak = 4096 net.ipv4.tcp_slow_start_after_idle = 1 net.ipv4.cipso_cache_enable = 1 net.ipv4.cipso_cache_bucket_size = 10 net.ipv4.cipso_rbm_optfmt = 0 net.ipv4.cipso_rbm_strictvalid = 1 修改内核参数: 执行命令   /sbin/sysctl -w kernel.domainname="example.com"  来修改指定的参数值,如 sysctl -w net.ipv4.tcp_tw_recycle="0" 执行命令   vi /etc/sysctl.conf  修改   /etc/sysctl.conf  文件中的参数。 执行命令   /sbin/sysctl -p  使配置生效。 Linux 网络相关内核参数引发的常见问题及处理 问题现象 原因分析 解决方案 无法在本地网络环境通过 SSH 连接 ECS Linux 实例,或者访问该 Linux 实例上的 HTTP 业务出现异常。Telnet 测试会被 reset。 如果您的本地网络是 NAT 共享方式上网,该问题可能是由于本地 NAT 环境和目标 Linux 相关内核参数配置不匹配导致。尝试通过修改目标 Linux 实例内核参数来解决问题:1. 远程连接目标 Linux 实例;2. 查看当前配置: cat /proc/sys/net/ipv4/tcp_tw_recyclecat /proc/sys/net/ipv4/tcp_timestamps 查看上述两个配置的值是不是 0,如果为 1的话,NAT 环境下的请求可能会导致上述问题。 通过如下方式将上述参数值修改为 0:1. 执行命令 vi /etc/sysctl.conf。2. 添加如下内容:net.ipv4.tcp_tw_recycle=0net.ipv4.tcp_timestamps=0。3. 输入指令 # sysctl -p 使配置生效。4. 重新 SSH 登录实例或者业务访问测试。 服务端 A 与 客户端 B 建立了 TCP 连接,之后服务端 A 主动断开了连接,但是在客户端 B 上仍然看到连接是建立的。示例见图一,图二。 通常是由于修改了服务端内核参数 net.ipv4.tcp_fin_timeout 默认设置所致。 1. 执行命令 vi /etc/sysctl.conf,修改配置:net.ipv4.tcp_fin_timeout=30。2. 执行命令 # sysctl -p 使配置生效。 通过 netstat 或 ss 可以看到大量处于 TIME_WAIT 状态的连接。 通过 netstat -n | awk ‘/^tcp/ {++y[$NF]} END {for(w in y) print w, y[w]}’ 查看 TIME_WAIT 数量。 1. 执行命令 vi /etc/sysctl.conf,修改或加入以下内容: net . ipv4 . tcp_syncookies = 1 net . ipv4 . tcp_tw_reuse = 1 net . ipv4 . tcp_tw_recycle = 1 net . ipv4 . tcp_fin_timeout = 30 2. 执行命令 /sbin/sysctl -p  使配置生效。 云服务器上出现大量 CLOSE_WAIT 状态的连接数。 根据实例上的业务量来判断 CLOSE_WAIT 数量是否超出了正常的范围。TCP 连接断开时需要进行四次挥手,TCP 连接的两端都可以发起关闭连接的请求,若对端发起了关闭连接,但本地没有进行后续的关闭连接操作,那么该链接就会处于 CLOSE_WAIT 状态。虽然该链接已经处于半开状态,但是已经无法和对端通信,需要及时的释放该链接。建议从业务层面及时判断某个连接是否已经被对端关闭,即在程序逻辑中对连接及时进行关闭检查。 通过命令 netstat -an|grep CLOSE_WAIT|wc -l 查看当前实例上处于 CLOSE_WAIT 状态的连接数。Java 语言:1. 通过 read 方法来判断 I/O 。当 read 方法返回 -1 时则表示已经到达末尾。2. 通过 close 方法关闭该链接。C 语言:1. 检查 read 的返回值,若是 0 则可以关闭该连接,若小于 0 则查看一下 errno,若不是 AGAIN 则同样可以关闭连接。 ECS Linux FIN_WAIT2 状态的 TCP 链接过多。 HTTP 服务中,SERVER 由于某种原因关闭连接,如 KEEPALIVE 的超时。这样,作为主动关闭的 SERVER 一方就会进入 FIN_WAIT2 状态。但 TCP/IP 协议栈中,FIN_WAIT2 状态是没有超时的(不像 TIME_WAIT 状态),如果 Client 不关闭,FIN_WAIT_2 状态将保持到系统重启,越来越多的 FIN_WAIT_2 状态会致使内核 Crash。 1. 执行命令 vi /etc/sysctl.conf,修改或加入以下内容: net . ipv4 . tcp_syncookies = 1 net . ipv4 . tcp_fin_timeout = 30 net . ipv4 . tcp_max_syn_backlog = 8192 net . ipv4 . tcp_max_tw_buckets = 5000 2. 执行命令 # sysctl -p 使配置生效。 查询服务器 /var/log/message 日志,发现全部是类似如下 kernel: TCP: time wait bucket table overflowt 的报错信息,报错提示 TCP time wait 溢出,见图三。 TCP 连接使用很高,容易超出限制。见图四。 1. 执行命令 netstat -anp |grep tcp |wc -l统计 TCP 连接数。2. 对比 /etc/sysctl.conf 配置文件的 net.ipv4.tcp_max_tw_buckets 最大值,看是否有超出情况。3. 执行命令 vi /etc/sysctl.conf,查询 net.ipv4.tcp_max_tw_buckets 参数。如果确认连接使用很高,容易超出限制。4. 调高参数 net.ipv4.tcp_max_tw_buckets,扩大限制。5. 执行命令 # sysctl -p 使配置生效。 ECS Linux 实例出现间歇性丢包的情况,通过 tracert, mtr 等手段排查,外部网络未见异常。同时,如下图所示,在系统日志中重复出现大量kernel nf_conntrack: table full, dropping packet.错误信息。见图五。 ip_conntrack 是 Linux 系统内 NAT 的一个跟踪连接条目的模块。ip_conntrack 模块会使用一个哈希表记录 TCP 通讯协议的 established connection 记录,当哈希表满了的时候,会导致 nf_conntrack: table full, dropping packet 错误。需要通过修改内核参数来调整 ip_conntrack 限制。 Centos 5.x 系统1. 使用管理终端登录实例。2. 执行命令 # vi /etc/sysctl.conf 编辑系统内核配置。3. 修改哈希表项最大值参数:net.ipv4.netfilter.ip_conntrack_max = 655350。4. 修改超时时间参数:net.ipv4.netfilter.ip_conntrack_tcp_timeout_established = 1200,默认情况下 timeout 是5天(432000秒)。5. 执行命令 # sysctl -p 使配置生效。Centos 6.x 及以上系统:1. 使用管理终端登录实例。2. 执行命令 # vi /etc/sysctl.conf 编辑系统内核配置。3. 修改哈希表项最大值参数:net.netfilter.nf_conntrack_max = 655350。4. 修改超时时间参数:net.netfilter.nf_conntrack_tcp_timeout_established = 1200,默认情况下 timeout 是5天(432000秒)。5. 执行命令 # sysctl -p 使配置生效。 客户端做了 NAT 后无法访问 ECS、RDS,包括通过 SNAT VPC 访问外网的 ECS 。无法访问连接其他 ECS 或 RDS 等云产品,抓包检测发现远端对客户端发送的 SYN 包没有响应。 若远端服务器同时开启 net.ipv4.tcp_tw_recycle 和 net.ipv4.tcp_timestamps,即参数取值为 1 时,服务器会检查每一个报文的时间戳(Timestamp),若 Timestamp 不是递增的关系,则不做处理。做了 NAT 后,服务器看到来自不同的客户端的 IP 相似,但 NAT 前每一台客户端的时间可能会有偏差,在服务器上就会看到 Timestamp 不是递增的情况。 - 远端服务器为 ECS:修改参数 net.ipv4.tcp_tw_recycle 为 0。- 远端服务器为 RDS 等 PaaS 服务:RDS 无法直接修改内核参数,需要在客户端上修改参数 net.ipv4.tcp_tw_recycle 和 net.ipv4.tcp_timestamps 为 0。 参考链接 Linux man-pages kernel/git/torvalds/linux.git_proc kernel/git/torvalds/linux.git_proc_net_tcp kernel/git/torvalds/linux.git_ip-sysctl kernel/git/torvalds/linux.git_netfilter-sysctl kernel/git/torvalds/linux.git_nf_conntrack-sysctl 图一: 客户端 B TCP 连接 图二: 客户端 A TCP 连接 图三: 报错提示 TCP time wait 溢出 图四: 查询 net.ipv4.tcp_max_tw_buckets 参数 图五: ECS Linux 实例间歇性丢包
KB小秘书 2019-12-02 02:05:57 0 浏览量 回答数 0

问题

Vue面试题汇总【精品问答】

是一套用于构建用户界面的渐进式JavaScript框架。与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用。Vue 的核心库只关注视图层,方便与第三方库或既有项目整合。 从0到1自己构架一个vue项目...
问问小秘 2020-05-25 18:02:28 20475 浏览量 回答数 4

回答

在开始谈我对架构本质的理解之前,先谈谈对今天技术沙龙主题的个人见解,千万级规模的网站感觉数量级是非常大的,对这个数量级我们战略上 要重 视 它 , 战术上又 要 藐 视 它。先举个例子感受一下千万级到底是什么数量级?现在很流行的优步(Uber),从媒体公布的信息看,它每天接单量平均在百万左右, 假如每天有10个小时的服务时间,平均QPS只有30左右。对于一个后台服务器,单机的平均QPS可以到达800-1000,单独看写的业务量很简单 。为什么我们又不能说轻视它?第一,我们看它的数据存储,每天一百万的话,一年数据量的规模是多少?其次,刚才说的订单量,每一个订单要推送给附近的司机、司机要并发抢单,后面业务场景的访问量往往是前者的上百倍,轻松就超过上亿级别了。 今天我想从架构的本质谈起之后,希望大家理解在做一些建构设计的时候,它的出发点以及它解决的问题是什么。 架构,刚开始的解释是我从知乎上看到的。什么是架构?有人讲, 说架构并不是一 个很 悬 乎的 东西 , 实际 上就是一个架子 , 放一些 业务 和算法,跟我们的生活中的晾衣架很像。更抽象一点,说架构其 实 是 对 我 们 重复性业务 的抽象和我 们 未来 业务 拓展的前瞻,强调过去的经验和你对整个行业的预见。 我们要想做一个架构的话需要哪些能力?我觉得最重要的是架构师一个最重要的能力就是你要有 战 略分解能力。这个怎么来看呢: 第一,你必须要有抽象的能力,抽象的能力最基本就是去重,去重在整个架构中体现在方方面面,从定义一个函数,到定义一个类,到提供的一个服务,以及模板,背后都是要去重提高可复用率。 第二, 分类能力。做软件需要做对象的解耦,要定义对象的属性和方法,做分布式系统的时候要做服务的拆分和模块化,要定义服务的接口和规范。 第三, 算法(性能),它的价值体现在提升系统的性能,所有性能的提升,最终都会落到CPU,内存,IO和网络这4大块上。 这一页PPT举了一些例子来更深入的理解常见技术背后的架构理念。 第一个例子,在分布式系统我们会做 MySQL分 库 分表,我们要从不同的库和表中读取数据,这样的抽象最直观就是使用模板,因为绝大多数SQL语义是相同的,除了路由到哪个库哪个表,如果不使用Proxy中间件,模板就是性价比最高的方法。 第二看一下加速网络的CDN,它是做速度方面的性能提升,刚才我们也提到从CPU、内存、IO、网络四个方面来考虑,CDN本质上一个是做网络智能调度优化,另一个是多级缓存优化。 第三个看一下服务化,刚才已经提到了,各个大网站转型过程中一定会做服务化,其实它就是做抽象和做服务的拆分。第四个看一下消息队列,本质上还是做分类,只不过不是两个边际清晰的类,而是把两个边际不清晰的子系统通过队列解构并且异步化。新浪微博整体架构是什么样的 接下我们看一下微博整体架构,到一定量级的系统整个架构都会变成三层,客户端包括WEB、安卓和IOS,这里就不说了。接着还都会有一个接口层, 有三个主要作用: 第一个作用,要做 安全隔离,因为前端节点都是直接和用户交互,需要防范各种恶意攻击; 第二个还充当着一个 流量控制的作用,大家知道,在2014年春节的时候,微信红包,每分钟8亿多次的请求,其实真正到它后台的请求量,只有十万左右的数量级(这里的数据可能不准),剩余的流量在接口层就被挡住了; 第三,我们看对 PC 端和移 动 端的需求不一样的,所以我们可以进行拆分。接口层之后是后台,可以看到微博后台有三大块: 一个是 平台服 务, 第二, 搜索, 第三, 大数据。到了后台的各种服务其实都是处理的数据。 像平台的业务部门,做的就是 数据存储和读 取,对搜索来说做的是 数据的 检 索,对大数据来说是做的数据的 挖掘。微博其实和淘宝是很类似 微博其实和淘宝是很类似的。一般来说,第一代架构,基本上能支撑到用户到 百万 级别,到第二代架构基本能支撑到 千万 级别都没什么问题,当业务规模到 亿级别时,需要第三代的架构。 从 LAMP 的架构到面向服 务 的架构,有几个地方是非常难的,首先不可能在第一代基础上通过简单的修修补补满足用户量快速增长的,同时线上业务又不能停, 这是我们常说的 在 飞 机上 换 引擎的 问题。前两天我有一个朋友问我,说他在内部推行服务化的时候,把一个模块服务化做完了,其他部门就是不接。我建议在做服务化的时候,首先更多是偏向业务的梳理,同时要找准一个很好的切入点,既有架构和服务化上的提升,业务方也要有收益,比如提升性能或者降低维护成本同时升级过程要平滑,建议开始从原子化服务切入,比如基础的用户服务, 基础的短消息服务,基础的推送服务。 第二,就是可 以做无状 态 服 务,后面会详细讲,还有数据量大了后需要做数据Sharding,后面会将。 第三代 架构 要解决的 问题,就是用户量和业务趋于稳步增加(相对爆发期的指数级增长),更多考虑技术框架的稳定性, 提升系统整体的性能,降低成本,还有对整个系统监控的完善和升级。 大型网站的系统架构是如何演变的 我们通过通过数据看一下它的挑战,PV是在10亿级别,QPS在百万,数据量在千亿级别。我们可用性,就是SLA要求4个9,接口响应最多不能超过150毫秒,线上所有的故障必须得在5分钟内解决完。如果说5分钟没处理呢?那会影响你年终的绩效考核。2015年微博DAU已经过亿。我们系统有上百个微服务,每周会有两次的常规上线和不限次数的紧急上线。我们的挑战都一样,就是数据量,bigger and bigger,用户体验是faster and faster,业务是more and more。互联网业务更多是产品体验驱动, 技 术 在 产 品 体验上最有效的贡献 , 就是你的性能 越来越好 。 每次降低加载一个页面的时间,都可以间接的降低这个页面上用户的流失率。微博的技术挑战和正交分解法解析架构 下面看一下 第三代的 架构 图 以及 我 们 怎么用正交分解法 阐 述。 我们可以看到我们从两个维度,横轴和纵轴可以看到。 一个 维 度 是 水平的 分层 拆分,第二从垂直的维度会做拆分。水平的维度从接口层、到服务层到数据存储层。垂直怎么拆分,会用业务架构、技术架构、监控平台、服务治理等等来处理。我相信到第二代的时候很多架构已经有了业务架构和技术架构的拆分。我们看一下, 接口层有feed、用户关系、通讯接口;服务层,SOA里有基层服务、原子服务和组合服务,在微博我们只有原子服务和组合服务。原子服务不依赖于任何其他服务,组合服务由几个原子服务和自己的业务逻辑构建而成 ,资源层负责海量数据的存储(后面例子会详细讲)。技 术框架解决 独立于 业务 的海量高并发场景下的技术难题,由众多的技术组件共同构建而成 。在接口层,微博使用JERSY框架,帮助你做参数的解析,参数的验证,序列化和反序列化;资源层,主要是缓存、DB相关的各类组件,比如Cache组件和对象库组件。监 控平台和服 务 治理 , 完成系统服务的像素级监控,对分布式系统做提前诊断、预警以及治理。包含了SLA规则的制定、服务监控、服务调用链监控、流量监控、错误异常监控、线上灰度发布上线系统、线上扩容缩容调度系统等。 下面我们讲一下常见的设计原则。 第一个,首先是系统架构三个利器: 一个, 我 们 RPC 服 务组 件 (这里不讲了), 第二个,我们 消息中 间 件 。消息中间件起的作用:可以把两个模块之间的交互异步化,其次可以把不均匀请求流量输出为匀速的输出流量,所以说消息中间件 异步化 解耦 和流量削峰的利器。 第三个是配置管理,它是 代码级灰度发布以及 保障系统降级的利器。 第二个 , 无状态 , 接口 层 最重要的就是无状 态。我们在电商网站购物,在这个过程中很多情况下是有状态的,比如我浏览了哪些商品,为什么大家又常说接口层是无状态的,其实我们把状态从接口层剥离到了数据层。像用户在电商网站购物,选了几件商品,到了哪一步,接口无状态后,状态要么放在缓存中,要么放在数据库中, 其 实 它并不是没有状 态 , 只是在 这 个 过 程中我 们 要把一些有状 态 的 东 西抽离出来 到了数据层。 第三个, 数据 层 比服 务层 更需要 设计,这是一条非常重要的经验。对于服务层来说,可以拿PHP写,明天你可以拿JAVA来写,但是如果你的数据结构开始设计不合理,将来数据结构的改变会花费你数倍的代价,老的数据格式向新的数据格式迁移会让你痛不欲生,既有工作量上的,又有数据迁移跨越的时间周期,有一些甚至需要半年以上。 第四,物理结构与逻辑结构的映射,上一张图看到两个维度切成十二个区间,每个区间代表一个技术领域,这个可以看做我们的逻辑结构。另外,不论后台还是应用层的开发团队,一般都会分几个垂直的业务组加上一个基础技术架构组,这就是从物理组织架构到逻辑的技术架构的完美的映射,精细化团队分工,有利于提高沟通协作的效率 。 第五, www .sanhao.com 的访问过程,我们这个架构图里没有涉及到的,举个例子,比如当你在浏览器输入www.sanhao网址的时候,这个请求在接口层之前发生了什么?首先会查看你本机DNS以及DNS服务,查找域名对应的IP地址,然后发送HTTP请求过去。这个请求首先会到前端的VIP地址(公网服务IP地址),VIP之后还要经过负载均衡器(Nginx服务器),之后才到你的应用接口层。在接口层之前发生了这么多事,可能有用户报一个问题的时候,你通过在接口层查日志根本发现不了问题,原因就是问题可能发生在到达接口层之前了。 第六,我们说分布式系统,它最终的瓶颈会落在哪里呢?前端时间有一个网友跟我讨论的时候,说他们的系统遇到了一个瓶颈, 查遍了CPU,内存,网络,存储,都没有问题。我说你再查一遍,因为最终你不论用上千台服务器还是上万台服务器,最终系统出瓶颈的一定会落在某一台机(可能是叶子节点也可能是核心的节点),一定落在CPU、内存、存储和网络上,最后查出来问题出在一台服务器的网卡带宽上。微博多级双机房缓存架构 接下来我们看一下微博的Feed多级缓存。我们做业务的时候,经常很少做业务分析,技术大会上的分享又都偏向技术架构。其实大家更多的日常工作是需要花费更多时间在业务优化上。这张图是统计微博的信息流前几页的访问比例,像前三页占了97%,在做缓存设计的时候,我们最多只存最近的M条数据。 这里强调的就是做系统设计 要基于用 户 的 场 景 , 越细致越好 。举了一个例子,大家都会用电商,电商在双十一会做全国范围内的活动,他们做设计的时候也会考虑场景的,一个就是购物车,我曾经跟相关开发讨论过,购物车是在双十一之前用户的访问量非常大,就是不停地往里加商品。在真正到双十一那天他不会往购物车加东西了,但是他会频繁的浏览购物车。针对这个场景,活动之前重点设计优化购物车的写场景, 活动开始后优化购物车的读场景。 你看到的微博是由哪些部分聚合而成的呢?最右边的是Feed,就是微博所有关注的人,他们的微博所组成的。微博我们会按照时间顺序把所有关注人的顺序做一个排序。随着业务的发展,除了跟时间序相关的微博还有非时间序的微博,就是会有广告的要求,增加一些广告,还有粉丝头条,就是拿钱买的,热门微博,都会插在其中。分发控制,就是说和一些推荐相关的,我推荐一些相关的好友的微博,我推荐一些你可能没有读过的微博,我推荐一些其他类型的微博。 当然对非时序的微博和分发控制微博,实际会起多个并行的程序来读取,最后同步做统一的聚合。这里稍微分享一下, 从SNS社交领域来看,国内现在做的比较好的三个信息流: 微博 是 基于弱关系的媒体信息流 ; 朋友圈是基于 强 关系的信息流 ; 另外一个做的比 较 好的就是今日 头 条 , 它并不是基于关系来构建信息流 , 而是基于 兴趣和相关性的个性化推荐 信息流 。 信息流的聚合,体现在很多很多的产品之中,除了SNS,电商里也有信息流的聚合的影子。比如搜索一个商品后出来的列表页,它的信息流基本由几部分组成:第一,打广告的;第二个,做一些推荐,热门的商品,其次,才是关键字相关的搜索结果。 信息流 开始的时候 很 简单 , 但是到后期会 发现 , 你的 这 个流 如何做控制分发 , 非常复杂, 微博在最近一两年一直在做 这样 的工作。刚才我们是从业务上分析,那么技术上怎么解决高并发,高性能的问题?微博访问量很大的时候,底层存储是用MySQL数据库,当然也会有其他的。对于查询请求量大的时候,大家知道一定有缓存,可以复用可重用的计算结果。可以看到,发一条微博,我有很多粉丝,他们都会来看我发的内容,所以 微博是最适合使用 缓 存 的系统,微博的读写比例基本在几十比一。微博使用了 双 层缓 存,上面是L1,每个L1上都是一组(包含4-6台机器),左边的框相当于一个机房,右边又是一个机房。在这个系统中L1缓存所起的作用是什么? 首先,L1 缓 存增加整个系 统 的 QPS, 其次 以低成本灵活扩容的方式 增加 系统 的 带宽 。想象一个极端场景,只有一篇博文,但是它的访问量无限增长,其实我们不需要影响L2缓存,因为它的内容存储的量小,但它就是访问量大。这种场景下,你就需要使用L1来扩容提升QPS和带宽瓶颈。另外一个场景,就是L2级缓存发生作用,比如我有一千万个用户,去访问的是一百万个用户的微博 ,这个时候,他不只是说你的吞吐量和访问带宽,就是你要缓存的博文的内容也很多了,这个时候你要考虑缓存的容量, 第二 级缓 存更多的是从容量上来 规划,保证请求以较小的比例 穿透到 后端的 数据 库 中 ,根据你的用户模型你可以估出来,到底有百分之多少的请求不能穿透到DB, 评估这个容量之后,才能更好的评估DB需要多少库,需要承担多大的访问的压力。另外,我们看双机房的话,左边一个,右边一个。 两个机房是互 为 主 备 , 或者互 为热备 。如果两个用户在不同地域,他们访问两个不同机房的时候,假设用户从IDC1过来,因为就近原理,他会访问L1,没有的话才会跑到Master,当在IDC1没找到的时候才会跑到IDC2来找。同时有用户从IDC2访问,也会有请求从L1和Master返回或者到IDC1去查找。 IDC1 和 IDC2 ,两个机房都有全量的用户数据,同时在线提供服务,但是缓存查询又遵循最近访问原理。还有哪些多级缓存的例子呢?CDN是典型的多级缓存。CDN在国内各个地区做了很多节点,比如在杭州市部署一个节点时,在机房里肯定不止一台机器,那么对于一个地区来说,只有几台服务器到源站回源,其他节点都到这几台服务器回源即可,这么看CDN至少也有两级。Local Cache+ 分布式 缓 存,这也是常见的一种策略。有一种场景,分布式缓存并不适用, 比如 单 点 资 源 的爆发性峰值流量,这个时候使用Local Cache + 分布式缓存,Local Cache 在 应用 服 务 器 上用很小的 内存资源 挡住少量的 极端峰值流量,长尾的流量仍然访问分布式缓存,这样的Hybrid缓存架构通过复用众多的应用服务器节点,降低了系统的整体成本。 我们来看一下 Feed 的存 储 架构,微博的博文主要存在MySQL中。首先来看内容表,这个比较简单,每条内容一个索引,每天建一张表,其次看索引表,一共建了两级索引。首先想象一下用户场景,大部分用户刷微博的时候,看的是他关注所有人的微博,然后按时间来排序。仔细分析发现在这个场景下, 跟一个用户的自己的相关性很小了。所以在一级索引的时候会先根据关注的用户,取他们的前条微博ID,然后聚合排序。我们在做哈希(分库分表)的时候,同时考虑了按照UID哈希和按照时间维度。很业务和时间相关性很高的,今天的热点新闻,明天就没热度了,数据的冷热非常明显,这种场景就需要按照时间维度做分表,首先冷热数据做了分离(可以对冷热数据采用不同的存储方案来降低成本),其次, 很容止控制我数据库表的爆炸。像微博如果只按照用户维度区分,那么这个用户所有数据都在一张表里,这张表就是无限增长的,时间长了查询会越来越慢。二级索引,是我们里面一个比较特殊的场景,就是我要快速找到这个人所要发布的某一时段的微博时,通过二级索引快速定位。 分布式服务追踪系统 分布式追踪服务系统,当系统到千万级以后的时候,越来越庞杂,所解决的问题更偏向稳定性,性能和监控。刚才说用户只要有一个请求过来,你可以依赖你的服务RPC1、RPC2,你会发现RPC2又依赖RPC3、RPC4。分布式服务的时候一个痛点,就是说一个请求从用户过来之后,在后台不同的机器之间不停的调用并返回。 当你发现一个问题的时候,这些日志落在不同的机器上,你也不知道问题到底出在哪儿,各个服务之间互相隔离,互相之间没有建立关联。所以导致排查问题基本没有任何手段,就是出了问题没法儿解决。 我们要解决的问题,我们刚才说日志互相隔离,我们就要把它建立联系。建立联系我们就有一个请求ID,然后结合RPC框架, 服务治理功能。假设请求从客户端过来,其中包含一个ID 101,到服务A时仍然带有ID 101,然后调用RPC1的时候也会标识这是101 ,所以需要 一个唯一的 请求 ID 标识 递归迭代的传递到每一个 相关 节点。第二个,你做的时候,你不能说每个地方都加,对业务系统来说需要一个框架来完成这个工作, 这 个框架要 对业务 系 统 是最低侵入原 则 , 用 JAVA 的 话 就可以用 AOP,要做到零侵入的原则,就是对所有相关的中间件打点,从接口层组件(HTTP Client、HTTP Server)至到服务层组件(RPC Client、RPC Server),还有数据访问中间件的,这样业务系统只需要少量的配置信息就可以实现全链路监控 。为什么要用日志?服务化以后,每个服务可以用不同的开发语言, 考虑多种开发语言的兼容性 , 内部定 义标 准化的日志 是唯一且有效的办法。最后,如何构建基于GPS导航的路况监控?我们刚才讲分布式服务追踪。分布式服务追踪能解决的问题, 如果 单一用 户发现问题 后 , 可以通 过请 求 ID 快速找到 发 生 问题 的 节 点在什么,但是并没有解决如何发现问题。我们看现实中比较容易理解的道路监控,每辆车有GPS定位,我想看北京哪儿拥堵的时候,怎么做? 第一个 , 你肯定要知道每个 车 在什么位置,它走到哪儿了。其实可以说每个车上只要有一个标识,加上每一次流动的信息,就可以看到每个车流的位置和方向。 其次如何做 监 控和 报 警,我们怎么能了解道路的流量状况和负载,并及时报警。我们要定义这条街道多宽多高,单位时间可以通行多少辆车,这就是道路的容量。有了道路容量,再有道路的实时流量,我们就可以基于实习路况做预警? 对应于 分布式系 统 的话如何构建? 第一 , 你要 定义 每个服 务节 点它的 SLA A 是多少 ?SLA可以从系统的CPU占用率、内存占用率、磁盘占用率、QPS请求数等来定义,相当于定义系统的容量。 第二个 , 统计 线 上 动态 的流量,你要知道服务的平均QPS、最低QPS和最大QPS,有了流量和容量,就可以对系统做全面的监控和报警。 刚才讲的是理论,实际情况肯定比这个复杂。微博在春节的时候做许多活动,必须保障系统稳定,理论上你只要定义容量和流量就可以。但实际远远不行,为什么?有技术的因素,有人为的因素,因为不同的开发定义的流量和容量指标有主观性,很难全局量化标准,所以真正流量来了以后,你预先评估的系统瓶颈往往不正确。实际中我们在春节前主要采取了三个措施:第一,最简单的就是有降 级 的 预 案,流量超过系统容量后,先把哪些功能砍掉,需要有明确的优先级 。第二个, 线上全链路压测,就是把现在的流量放大到我们平常流量的五倍甚至十倍(比如下线一半的服务器,缩容而不是扩容),看看系统瓶颈最先发生在哪里。我们之前有一些例子,推测系统数据库会先出现瓶颈,但是实测发现是前端的程序先遇到瓶颈。第三,搭建在线 Docker 集群 , 所有业务共享备用的 Docker集群资源,这样可以极大的避免每个业务都预留资源,但是实际上流量没有增长造成的浪费。 总结 接下来说的是如何不停的学习和提升,这里以Java语言为例,首先, 一定要 理解 JAVA;第二步,JAVA完了以后,一定要 理 解 JVM;其次,还要 理解 操作系统;再次还是要了解一下 Design Pattern,这将告诉你怎么把过去的经验抽象沉淀供将来借鉴;还要学习 TCP/IP、 分布式系 统、数据结构和算法。
hiekay 2019-12-02 01:39:25 0 浏览量 回答数 0

回答

1.产品2.UI3.CSS4.JS5.后端(Java/php/python)6.DBA(mysql/oracle)7.运维(OP) 8.测试(QA)9.算法(分类/聚类/关系抽取/实体识别)10.搜索(Lucene/Solr/elasticSearch)11.大数据工程师(Hadoop)12.Android13.IOS14.运营 一.产品1 工作内容:了解用户需求,做竞品调研,画产品原型,写产品文档,讲解产品需求,测试产品Bug,收集用户反馈,苦练金刚罩以防止程序员拿刀砍。2 需要技能:PPT,Word, Axure,XP,MVP,行业知识,沟通。 二. UI1 工作内容:收到产品原型,给原型上色,偶尔会自作主张调整下原型的位置,出不同的风格给老板和客户选,然后听他们的意见给出一个自己极不喜欢的风格,最好给Android,IOS或者是CSS做好标注,还有的需要直接帮他们切好图,最后要练出来象素眼,看看这些不靠谱的程序员们有没有上错色或者是有偏差。2 需要技能:PS,Illustrator,Sketch,耐性,找素材。 三. CSS1 工作内容:产品设计好原型,UI做出来了效果图,剩下的就是CSS工程师用代码把静态文件写出来的。 2 需要技能:环境【IDE(WEBStorm,Sublime,EditPlus),源码管理(SVN/Git) ,WEB服务器(nginx)】基础【PS,域名,Html,Html5,CSS,CSS3】扩展【自适应,响应式,Bootstrap,Less,Flex】 四 .JS 1 工作内容:JS工程师其实分成两类,在之前讲CSS的时候已经提到过,一个是套页面的,一个是前后端分离的。对这两个概念还是分不太清的,可以回过头去看CSS的部分。 2 需要技能:环境【IDE(WEBStorm,Sublime,EditPlus),源码管理(SVN/Git) ,WEB服务器(nginx)】基础【Http,REST,跨域,语法,组件,F12,Json,Websocket】框架【JQuery,AngularJS,Bower,RequireJS,GruntJS,ReactJS,PhoneGap】业务【金融,教育,医疗,汽车,房产等等等等各种行业】 五 .后端(Java/python/go) 1 工作内容:大部分的后端工程师都停留在功能实现的层面上。这是现在国内二流或者是三流的公司的现状,甚至是在某些一流的公司。很多时候都是架构师出了架构设计,更多的外包公司根本就是有DBA来做设计,然后后端程序员从JS到CSS到Java全写,完全就是一个通道,所有的复杂逻辑全部交给DB来做,这也是几年前DBA很受重视的原因。 2 需要技能:环境【IDE(Idea/Eclipse,Maven,jenkins,Nexus,Jetty,Shell,Host),源码管理(SVN/Git) ,WEB服务器(nginx,tomcat,Resin)】基础【Http,REST,跨域,语法,Websocket,数据库,计算机网络,操作系统,算法,数据结构】框架【Spring,AOP,Quartz,Json TagLib,tiles,activeMQ,memcache,redis,mybatis,log4j,junit等等等等等】业务【金融,教育,医疗,汽车,房产等等等等各种行业】。 六 .DBA  1 工作内容:如果你做了一个DBA,基本上会遇到两种情况。一种是你的后端工程师懂架构,知道怎么合便使用DB,知道如何防止穿透DB,那么恭喜你,你只是需要当一个DB技术兜底的顾问就好,基本上没什么活可以做,做个监控,写个统计就好了。你可以花时间在MongoDB了,Hadoop了这些,随便玩玩儿。再按照我之前说的,做好数据备份。如果需求变动比较大,往往会牵涉到一些线上数据的更改,那么就在发布的时候安静的等着,等着他们出问题。。。。如果不出问题就可以回家睡觉了。 2 需要技能:环境【Linux,Mysql,Oracle,MongoDB,Hadoop】工具【各种DB的版本,工具,备份,日志等】。 七. 运维  1 工作内容:运维的工作大概分成几个部分,我对于修真院学习运维的少年们都这么说,大概是:A。基础环境的搭建和常用软件的安装和配置(兼网管的还有各种程控机),常用软件指的是SVN,Git,邮箱这种,更细节的内容请参考修真院对于运维职业的介绍。B。日常的发布和维护,如刚刚讲到的一样,测试环境和线上环境的发布和记录,原则上,对线上所有的变更都应该有记录。C。数据的备份和服务的监控&安全配置。各种数据,都要做好备份和回滚的手段,提前准备好各种紧急预案,服务的监制要做好。安全始终都是不怎么被重点考虑的问题,因为这个东西无底洞,你永远不知道做到什么程度算是比较安全了,所以大多数都是看着情况来。D。运维工具的编写。这一点在大的云服务器商里格外常见,大公司也是一样的。E。Hadoop相关的大数据体系架构的运维,确实有公司在用几百台机器做Hadoop,所以虽然不常见,我还是列出来吧。 2 需要技能:环境【Linux,Mysql,Oracle,MongoDB,Hadoop,nginx,apache,F5,lvs,vpn,iptable,svn,git,memcache,redis】工具【linux 常用工具,Mysql常用工具,Jenkins,zabbix,nagios】自动化运维【openstack,docker,ansible】语言【shell,python】 八 .QA  1 工作内容:QA需要了解需求,很多公司会要求QA写测试用例,我觉得是扯淡。完全是在浪费时间。通常开发三周,QA测试的时间只有一周到一周半。还有关于提前写测试用例的,都不靠谱。 2 需要技能:流程【Bug修复流程,版本发布流程】工具【禅道,BugZilla,Jira,Excel表格来统计Bug数,自动化测试】性格【严谨,耐心】 九. 算法工程师  1 工作内容:算法工程师的工作内容,大部分时间都是在调优。就是调各种参数和语料,寻找特征,验证结果,排除噪音。也会和Hadoop神马的打一些交道,mahout神马的,我那个时候还在用JavaML。现在并不知道有没有什么更好用的工具了。有的时候还要自己去标注语料---当然大部分人都不爱做这个事儿,会找漂亮的小编辑去做。2 需要技能:基础【机器学习,数据挖掘】工具【Mahout,JavaML等其他的算法工具集】 十. 搜索工程师  1 工作内容: 所以搜索现在其实分成两种。一种是传统的搜索。包括:A。抓取 B。解析C。去重D。处理E。索引F。查询另一种是做为架构的搜索。并不包括之前的抓取解析去重,只有索引和查询。A。索引B。查询 2 需要技能:环境【Linux】框架【Luence,Slor,ElasticSearch,Cassandra,MongoDB】算法【倒排索引,权重计算公式,去重算法,Facet搜索的原理,高亮算法,实时索引】 十一. 大数据工程师  1 工作内容:工作内容在前期会比较多一些,基础搭建还是一个挺讲究的事儿。系统搭建好之后呢,大概是两种,一种是向大数据部门提交任务,跑一圈给你。一种是持续的文本信息处理中增加新的处理模块,像我之前说的增加个分类啦,实体识别神马的。好吧第一种其实我也不记得是从哪得来的印象了,我是没有见到过的。架构稳定了之后,大数据部门的工作并不太多,常常会和算法工程师混到一起来。其他的应该就是大数据周边产品的开发工作了。再去解决一些Bug什么的。2 需要技能:环境【Linux】框架【Hadoo,spark,storm,pig,hive,mahout,zookeeper 】算法【mapreduce,hdfs,zookeeper】。 十二. Android工程师  1 工作内容:Android工程师的日常就是听产品经理讲需求,跟后端定接口,听QA反馈哪款机器不兼容,闹着申请各种测试机,以及悲催的用Android做IOS的控件。 2 需要技能:环境【Android Studio,Maven,Gradle】基础【数据结构,Java,计算机网络】组件【IM,地图,支付,拍照,视频,音频,统计,分享,手势密码】 十三. IOS工程师  1 工作内容:IOS工程师的工作内容真的挺简单的,听需求,定接口。做个适配,抛弃一下iphone4。还有啥。。马丹,以我为数不多的IOS知识来讲,真的不知道还有啥了。我知道的比较复杂的系统也是各种背景高斯模糊,各种渐变,各种图片滤镜处理,其他并没有什么。支付,地图,统计这些东西。 嗯。2 需要技能:环境【Xcode】基础【数据结构,Object,计算机网络】组件【IM,地图,支付,拍照,视频,音频,统计,分享,手势密码】
行者武松 2019-12-02 01:21:45 0 浏览量 回答数 0

云产品推荐

上海奇点人才服务相关的云产品 小程序定制 上海微企信息技术相关的云产品 国内短信套餐包 ECS云服务器安全配置相关的云产品 开发者问答 阿里云建站 自然场景识别相关的云产品 万网 小程序开发制作 视频内容分析 视频集锦 代理记账服务 阿里云AIoT