Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >中断与异常简介与分析

中断与异常简介与分析

作者头像
杨源鑫
发布于 2019-07-04 08:18:27
发布于 2019-07-04 08:18:27
1.2K00
代码可运行
举报
文章被收录于专栏:嵌入式开发圈嵌入式开发圈
运行总次数:0
代码可运行

一、用户态、内核态

开篇,我们先来了解下什么是用户态、内核态。

一般现代CPU都有几种不同的指令执行级别。

在高执行级别下,代码可以执行特权指令,访问任意的物理地址,这种CPU执行级别就对应着内核态。

而在相应的低级别执行状态下,代码的掌控范围会受到限制。只能在对应级别允许的范围内活动。

举例:

intel x86 CPU有四种不同的执行级别0-3,linux只使用了其中的0级和3级分别来表示内核态和用户态。

二、如何区分用户态和内核态?

一般来说在linux中,地址空间是一个显著的标志:0xc0000000以上的地址空间只能在内核态下访问,0x00000000-0xbfffffff的地址空间在两种状态下都可以访问。

注意:这里所说的地址空间是逻辑地址而不是物理地址。

孟宁老师在讲解内核知识点已经把这个知识点最精华的部分提取出来了,那么到底内核中有什么样的接口是跟老师说的相关的呢?

其实写过linux内核驱动程序的同学应该就知道,实现一个字符设备驱动,在write方法和read方法中,内核态和用户态之间的桥梁就是copy_to_user和copy_form_user这两个接口,因为在高执行级别下,代码可以执行特权指令,访问任意的物理地址,这种CPU执行级别就对应着内核态,而在相应的低级别执行状态下,代码的掌控范围会受到限制。只能在对应级别允许的范围内活动。其实正好说明了这个问题,程序员或者软件应用工程师在编写应用程序去控制设备驱动的时候,首先肯定是会打开相应的文件描述符,然后对相应的文件描述符进行读写,ioctl,lseek之类的操作。当在应用层编写程序即是属于用户态,在应用程序不能访问任意的硬件物理地址,所以当用户需要读取文件描述符的内的内容时,就需要调用read,当用户需要写数据进文件描述符时,就需要用write,在用户态调用这两个接口,进而就会进行系统调用,产生相应的系统调用号,然后内核会根据系统调用号找到相应的驱动程序,此时系统就处在内核态中,在驱动程序中,首先进行驱动程序初始化,然后注册,产生驱动程序最重要主设备号和次设备号。初始化的过程中由于对相应的read方法和wirte方法进行初始化,故用户态执行read操作,就会进而使CPU产生异常,然后进入内核态找到相应的read,write当然也是一样的。

当然,我的分析依然还是处于非常片面的,只能说个大概,因为操作系统在执行系统调用的过程依然是非常复杂的,但是复杂归复杂,对于这样的一个流程我们还是应当要去了解清楚。

还有一个例子就是,假设我需要实现一个led驱动或者其它的驱动,在内核驱动中,我需要将相应的物理地址ioremap成为一个虚拟地址,当驱动调用结束后,还应当取消相应的地址映射,这其实就是在内核态进行的操作,因为在内核中,访问这些地址以虚拟地址的形式进行相应的内存分配。为了使软件访问I/O内存,必须为设备分配虚拟地址.这就是ioremap的工作。

以上是Linux内核中断以及异常需要了解的基础。

三、中断基础

中断,通常被定义为一个事件。打个比方,你烧热水,水沸腾了,这时候你要去关掉烧热水的电磁炉,然后再去办之前手中停不下来的事情。那么热水沸腾就是打断你正常工作的一个信号机制。当然,还有其它的情况,我们以后再做分析。

中断也就是这样产生的,中断分为同步中断还有异步中断。

同步中断在Intel的手册中被称为异常,而异步中断被称作中断。打个比方在ARM处理器的异常种类就有不少,有未定义指令异常,软中断异常,快中断异常等等。异常是由程序错误产生的,或者是内核必须处理的异常条件产生的。如果你曾经学过单片机,那么你一定会清楚,51单片机的P32,P33是外部中断0和1,假设当你在程序中开启了外部中断0,然后在中断中执行了相应的程序,这时你在外部中断0的一脚连接一个按键,这时候你按下去P30这个引脚就会产生一个中断。那么中断服务程序就会响应你的操作,比如点亮一个LED灯,或者说让蜂鸣器叫一下。

那么在linux内核中的中断其实也是和单片机类似的,只不过linux内核的中断定义的比较丰富,但是基本思想还是一样的。linux内核处理中断有一种叫做中断信号的机制。它的作用就是当一个中断信号到来时,CPU必须停止它当然正在做的事情,然后切换到一个新的活动,为了做到这一点,内核态堆栈保存的程序计数器的当前值,其实就是eip和cs寄存器的存储数据,然后把中断相关类型的一个地址放到一个程序计数器当中去。

其实在内核中,中断这样的切换机制很像进程的调度,上下文切换这样的机制,但是依然存在着一个非常明显的差异,那就是中断或者异常在处理的代码并不是一个进程。

中断信号的来临必将会引起中断的处理,那么中断处理必须要满足以下的约束:

1、linux内核在响应中断以后必须要进行的操作分为两部分:我们把非常重要的,非常紧急的处理程序让内核立即去运行。剩下的有延时的部分就让它后面再去执行。这样也就验证了水沸腾,而人停下手中的事去关电磁炉,再回去做他的事一样的道理。

2、中断编写的程序必须编写成可以使内核控制的路径能以嵌套的方式来执行,或者说,当最后一个内核控制路径终止的时候,内核必须能恢复被中断进程的执行,或者说,中断信号已经导致了进程重新调度,内核能切换到另外一个进程。这是我们分析的另外一种情况,水开了,人去关电磁炉,然后人接着做事,这是第一种情况。水开了,人去关电磁炉,接下来门铃响了,客人来了,你必须去迎接客人,然后就打断了你之前在做的事情,也就是客人来了打断了你正在做的这件事进入到与陪客的阶段。

3、在临界区中,中断必须要被禁止。临界区其实就是加锁和去锁的实现。程序员将非常关键的步骤放进临界区,就是为了防止中断或者其它的信号去影响到它,其实在内核中这样的步骤是有必要的。临界区的代码必须在短时间内被执行,而不应该出现延时的操作,且必须尽可能的去限制这样的临界区,因为,内核在处理中断程序的时候,应该是在大部分时间以开中断的方式去运行。

在intel的文档中,中断和异常通常分为几类:中断有可屏蔽的,不可屏蔽的。异常有处理器探测异常,这就包括故障的产生,陷阱,异常的中止,还有编程异常的状况。每个中断和异常都是由0-255之间的一个数来标识。intel管这东西叫向量。

其实在ARM中就有那么一张表叫异常向量表,那就是我刚刚文章里说过的那几个。

在linux中也有这么一张表:

在linux内核中,每一个能够发出中断请求的硬件设备控制器都有一条名为IRQ的输出线。所有现在存在的IRQ线都与一个名为可编程中断控制器的硬件电路的输入引脚相连,上次讲到单片机的时候,我就讲到了单片机中断的一些概念。我们现在来看一幅图,更好说明一个问题:

下面的这幅图是51单片机的一个关于矩阵键盘的学习的一个proteus的仿真电路图。

其中P3.2和P3.3为外部中断引脚,当可编程控制器(51MCU)收到外部中断响应的时候,会执行一些特定的操作,当然这需要开发者去编写一个中断初始化程序和一个中断服务程序。

那么,可编程中断控制器会做以下的操作:

1、监视IRQ线,我们可以理解就是监视单片机外部中断的IO口,检查产生的信号。如果有条或者两条以上的IRQ上产生信号,就选择引脚编号较小的IRQ线。

2、如果一个引发信号出现在IRQ线上:

a.把接收到的引发信号转换成对应的向量。

b.把这个向量存放在中断控制器的一个I/O端口,从而允许CPU通过数据总线读这个向量。

c.把引发信号发送到处理器的INTR引脚,即会产生一个中断。

d.等待,直到CPU通过把这个中断信号写进可编程中断控制器的一个I/O端口来确认它,当这种情况发送时,清INTR线。

3、最后一步返回到第一步继续监视,然后依次执行。

当然,也存在着一些更加高级的可编程中断控制器,其中ARM算一种,Intel也是,等等。。。单片机算是最简单的一种。像多APIC系统的结构,会存在以下的一个图的关系:

中断信号通过IO引脚,然后通过中断控制器I2C总线与相应的CPU进行通信。

一般情况下,有两种分发的方式:

1、静态分发模式:IRQ信号传递给重定向表相应的项中所列出的本地APIC,然后中断立即传递一个特定的CPU,或者是一组CPU,或者是所有的CPU。其实这是广播模式的一种模型,接触过UNIX网络编程应该会知道。

2、动态分发模式:如果处理器正在执行最低优先级的进程,IRQ信号线就会传递给这种处理器的本地APIC。也就是说,在CPU内部有一个控制优先级的寄存器,用来计算当前运行进程的优先级。如果两个或者多个CPU共享最低优先级,那么就利用仲裁的技术在这些CPU之间分配负荷等等的形式。

异常有很多种,在8086处理器可以找到多达20种不同的异常,内核必须为每种异常提供一个专门的异常处理程序。对于某些异常,CPU控制单元会在开始执行异常处理程序前产生一个硬件出错码,并且压入内核态的堆栈中去。

关于这个异常处理信息,我们有必要来了解以下perror这个函数。

perror( ) 用来将上一个函数发生错误的原因输出到标准设备(stderr)。参数 s 所指的字符串会先打印出,后面再加上错误原因字符串。此错误原因依照全局变量errno(这里的说法不准确,errno是一个宏,该宏返回左值) 的值来决定要输出的字符串。在库函数中有个errno变量,每个errno值对应着以字符串表示的错误类型。当你调用"某些"函数出错时,该函数已经重新设置了errno的值。perror函数只是将你输入的一些信息和现在的errno所对应的错误一起输出。

用法:void perror(const char *s); perror ("open_port");

我们写段代码来看看就知道了:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 1#include <stdio.h>
 2#include <stdlib.h>
 3
 4int main(void)
 5{
 6    FILE *filp = NULL; 
 7    filp = fopen("txt","r"); 
 8    if(NULL == filp)
 9    {
10        perror("没有相应的文件");
11    }
12        fclose(filp);
13    return 0 ;
14}

运行结果:

在当前目录下,找不到txt这个文件,所以perror会根据相应的出错信息打印No such file or directory。

看了这个函数的应用,相信更会理解上面的异常的相关知识。当然还有更多日常写程序发现的BUG,比如段错误,段错误是最常见的,一些初学者在使用指针的时候,没有分配相应的空间,这时候给指针赋值,虽然没有语法错误,但可能会有警告。当程序运行的时候,就会自动退出并提示段错误(Segment fault),这一般是在linux上会出现这两个英语单词,在window的Devcpp上是这样,:

段错误的产生原因有很多种,程序在进行递归的时候,如果没有相应的条件退出的话,程序一旦进行死循环递归之后就会产生爆栈错误,也就是栈被挤爆了,栈这个概念其实并不陌生。我们在写C语言程序的时候,一旦写了一个子函数,那就相当于建立了一个堆栈,一般情况下函数在执行完退出后堆栈是自动分配,自动销毁的,不用程序员去手动malloc申请内存再free释放内存。因为手动分配的内存是用了堆区的内存,而自动分配是在栈区进行分配的。在32位操作系统上,栈的大小就只有12M,所以写代码的时候,一定要记得防止爆栈错误的产生,特别是递归!在main函数中多写些子函数是有好处的,要养成良好的编程习惯。

四、Linux中断应用

接下来我们结合一个真实的驱动案例来描述linux内核中驱动的中断机制,首先我们先了解一下linux内核中提供的中断接口。

这个接口我们需要包含一个头文件:#include <linux/interrupt.h>,在Linux中断编程中,最重要的是要了解以下的接口函数:

1、这个是请求中断函数

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 1int request_irq(unsigned int irq, irq_handler_t handler, 
 2        unsigned long irqflags, const char *devname, void *dev_id)
 3    irq:
 4        中断号 arch/arm/plat-s3c64xx/include/plat/irqs.h
 5    handler:
 6        中断处理函数 irqreturn_t handler(int irq, void *dev_id);
 7        irqreturn_t:
 8            See include/linux/irqreturn.h
 9
10    irqflags:
11        See line 21-59 in include/linux/interrupt.h
12        使用IRQF_SHARED共享irq时, irqflags必须相同
13        :      request_irq(IRQ_EINT(0), handler1, 
14                IRQF_TRIGGER_FALLING | IRQF_SHARED, "dev1", &dev1);
15
16            request_irq(IRQ_EINT(0), handler2, 
17                IRQF_TRIGGER_FALLING | IRQF_SHARED, "dev2", &dev2);
18
19    devname:
20        设备名, cat /proc/interrupts
21
22    dev_id:
23        发生中断时将dev_id传递给handler函数,
24            irqflags含有IRQF_SHARED时dev_id不能为NULL, 并且要保证唯一
25        dev_id一般采用当前设备的结构体指针

2、释放中断

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
1void free_irq (    unsigned int irq, void * dev_id);
2    释放匹配irq和dev_id的中断, 如果irq有多个相同的dev_id, 将释放第一个
3    So, 共享中断的dev_id不是唯一时, 可能会释放到其它设备的中断

3、开启中断

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
1void enable_irq(unsigned int irq);
2    开启irq号中断    

4、关闭中断

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
1void disable_irq(unsigned int irq);
2    关闭irq号中断

5、关闭当前CPU中断并保存在flag中去

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
1void local_irq_save(unsigned long flags);

6、恢复flag到CPU中去

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
1void local_irq_restore(unsigned long flags);
2    恢复flags到当前CPU

7、关闭当前的CPU中断

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
1void local_irq_disable(void);

8、开始当前的CPU中断

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
1void local_irq_enable(void);

接下来我们来看一个按键中断的例子,这个例子是基于Tiny4412按键驱动的源码:

使用的Linux3.5的内核,虽然版本有点老,但作为开发者来说,其实并没有什么差别。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
  1#include <linux/module.h>
  2#include <linux/kernel.h>
  3#include <linux/fs.h>
  4#include <linux/init.h>
  5#include <linux/delay.h>
  6#include <linux/poll.h>
  7#include <linux/sched.h>
  8#include <linux/irq.h>
  9#include <asm/irq.h>
 10#include <asm/io.h>
 11#include <linux/interrupt.h>
 12#include <asm/uaccess.h>
 13#include <mach/hardware.h>
 14#include <linux/platform_device.h>
 15#include <linux/cdev.h>
 16#include <linux/miscdevice.h>
 17#include <linux/gpio.h>
 18
 19#include <mach/map.h>
 20#include <mach/gpio.h>
 21#include <mach/regs-clock.h>
 22#include <mach/regs-gpio.h>
 23
 24//设备名称
 25 #define DEVICE_NAME        "buttons"
 26
 27 struct button_desc {
 28    int gpio;
 29    int number;
 30    char *name; 
 31    struct timer_list timer;
 32};
 33
 34//定义按键相关的寄存器
 35static struct button_desc buttons[] = {
 36    { EXYNOS4_GPX3(2), 0, "KEY0" },
 37    { EXYNOS4_GPX3(3), 1, "KEY1" },
 38    { EXYNOS4_GPX3(4), 2, "KEY2" },
 39    { EXYNOS4_GPX3(5), 3, "KEY3" },
 40};
 41
 42//存储按键的键值
 43 static volatile char key_values[] = {
 44    '0', '0', '0', '0', '0', '0', '0', '0'
 45};
 46
 47//创建一个等待队列头并初始化
 48 static DECLARE_WAIT_QUEUE_HEAD(button_waitq);
 49
 50 static volatile int ev_press = 0;
 51
 52//按键定时器
 53 static void tiny4412_buttons_timer(unsigned long _data)
 54{
 55    struct button_desc *bdata = (struct button_desc *)_data;
 56    int down;
 57    int number;
 58    unsigned tmp;
 59    //获取按键的值
 60    tmp = gpio_get_value(bdata->gpio);
 61    //判断是否为低电平
 62    down = !tmp;
 63    printk(KERN_DEBUG "KEY %d: %08x\n", bdata->number, down);
 64
 65    number = bdata->number;
 66    //如果此时不为低电平,中断处理进入休眠状态,一般有事件产生就会立即被唤醒
 67    if (down != (key_values[number] & 1)) {
 68        key_values[number] = '0' + down;
 69
 70        ev_press = 1;
 71        //中断休眠
 72        wake_up_interruptible(&button_waitq);
 73    }
 74}
 75//按键中断处理函数
 76//irq:中断号
 77//dev_id:设备ID号
 78 static irqreturn_t button_interrupt(int irq, void *dev_id)
 79{
 80    struct button_desc *bdata = (struct button_desc *)dev_id;
 81    //注册一个定时器
 82    mod_timer(&bdata->timer, jiffies + msecs_to_jiffies(40));
 83    //返回一个中断句柄
 84    return IRQ_HANDLED; 
 85}
 86//按键打开函数
 87//inode : 节点
 88//file : 打开文件的形式
 89 static int tiny4412_buttons_open(struct inode *inode, struct file *file)
 90{
 91    int irq;
 92    int i;
 93    int err = 0;
 94    //循环遍历四个IO口,看看有哪个按键被按下了
 95    for (i = 0; i < ARRAY_SIZE(buttons); i++) {
 96        if (!buttons[i].gpio)
 97            continue;
 98        //初始化定时器
 99        setup_timer(&buttons[i].timer, tiny4412_buttons_timer,
100                (unsigned long)&buttons[i]);
101        //设置GPIO为中断引脚,也就是对应那四个按键
102        irq = gpio_to_irq(buttons[i].gpio);
103        err = request_irq(irq, button_interrupt, IRQ_TYPE_EDGE_BOTH,  //请求中断处理函数
104                buttons[i].name, (void *)&buttons[i]);
105        if (err)
106            break;
107    }
108
109    if (err) {
110        i--;
111        for (; i >= 0; i--) {
112            if (!buttons[i].gpio)
113                continue;
114
115            irq = gpio_to_irq(buttons[i].gpio);
116            disable_irq(irq); //关中断
117            free_irq(irq, (void *)&buttons[i]);//释放中断
118
119            del_timer_sync(&buttons[i].timer);//删除一个定时器
120        }
121
122        return -EBUSY;
123    }
124
125    ev_press = 1;
126    return 0;
127}
128 //按键关闭处理函数
129 static int tiny4412_buttons_close(struct inode *inode, struct file *file)
130{
131    int irq, i;
132
133    for (i = 0; i < ARRAY_SIZE(buttons); i++) {
134        if (!buttons[i].gpio)
135            continue;
136        //同样的,这里也是释放
137        irq = gpio_to_irq(buttons[i].gpio);
138        free_irq(irq, (void *)&buttons[i]);
139 <span style="white-space:pre">        </span>//删除一个定时器
140        del_timer_sync(&buttons[i].timer);
141    }
142
143    return 0;
144 }
145 //读取按键的键值函数
146 static int tiny4412_buttons_read(struct file *filp, char __user *buff,
147        size_t count, loff_t *offp)
148{
149    unsigned long err;
150
151    if (!ev_press) {
152        if (filp->f_flags & O_NONBLOCK)
153            return -EAGAIN;
154        else    //等待中断的事件产生
155            wait_event_interruptible(button_waitq, ev_press);
156    }
157
158    ev_press = 0;
159    //将获取到的键值返回到用户空间
160    err = copy_to_user((void *)buff, (const void *)(&key_values),
161            min(sizeof(key_values), count));
162
163    return err ? -EFAULT : min(sizeof(key_values), count);
164}
165
166 //按键非阻塞型接口设计
167 static unsigned int tiny4412_buttons_poll( struct file *file,
168        struct poll_table_struct *wait)
169{
170    unsigned int mask = 0;
171 <span style="white-space:pre">    </span>//非阻塞型等待
172    poll_wait(file, &button_waitq, wait);
173    if (ev_press)
174        mask |= POLLIN | POLLRDNORM;
175
176    return mask;
177 }
178
179 //驱动文件操作结构体成员初始化
180 static struct file_operations dev_fops = {
181    .owner      = THIS_MODULE,
182    .open       = tiny4412_buttons_open,
183    .release    = tiny4412_buttons_close, 
184    .read       = tiny4412_buttons_read,
185    .poll       = tiny4412_buttons_poll,
186 };
187 //注册杂类设备的结构体成员初始化
188 static struct miscdevice misc = {
189    .minor      = MISC_DYNAMIC_MINOR,
190    .name       = DEVICE_NAME,
191    .fops       = &dev_fops, //这里就是把上面那个文件操作结构体的成员注册到杂类操作这里
192 };
193 //按键驱动初始化
194 static int __init button_dev_init(void)
195{
196    int ret;
197    //先注册一个杂类设备
198    //这相当于让misc去管理open ,read,write,close这些接口
199    ret = misc_register(&misc);
200    //
201    printk(DEVICE_NAME"\tinitialized\n");
202
203    return ret;
204}
205  //按键驱动注销
206  static void __exit button_dev_exit(void)
207{
208    //注销一个杂类设备驱动
209    misc_deregister(&misc);
210}
211
212 module_init(button_dev_init);
213 module_exit(button_dev_exit);
214
215 MODULE_LICENSE("GPL");
216 MODULE_AUTHOR("Yang.yuanxin");

运行结果:

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-04-22,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 嵌入式开发圈 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
DNS负载均衡与负载均衡器两种方案的选择[通俗易懂]
  web应用服务器集群系统,是由一群同时运行同一个web应用的服务器组成的集群系统,在外界看来,就像是一个服务器一样。为了均衡集群服务器的负载,达到优化系统性能的目的,集群服务器将众多的访问请求,分散到系统中的不同节点进行处理。从而实现了更高的有效性和稳定性,而这也正是基于Web的企业应用所必须具备的特性。   高可靠性可以看作为系统的一种冗余设定。对于一个特定的请求,如果所申请的服务器不能进行处理的话,那么其他的服务器能不能对之进行有效的处理呢?对于一个高效的系统,如果一个Web服务器失败的话,其他的服务器可以马上取代它的位置,对所申请的请求进行处理,而且这一过程对用户来说,要尽可能的透明,使用户察觉不到!   稳定性决定了应用程序能否支持不断增长的用户请求数量,它是应用程序自身的一种能力。稳定性是影响系统性能的众多因素的一种有效的测量手段,包括机群系统所能支持的同时访问系统的最大用户数目以及处理一个请求所需要的时间。   在现有众多的均衡服务器负载的方法中,广泛研究并使用的是以下两个方法:   DNS负载平衡的方法RR-DNS(Round-Robin Domain Name System)   负载均衡器
全栈程序员站长
2022/09/14
1.4K0
Load balancer 负载均衡
负载均衡器将传入的请求分发到应用服务器和数据库等计算资源。无论哪种情况,负载均衡器将从计算资源来的响应返回给恰当的客户端。负载均衡器的效用在于:
一个会写诗的程序员
2020/05/27
1.4K0
Load balancer 负载均衡
【万字长文】吃透负载均衡
更多干货内容,请关注公众号:高性能架构探索。回复【pdf】更有计算机经典资料免费获取
高性能架构探索
2021/10/27
7130
Web负载均衡器的工作过程和策略
为了平衡负载,当服务器的性能不足以应对当前的请求量时,可以使用负载均衡来将请求分配给多台服务器处理。这种机制可以提高系统的可用性、可扩展性和性能。
一凡sir
2023/08/28
3260
Web负载均衡器的工作过程和策略
系统设计:负载均衡
负载平衡开始于20世纪90年代,当时硬件设备通过网络分发流量。组织希望提高服务器上运行的应用程序的可访问性。最终,随着应用程序交付控制器(ADC)的出现,负载平衡承担了更多的责任。它们提供了安全性以及在高峰时间对应用程序的无缝访问。
小诚信驿站
2021/06/18
1.7K0
系统设计:负载均衡
选择正确的负载均衡器:LVS还是Nginx?
LVS和nginx都是负载均衡软件。LVS是Linux内核级别的负载均衡软件,nginx则是应用级的、采用事件驱动的方式进行负载均衡软件。LVS是内核级的,更加专注于负载均衡功能的实现,可以提供更高的性能和稳定性;而Nginx的功能更加多元,除了负载均衡外,还可以作为Web服务器、反向代理服务器、缓存服务器等多种用途。
Lion Long
2024/07/28
6560
选择正确的负载均衡器:LVS还是Nginx?
负载均衡技术全景:理论、实践与案例研究
在互联网的早期阶段,大型网站面临着巨大的挑战。随着用户数量的增长和数据量的爆发,单一的服务器往往难以承受如此巨大的压力。这就导致了性能瓶颈的出现,服务器的响应时间变长,用户体验下降。同时,单一服务器的可扩展性也受到了限制,随着业务的发展,流量可能会急剧增加,单个服务器很难通过增加硬件资源来满足需求。更为严重的是,所有请求都发送到同一台服务器,一旦该服务器出现故障,整个服务就会中断。
栗筝i
2023/10/16
1.4K0
负载均衡技术全景:理论、实践与案例研究
如何利用负载均衡器实现终极自由
开源软件的流行程度与云计算的使用增长同步飙升,包括多云和混合云基础设施。Pluralsight 的 2023 年云状况报告显示,65% 的组织 积极使用多云环境。
云云众生s
2024/06/27
1940
如何利用负载均衡器实现终极自由
[享学Netflix] 三十七、源生Ribbon介绍 --- 客户端负载均衡器
代码下载地址:https://github.com/f641385712/netflix-learning
YourBatman
2020/03/18
2.5K0
一文了解负载均衡器、反向代理、API 网关区别
您是否理解负载均衡器、反向代理和 API 网关等多样组件之间的差异?不确定哪个组件最适合您的 Web 应用程序?这些关键组件在现代 Web 架构中发挥着至关重要的作用,了解它们的工作原理对于构建高效、安全和可扩展的 Web 应用程序至关重要。在本文中,我们将揭开这些概念的神秘面纱,并希望帮助您为下一个项目架构实现做出明智的决策。
用户1107783
2023/09/27
7130
一文了解负载均衡器、反向代理、API 网关区别
为什么对gRPC做负载均衡会很棘手?
在过去的几年中,随着微服务的增长,gRPC在这些较小的服务之间的相互通信中获得了很大的普及,在后台,gRPC使用http/2在同一连接和双工流中复用许多请求。
全球技术精选
2021/03/03
2.6K0
为什么对gRPC做负载均衡会很棘手?
Ribbon的负载均衡策略及原理[通俗易懂]
Load Balance负载均衡是用于解决一台机器(一个进程)无法解决所有请求而产生的一种算法。像nginx可以使用负载均衡分配流量,ribbon为客户端提供负载均衡,dubbo服务调用里的负载均衡等等,很多地方都使用到了负载均衡。
全栈程序员站长
2022/11/08
1.8K0
Ribbon的负载均衡策略及原理[通俗易懂]
SSL 是否应当在负载均衡器上卸载?
StackExchange 网站的一名用户 Matt Goforth 对于 SSL 在负载均衡设备上的处理提出了他的疑惑:
星哥玩云
2022/07/19
9570
​dubbo 负载均衡
负载均衡是一种计算机的技术,用来在多个计算机集群、网络连接、CPU、磁碟驱动器或其他资源中分配负载,以达到最佳化资源使用、最大化吞吐率、最小化响应时间、同时避免过载的目的。 使用带有负载平衡的多个伺服器组件,取代单一的组件,可以通过冗余提高可靠性。负载平衡服务通常是由专用软件和硬件来完成。 主要作用是将大量作业合理地分摊到多个操作单元上进行执行,用于解决互联网架构中的高并发和高可用的问题。
mySoul
2020/06/16
6390
微服务负载均衡 —— ribbon
    负载均衡是系统高可用、缓解网络流量和处理能力扩容的重要手段,广义的负载均衡指的是服务端负载均衡,如硬件负载均衡(F5)和软件负载均衡(Nginx)。负载均衡设备会维护一份可用的服务器的信息,当客户端请求到达负载均衡设备之后,设备会根据一定的负载均衡算法从可用的服务器列表中取出一台可用的服务器,然后将请求转发到该服务器。对应的负载均衡架构如下图所示:
Mister24
2019/03/04
6650
负载均衡以及Nginx如何实现负载均衡
负载均衡是指在一组后端服务器(也称为服务器群或服务器池)之间有效地分配传入网络流量。 现代高流量网站必须以快速可靠的方式处理来自用户或客户端的数十万并发请求,并返回正确的文本、图像、视频或应用程序数据。为了经济高效地扩展以满足这些高容量,现代计算最佳实践通常需要添加更多服务器。 负载均衡器充当“流量交警”,位于你的服务器前,并在所有服务器之间路由客户端请求,这些服务器能够以最大限度地提高速度和容量利用率的方式满足这些请求,并确保没有任何服务器过度工作,这可能会降低性能.如果单个服务器出现故障,负载均衡器会将流量重定向到其余的在线服务器。将新服务器添加到服务器组时,负载均衡器会自动开始向其发送请求。 负载均衡建立在现有网络结构之上,它提供了一种廉价有效透明的方法扩展网络设备和服务器的带宽、增加吞吐量、加强网络数据处理能力、提高网络的灵活性和可用性。
SakuraTears
2022/01/13
4.2K0
Jtti:如何理解网络负载均衡?
网络负载均衡(Network Load Balancing,NLB)是一种用于分布式计算或网络服务的技术,旨在均衡服务器集群之间的负载,以提高性能、可用性和可伸缩性。网络负载均衡将网络流量分发到多个服务器,以确保每个服务器都能有效地处理请求,而不会过载或不平衡。以下是网络负载均衡的主要特点和原理:
jtti
2023/10/30
1870
[Linux] LVS虚拟服务器四层负载均衡
随着互联网的爆炸性增长及其在我们生活中日益重要的作用,互联网上的流量急剧增加,并且每年以超过100%的速度增长。服务器上的工作负载正在迅速增加,因此服务器很容易在短时间内过载,尤其是对于流行的网站。为了克服服务器的过载问题,有两种解决方案。一种是单服务器解决方案,即将服务器升级到性能更高的服务器,但是当请求增加时很快就会超载,因此我们必须再次升级,升级过程复杂且成本高。另一种是多服务器解决方案,即在服务器集群上构建可扩展的网络服务系统。当负载增加时,我们可以简单地将新服务器或更多服务器添加到集群中以满足不断增长的请求,而商用服务器具有最高的性能/成本比。因此,为网络服务构建服务器集群系统更具可扩展性和成本效益。
唯一Chat
2019/09/10
1.2K0
流量引导:网络世界的负载均衡解密
大型的多站点互联网系统,包括内容分发网络(CDN)和云服务提供商,用一些方法来均衡来访的流量。这篇文章我们讲一下常见的流量均衡设计,包括它们的技术手段和利弊权衡。
用户1880875
2021/09/23
6990
客户端服务负载均衡
在正式开始讨论之前,我们先来区分清楚几个容易混淆的概念,分别是前面两讲中我介绍过的服务发现、网关路由,以及这节课要探讨的负载均衡,还有在下一讲中将会介绍的调用容错。这几个技术名词都带有“从服务集群中寻找到一个合适的服务来调用”的含义,那么它们之间的差别都体现在哪呢?下面我就通过一个具体的案例场景来给你说明一下。
燃192
2023/04/11
1.2K0
客户端服务负载均衡
推荐阅读
相关推荐
DNS负载均衡与负载均衡器两种方案的选择[通俗易懂]
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验