聊聊常用的软件架构风格

今天和大家聊聊软件的架构风格。所谓的软件架构风格,就是一种可以重复利用的软件结构模式,其最大的作用是用相同的结构解决某一特殊领域的问题。如著名的三层B/S架构设计,其主要目的就是为了解决Web系统服务端与客户端的高耦合与维护成本高的问题。使用B/S三层架构模式,实现了服务端与客户端的分离,真正的实现了零客户端 ,使用户在软件升级时更方便,提高了软件的可修改性。而服务器端的三层结构设计,对逻辑层、表现层与数据层进行了分离,不仅方便系统的维护,而且提高了系统的可扩展性。由于有了这么多的优点,当今几乎所有的Web系统都是用了MVC的概念进行设计。所以MVC就是一种软件架构风格,它解决了Web系统这一领域的问题。

当然,无论是B/S系统还是C/S系统。只用一种架构风格是解决不了所有问题的。每种架构风格只能解决一些特定的问题,同时也存在一些不足之处。还是以三层B/S架构为例,虽然有以上提到的一些优点,但也存在动态交互能力不强(B/S系统以页面为单位提交数据)、安全性差(容易被注入,如果使用非SSL链接,则传输过程中数据容易被窃取)、数据查询速度低(由于采用B/S三层架构模式连接数据库只能使用TCP的方式连接,查询速度会受到网络传输速度影响)等缺点。所以在设计系统时,应采用多种架构风格结合的方式,取长补短,按需配置。

除了我们非常熟悉的三层B/S架构、三层C/S架构外。还有一些架构风格也经常会被用到,如消息队列架构风格、过滤器架构风格、仓库风格、事件驱动风格等。三层架构大家应该已经非常熟悉了,对应的各种语言的框架也有很多,在此就不在赘述。仓库风格与过滤器风格在Web系统上用的不多,在下也不是很熟悉,所以也不在此讨论。下面主要介绍下消息队列架构与事件驱动架构的实现。当然,以下是我自己的理解,如有不对,还请指正。

消息队列可以解决很多问题,比如12306的网上购票业务。在过年过节的时候会有大量用户高并发的访问网站,如果每个链接都开启一个处理进程,恐怕再多的服务器也承受不了。因为在一个链接打开时,服务器就需要开始处理逻辑,处理逻辑就会消耗服务器资源,同时的高并发处理会瞬间使服务器挂掉。这时,如果一个用户连接到来,系统只是将用户的请求放到一个队列里就关闭连接或进行其它逻辑的处理。而放到队列里的请求,则交给队列服务器依次处理,处理完毕后,可以将处理结果直接通知给用户,也可等用户自己来获取。这样服务器消耗的资源就会降低很多。而由于是异步处理,客户端也不必等待服务器执行完相应的逻辑就可以执行其它事务,增加了效率。所以,消息队列主要解决了2类问题,一类是排队问题,有先后次序处理要求的问题。第二类是异步处理问题,需要异步处理以节省服务器资源及增加效率的问题。以下是我写的一个消息队列的代码样例,由于消息队列风格与事件驱动风格都涉及到进程间通信,为了方便,我将需要交互的变量写在memcache里了。

首先新建项目目录,目录名为queue。以下所有文件均在queue目录下。

建立文件index.php

<?php
 set_time_limit(0);
 session_start();
 $memcache = new Memcache();
 $memcache->addServer(‘127.0.0.1‘,11211);
 $position = $_GET[‘r‘];
 if(!isset($_SESSION[‘uuid‘])){//判断客户端是否执行完该任务
  $uuid = time()+rand(0,9);
  $_SESSION[‘uuid‘]=$uuid;
  $arr = array($position,$uuid);
  $queue = $memcache->get(‘queue‘);
  $queue[] = $arr;
  $memcache->set(‘queue‘,$queue); //将请求加入队列
 }
 $now_queue = $memcache->get(‘queue‘); //取得目前队列中所有的请求
 if(!empty($now_queue)){
  foreach($now_queue as $k=>$q){
   if($q[1]==$_SESSION[‘uuid‘]){//根据uuid session判断前面还需等待几个任务执行。
    if(!isset($_SESSION[‘js‘]) OR $_SESSION[‘js‘]!=$k){
     $_SESSION[‘js‘] = $k;
     $flag = true;
     echo ‘前面有‘.($k+1).‘个任务在执行,请等待!!‘."\n";
    }
    break;
   }
  }
 }
 $rs = $memcache->get($_SESSION[‘uuid‘]);//取任务执行的结果
 if(!empty($rs)){//如果取得到结果,则注销这个任务
  unset($_SESSION[‘js‘]);
  unset($_SESSION[‘uuid‘]);
  print_r($rs);
 }else if(!isset($flag) OR !$flag){
  echo ‘前面有‘.($_SESSION[‘js‘]+1).‘个任务在执行,请等待!!‘."\n";
 }
 
?>

建立文件service.php

<?php
 $memcache = new Memcache();
 $memcache->addServer(‘127.0.0.1‘,11211);
 for(;;){//处理队列请求
  $queue = $memcache->get(‘queue‘);
  if(!empty($queue)){
   $handle = array_shift($queue);
   $memcache->set(‘queue‘,$queue);
   if(function_exists($handle[0])){
    $rs = $handle[0]();
    $memcache->set($handle[1],$rs);
   }
  }
 }
 //具体请求1
 function fun1(){
  sleep(3);
  return array(‘fun1‘);
 }
 //具体请求2
 function fun2(){
  sleep(3);
  return array(‘fun2‘);
 }
 
?>

首先在控制台执行service.php。/yourpath/php /yourpath/queue/service.php。

然后在浏览器执行http://localhost/queue/index.php?r=fun1http://localhost/queue/index.php?r=fun2,r=fun1时,将执行fun1的任务加入队列,r=fun2时,将执行fun2的任务加入队列。加入队列的任务不会并发完成,而是依次完成,并且是与客户端异步的。

事件驱动模式主要解决触发式需求。比如当鼠标点击某一按钮时会触发一系列的处理过程。事件驱动系统风格是客户端不直接调用方法,而是触发或广播一个或多个事件。系统中的方法在一个或多个事件中注册。当一个事件被触发,系统自动调用在这个事件中注册的所有方法。“鼠标点击按钮”称为事件,相应的处理过程则是被调用的方法。那么,为什么要这么设计呢?个人觉得还是解耦的需要。根据迪米特法则,“如果两个类不必彼此直接通信,那么这两个类就不应当发生直接的相互作用。如果其中一个类需要调用另一个类的某一个方法的话,可以通过第三者转发这个调用。”。在鼠标点击按钮执行处理过程这一场景下,客户端可以不直接和触发的方法产生交互,而是只用设置“鼠标点击按钮”这一事件即可。在实际应用中,我们可以将客户端事件设置,事件触发方法这两部进行物理分离,用两个进程来异步处理,进一步解耦。以下是我写的一个事件驱动模式的代码样例:

首先新建项目目录,目录名为event。以下所有文件均在event目录下。

新建client.php文件

<?php
require ‘event.php‘;
$event = new event();
$event->setEvent3(true); //触发event事件
?>

新建event.php文件

<?php
 //定义事件
 class event{
  private $memcache;
  public function __construct(){
   $this->memcache = new Memcache();
   $this->memcache->addServer(‘127.0.0.1‘,11211);
  }
  public function setEvent1($open){
   $this->memcache->set(‘event1‘,$open);
  }
  public function setEvent2($open){
   $this->memcache->set(‘event2‘,$open);
  }
  public function setEvent3($open){
   $this->memcache->set(‘event3‘,$open);
  }
  public function getEvent1(){
   return $this->memcache->get(‘event1‘);
  }
  public function getEvent2(){
   return $this->memcache->get(‘event2‘);
  }
  public function getEvent3(){
   return $this->memcache->get(‘event3‘);
  }
 }
?>

新建function.php文件

<?php
 //定义事件触发执行的方法
 class process{
  public function fun1(){
   echo "process1 starting !!!...\n";
  }
  public function fun2(){
   echo "process2 starting !!!...\n";
  }
  public function fun3(){
   echo "process3 starting !!!...\n";
  }
  public function fun4(){
   echo "process4 starting !!!...\n";
  }
  public function fun5(){
   echo "process5 starting !!!...\n";
  }
  public function fun6(){
   echo "process6 starting !!!...\n";
  }
 }
?>

新建listener.php文件

<?php
 //事件监听服务器
 require ‘event.php‘;
 require ‘function.php‘;
 class listener{
  private $event;
  private $register;
  private $process;
  private $memcache;
  public function __construct(){
   $this->process = new process();
   $this->event = new event();
   $this->register = require ‘register.php‘;
   $this->memcache = new Memcache();
   $this->memcache->addServer(‘127.0.0.1‘,11211);
  }
  public function listen(){
   for(;;){
    $event_keys = array_keys($this->register);
    foreach($event_keys as $ek){
     $getstatusfunc = ‘get‘.ucfirst($ek);
     if($this->event->$getstatusfunc()){
      foreach($this->register[$ek] as $r){
       $this->process->$r();
      }
      $this->memcache->set($ek,false);
     }
    }
   }
  }
 }
 $listener = new listener();
 $listener->listen();
 
?>

新建register.php文件

<?php
 //事件与方法注册绑定
 return array(
  ‘event1‘=>array(
    ‘fun1‘,‘fun2‘,‘fun3‘, //当event1事件触发时,执行fun1, fun2, fun3方法
   ),
  ‘event2‘=>array(
    ‘fun2‘,‘fun3‘,‘fun4‘,
   ),
  ‘event3‘=>array(
    ‘fun4‘,‘fun5‘,‘fun6‘,
   ),
 );
?>

首先在控制台执行listener.php。/yourpath/php /yourpath/event/listener.php。

然后在浏览器执行http://localhost/event/client.php,此时控制台会显示具体的方法执行的信息。这里client.php只与event类交互,然后通过event类触发process类方法。并且触发的方法与客户端之间也是异步执行的。

以上我们介绍了消息队列架构风格与事件驱动架构风格。它们与MVC结合在一起为Web系统提供了较为完善的解决方案,能够满足大多数的Web需求。另外,消息架构风格除了队列外,还有一种发布形式的风格,这种风格主要解决的是满足多客户端同时获取消息的需求。就像多个IP地址加入到同一个组播地址一样,当不同的客户端同时加入到一个“主题”(这里的主题就相当于组播地址),服务器发送给主题的任何消息,所有加入同一主题的客户端都能同时收到。在实际应用中,也经常用到。例如RSS订阅系统等。希望此文能帮助大家对消息队列与事件驱动架构风格有一个基础的认识。当然,这也只是我个人的一些见解,如果有不对的地方,也请大家不吝指正。

时间: 2024-11-16 10:10:57

聊聊常用的软件架构风格的相关文章

一种软件架构风格-restful-api

定义: 一种软件架构风格,设计风格而不是标准,只是提供了一组设计原则和约束条件.它主要用于客户端和服务器交互类的软件. 基于这个风格设计的软件可以更简洁,更有层次,更易于实现缓存等机制. 前端设备层出不穷(手机.平板.桌面电脑.其他专用设备). restful-api 是目前比较成熟的一套互联网应用程序的API设计理论 API的就是程序员的UI,和其他UI一样,你必须仔细考虑它的用户体验 相关概念知悉: http动词 GET(SELECT):从服务器取出资源(一项或多项). POST(CREAT

restfull软件架构风格

概念:restfull是一种软件架构风格,实现该风格不需导jar包,但要使用@PathVariable注解:特点:没有参数,没有扩展名优势: 1.安全 2.简洁高效 3.容易被搜索引擎所收录 如何利用springmvc实现restfull软件架构风格? 1.web.xml 拦截所有 <servlet-mapping> <servlet-name>springmvc</servlet-name> <url-pattern>/</url-pattern&g

软件架构风格

# 软件架构风格 软件架构设计的一个核心问题是能否使用重复的架构模式,即能否达到架构级的软件重用. 也就是说,能否在不同的软件系统中,使用同一架构. 软件架构风格是描述某一特定应用领域中系统组织方式的惯用模式. 架构风格反映了领域中众多系统所共有的结构和语义特性,并指导如何将各个模块和子系统有效滴组织成一个完整的系统. - 数据流风格:批处理序列,管道/过滤器.- 调用/返回风格:主程序/子系统,面向对象风格,层次结构.- 独立构件风格:进程通信,事件系统.- 虚拟机风格:解释器,基于规则的系统

软件架构风格整理

一.软件架构风格整理(1 数据流风格) 二.软件架构风格整理(2 调用/返回) 三.软件架构风格整理(3 独立构件风格 4 虚拟机风格) 四.软件架构风格整理(5 仓库风格 6复制风格) 五.软件架构风格整理(7 DSSA,HA,Agent,正交等) 原文地址:https://www.cnblogs.com/leucojum/p/9976848.html

架构_10 个常用的软件架构模式

你是否曾经思考过如何设计大型的企业级系统?在决定启动软件开发之前,首要的是选择恰当的架构来指引系统的功能及质量属性设计.因此在将软件架构应用于设计之前,必需要了解常用的架构模式. 什么是架构模式? Wikipedia 的解释: 在软件架构中,架构模式是对特定环境下常见问题的通用且可重用的解决方案.架构模式与软件设计模式很相似,但架构模式的层次更高,且外延更大. 这篇文章将简述常见的 10 种架构模式的概念.用法以及其优缺点. 分层模式(Layered pattern) 客户端/服务器模式(Cli

描述一下你最常用的编程风格---JAVA

(1)类名首字母应该大写.字段.方法以及对象(句柄)的首字母应小写.对于所有标识符,其中包含的所有单词都应紧靠在一起,而且大写中间单词的首字母.Java包(Package)属于一种特殊情况:它们全都是小写字母,即便中间的单词亦是如此.对于域名扩展名称,如com,org,net或者edu等,全部都应小写(这也是Java1.1和Java 1.2的区别之一). (2)为了常规用途而创建一个类时,请采取“经典形式”,并包含对下述元素的定义:equals()hashCode()toString()clon

REST风格的软件架构

如果一个网站不是 REST 风格架构,肯会被程序员鄙视一番! 移动互联网的飞速发展,特别是移动互联网,给开发者带来了新的机遇和挑战.手机端除了app,我们还会经常接触到移动web,除了浏览器中,很多app里面也会使用web服务,我们会在手机上面做更多复杂的操作,老一代的系统架构已经不再适应了,需要更加规范和优秀的软件架构来应对今天的挑战,那就是 REST . 从 HTTP 协议说起 首先的熟悉一个概念 URI,Web上可用的每种资源 -HTML文档.图像.视频片段.程序等 - 由一个通用资源标识

界面设计过程中的常用字体规范

好长时间没发帖,净想过年了,过年哈,倒腾工作总结和年货是大事. 这几天有人问我说:“最近看了好多教程,都老高大上了,但是老弟我做不到呀,想学点直接能拿来用的,这个要求过分吗……” 这个,好吧,那就直接说说能用的知识:字体字号. 也许你会说:字体字号?也太Low了吧,这个谁不知道重要呀. 对于这个问题,我想说:会和熟练,是两回事.一个App,不同部分的字体字号你能准确地说出来吗? 很多刚做APP界面的设计师,经常会因为字号,字体颜色,间距而困扰. 拿到设计需求后,开始进行设计,不知道从何去调整界面

归纳各种软件架构的特征

软件基本模型=实体(语言) + 连接和交互 1.概念: 软件架构设计的一个核心问题是能否使用重复的架构模式,即能否达到架构级的软件重用.也就是说,能否在不同的软件系绕中使用同一架构.软件架构风格是描述某一特定应用领域中系统组织方式的惯用模式(idiomatic paradigm). 架构风格定义了一个系统家族,即一个架构定义一个词汇表和一组约束.词汇表中包含一些构件和连接件类型,而这组约束指出系统是如何将这些构件和连接件组合起来的.架构风格反映了领域中众多系统所共有的结构和语义特性,并指导如何将