好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

CDN是如何工作的?

CDN是如何工作的?

CDN是互联网中使用较频繁的一种技术。你也许常听人说:“我们的网站使用了CDN技术”,但可能他们对CDN的了解并不多,也许只局限于--用了以后网站访问速度会变快。

其实,CDN的原理非常简单。当浏览器请求一资源时,第一步是做DNS解析,DNS解析就像是从通讯录根据姓名找号码,浏览器发送域名,然后得到DNS服务器返回的IP地址。浏览器通过IP地址和服务器连接并获取资源(DNS服务器会有很多层的缓存,但超出本文范围)。

对于小站点或个人博客,一个域名对应一个IP地址,而大站点可能含多个IP地址。

当请求一个资源时(如网站),距离会影响连接速度,所以从国内访问国外的网站会比较慢。因此,一些大公司在世界各地配置服务器并同步数据,这就叫CDN,而那些离当地用户最近的服务器叫“边缘服务器(edge servers)”。

DNS解析

当浏览器通过CDN做域名解析请求时,针对单IP的网站会有一些不同。DNS服务器会找出最适合的服务器来处理请求,而且非常简单,DNS会找出离请求地点最近的边缘服务器。如下图所示,如果我从维吉尼亚州发送一个指向美国中部服务器的请求,就会得到位于东海岸的边缘服务器地址,如果我从加利福尼亚州发送请求,就会得到位于西海岸的边缘服务器地址。

也就是说处理请求的第一步:找出离请求位置最近的服务器。有些公司可能会用其他的方式优化CDN服务器,例如,如果最近的服务器满负荷运作,那么接下来的请求就会转到其他闲置的服务器。总之,CDN总会找出最适合的服务器来处理请求。

获取内容

边缘服务器是一种代理缓存,类似浏览器缓存。当请求到达边缘服务器,它会首先检查内容是否是最新的。缓存标识(key)就是整个Url地址(跟浏览器一样),如果内容已被缓存且没有过期,就直接返回缓存内容。

如果没有缓存或已过期,边缘服务器会向源服务器发送请求获取内容,并缓存起来。

雅虎创建了一个开源项目叫 Apache Traffic Server ,用来管理CDN直接的交互,如果想了解更多代理缓存的原理,推荐你读一下这个项目的文档。

示例

雅虎的CDN服务中,使用一个工具叫“组合处理器(combo handler)”,它会把多个文件的请求整合到一起,变成一个请求-响应操作。下面是例子:

http://yui.yahooapis.com/combo?3.4.1/build/yui-base/yui-base-min.js&3.4.1/build/array-extras/array-extras-min.js

域名yui.yahooapis.com是雅虎CDN服务的一部分,会把你的请求转给离你最近的边缘服务器,这个请求包含两个文件yui-base-min.js和array-extras-min.js,但只需一次响应便可完成。这些逻辑处理操作不在边缘服务器,只能在源服务器上。

静态指什么?什么情况适合使用CDN?

每当我描述类似上文的“组合处理器”之类的系统时,经常会看到别人困惑的表情。CDN有时候容易跟FTP资源混淆,因为它们都是上传静态资源供其他人获取。我希望我上文的描述能让大家搞清楚两者不一回事。边缘服务器是一个代理,源服务器告诉边缘服务器返回什么内容,源服务器可能是Java,Ruby,Node.js,.Net等,因此可以实现任何逻辑。边缘服务器什么也不做只是发生请求并返回内容。

既然CDN如此高效,为什么不把网站所有东西都用CDN来提高性能?CDN本质是缓存,如果保存的是动态页面,每次页面内容都会有所变化,那么每次请求都要边缘服务器和源服务器交互一次,那么这个缓存也就没有意义。

这也是为什么Javascript,CSS,images,Flash,音频,视频等文件特别适合使用CDN技术,因为这些文件是不变的,所有的用户获取的都一样,一旦通过CDN缓存,所有用户都将受益。

缓存过期

雅虎性能指南 规定静态资源应该要有缓存过期标识保存在Http协议的header中,这么做有两个原因:其一,浏览器会缓存资源,其二,CDN也会将资源缓存一段时间。这同样意味着你不能使用重复的文件名,因为他们至少会被缓存在两个地方,用户可能会一直获取不到最新版本的文件。

有几种方式解决这个问题,YUI 库用包含不同版本库的目录来区分。通常也可以在文件名末尾加入标识符,如MD5的哈希值或者版本控制软件的修订号。任何一种方式都为了确保当用户的请求包含过期标识的时候,依然能获得最新版本的资源文件。

结语

CDN技术已经是当今互联网重要的一部分,随着时间的推移,它只会变得越来越重要。即便是现在,一些公司仍然努力尝试把更多的功能移到边缘服务器,以便能给用户更快速的体验。这里包含了一种技术叫 Edge Side Includes (ESI) ,用来缓存页面的部分内容。

更好的理解CDN技术及工作原理是提升CDN性能的关键。

原文: http://www.nczonline.net/blog/2011/11/29/how-content-delivery-networks-cdns-work/

注:这是我第一次翻译英文文章,花了比想象中要多的时间,如果看完文章对你有帮助是我最大的欣慰,不足的地方欢迎批评指出。

从高耦合到低耦合到底有多远?

 

无论书还是博客, 耦合这个词已被无数人说烂,任何一位程序员都会告诉你设计软件要注意低耦合,可究竟什么是低耦合?每次去查这个问题,就会牵扯出各种术语和理论,让人头晕。最近看了一些英文资料,发现低耦合其实没那么复杂。

什么是耦合?怎样的代码叫高耦合?

“耦合”翻译自英文( coupling ),英文描述是:" when a component has a dependency on something else".  这句话简单易懂--当一个组件对其他东西有依赖就叫耦合,为方便描述,先给段代码:

 public class   EmailService
 {
     public void  SendMessage() { }
}

 public class   NotificationSystem
 {
     private   EmailService  svc;

     public  NotificationSystem()
    {
        svc =  new   EmailService ();
    }

     public void  InterestingEventHappend()
    {
        svc.SendMessage();
    }
}

代码的逻辑很简单: NotificationSystem 通过内置的 EmailService 类发送邮件,即 NotificationSystem 的功能依赖 EmailService 类。 我相信应有不少人对代码感觉亲切,我参与过的项目基本都这种风格,可惜这就是高耦合的设计。

高耦合翻译自“ tightly coupled ”,描述是这样的:" A class that knows a lot about the other classes it interacts with is said to be tightly coupled". 翻译过来就是---它知道的太多了。^_^

最快的解耦方式

为了让它知道的不那么多,现在贴一份改良后的代码:

 public interface   IMessageService 
     {
         void  SendMessage();
    }

     public class   EmailService  :  IMessageService
     {
         public void  SendMessage() { }
    }

     public class   NotificationSystem
     {
         private   IMessageService  svc;

         public  NotificationSystem()
        {
            svc =  new   EmailService ();
        }

         public void  InterestingEventHappend()
        {
            svc.SendMessage();
        }
    }

与之前比较,svc变量类型变成了接口 IMessageService  ,从而使 NotificationSystem 依赖 IMessageService 接口,而不是 EmailService 类。   但svc通过 new  方式赋值,这让两个类藕断丝连,一旦 EmailService 变化, NotificationSystem 也跟着变,违背了开闭原则。

通过控制反转彻底解耦

想彻底解耦,就要换一种方式对svc赋值,于是想到控制反转模式,控制反转翻译自“ inversion of control ”简称Ioc,一句话描述:“ Moving the creation of dependencies outside of the class that consumes those dependencies ”,简单翻译过来就是:在外面创建这个类。

现在我们先抽象一个接口用于“外部创建”。

 public interface   IMessageService 
     {
         void  SendMessage();
    }

     public class   EmailService  :  IMessageService
     {
         public void  SendMessage() { }
    }

     public interface   IServiceLocator
     {
         IMessageService  GetMessageService();
    }

     public class   NotificationSystem
     {
         private   IMessageService  svc;

         public  NotificationSystem( IServiceLocator  locator)
        {
            svc = locator.GetMessageService();
        }

         public void  InterestingEventHappend()
        {
            svc.SendMessage();
        }
    }

从代码看出,现在svc是通过 IServiceLocator 接口 类 创建,从而让原类之间解耦。 IServiceLocator 的实现类 就像工厂模式,通过参数或配置文件等决定生成哪个类。然而这种做法让 IServiceLocator 和 IMessageService  的实现类之间增加了耦合,每添加一个 IMessageService  的实现 类,就要修改 IServiceLocator 的代码,可能是switch或连续的if,这样看似不错的模式仍然违反开闭原则:

 public class   ServiceLocator : IServiceLocator
     {
         public   IMessageService  GetMessageService()
        {
             string  type =  "type1" ;
             switch  (type)
            {
                 case   "type1" : return new   EmailService1 ();
                 case   "type2" :  return new   EmailService2 ();
                 case   "type3" :  return new   EmailService3 ();
                   …………
            }
        }
    }
用Ioc容器完成高耦合到低耦合的蜕变

完全蜕变,就要求助于依赖注入了,这个词和控制反转是好基友,一般都同时出现。实际开发中,我们往往使用IoC容器来实现依赖注入的需求。通过Ioc容器(以Autofac为例)改善代码如下:

 public class   NotificationSystem
     {
         private   IMessageService  svc;
        
         public  NotificationSystem( IMessageService  messageService)
        {
            svc = messageService;
        }

         public void  InterestingEventHappend()
        {
            svc.SendMessage();
        }
    }

可以看到 NotificationSystem 的构造函数直接传入 IMessageService 接口变量做参数。在全局类的代码如下:

 var  builder =  new   ContainerBuilder ();
   builder.RegisterType< EmailService >().As< IMessageService >();

通过依赖注入来实例化 NotificationSystem 类:

 IMessageService  messageService= container.Resolve< IMessageService >();
    NotificationSystem  system= new   NotificationSystem (messageService);

借助Ioc的帮助,当 IMessageService 添加新的实现类时,也不用修改其他类的内部代码,在配置代码中,仅修改类名便可实现功能的切换。

结语

现在很多的开源代码都是这种模式,类内部依赖接口,通过Ioc容器灵活配置,熟悉了这种模式,有助于理解别人的设计意图,我也从中收益良多。但也有让我不爽的地方就是看别人的代码时,每次用F12跟踪源码,都会跳转到描述接口的代码文件中,想看具体实现总要害我找半天。

参考资料:< Professional Asp.Net MVC 3 >

随笔- 10  文章- 13  评论- 85 

05 2011 档案

 

.Net集合类的研究-有序集合(二)-SortedDictionary<TKey,TValue>

摘要: 从类名就可以看出SortedDictionary<TKey,TValue>和上篇介绍的SortedList一样,都是有序集合,但从类内部的存储结构上看,两者有很大区别,SortedList内部用数组保存,只能算是有序线性表,而SortedDictionary<TKey,TValue>的内部结构是红黑树。 园子里有不少关于红黑树的好文章,已将红黑树分析的很透彻。所以这里不讨论红黑树的结构原理,而讨论... 阅读全文

posted @  2011-05-30 11:27  两会 阅读(1594) |  评论 (3)   编辑

.Net集合类的研究-有序集合(一)-SortedList、SortedList<TKey,TValue>

摘要: 无论是常用的List<T>、Hashtable还是ListDictionary<TKey,TValue>,在保存值的时候都是无序的,而今天要介绍的集合类SortedList和SortedList<TKey,TValue>在保存值的时候是有序保存。SortedList之二分查找法一个集合有序,意味着什么?意味着可以利用一些算法来提高遍历集合时的效率,最常见的就是运用二分查找法,SortedList集合的核心就是运用二分查找。SortedList保存数据时和哈希表一样用Key-Value的方式进行存储,但不同的是,它把Key和Value分别保存在两个object 阅读全文

posted @  2011-05-24 09:26  两会 阅读(1810) |  评论 (4)   编辑

.net集合类的研究--链表—ListDictionary,LinkedList<T>

摘要: 链表是数据结构中存储数据的一种形式,我们经常使用的List<T>,ArrayList,Hashtable等容器类,存取操作时是用数组Array来保存,ListDictionary和LinkedList<T>不用Array,而是用链表的形式来保存。 链表的优点和缺点 以ListDictionary为例,在源码中,看不到Array类型的的变量,取而代之的是一个DictionaryNode类型的变量,查... 阅读全文

posted @  2011-05-18 22:09  两会 阅读(2108) |  评论 (6)   编辑

.net集合类的研究--哈希表(二)--HashSet<T>

摘要: .Net3.5之后出现了HashSet<T>,硬翻译过来就是“哈希集合”,跟“哈希”两字挂钩说明这种集合的内部实现用到了哈希算法,用Reflector工具就可以发现,HashSet<T>和Dictionary<TKey,TValue>使用了相同的存储方式和哈希冲突算法,那么,它跟Dictionary<TKey,TValue>和Hashtable在使用上到底有什么不同?HashSet<T>对集合运算的操作HashSet<T>是一个Set集合,虽然List、Collection也叫集合,但Set集合和它们却大有不同。HashS 阅读全文

posted @  2011-05-09 11:28  两会 阅读(2905) |  评论 (16)   编辑

.net集合类的研究-哈希表(一)--Hashtable,Dictionary<TKey,TValue>

摘要: 今天来探究哈希表,.net内置的哈希表容器是Hashtable类,而Dictionary<TKey,TValue>是对应的泛型哈希表.哈希表-Hashtable的实例化一般我们实例化ArrayList或List<T>的时候,如果不指定容量,则其内部是赋值为一个静态的空数组。当有添加操作时,会实例化为一个长度为4的数组,如果容量满了以后,再添加,就会自动扩充为两倍的容量。哈希表也有一个类似的情况,new Hashtable()如果不指定长度,则会将内置bucket数组的长度默认指定为11。如果给定一个值如new Hashtable(20),也并不会将bucket数组长度设 阅读全文

posted @  2011-05-06 18:14  两会 阅读(2226) |  评论 (12)   编辑

.net集合类的研究--Array,ArrayList,List<T>

摘要: 最近研究Nhibernate,看着样例代码一知半解,苦恼万分,发现中间又引用了一个Iesi.Collections,不禁要产生疑问--为什么要专门引用一个集合类程序集?这个程序集里的集合数组类与.net自带的有什么不一样?结果此问题一出就一发不可收拾,扪心自问冒出了一大堆的问题--.net有哪些集合类?array和ArrayList有什么区别?Hashtable与集合有什么不一样?....等等.这时才意识到,如果对.net本身提供的集合类不了解,根本不会明白引用Iesi.Collections的用意.由<<CLR via C#>>的书中所说:"所有的数组(如i 阅读全文

posted @  2011-05-02 22:17  两会 阅读(556) |  评论 (2)   编辑


作者: Leo_wl

    

出处: http://www.cnblogs.com/Leo_wl/

    

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

版权信息

查看更多关于CDN是如何工作的?的详细内容...

  阅读:42次