跳至主要內容

系统设计

HeChuangJun约 2671 字大约 9 分钟

软件开发阶段及作用?敏捷开发与devOps?

可行性分析:评估项目的技术、经济、法律可行性。确定项目是否值得开发,以及潜在的风险和收益
需求分析:与用户或客户沟通,明确软件需要实现的功能和需求。形成需求规格说明书,作为开发的基础
软件设计:包括概要设计(系统架构设计)和详细设计(模块、接口等的具体实现方式)。使用各种设计文档和工具将需求转化为可实现的软件方案
程序编码:根据设计文档编写源代码。遵循编程规范和最佳实践,保证代码的可读性和可维护性。
软件测试:包括单元测试、集成测试、系统测试和验收测试。发现并修复缺陷,确保软件质量。测试方法有白、黑盒测试

DevOps:强调组织团队(开发、运维、测试)通过自动化工具协作和沟通来完成软件生命周期管理,从而更快、更频繁地交付更稳定的软件
敏捷开发:不追求前期完美的设计、完美编码,力求短周期内开发出产品的核心功能,尽早发布可用版本。在后续生产周期内按照新需求不断迭代升级,完善产品

devops.png
devops.png

DDD?如何建立领域模型?

通过将软件的设计紧密围绕业务领域来解决复杂的软件开发问题。

业务分析:项目团队的成员主要包括领域专家、设计人员、开发人员等一起梳理业务问题域以及业务期望,在业务领域中发现领域事件、领域对象及其对应的领域行为和各自的关联关系
战略设计:通过DDD理论对业务进行领域划分构建领域模型,梳理出相应的限界上下文,通过统一的领域语言从战略层面进行领域划分以及构建领域模型。梳理出对应的聚合根、实体、以及值对象。
战术设计:以领域模型为战术设计的输入,以限界上下文作为微服务划分的边界进行微服务拆分,在每个微服务中进行领域分层,实现领域模型对于代码的映射

实体Entity:具备唯一ID,能够持久化,对应现实世界业务对象的业务属性以及业务行为。
值对象Value Object:不具有唯一ID,由对象的属性描述,一般为内存中的临时对象,用来传递参数或对实体进行补充描述。值对象以及实体都是领域模型中的领域对象,
领域服务Domain Service:为上层建筑提供可操作的接口,负责对领域对象进行调度和封装,同时可以对外提供各种形式的服务。
聚合根Aggregate Root:属于实体对象,具有全局唯一ID,聚合根在聚合之内采用引用依赖的方式对实体和值对象进行组织和协调,聚合根和聚合根之间通过唯一 id 进行聚合之间的协同。
工厂Factories:用来创建聚合根,一般采用IOC容器来实现
仓储Repository:封装了基础设施来提供查询和持久化聚合操作。
聚合:有业务关联关系的实体以及值对象的集合,通过实体、值对象以及各自之间的业务逻辑聚合在一起完成某个业务节点。可以根据业务的单一职责以及高内聚的的设计原来来进行聚合的划分

业务分析:领域专家、DDD 专家、架构师、产品经理、项目经理、开发人员以及测试人员等集合在一起之后需要通过头脑风暴的方式梳理当前的业务域问题
领域建模:找出实体和值对象,构建聚合,划分聚合到边界上下文

Java处理高并发

  • 采用分布式部署的方式,部署多台服务器,把流量分流开,让每个服务器都承担一部分的并发和流量,提升整体系统的并发能力。
  • 微服务拆分,把一个单体的应用,按功能单一性,拆分为多个服务模块。比如一个电商系统,拆分为用户系统、订单系统、商品系统等等
  • 分库分表
  • 主从分离:实时性要求不高的读请求,都去读从库,写的请求或者实时性要求高的请求,才走主库
  • 池化技术:数据库连接池、Redis 连接池、线程池
  • 缓存:Redis缓存
  • CDN加速静态资源访问
  • 消息队列,削锋
  • ElasticSearch:支持简单的查询搜索、统计类的操作。
  • 降级熔断:开源组件Hystrix
  • 限流:可以使用Guava的RateLimiter单机版限流,也可以使用Redis分布式限流,还可以使用阿里开源组件sentinel限流。
  • 异步:后端可以借用消息队列实现。比如在海量秒杀请求过来时,先放到消息队列中,快速响应用户,告诉用户请求正在处理中,这样就可以释放资源来处理更多的请求。秒杀请求处理完后,通知用户秒杀抢购成功或者失败
  • 接口的常规优化
  • 压力测试确定系统瓶颈:压测完要分析整个调用链路,性能可能出现问题是网络层(如带宽)、Nginx层、服务层、还是数据路缓存等中间件等等。loadrunner是一款不错的压力测试工具,jmeter则是接口性能测试工具,都可以来做下压测。
  • 应对突发流量峰值:扩容+切流量:扩容:比如增加从库、提升配置的方式,提升系统/组件的流量承载能力。比如增加MySQL、Redis从库来处理查询请求。
    切流量:服务多机房部署,如果高并发流量来了,把流量从一个机房切换到另一个机房。
  • HTML静态化
  • 图片服务器分离
  • 数据库集群,库表散列
  • 镜像
  • 负载均衡

请说出2种减少页面加载时间的方法

    1. 减少重复的HTTP请求数量
    1. 压缩Javascript、CSS代码
    1. 在文件头部放置css样式的定义
    1. 在文件末尾放Javascript脚本
    1. css、javascript改由外部调用
    1. 尽可能减少DCOM元素
    1. 避免使用CSS脚本(CSS Expressions)
    1. 服务器启用gzip压缩功能
    1. Ajax采用缓存调用
    1. Ajax调用尽量采用GET方法调用
    1. 养成良好的开发维护习惯,尽量避免脚本重复调用
    1. 缩减iframe的使用,如无必要,尽量不要使用

英文字母和中文汉字在不同字符集编码下的字节数

  • 英文字母都是1字节:GB2312,GBK,ISO-8859-1,UTF-8
  • 中文汉字:GB2312 2字节:GBK 2字节 ;ISO-8859-1 1字节;UTF-8 3字节

对"高内聚,低耦合"方法理解,你在程序设计和架构设计中的经验

  • 降低耦合度的方法
    • 1、少使用类的继承,多用接口隐藏实现的细节。 Java面向对象编程引入接口除了支持多态外, 隐藏实现细节也是其中一个目的。
    • 2、模块的功能化分尽可能的单一,道理也很简单,功能单一的模块供其它模块调用的机会就少。(其实这是高内聚的一种说法,高内聚低耦合一般同时出现)。
    • 3、遵循一个定义只在一个地方出现。
    • 4、少使用全局变量。
    • 5、类属性和方法的声明少用public,多用private关键字。
    • 6、多用设计模式,比如采用MVC的设计模式就可以降低界面与业务逻辑的耦合度。
    • 7、尽量不用“硬编码”的方式写程序,同时也尽量避免直接用SQL语句操作数据库。
    • 8、最后当然就是避免直接操作或调用其它模块或类(内容耦合);如果模块间必须存在耦合,原则上尽量使用数据耦合,少用控制耦合,限制公共耦合的范围,避免使用内容耦合。
  • 增强内聚度方法
    • 1、模块只对外暴露最小限度的接口,形成最低的依赖关系。
    • 2、只要对外接口不变,模块内部的修改,就不得影响其他模块。
    • 3、删除一个模块,应当只影响有依赖关系的其他模块,而不应该影响其他无关部分。

讲一下对复用的几个层次,代码级,函数级,模块级,服务级的理解,以及在设计过程中的思路和原则

shiro组件,认证,权限怎么做?与spring security区别?spring Security认证和鉴权?spring Security oauth2认证

![SpringSecurity](SpringSecurity.md/#SpringSecurity)

40亿QQ号, 1G内存,怎么去重?

每个QQ号占用4字节空间(比如32位整数),40亿x4字节=160亿字节=16GB
1.bitMap进行海量数据去重,40亿个QQ号要40亿个bit。500MB的内存(40亿bit / 8 = 500MB)
假设读到第一个QQ号是12345678,那我们就把位图中的第12345678个位置标记为“1”,表示这个QQ号出现了。重复的号码再次被读取时,它对应的位已经是“1”了,所以我们就知道这个QQ号已经存在,不会重复处理。
适用场景有限,只能用来处理“整数”类的数据,不能处理比如字符串(例如邮箱地址)
存储“稀疏”数据时效率不高
位图最大值限制
数据为整数型,且取值范围明确;
数据量大且分布较为密集;
不能容忍任何误判(需要100%准确性);
内存空间充足,可以根据数据范围分配足够的位图大小。
2.布隆过滤器进行海量数据去重
数据量非常大(数百万甚至数亿条);
允许少量误判(假阳性);
内存有限且需要高效存储;
数据类型多样,可能是字符串、URL等非整数型数据;
数据规模不固定,或者数据分布比较稀疏。