CDN 的那些事

148 阅读5分钟

CDN (Content Delivery Network,内容分发网络)

CDN 是一种分布式网络架构,它将网站或应用程序的静态和动态内容复制到多个数据中心的边缘服务器中,并通过就近路由机制为用户提供服务。

作用

将用户请求的内容从源站点缓存复制到离用户更近的服务器,从而提高内容传输速度和用户访问体验。

工作原理

当用户请求访问某个网站或应用程序时, CDN 系统会自动分析用户的位置,通过就近的边缘服务器向用户提供所请求的内容。

CDN 服务器会缓存网站的静态内容,例如图片、CSS、HTML 文件等,并通过负载均衡技术将流量分配到多个服务器,从而实现快速、可靠的网络内容传输。

主要优点

  1. 加速网站访问速度: CDN 通过在全球各地建立缓存服务器,将网站的静态内容缓存在用户所在地区的服务器上,大大减少了用户请求资源时的访问延迟,从而提高了网站的访问速度。

  2. 提高网站的可靠性和稳定性:通过将内容复制到多个服务器上, CDN 可以防止单点故障,提高网站的可靠性和稳定性。

  3. 减少源站点的网络带宽压力:由于 CDN 缓存了网站的静态内容,这些内容可以由缓存服务器直接提供,减少了源站点的网络带宽压力。

  4. 提高安全性: CDN 可以提供一些安全服务,例如防止 DDoS 攻击、防止恶意访问等。

常见的缓存算法

  • Least Recently Used(LRU):这是一种最常见的缓存算法,它根据最近最少使用的原则进行缓存替换。当缓存达到最大容量时,会将最久未被访问的缓存替换掉。 这种算法适用于访问模式类似于“热点”的情况,即一小部分资源被频繁访问,而其他资源很少被访问的情况。

    class CacheNode<K, V> {
      constructor(
        public key: K,
        public value: V,
        public prev: CacheNode<K, V> | null = null,
        public next: CacheNode<K, V> | null = null
      ) {}
    }
    
    /**
     * Least Recently Used 最近最少被使用
     * 当缓存的容量到达上限的时候,删除链尾资源,再将新的资源添加到链表头
     */
    class LRUCache<K, V> {
      private map = new Map<K, CacheNode<K, V>>();
      private head: CacheNode<K, V> | null = null;
      private tail: CacheNode<K, V> | null = null;
      private _size = 0;
      get size(): number {
        return this._size;
      }
    
      private readonly capacity: number;
    
      constructor(capacity: number) {
        this.capacity = capacity;
      }
    
      get(key: K): V | undefined {
        const node = this.map.get(key);
        if (!node) return undefined;
        if (node !== this.head) {
          this.remove(node);
          this.setHead(node);
        }
        return node.value;
      }
    
      put(key: K, value: V) {
        const node = this.map.get(key);
    
        if (node) {
          node.value = value;
    
          if (node !== this.head) {
            this.remove(node);
            this.setHead(node);
          }
        } else {
          const newNode = new CacheNode<K, V>(key, value);
    
          if (this._size === this.capacity) {
            this.map.delete(this.tail!.key);
            this.remove(this.tail!);
          }
    
          this.setHead(newNode);
    
          this.map.set(key, newNode);
        }
      }
    
      private remove(node: CacheNode<K, V>): void {
        if (node.prev) {
          node.prev.next = node.next;
        } else {
          this.head = node.next;
        }
    
        if (node.next) {
          node.next.prev = node.prev;
        } else {
          this.tail = node.prev;
        }
    
        this._size--;
      }
    
      private setHead(node: CacheNode<K, V>): void {
        node.next = this.head;
        node.prev = null;
    
        if (this.head) {
          this.head.prev = node;
        }
    
        this.head = node;
    
        if (!this.tail) {
          this.tail = node;
        }
    
        this._size++;
      }
    }
    
    
  • Least Frequently Used(LFU):该算法根据访问频率来决定缓存是否被替换。当缓存达到最大容量时,会先替换访问次数最少的缓存。这种算法适用于访问模式比较平均分布的情况。

    interface Entry<K, V> {
      key: K;
      value: V;
      freq: number;
    }
    
    class LFUCache<K, V> {
      private map: Map<K, Entry<K, V>> = new Map<K, Entry<K, V>>();
      private freqMap: Map<number, Set<K>> = new Map<number, Set<K>>();
      private readonly capacity: number;
      private minFreq: number = 0;
    
      constructor(capacity: number) {
        this.capacity = capacity;
      }
    
      get(key: K): V | undefined {
        const entry = this.map.get(key);
    
        if (!entry) return undefined;
    
        this.updateFreq(entry);
    
        return entry.value;
      }
    
      put(key: K, value: V): void {
        if (this.capacity === 0) return;
    
        const entry = this.map.get(key);
    
        if (entry) {
          entry.value = value;
    
          this.updateFreq(entry);
        } else {
          if (this.map.size === this.capacity) this.evict();
    
          const newEntry = { key, value, freq: 1 };
    
          this.addEntry(newEntry);
    
          this.map.set(key, newEntry);
    
          this.minFreq = 1;
        }
      }
    
      private updateFreq(entry: Entry<K, V>): void {
        const freq = entry.freq;
    
        this.freqMap.get(freq)!.delete(entry.key);
    
        if (this.minFreq === freq && !this.freqMap.get(freq)?.size) {
          this.minFreq++;
        }
    
        entry.freq++;
    
        this.addEntry(entry);
      }
    
      private addEntry(entry: Entry<K, V>): void {
        const freq = entry.freq;
    
        let set = this.freqMap.get(freq);
    
        if (!set) {
          set = new Set<K>();
    
          this.freqMap.set(freq, set);
        }
    
        set.add(entry.key);
      }
    
      private evict(): void {
        const set = this.freqMap.get(this.minFreq);
    
        const key = set!.values().next().value;
    
        set!.delete(key);
    
        if (!set!.size) {
          this.freqMap.delete(this.minFreq);
        }
    
        this.map.delete(key);
      }
    }
    
  • First In First Out(FIFO):该算法采用先进先出的原则进行缓存替换。当缓存达到最大容量时,会先替换最早被缓存的缓存。这种算法适用于缓存资源更新频繁的情况。

  • Random Replacement(RR):该算法是一种随机缓存替换算法,当缓存达到最大容量时,会随机选择一个缓存进行替换。这种算法适用于访问模式难以预测的情况。

  • Adaptive Replacement Cache(ARC):该算法结合了 LRU 和 LFU 算法的优点,能够动态调整缓存大小以适应不同的访问模式。ARC 算法可以根据访问频率和最近访问时间来进行缓存替换,从而提高缓存效率。

实际应用

  • 网站加速:通过将内容部署在多个节点上,CDN 可以在用户离服务器较远时提高网站的响应速度和性能,从而提高用户体验。

  • 视频直播:CDN 可以将音视频流部署在全球各地的节点上,从而在全球范围内提供更快、更稳定的视频流,并减少延迟和卡顿等问题。

  • 图片加速:CDN 可以将图片缓存到离用户最近的节点上,从而提高图片加载速度和性能,减少网站加载时间和带宽消耗。

  • 游戏加速:CDN 可以将游戏资源部署在离玩家最近的节点上,从而提高游戏的响应速度和稳定性,减少延迟和卡顿等问题。

  • 应用加速:CDN 可以将应用部署在多个节点上,从而提高应用的响应速度和性能,减少应用加载时间和带宽消耗。

  • 安全加固:CDN 可以通过拦截恶意流量、DDoS 攻击和网络威胁等,提高网站或应用的安全性和稳定性。

好文推荐

产品信息