整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:

大厂前端工程师必备能力合辑:响应式设计、CSS动画

大厂前端工程师必备能力合辑:响应式设计、CSS动画

过调研一线互联网大厂的招聘JD(字节跳动、美团、腾讯、网易、京东等),小编对标C站能力认证要求,为大家整理了系列技术干货合集,助力小伙伴们顺利进大厂~本篇为响应式设计、css动画,核心能力点都会陆续更新中,欢迎大家关注csdn高校俱乐部。

在如今这个时间和知识都是碎片化的时代,C站根据C1-C4认证的成长路径,进行知识细化整理,形成系统化的知识图谱。

小编根据C4认证的成长路径整理了前端的相关资源,从零基础带你进入前端的世界。

欢迎大家一起学习~

一、响应式设计(30篇)

【自适应响应式网页设计(Responsive Web Design)】

【响应式网页设计】

【响应式网页设计实战】

【什么是响应式网页设计?】

【用3个步骤实现响应式网页设计】

【网页响应式设计】

【网页设计之响应式布局】

【RWD----响应式网页设计】

【基本响应式设计概念】

【响应式设计与自适应设计】

【基于Bootstrap的响应式网页】

【Web页响应式设计的一些解决方案】

【响应式网页与自适应网页的区别】

【响应式网页css代码写法】

【响应式设计】

【详细解析网页响应式设计的现状和趋势】

【响应式网页设计示例】

【响应式设计介绍】

【响应式设计中的HTML5】

【响应式Web设计总结】

【web前端响应式设计总结】

【响应性设计】

【响应式网页设计教程:展示响应式设计的基本原理】

【HTML+CSS十分钟实现响应式布局页面,响应式布局实战教程】

【什么是响应式布局设计?】

【vue项目中页面响应式布局设计方案】

【响应式页面排版】

【vueweb端响应式布局_移动端和pc端,响应式设计布局】

【自适应网页设计 or 响应式Web设计】

【响应式网页开发注意事项】

二、CSS动画(20篇)

【css 动画】

【CSS动画效果】

【超好看的css动画特效实现】

【CSS动画】

【9种常用CSS动画】

【css动画让文字一行一行逐渐显示】

【利用css3制作网页动画】

【用html和css制作网页动画(transform transition animation)】

【CSS3(三)Animation 入门详解】

【css动画-animation各个属性详解】

【css动画及js动画的区别】

【CSS动画入门:一分钟实现球体上下跳动动画效果】

【CSS动画案例-无缝滚动】

【css动画与js动画的区别】

【CSS3动画教程--制作Css动画的两种方式】

【常见 CSS 动画库】

【css动画和js动画比较!】

【用css动画效果做小熊奔跑】

【css动画animation绘制向四周扩散的圆圈】

【css动画效果,图片旋转】

小科普

CSDN软件工程师能力认证(以下简称C系列认证)是由中国软件开发者网CSDN制定并推出的一个能力认证标准。C系列认证历经近一年的实际线下调研、考察、迭代、测试,并梳理出软件工程师开发过程中所需的各项技术技能,结合企业招聘需求和人才应聘痛点,基于公开、透明、公正的原则,甑别人才时确保真实业务场景、全部上机实操、所有过程留痕、存档不可篡改。

————————————————

博主热门文章


前端工程师必备50篇:HTML语义化及媒体标签、表单及CSS选择器等

前端框架入门必备100文章:vue、Element、vuetify、iview等

前端学习知识库:大厂面试必考的前端工程师项目能力精选文章50篇

版权声明:本文为CSDN博主「软件工程师能力认证」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。

近大家刷抖音,是否有刷到拉斯维加斯的新地标 「Sphere」:

场馆内部的视觉效果非常惊人,其中一个效果让我虎躯一震:

我的第一想法就是,这个看起来用 CSS 也可以实现嘛?还有 CSS 不能实现的?

本文,就将尝试使用 CSS,大致还原这个效果。

拆解动画效果

其实,上述的动画效果,本质就是一个 3D 立方体。

同时,3D 立方体上每个面存在颜色不一样的文字,文字和颜色都在随机变化。

也就是说,我们需要实现一个 3D 立方体:

同时,我们还需要实现这样一个动画效果 -- 文字和颜色都在随机变化的平面效果:

两者组合一下,再挪动 3D 元素的景深距离,就能实现我们想要的效果!

好,下面我们一个一个实现。

实现一个 3D 立方体

实现一个 3D 立方体,相对另外一个文字和颜色都在随机变化的平面效果而言,属于非常非常简单的一步了。

我们在非常多篇文章中也讲过具体的实现方式:

最常见的 3D 图形,莫过于一个 3D 立方体。

如果没有上下两个面,只是一个 4 个面的图形,大概是这样:

这样一个图形,利用 CSS 3D,如何快速实现呢?

首先,构造这么一个结构:

<div class="perspective">
        <div class="container">
                <div class="img">3</div>
                <div class="img">D</div>
                <div class="img">视</div>
                <div class="img">图</div>
        </div>
</div>

4 个面,就是最内层的 4 个 .img,首先,需要给两个父容器,设置 3D 的属性:

.perspective {
  perspective: 3000px;
}
.container {
  width: 400px;
  height: 400px;
  transform-style: preserve-3d;
}

简单解释一下:

  1. perspective 可以作用于元素的后代,设置在最上层即可;
  2. transform-style: preserve-3d 设置给最终需要 3D 空间的元素的父容器之上,由于最终是 4 个 .img 需要 3D 空间,因此设置给 .container 即可。

接下来,就是最为核心的,如何设置 4 个 .img 元素的 3D 变换,使之形成 3D 立方体。

技巧就是:先旋转,再位移

这里给出一个俯视效果图:

以上述 Demo 中的正方体为例子,class 为 .img 的 div 块的高宽为 400px*400px。那么要利用 4 个 这样的 div 拼接成一个正方体,需要分别将 4 个 div 绕 Y 轴旋转 [90°, 180°, 270°, 360°],再 translateY(200px) 。

值得注意的是,一定是先旋转角度,再偏移距离,这个顺序很重要

代码如下:

.img {
        position: absolute;
        top: 0;
        left: 0;
        width: 400px;
        height: 400px;
}
@for $i from 1 through $imgCount {
        .img:nth-child(#{$i}) {
                transform: rotateY(($i * 90deg)) translateZ(200px);
        }
}

效果如下:

此时,可能会觉得图片太太太大了,此时,我们可以通过给中间层 .container 设置一个恰当的 translateZ 进行视觉大小上的调节。

.container {
    transform: translateZ(-3000px);
}

这样,就能得到恰当大小的立方体元素效果:

当然,对于我们这个效果,我们 5 要五个面(前后左右与上方即可),因此,我们基于上述的基础知识铺垫,重新实现一个我们需要的框架结构:

<div class="perspective">
  <div class="container">
    <div class="g-panel"></div>
    <div class="g-panel"></div>
    <div class="g-panel"></div>
    <div class="g-panel"></div>
    <div class="g-panel"></div>
  </div>
</div>

并且,我们希望我们的图形是一个立方体,只需要稍微改造长宽和 translateZ() 的即可。这样,我们就能得到一个前后左右与上方 5 个面的立方体元素。

示意效果如下:

实现文字动画效果

OK,立方体我们先放在一边。

接下来,我们尝试来实现这个效果:

这个效果如果一个文字用一个 DIV 承载实现,那是非常容易的,但是这样势必会造成元素过多,再设置动画效果,则会导致页面太为卡顿

所以,我们需要另辟蹊径。这里,我们可以使用多层渐变配合 background-clip: text

首先,我们利用等宽字体,随机实现一列文字:

<div>ABCDEFGHIJKLMN</div>
div {
    font-family: monospace;
    text-align: center;
    font-size: 25px;
    width: 25px;
    line-height: 25px;
    color: #fff;
}

效果大致如下:

此时,如果我们再利用线性渐变,给每个字符的对应空间(也就 25px x 25px),设置上不同的颜色,大概是这样:

@function randomLinear($count) {
    $value: '';
    
    @for $i from 0 through ($count - 1) {
        $value: $value + randomColor() + string.unquote(" 0 #{$i * 25}px,");
    }
    
    @return linear-gradient(string.unquote(#{$value}) randomColor() 0 100%);
}
@function randomColor() {
    @return rgb(randomNum(255), randomNum(255), randomNum(255));
}
div {
    // ...
    background: randomLinear(14);
}

其中,randomLinear(14) 是一个 SASS 函数,参数 14 表示生成 14 层线性渐变,每一个文字区域的颜色都是随机的,经过编译后的其中一种结果如下:

div {
    // ...
    background: linear-gradient(#feea96 0 25px, #edde42 0 50px, #e2344a 0 75px, #cdab7e 0 100px, #e16c8b 0 125px, #dcdc7d 0 150px, #dcb42a 0 175px, #d6a587 0 200px, #984f71 0 225px, #221e34 0 250px, #5e9a69 0 275px, #a955e4 0 300px, #4e908f 0 325px, #8d177e 0 350px);
}

上面,我们按照每间隔 25px 的高度,利用线性渐变随机设置了一种颜色,最终,能够得到这么个效果:

此时,我们只需要再设置 background-clip: text,配合透明文字颜色 color: transparent,就可以实现单个 div 内,单列文字,每个字体的颜色都是不一样的:

div {
    // ...
    background: randomLinear(14);
    background-clip: text;
    color: transparent;
}

此时,效果如下:

当然,文字颜色可以随机,那么文字本身也应该随机。这个不难,我们也可以借助 SASS 函数,编写一个随机字符的函数,通过元素的伪元素 content 进行设置。

那么此时,完整的代码可能是这样的:

<div></div>
$str: 'QWERTYUIOPASDFGHJKLZXCVBNMabcdefghigklmnopqrstuvwxyz123456789';
$length: str-length($str);

@function randomLinear($count) {
    $value: '';
    
    @for $i from 0 through ($count - 1) {
        $value: $value + randomColor() + string.unquote(" 0 #{$i * 25}px,");
    }
    
    @return linear-gradient(string.unquote(#{$value}) randomColor() 0 100%);
}
@function randomColor() {
    @return rgb(randomNum(255), randomNum(255), randomNum(255));
}
@function randomChar() {
    $r: random($length);
    @return str-slice($str, $r, $r);
}
@function randomChars($number) {
    $value: '';

    @if $number > 0 {
        @for $i from 1 through $number {
            $value: $value + randomChar();
        }
    }
    @return $value;
}

div {
    position: relative;
    width: 25px;
    height: 350px;

    &::before {
        content: randomChars(14);
        position: absolute;
        font-family: monospace;
        background: randomLinear(14);
        background-clip: text;
        color: transparent;
        text-align: center;
        font-size: 25px;
        width: 25px;
        line-height: 25px;
    }
}

这样,每次 div 内的文字,都是从上面 SASS 函数中 $str 变量中随机取的:

接下来,我们需要实现文字的随机跳变,也很好做,我们需要在一开始,随机生成多个不同的 content,然后,借助 CSS 动画,进行切换。

div {
   &::before {
        content: randomChars(14);
        --content1: "#{randomChars(14)}";
        --content2: "#{randomChars(14)}";
        --content3: "#{randomChars(14)}";
        --content4: "#{randomChars(14)}";
        animation: contentChange 1s infinite;
    }
}

@keyframes contentChange {
    20% {
        content: var(--content1);
    }
    40% {
        content: var(--content2);
    }
    60% {
        content: var(--content3);
    }
    80% {
        content: var(--content4);
    }
}

这里,我们一次生成了 5 个 content,其中 4 个用 CSS 变量保存了起来,随后,在 CSS 动画中,利用提前生成好的 content,进行字符内容的替换,此时,整个效果如下:

随机内容有了,单个字体颜色不一样有了,就差颜色的随机跳变动画了,这个也非常好做,我们在多篇文章也提及过,利用 filter: hue-rotate() 可以快速实现内容的颜色切换。

div {
    animation: colorChange 1s steps(12) infinite;
}
@keyframes colorChange {
    100% {
        filter: hue-rotate(360deg);
    }
}

我们利用了 filter: hue-rotate() 加上了步骤动画(steps),成功的实现了颜色的跳变!效果如下:

当然,我们最终要实现的是整个面随机颜色加上随机文字的跳变动画,只需要在上述的基础上,利用 SASS 函数,循环重复多列操作即可。基于上述所有内容的铺垫,我们最终的单个面下的动画效果代码如下:

<div class="g-container">
  <div></div>
  // ... 一个 32 个子 div
  <div></div>
</div>
@use "sass:string";

$str: 'QWERTYUIOPASDFGHJKLZXCVBNMabcdefghigklmnopqrstuvwxyz123456789';
$length: str-length($str);
$size: 25;
$count: 41;

@function randomNum($max, $min: 0, $u: 1) {
    @return ($min + random($max)) * $u;
}

@function randomLinear($count) {
    $value: '';
    
    @for $i from 0 through ($count - 1) {
        $value: $value + randomColor() + string.unquote(" 0 #{$i * 25}px,");
    }
    
    @return linear-gradient(string.unquote(#{$value}) randomColor() 0 100%);
}

@function randomColor() {
    @return rgb(randomNum(255), randomNum(255), randomNum(255));
}

@function randomChar() {
    $r: random($length);
    @return str-slice($str, $r, $r);
}

@function randomChars($number) {
    $value: '';

    @if $number > 0 {
        @for $i from 1 through $number {
            $value: $value + randomChar();
        }
    }
    @return $value;
}

body,
html {
    width: 100%;
    height: 100%;
    background: #000;
    font-family: monospace;
}

.g-container {
    position: relative;
    width: 800px;
    height: 800px;
    display: flex;
    animation: colorChange 1s steps(12) infinite;
    
    div {
        position: relative;
        width: #{$size}px;
        height: 800px;
        flex-shrink: 0;
        
        &::before {
            position: absolute;
            inset: 0;
            text-align: center;
            font-size: #{$size}px;
            width: #{$size}px;
            text-align: center;
            line-height: #{$size}px;
            color: transparent;
        }
    }
    
    @for $i from 1 to $count {
        div:nth-child(#{$i}) {
            &::before {
                content: randomChars(32);
                --content1: "#{randomChars(32)}";
                --content2: "#{randomChars(32)}";
                --content3: "#{randomChars(32)}";
                --content4: "#{randomChars(32)}";
                animation: contentChange 1s infinite;
                background: randomLinear(32);
                background-clip: text;
            }
        }
    }
}
@keyframes colorChange {
    100% {
        filter: hue-rotate(360deg);
    }
}
@keyframes contentChange {
    20% {
        content: var(--content1);
    }
    40% {
        content: var(--content2);
    }
    60% {
        content: var(--content3);
    }
    80% {
        content: var(--content4);
    }
}

这样,我们就成功的实现了单个平面下的,颜色随机,文字随机,且不断变化的动画效果:

实现立体效果

有了上面的立方体和单个平面的效果,要实现立体效果就不难了。我们尝试将两者结合起来。

改造原有的立方体结构,大致改成如下形式:

.perspective
    .container
        .g-panel
            -for(var i=0; i<32; i++)
                div
        .g-panel
            -for(var i=0; i<32; i++)
                div
        .g-panel
            -for(var i=0; i<32; i++)
                div
        .g-panel
            -for(var i=0; i<32; i++)
                div
        .g-panel
            -for(var i=0; i<32; i++)
                div

上面采用了 PUG 模板引擎来简化代码,编译后的效果如下:

<div class="perspective">
  <div class="container">
    <div class="g-panel">
      <div></div>
      // ... 32 个
      <div></div>
    <div class="g-panel">
      <div></div>
      // ... 32 个
      <div></div>
    <div class="g-panel">
      <div></div>
      // ... 32 个
      <div></div>
    <div class="g-panel">
      <div></div>
      // ... 32 个
      <div></div>
    <div class="g-panel">
      <div></div>
      // ... 32 个
      <div></div>
  </div>
</div>

这里,我们只需要实现 5 个面的立方体即可(前后左右以及上方)。

每个 .g-panel,实现一个我们上面铺垫的单面文字跳变效果,这样,我们就能得到这么一个立体的 3D 立方体动画效果:

接下来,我们只需要稍加调试,通过控制 perspective 和 transform: translateZ() 控制视觉上的纵深,将画面的视角放置于整个立方体之中,即可得到这么个效果:

好,最后,我们模拟文章开头拉斯维加斯球的效果,让顶部的平面,向下运动,实现一种天花板往下掉的动画效果,最终,我们即可使用纯 CSS,大致模拟出整个效果:

由于 GIF 录制问题,实际效果会比 GIF 展示效果更为震撼。

今,在各种互联网应用中,随着站点对硬件性能、响应速度、服务稳定性、数据可靠性等要求也越来越高,单台服务器也将难以无法承担所有的访问需求。

图片来自 Pexels

当然了,除了使用性价比高的设备和专用负载分流设备外,还有一些其他选择来帮你解决此问题,就是搭建集群服务器通过整合多台普通的服务器设备并以同一个地址对外提供相同的服务。

今天就带大家学习企业中常用的一种群集技术 LVS:

  • 什么是 LVS
  • 为什么要用 LVS
  • LVS 的组成及作用
  • 负载均衡的由来及所带来的好处
  • LVS 负载均衡集群的类型
  • DNS/软硬件负载均衡的类型
  • LVS 集群的通用体系结构
  • LVS 负载均衡的基本原理
  • LVS 负载均衡的三种工作模式
  • LVS 的十种负载调度算法
  • LVS 涉及相关的术语与说明
  • 总结

什么是 LVS?

LVS 是 Linux Virtual Server 的简写,也就是 Linux 虚拟服务器,是一个虚拟的服务器集群系统,本项目在 1998 年 5 月由章文嵩博士成立,是中国国内最早出现的自由软件项目之一。

官方网站:http://www.linuxvirtualserver.org,LVS 实际上相当于基于 IP 地址的虚拟化应用,为基于 IP 地址和内容请求分发的负载均衡提出了高效的解决方法,现在 LVS 已经是 Linux 内核标准的一部分。

使用 LVS 可以达到的技术目标是:通过 LVS 达到的负载均衡技术和 Linux 操作系统实现一个高性能高可用的 Linux 服务器集群,具有良好的可靠性、可扩展性和可操作性,从而以低廉的成本实现最优的性能。

LVS 是一个实现负载均衡集群的开源软件项目,LVS 架构从逻辑上可分为调度层、Server 集群层和共享存储层。

为什么要用 LVS?

那为什么还需要用 LVS 呢?随着 Internet 的爆炸性增长以及日常生活中的日益重要的作用,Internet 上的流量速度增长,以每年 100% 以上的速度增长。

服务器上的工作负载压力也迅速增加,因此服务器在短时间内将会过载,尤其是对于受欢迎的网站而言。

为了克服服务器的过载压力问题,有两种解决方案:

  • 一种是:单服务器解决方案,即将服务器升级到性能更高的服务器,但是当请求增加时,将很快过载,因此必须再次对其进行升级,升级过程复杂且成本高;
  • 另一个是:多服务器解决方案,即在服务器集群上构建可扩展的网络服务系统。当负载增加时,可以简单地在群集中添加新服务器或更多服务器以满足不断增长的需求,而商用服务器具有最高的性能/成本比。因此,构建用于网络服务的服务器群集系统更具可伸缩性,并且更具成本效益。

构建服务器集群的方法如下:

基于 DNS 的负载均衡集群:DNS 负载均衡可能是构建网络服务群集的最简单方法。

使用域名系统通过将域名解析为服务器的不同 IP 地址来将请求分发到不同的服务器。

当 DNS 请求到达 DNS 服务器以解析域名时,DNS 服务器将基于调度策略发出服务器 IP 地址之一,然后来自客户端的请求使用相同的本地缓存名称服务器将在指定的名称解析生存时间(TTL)中发送到同一服务器。

但是,由于客户端和分层 DNS 系统的缓存特性,很容易导致服务器之间的动态负载不平衡,因此服务器很难处理其峰值负载。在 DNS 服务器上不能很好地选择名称映射的 TTL 值。

如果值较小,DNS 流量很高,而 DNS 服务器将成为瓶颈;如果值较大,则动态负载不平衡将变得更糟。

即使 TTL 值设置为零,调度粒度也是针对每个主机的,不同用户的访问模式可能会导致动态负载不平衡,因为有些人可能从站点中拉出很多页面,而另一些人可能只浏览了几页然后转到远。

而且,它不是那么可靠,当服务器节点发生故障时,将名称映射到 IP 地址的客户端会发现服务器已关闭。

基于分派器的负载平衡集群:分派器,也称为负载平衡器,可用于在群集中的服务器之间分配负载,以便服务器的并行服务可以在单个 IP 地址上显示为虚拟服务,并且最终用户可以像单个服务器一样进行交互不知道群集中的所有服务器。

与基于 DNS 的负载平衡相比,调度程序可以按精细的粒度(例如每个连接)调度请求,以实现服务器之间的更好负载平衡。一台或多台服务器发生故障时,可以掩盖故障。

服务器管理变得越来越容易,管理员可以随时使一台或多台服务器投入使用或退出服务,而这不会中断最终用户的服务。

负载均衡可以分为两个级别,即应用程序级别和 IP 级别。例如,反向代理和 pWEB是用于构建可伸缩 Web 服务器的应用程序级负载平衡方法。

他们将 HTTP 请求转发到群集中的其他 Web 服务器,获取结果,然后将其返回给客户端。

由于在应用程序级别处理 HTTP 请求和答复的开销很高,我相信当服务器节点数增加到 5 个或更多时,应用程序级别的负载均衡器将成为新的瓶颈,这取决于每个服务器的吞吐量服务器。

LVS 与 Nginx 功能对比如下:

  • LVS 比 Nginx 具有更强的抗负载能力,性能高,对内存和 CPU 资源消耗较低。
  • LVS 工作在网络层,具体流量由操作系统内核进行处理,Nginx 工作在应用层,可针对 HTTP 应用实施一些分流策略。
  • LVS 安装配置较复杂,网络依赖性大,稳定性高。Nginx 安装配置较简单,网络依赖性小。
  • LVS 不支持正则匹配处理,无法实现动静分离效果。
  • LVS 适用的协议范围广。Nginx 仅支持 HTTP、HTTPS、Email 协议,适用范围小。

LVS 的组成及作用

LVS 由两部分程序组成:

  • ipvs(ip virtual server):LVS 是基于内核态的 Netfilter 框架实现的 IPVS 功能,工作在内核态。用户配置 VIP 等相关信息并传递到 IPVS 就需要用到 ipvsadm 工具。
  • ipvsadm:ipvsadm 是 LVS 用户态的配套工具,可以实现 VIP 和 RS 的增删改查功能,是基于 Netlink 或 raw socket 方式与内核 LVS 进行通信的,如果 LVS 类比于 Netfilter,那 ipvsadm 就是类似 iptables 工具的地位。

作用如下:

  • 主要用于多服务器的负载均衡。
  • 工作在网络层,可实现高性能,高可用的服务器集群技术。
  • 廉价,可把许多低性能的服务器组合在一起形成一个超级服务器。
  • 易用,配置简单,有多种负载均衡的方法。
  • 稳定可靠,即使在集群的服务器中某台服务器无法正常工作,也不影响整体效果。
  • 可扩展性好。

负载均衡的由来及所带来的好处

在业务刚起步时,一般先使用单台服务器对外进行提供服务。随着后期的业务增长,流量也越来越大。

当这单台服务器的访问量越大时,服务器所承受的压力也就越大,性能也将无法满足业务需求,超出自身所指定的访问压力就会崩掉,避免发生此类事情的发生。

我们将采取其他方案,将多台服务器组成集群系统从而来提高整体服务器的处理性能,使用统一入口(流量调度器)的方式通过均衡的算法进行对外提供服务,将用户大量的请求均衡地分发到后端集群不同的服务器上。

因此也就有了负载均衡来分担服务器的压力。使用负载均衡给我们所带来的好处:提高系统的整体性能、提高系统的扩展性、提高系统的高可用性。

LVS 负载均衡集群的类型

负载均衡群集:Load Balance Cluster,以提高应用系统的响应能力,尽可能处理更多的访问请求、减少延迟为目标,从而获得高并发、高负载的整体性能。

高可用群集:High Availability Cluster,以提高应用系统的可靠性,尽可能的减少终端时间为目标、确保服务的连续性,达到高可用的容错效果。

高性能运算群集:High Performance Computer Cluster,以提高应用系统的 CPU 运算速度、扩展硬件资源和分析能力为目标、从而获得相当于大型、超级计算机的高性能计算能力。

DNS/软硬件负载均衡的类型

①DNS 实现负载均衡

一个域名通过 DNS 解析到多个 IP,每个 IP 对应不同的服务器实例,就完成了流量的调度,这也是 DNS 实现负载均衡是最简单的方式。

使用该方式最大的优点:实现简单,成本低,无需自己开发或维护负载均衡设备。

不过存在一些缺点:服务器故障切换延迟大,升级不方便、流量调度不均衡,粒度大、流量分配策略较简单,支持的算法较少、DNS 所支持的 IP 列表有限制要求。

②硬件负载均衡

硬件负载均衡是通过专门的硬件设备从而来实现负载均衡功能,比如:交换机、路由器就是一个负载均衡专用的网络设备。

目前典型的硬件负载均衡设备有两款:F5 和 A10。不过话说,能用上这种硬件负载均衡设备的企业都不是一般的公司,反而普通业务量级小的其他企业基本用不到。

硬件负载均衡的优点:

  • 功能强大:支持各层级负载均衡及全面负载均衡算法。
  • 性能强大:性能远超常见的软件负载均衡器。
  • 稳定性高:硬件负载均衡,大规模使用肯定是严格测试过的。
  • 安全防护:除具备负载均衡功能外,还具备防火墙、防 DDoS 攻击等安全功能。

硬件负载均衡的缺点:

  • 价格昂贵。
  • 可扩展性差。
  • 调试维护麻烦。

③软件负载均衡

软件负载均衡有如下几种:

  • Nginx:支持 4 层/7 层负载均衡,支持 HTTP、E-mail 协议。
  • LVS:纯 4 层负载均衡,运行在内核态,性能是软件负载均衡中最高的。
  • HAproxy:是 7 层负载均衡软件,支持 7 层规则的设置,性能也不错。

软件负载均衡的优点:简单、灵活、便宜(直接在 Linux 操作系统上安装上述所使用的软件负载均衡,部署及维护较简单,4 层 和 7 层负载均衡可根据业务进行选择也可根据业务特点,比较方便进行扩展及定制功能)。

LVS 集群的通用体系结构

第一层:负载调度器:Load Balancer,它是访问整个群集系统的唯一入口,对外使用所有服务器共有的虚拟 IP 地址,也成为群集 IP 地址。

负载均衡器:是服务器群集系统的单个入口点,可运行 IPVS,该 IPVS 在 Linux 内核或 KTCPVS 内部实现 IP 负载均衡技术,在 Linux 内核中实现应用程序级负载平衡。

使用 IPVS 时,要求所有服务器提供相同的服务和内容,负载均衡器根据指定的调度算法和每个服务器的负载将新的客户端请求转发到服务器。无论选择哪个服务器,客户端都应获得相同的结果。

使用 KTCPVS 时,服务器可以具有不同的内容,负载均衡器可以根据请求的内容将请求转发到其他服务器。

由于 KTCPVS 是在 Linux 内核内部实现的,因此中继数据的开销很小,因此仍可以具有较高的吞吐量。

第二层:服务器池 Server Pool,群集所提供的应用服务,比如:HTTP、FTP 服务器池来承担,每个节点具有独立的真实 IP 地址,只处理调度器分发过来的客户机请求。

服务器群集的节点可根据系统所承受的负载进行分担。当所有服务器过载时,可添加多台服务器来处理不断增加的工作负载。

对于大多数 Internet 服务(例如Web),请求通常没有高度关联,并且可以在不同服务器上并行运行。因此,随着服务器群集的节点数增加,整体性能几乎可以线性扩展。

第三层:共享存储 Shared Storage,为服务器池中的所有节点提供稳定、一致的文件存储服务,确保整个群集的统一性,可使用 NAS 设备或提供 NFS (Network File System)网络文件系统共享服务的专用服务器。

共享存储:可以是数据库系统,网络文件系统或分布式文件系统。服务器节点需要动态更新的数据应存储在基于数据的系统中,当服务器节点并行在数据库系统中读写数据时,数据库系统可以保证并发数据访问的一致性。

静态数据通常保存在网络文件系统(例如 NFS 和 CIFS)中,以便可以由所有服务器节点共享数据。

但是,单个网络文件系统的可伸缩性受到限制,例如,单个 NFS / CIFS 只能支持 4 到 8 个服务器的数据访问。

对于大型集群系统,分布式/集群文件系统可以用于共享存储,例如 GPFS,Coda 和 GFS,然后共享存储也可以根据系统需求进行扩展。

LVS 负载均衡的基本原理

Netfilter 的基本原理

在介绍 LVS 负载均衡基本原理之前,先说一下 Netfilter 的基本原理。因为 LVS 是基于 Linux 内核中 Netfilter 框架实现的负载均衡系统。

Netfilter 其实很复杂也很重要,平时说的 Linux 防火墙就是 Netfilter,不过我们操作的还是 iptables,iptables 和 Netfilter 是 Linux 防火墙组合工具,是一起来完成系统防护工作的。

iptables 是位于用户空间,而 Netfilter 是位于内核空间。iptables 只是用户空间编写和传递规则的工具而已,真正工作的还是 Netfilter。

两者间的区别:Netfilter 是内核态的 Linux 防火墙机制,它作为一个通用、抽象的框架,提供了一整套的 hook 函数管理机制,提供数据包过滤、网络地址转换、基于协议类型的连接跟踪的功能,可在数据包流经过程中,根据规则设置若干个关卡(hook 函数)来执行相关操作。

它共设置了 5 个点,包括:

  • prerouting:在对数据包做路由选择之前,将应用此链中的规则。
  • input:当收到访问防火墙本机地址的数据包时,将应用此链中的规则。
  • forward:当收到需要通过防火中转发给其他地址的数据包时,将应用此链中的规则。
  • output:当防火墙本机向外发送数据包时,将应用此链中的规则。
  • postrouting:在对数据包做路由选择之后,将应用此链中的规则。

iptable 是用户层的工具,提供命令行接口,能够向 Netfilter 中添加规则策略,从而实现报文过滤,修改等功能。

通过下图我们可以来了解下 Netfilter 的工作机制:

当数据包通过网络接口进入时,经过链路层之后进入网络层到达PREROUTING,然后根据目标 IP 地址进行查找路由。

如目标 IP 是本机,数据包会传到 INPUT 上,经过协议栈后根据端口将数据送到相应的应用程序;应用程序将请求处理后把响应数据包发送至 OUTPUT 里,最终通过 POSTROUTING 后发送出网络接口。

如目标 IP 不是本机,并且服务器开启了 FORWARD 参数,这时会将数据包递送给 FORWARD,最后通过 POSTROUTING 后发送出网络接口。

LVS 的基本原理

LVS 基于 Netfilter 框架,工作在 INPUT 链上,在 INPUT 链上注册 ip_vs_in HOOK 函数,进行 IPVS 相关主流程。

详细原理概述如下:

①当客户端用户访问 www.baidu.com 网站时,用户访问请求通过层层网络,最终通过交换机进入 LVS 服务器网卡进入内核空间层。

②进入 PREROUTING 后通过查找路由,确定访问目的 VIP 是本机 IP 地址的话,数据包将进入 INPUT 链中。

③因为 IPVS 工作在 INPUT 链上,会根据访问的 VIP 和端口判断请求是否为 IPVS 服务,是的情况下,则调用注册的 IPVS HOOK 函数,进行 IPVS 相关流程,并强制修改数据包的相关数据,并将数据包发往 POSTROUTING 链中。

④POSTROUTING 链收到数据包后,将根据目标 IP 地址服务器,通过路由选路,将数据包最终发送至后端真实服务器中。

上面就是我们所介绍的 LVS 的工作原理,那么 LVS 负载均衡还包括三种工作模式,且每种模式工作原理都有所不同,适用于不同应用场景,其最终目的都是能实现均衡的流量调度和良好的扩展性。

LVS 负载均衡的三种工作模式

群集的负载调度技术,可基于 IP、端口、内容等进行分发,其中基于 IP 的负载均衡是效率最高的。

基于 IP 的负载均衡模式,常见的有地址转换(NAT)、IP 隧道(TUN)和直接路由(DR)三种工作模式。

NAT 模式

地址转换:Network Address Translation,简称:NAT 模式,类似于防火墙的私有网络结构,负载调度器作为所有服务器节点的网关,作为客户机的访问入口,也是各节点回应客户机的访问出口,服务器节点使用私有 IP 地址,与负载调度器位于同一个物理网络,安全性要优于其他两种方式。

NAT 实现原理过程如下:

①客户端发出的请求数据包经过网络到达 LVS 网卡,数据包源 IP 为 CIP,目的 IP 为 VIP。

②然后进入 PREROUTING 链中,根据目的 IP 查找路由,确定是否为本机 IP 地址,随后将数据包转发至 INPUT 链中,源 IP 和 目的 IP 不变。

③到达 LVS 后,通过目的 IP 和目的 PORT 查找是否为 IPVS 服务,如是 IPVS 服务,将会选择一个 RS 来作为后端服务器,数据包的目的 IP 地址将会修改为 RIP,这时并以 RIP 为目的 IP 去查找路由,确定下一跳及 PORT 信息后,数据包将会转发至 OUTPUT 链中。

④被修改过的数据包经过 POSTROUTING 链后,到达 RS 服务器,数据包源 IP 为 CIP,目的 IP 为 RIP。

⑤RS 服务器经过处理后,将会把数据包发送至用户空间的应用程序,待处理完成后,发送响应数据包,RS 服务器的默认网关为 LVS 的 IP,应用程序将会把数据包转发至下一跳 LVS 服务器,数据包源 IP 为 RIP,目的 IP 为 CIP。

⑥LVS 服务器收到 RS 服务器响应的数据包后,查找路由,目的 IP 不是本机 IP并且 LVS 服务器开启了 FORWARD 模式,会将数据包转发给它,数据包不变。

⑦LVS 服务器收到响应数据包后,根据目的 IP 和 目的 PORT 查找相应的服务,这时,源 IP 为 VIP,通过查找路由,确定下一跳信息并将数据包发送至网关,最终回应给客户端用户。

NAT 模式的优点:

  • 支持 Windows 操作系统。
  • 支持端口映射,如 RS 服务器 PORT 与 VPORT 不一致的话,LVS 会修改目的 IP 地址和 DPORT 以支持端口映射。

NAT 模式的缺点:

  • RS 服务器需配置网关。
  • 双向流量对 LVS 会产生较大的负载压力。

NAT 模式的使用场景:对 Windows 操作系统的用户比较友好,使用 LVS ,必须选择 NAT 模式。

TUN 模式

IP 隧道:IP Tunnel,简称:TUN 模式,采用开放式的网络结构,负载调度器作为客户机的访问入口,各节点通过各自的 Internet 连接直接回应给客户机,而不经过负载调度器,服务器节点分散在互联网中的不同位置,有独立的公网 IP 地址,通过专用 IP 隧道与负载调度器相互通信。

TUN 实现原理过程如下:

①客户端发送数据包经过网络后到 LVS 网卡,数据包源 IP 为 CIP,目的 IP 为 VIP。

②进入 PREROUTING 链后,会根据目的 IP 去查找路由,确定是否为本机 IP,数据包将转发至 INPUT 链中,到 LVS,源 IP 和 目的 IP 不变。

③到 LVS 后,通过目的 IP 和目的 PORT 查找是否为 IPVS 服务,如是 IPVS 服务,将会选择一个 RS 后端服务器, 源 IP 为 DIP,目标 IP 为 RIP,数据包将会转发至 OUTPUT 链中。

④数据包根据路由信息到达 LVS 网卡,发送至路由器网关,最终到达后端服务器。

⑤后端服务器收到数据包后,会拆掉最外层的 IP 地址后,会发现还有一层 IP 首部,源 IP 为 CIP,目的 IP 为 VIP,TUNL0 上配置 VIP,查找路由后判断为本机 IP 地址,将会发给用户空间层的应用程序响应后 VIP 为源 IP,CIP 为目的 IP 数据包发送至网卡,最终返回至客户端用户。

TUN 模式的优点:

  • 单臂模式,LVS 负载压力小。
  • 数据包修改小,信息完整性高。
  • 可跨机房。

TUN 模式的缺点:

  • 不支持端口映射。
  • 需在 RS 后端服务器安装模块及配置 VIP。
  • 隧道头部 IP 地址固定,RS 后端服务器网卡可能会不均匀。
  • 隧道头部的加入可能会导致分片,最终会影响服务器性能。

TUN 模式的使用场景:如对转发性要求较高且具有跨机房需求的,可选择 TUN 模式。

DR 模式

直接路由:Direct Routing,简称 DR 模式,采用半开放式的网络结构,与 TUN 模式的结构类似,但各节点并不是分散在各个地方,而是与调度器位于同一个物理网络,负载调度器与各节点服务器通过本地网络连接,不需要建立专用的 IP 隧道。它是最常用的工作模式,因为它的功能性强大。

DR 实现原理过程如下:

①当客户端用户发送请求给 www.baidu.com 网站时,首先经过 DNS 解析到 IP 后并向百度服务器发送请求,数据包经过网络到百度 LVS 负载均衡服务器。

这时到达 LVS 网卡时的数据包包括:源 IP 地址(客户端地址)、目的 IP 地址(百度对外服务器 IP 地址,也就是 VIP)、源 MAC 地址(CMAC / LVS 连接路由器的 MAC 地址)、目标 MAC 地址(VMAC / VIP 对应的 MAC 地址)。

②数据包到达网卡后,经过链路层到达 PREROUTING 链,进行查找路由,发现目的 IP 是 LVS 的 VIP,这时就会发送至 INPUT 链中并且数据包的 IP 地址、MAC 地址、Port 都未经过修改。

③数据包到达 INPUT 链中,LVS 会根据目的 IP 和 Port(端口)确认是否为 LVS 定义的服务。

如是定义过的 VIP 服务,会根据配置的服务信息,从 RealServer 中选择一个后端服务器 RS1,然后 RS1 作为目标出方向的路由,确定下一跳信息及数据包通过具体的哪个网卡发出,最好将数据包通过 INET_HOOK 到 OUTPUT 链中。

④数据包通过 POSTROUTING 链后,目的 MAC 地址将会修改为 RealServer 服务器 MAC 地址(RMAC)源 MAC 地址修改为 LVS 与 RS 同网段的 IP 地址的 MAC 地址(DMAC)此时,数据包将会发至 RealServer 服务器。

⑤数据包到达 RealServer 服务器后,发现请求报文的 MAC 地址是自己的网卡 MAC 地址,将会接受此报文,待处理完成之后,将响应报文通过 lo 接口传送给 eth0 网卡然后向外发出。

此时的源 IP 地址为 VIP,目标 IP 为 CIP,源 MAC 地址为 RS1 的 RMAC,目的 MAC 地址为下一跳路由器的 MAC 地址(CMAC),最终数据包通过 RS 相连的路由器转发给客户端。

DS 模式的优点:

  • 响应数据不经过 LVS,性能高。
  • 对数据包修改小,信息完整性好。

DS 模式的缺点:

  • LVS 与 RS 必须在同一个物理网络。
  • RS 上必须配置 lo 和其他内核参数。
  • 不支持端口映射。

DS 模式的使用场景:对性能要求高的,可首选 DR 模式,还可透传客户端源 IP 地址。

NAT 模式:只需一个公网 IP 地址,是最易用的一种负载均衡模式,安全性较好。

TUN 模式 和 DR 模式:负载能力强大、适用范围广、节点安全性较差。

LVS 的十种负载调度算法

LVS 的十种负载调度算法如下:

①轮询:Round Robin,将收到的访问请求按顺序轮流分配给群集中的各节点真实服务器中,不管服务器实际的连接数和系统负载。

②加权轮询:Weighted Round Robin,根据真实服务器的处理能力轮流分配收到的访问请求,调度器可自动查询各节点的负载情况,并动态跳转其权重,保证处理能力强的服务器承担更多的访问量。

③最少连接:Least Connections,根据真实服务器已建立的连接数进行分配,将收到的访问请求优先分配给连接数少的节点,如所有服务器节点性能都均衡,可采用这种方式更好的均衡负载。

④加权最少连接:Weighted Least Connections,服务器节点的性能差异较大的情况下,可以为真实服务器自动调整权重,权重较高的节点将承担更大的活动连接负载。

⑤基于局部性的最少连接:LBLC,基于局部性的最少连接调度算法用于目标 IP 负载平衡,通常在高速缓存群集中使用。

如服务器处于活动状态且处于负载状态,此算法通常会将发往 IP 地址的数据包定向到其服务器;如果服务器超载(其活动连接数大于其权重),并且服务器处于半负载状态,则将加权最少连接服务器分配给该 IP 地址。

⑥复杂的基于局部性的最少连接:LBLCR,具有复杂调度算法的基于位置的最少连接也用于目标 IP 负载平衡,通常在高速缓存群集中使用。

与 LBLC 调度有以下不同:负载平衡器维护从目标到可以为目标提供服务的一组服务器节点的映射。对目标的请求将分配给目标服务器集中的最少连接节点。

如果服务器集中的所有节点都超载,则它将拾取群集中的最少连接节点,并将其添加到目标服务器群中;如果在指定时间内未修改服务器集群,则从服务器集群中删除负载最大的节点,以避免高度负载。

⑦目标地址散列调度算法:DH,该算法是根据目标 IP 地址通过散列函数将目标 IP 与服务器建立映射关系,出现服务器不可用或负载过高的情况下,发往该目标 IP 的请求会固定发给该服务器。

⑧源地址散列调度算法:SH,与目标地址散列调度算法类似,但它是根据源地址散列算法进行静态分配固定的服务器资源。

⑨最短延迟调度:SED,最短的预期延迟调度算法将网络连接分配给具有最短的预期延迟的服务器。

如果将请求发送到第 i 个服务器,则预期的延迟时间为(Ci +1)/Ui,其中 Ci 是第 i 个服务器上的连接数,而 Ui 是第 i 个服务器的固定服务速率(权重) 。

⑩永不排队调度:NQ,从不队列调度算法采用两速模型。当有空闲服务器可用时,请求会发送到空闲服务器,而不是等待快速响应的服务器。

如果没有可用的空闲服务器,则请求将被发送到服务器,以使其预期延迟最小化(最短预期延迟调度算法)。

LVS 涉及相关的术语及说明

上述内容中涉及到很多术语或缩写,这里简单解释下具体的含义,便于理解:

  • DS:Director Server,前端负载均衡节点服务器。
  • RS:Real Server,后端真实服务器。
  • CIP:Client IP,客户端 IP 地址。
  • VIP:Virtual IP,负载均衡对外提供访问的 IP 地址,一般负载均衡 IP 都会通过 Virtual IP 实现高可用。
  • RIP:RealServer IP,负载均衡后端的真实服务器 IP 地址。
  • DIP:Director IP,负载均衡与后端服务器通信的 IP 地址。
  • CMAC:客户端 MAC 地址,LVS 连接的路由器的 MAC 地址。
  • VMAC:负载均衡 LVS 的 VIP 对应的 MAC 地址。
  • DMAC:负载均衡 LVS 的 DIP 对应的 MAC 地址。
  • RMAC:后端真实服务器的 RIP 地址对应的 MAC 地址。

总结

回顾下,通过本文你可学习到什么是 LVS、为什么要用 LVS、LVS 的组成及工作原理等。

参考文献:

  • http://www.linuxvirtualserver.org/
  • http://www.linuxvirtualserver.org/how.html
  • http://www.linuxvirtualserver.org/Documents.html