linux内核一文读懂IPI核间中断(arm64架构)

1、IPI概况

IPI,全称是Inter-Processor Interrupt,是在soc内多个core之间触发的中断,这一点有别与常见的外设中断,因此内核专门预留了部分中断号给IPI,在arm64架构上是0-15这16个中断号。以常用的gicv3中断控制器驱动为例,IPI中断的处理在如下代码中:

<drivers/irqchip/irq-gic-v3.c>618 static asmlinkage void __exception_irq_entry gic_handle_irq(struct pt_regs *regs)                   619 {620         u32 irqnr;                                                                                  621                                                                                                     622         irqnr = gic_read_iar();  /* 通过读gic中断控制器的iar寄存器获得当前pending的中断号 */           623             ....../* 此处省略对中断号[16,1020)的处理流程 */655         if (irqnr < 16) {                                                                           656                 gic_write_eoir(irqnr);       /* 做eoi(end of interrupt)清中断 */657                 if (static_branch_likely(&supports_deactivate_key))                                 658                         gic_write_dir(irqnr);                                                       659 #ifdef CONFIG_SMP              /*如果配置了对称多处理器。才会有核间中断需要处理*/                        660                 /*                                                                                  661                  * Unlike GICv2, we don't need an smp_rmb() here.                                   662                  * The control dependency from gic_read_iar to                                      663                  * the ISB in gic_write_eoir is enough to ensure                                    664                  * that any shared data read by handle_IPI will                                     665                  * be read after the ACK.                                                           666                  */                                                                                 667                 handle_IPI(irqnr, regs);   /* IPI中断处理 */                                    668 #else                                                                                               669                 WARN_ONCE(true, "Unexpected SGI received!\n");   /* 如果未定义SMP,报错 */        670 #endif                                                                                              671         }                                                                                           672 }    

handle_IPI是处理IPI中断的核心

<arch/arm64/kernel/smp.c>873 /*                                                                                                  874  * Main handler for inter-processor interrupts                                                      875  */                                                                                                 876 void handle_IPI(int ipinr, struct pt_regs *regs)                                                    877 {                                                                                                   878         unsigned int cpu = smp_processor_id(); /*获得当前运行改代码的cpu id*/ 879         struct pt_regs *old_regs = set_irq_regs(regs); /*pt_regs结构体主要包含当前的寄存器信息,x0到x31,sp,pc,pstate等,这里是把当前cpu的pt_regs保存到old_regs中,将参数中的regs设置到本cpu中,old_regs用来做中断处理完对中断前现场的恢复 */                                   880                                                                                                     881         if ((unsigned)ipinr < NR_IPI) {  /*当前有效的IPI中断为7(NR_IPI)个*/ 882                 trace_ipi_entry_rcuidle(ipi_types[ipinr]); /* ftrace记录进入ipi中断,用于debug */883                 __inc_irq_stat(cpu, ipi_irqs[ipinr]); /* 统计各cpu不同类型的ipi中断数量,cat /proc/interrupts中IPI相关中断的数据即来自于此 */       884         }                                                                                           885                                                                                                     886         switch (ipinr) {                                                                            887         case IPI_RESCHEDULE:                                                                        888                 scheduler_ipi();  /* 如果IPI类型是触发重调度,那就进该逻辑,详细描述见第2小结 */889                 break;                                                                              890                                                                                                     891         case IPI_CALL_FUNC:                                                                         892                 irq_enter();  /*将preempt_count中HARDIRQ的部分+1,可以禁止调度或抢占的发生,直到执行到irq_exit,以下同不再赘述 */                                                                      893                 generic_smp_call_function_interrupt();/* 执行本cpu所有function回调(别的cpu给安排的),详细描述见第3小结 */   894                 irq_exit();                                                                         895                 break;                                                                              896                                                                                                     897         case IPI_CPU_STOP:                                                                          898                 irq_enter();                                                                        899                 local_cpu_stop();  /* 将本cpu停下来,进入低功耗状态,详细描述见第4小结 */                900                 irq_exit();                                                                         901                 break;                                                                              902                                                                                                     903         case IPI_CPU_CRASH_STOP:                                                                    904                 if (IS_ENABLED(CONFIG_KEXEC_CORE)) { /* 如果配置了KEXEC,即在系统panic时会进入第二内核,才会有本IPI中断的操作,详细描述见第5小结 */                                            905                         irq_enter();                                                                906                         ipi_cpu_crash_stop(cpu, regs);                                              907                                                                                                     908                         unreachable();         909                 }                                                                                   910                 break;                                                                              911                                                                                                     912 #ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST                                                         913         case IPI_TIMER:                                                                             914                 irq_enter();                                                                        915                 tick_receive_broadcast();  /* 接收timer广播,执行timer的中断回调,详细描述见第6小结 */    916                 irq_exit();                                                                         917                 break;                                                                              918 #endif                                                                                              919                                                                                                     920 #ifdef CONFIG_IRQ_WORK                                                                              921         case IPI_IRQ_WORK:                                                                          922                 irq_enter();                                                                        923                 irq_work_run(); /* 本cpu执行irq_work,详细描述见第7小结 */                        924                 irq_exit();                                                                         925                 break;                                                                              926 #endif                                                                                              927                                                                                                     928 #ifdef CONFIG_ARM64_ACPI_PARKING_PROTOCOL                                                           929         case IPI_WAKEUP:        /* 从parked状态中唤醒本cpu,详细描述见第8小结 */930                 WARN_ONCE(!acpi_parking_protocol_valid(cpu),                                        931                           "CPU%u: Wake-up IPI outside the ACPI parking protocol\n",                 932                           cpu);                                                                     933                 break;                                                                              934 #endif                                                                                              935                                                                                                     936         default:                                                                                    937                 pr_crit("CPU%u: Unknown IPI message 0x%x\n", cpu, ipinr);                           938                 break;                                                                              939         }                                                                                           940                                                                                                     941         if ((unsigned)ipinr < NR_IPI)                                                               942                 trace_ipi_exit_rcuidle(ipi_types[ipinr]);                                           943         set_irq_regs(old_regs);                                                                     944 }

2、IPI_RESCHEDULE

一般的使用场景(可参考文末推进阅读[2]中对resched_curr的描述)是先为进程设置TIF_NEED_RESCHED 标志(意味着需要调度该进程),如果发现该进程没有在当前CPU上,那就通过smp_send_reschedule接口触发IPI_RESCHEDULE中断给相应CPU,相应CPU最终进入hadle_IPI的scheduler_ipi中

<kernel/sched/core.c>
2312 void scheduler_ipi(void)                                                                            
2313 {                                                                                                   
2314         /*                                                                                          
2315          * Fold TIF_NEED_RESCHED into the preempt_count; anybody setting                            
2316          * TIF_NEED_RESCHED remotely (for the first time) will also send                            
2317          * this IPI.                                                                                
2318          */                                                                                         
2319         preempt_fold_need_resched(); /* 更新thread_info结构体中need_resched变量的值,暂不清楚这个操作的目的*/ 
2320                                                                                                     
2321         if (llist_empty(&this_rq()->wake_list) && !got_nohz_idle_kick()) /*如果runqueue的wack_list是空的,那就什么都不做 (nohz这个判断不清楚是什么意思)*/                           
2322                 return;                                                                             
2323                                                                                                     
2324         /*                                                                                          
2325          * Not all reschedule IPI handlers call irq_enter/irq_exit, since                           
2326          * traditionally all their work was done from the interrupt return                          
2327          * path. Now that we actually do some work, we need to make sure                            
2328          * we do call them.                                                                         
2329          *                                                                                          
2330          * Some archs already do call them, luckily irq_enter/exit nest                             
2331          * properly.                                                                                
2332          *                                                                                          
2333          * Arguably we should visit all archs and update all handlers,                              
2334          * however a fair share of IPIs are still resched only so this would                        
2335          * somewhat pessimize the simple resched case.                                              
2336          */                                                                                         
2337         irq_enter();  /*将preempt_count中HARDIRQ的部分+1,可以禁止调度或抢占的发生,直到执行到irq_exit*/
2338         sched_ttwu_pending(); /* 尝试唤醒pending着的线程*/                                  
2339                                                                                                     
2340         /*                                                                                          
2341          * Check if someone kicked us for doing the nohz idle load balance.                         
2342          */              
2343         if (unlikely(got_nohz_idle_kick())) {                                                       
2344                 this_rq()->idle_balance = 1;                                                        
2345                 raise_softirq_irqoff(SCHED_SOFTIRQ); /* 触发软中断做负载均衡,这里细节暂不清楚 */
2346         }                                                                                           
2347         irq_exit();                                                                                 
2348 } 

3、IPI_CALL_FUNC

当希望在某个cpu上调用一个函数(func)时,可能会触发IPI_CALL_FUNC中断(“可能”是因为如果希望执行func的cpu与本cpu相同,那就不用费劲发中断了,直接执行),常用smp_call_function接口触发target cpu的IPI_CALL_FUNC软中断(会在之后的文章中详细讲这个过程),target cpu会经历以下调用handle_IPI->generic_smp_call_function_interrupt-->generic_smp_call_function_single_interrupt-->flush_smp_call_function_queue调用一遍所有pending状态中的function回调。

<kernel/smp.c>
210 static void flush_smp_call_function_queue(bool warn_cpu_offline)                                    
211 {                                                                                                   
212         struct llist_head *head;                                                                    
213         struct llist_node *entry;                                                                   
214         call_single_data_t *csd, *csd_next;                                                         
215         static bool warned;                                                                         
216                                                                                                     
217         lockdep_assert_irqs_disabled();                                                             
218                                                                                                     
219         head = this_cpu_ptr(&call_single_queue); /*拿到本cpu的call_single_queue全局链表,当其他cpu想让本cpu执行某个func时,会通过generic_exec_single()接口往对应cpu的call_signal_queue中添加相应的call_single_data_t结构,这其中包含着需要执行的func回调*/                                                   
220         entry = llist_del_all(head);                                                                
221         entry = llist_reverse_order(entry);                                                         
222                                                                                                     
223         /* There shouldn't be any pending callbacks on an offline CPU. */                           
224         if (unlikely(warn_cpu_offline && !cpu_online(smp_processor_id()) &&                         
225                      !warned && !llist_empty(head))) { /* 如果发现本cpu不是在online的状态,就报错(不过我不理解为什么一个offline的cpu能响应这个CALL_FUNC的IPI中断呢?) */
226                 warned = true;                                                                      
227                 WARN(1, "IPI on offline CPU %d\n", smp_processor_id());                             
228                                                                                                     
229                 /*                                                                                  
230                  * We don't have to use the _safe() variant here                                    
231                  * because we are not invoking the IPI handlers yet.                                
232                  */                                                                                 
233                 llist_for_each_entry(csd, entry, llist)                                             
234                         pr_warn("IPI callback %pS sent to offline CPU\n",                           
235                                 csd->func);                                                         
236         }                                                                                           
237                                                                                                     
238         llist_for_each_entry_safe(csd, csd_next, entry, llist) { /* 循环遍历call_single_queue链表,把每个成员的func执行一遍 */                                   
239                 smp_call_func_t func = csd->func;                                                   
240                 void *info = csd->info;                                                             
241         
242                 /* Do we wait until *after* callback? */                                            
243                 if (csd->flags & CSD_FLAG_SYNCHRONOUS) {/* 根据func回调设置的属性,是否是同步接口,决定执行顺序 */                                            
244                         func(info);    /* 如果是同步的,就先执行func回调,再放相应csd句柄的锁 */               
245                         csd_unlock(csd);                                                            
246                 } else {                                                                            
247                         csd_unlock(csd);    /* 如果是异步的,先放相应csd句柄的锁,再执行func回调 */  
248                         func(info);                                                                 
249                 }                                                                                   
250         }                                                                                           
251                                                                                                     
252         /*                                                                                          
253          * Handle irq works queued remotely by irq_work_queue_on().                                 
254          * Smp functions above are typically synchronous so they                                    
255          * better run first since some other CPUs may be busy waiting                               
256          * for them.                                                                                
257          */                                                                                         
258         irq_work_run();  /*执行irq works(暂不清楚这里的背景,会在之后的文章讨论这个话题)*/                   
259 }                                                                                                   
260      

4、IPI_CPU_STOP

当某个cpu想让其他cpu停下来时,会发送该IPI中断,主要的接口是machine_haltmachine_power_offmachine_restart,这些接口都会调用smp_send_stop触发IPI_CPU_STOP中断,target cpu接收到该中断后,做如下处理:

<arch/arm64/kernel/smp.c>830 static void local_cpu_stop(void)                                                      831 {                                                                                                   832         set_cpu_online(smp_processor_id(), false);/*把当前cpu offline*/833                                                                                                     834         local_daif_mask();/* 设置pstate的D A I F状态位为1,关闭本cpu的系统调试(D),系统错误SError interrupt(A),中断IRQ interrupt(I), 快速中断FIQ interrupt(F)*/835         sdei_mask_local_cpu(); /* 不清楚这里在做什么 */ 836         cpu_park_loop(); /* 通过wfe和wfi指令,让当前cpu进入low-power standby模式 */                   837 }

5、IPI_CPU_CRASH_STOP

在系统crash时,发生crash的cpu给其他cpu发送该中断,在使能了KEXEC的系统中,做出以下响应,主要是将寄存器信息保存下来,传递给第二内核。KEXEC常用来做系统crash时在不重启的情况下快速进入第二内核。第二内核的目的是把当前的ddr内存镜像保存下来,方便之后通过crash tool分析系统crash问题,感兴趣可以参考该文章了解。

<arch/arm64/kernel/smp.c>853 static void ipi_cpu_crash_stop(unsigned int cpu, struct pt_regs *regs)                           854 {                                                                                                   855 #ifdef CONFIG_KEXEC_CORE                                                                            856         crash_save_cpu(regs, cpu); /* 保存当前cpu寄存器信息,方便定位问题*/857                                                                                                     858         atomic_dec(&waiting_for_crash_ipi);                                                         859                                                                                                     860         local_irq_disable();                                                                        861         sdei_mask_local_cpu();                                                                      862                                                                                                     863 #ifdef CONFIG_HOTPLUG_CPU                                                                           864         if (cpu_ops[cpu]->cpu_die)                                                                  865                 cpu_ops[cpu]->cpu_die(cpu);                                                         866 #endif                                                                                              867                                                                                                     868         /* just in case */                                                                          869         cpu_park_loop();     /* 本cpu进入低功耗,但一般不需要,crash的cpu会拉着整个系统重启 */                         870 #endif                                                                                              871 }  

6、IPI_TIMER

当某cpu调用tick_broadcast(const struct cpumask *mask)时,即调用IPI_TIMER中断给相应cpu(通过mask指定cpu)发送timer的广播中断,target cpu执行以下函数进行响应

<kernel/time/tick-broadcast.c>244 #ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST                                                         245 int tick_receive_broadcast(void)                                              246 {                                                                                                   247         struct tick_device *td = this_cpu_ptr(&tick_cpu_device);                                    248         struct clock_event_device *evt = td->evtdev; /*拿出本cpu的tick_device的clock_event_device,这在某个cpu上是唯一的 */                                               249                                                                                                     250         if (!evt)                                                                                   251                 return -ENODEV;                                                                     252                                                                                                     253         if (!evt->event_handler)                                                                    254                 return -EINVAL;                                                                     255                                                                                                     256         evt->event_handler(evt);  /* 执行tick clock的回调函数 */                                                                  257         return 0;                                                                                   258 }                                                                                                   259 #endif

7、IPI_IRQ_WORK

暂不清楚irq_work的应用场景,当收到该IPI中断时,处理如下:

<kernel/irq_work.c>
178 void irq_work_run(void)                                                                             
179 {                                                     /*将本cpuraised_list和lazy_list链表上挂载的irq_work执行一遍*/
180         irq_work_run_list(this_cpu_ptr(&raised_list));                                              
181         irq_work_run_list(this_cpu_ptr(&lazy_list));                                                
182 }                                                                                                   
183 EXPORT_SYMBOL_GPL(irq_work_run);  142 static void irq_work_run_list(struct llist_head *list)                                              
143 {                                                                                                   
144         struct irq_work *work, *tmp;                                                                
145         struct llist_node *llnode;                                                                  
146         unsigned long flags;                                                                        
147                                                                                                     
148         BUG_ON(!irqs_disabled());                                                                   
149                                                                                                     
150         if (llist_empty(list))                                                                      
151                 return;                                                                             
152                                                                                                     
153         llnode = llist_del_all(list);                                                               
154         llist_for_each_entry_safe(work, tmp, llnode, llnode) {                                      
155                 /*                                                                                  
156                  * Clear the PENDING bit, after this point the @work                                
157                  * can be re-used.                                                                  
158                  * Make it immediately visible so that other CPUs trying                            
159                  * to claim that work don't rely on us to handle their data                         
160                  * while we are in the middle of the func.                                          
161                  */                                                                                 
162                 flags = work->flags & ~IRQ_WORK_PENDING;                                            
163                 xchg(&work->flags, flags);                                                          
164                                                                                                     
165                 work->func(work);   /*遍历链表中所有的work,将其回调全执行一遍 */  
166                 /*                                                                                  
167                  * Clear the BUSY bit and return to the free state if                               
168                  * no-one else claimed it meanwhile.                                                
169                  */                                                                                 
170                 (void)cmpxchg(&work->flags, flags, flags & ~IRQ_WORK_BUSY);                         
171         }                                                                                           
172 }                                                                                                   
173     

8、IPI_WAKEUP

当cpu接收到该IPI中断,即从parked的状态(应该是wfi和wfe的低功耗状态)唤醒过来,更多信息参见patch comment(arm64: kernel: implement ACPI parking protocol

<arch/arm64/kernel/acpi_parking_protocol.c>39 bool acpi_parking_protocol_valid(int cpu)                                                           40 {                                                                                                   41         struct cpu_mailbox_entry *cpu_entry = &cpu_mailbox_entries[cpu];                            42                                                                                                     43         return cpu_entry->mailbox_addr && cpu_entry->version;     /* 不明白这样做是怎么唤醒的cpu */          44 }  

在 Linux 内核中,IPI(Inter-Processor Interrupt,处理器间中断)用于让一个 CPU 向另一个 CPU 发送中断请求,以便执行特定任务。不同类型的 IPI 适用于不同的场景,以下是它们的区别和适用场景:


1. IPI_CALL_FUNC

作用

  • 让目标 CPU 执行一个回调函数,通常用于跨 CPU 调用。
  • 典型的函数是 smp_call_function*() 系列(如 smp_call_function_single())。

适用场景

  • 让另一个 CPU 执行特定代码,例如刷新 TLB、更新某些共享数据。
  • 主要用于 SMP(对称多处理)系统中的 核间通信

调用路径

smp_call_function_single() → generic_exec_single() → arch_send_call_function_ipi()

示例

当某个 CPU 需要让其他 CPU 刷新 TLB 时,可能会调用:

smp_call_function(flush_tlb_func, NULL, 1);

2. IPI_RESCHEDULE

作用

  • 用于触发目标 CPU 立即进行调度(即 schedule()),一般是 有更高优先级任务需要运行 时触发。
  • 不携带额外数据,只告诉目标 CPU 需要重新调度。

适用场景

  • 负载均衡(sched_balance
  • 任务迁移(wake_up_process()
  • CPU 负载变化时让空闲 CPU 重新调度

调用路径

reschedule_ipi_handler() → scheduler_tick() → schedule()

示例

  • 当有新任务需要调度到目标 CPU 时,触发 IPI_RESCHEDULE
resched_cpu(cpu);

3. IPI_CPU_STOP

作用

  • 让目标 CPU 立即停止执行,常用于 CPU 离线(hotplug)或系统崩溃 时。

适用场景

  • CPU hotplug(动态启停 CPU)
  • 系统关机或重启
  • 紧急情况下关闭 CPU(如崩溃恢复)

调用路径

stop_machine() → stop_cpu()

示例

  • 当一个 CPU 需要下线(offlining)时,其他 CPU 需要发送 IPI_CPU_STOP
cpu_down(1);

4. IPI_WAKEUP

作用

  • 唤醒目标 CPU(如果它处于休眠状态)。

适用场景

  • 处理器从 idle 状态被唤醒(wakeup_secondary_cpu()
  • SMP 系统中的电源管理

调用路径

wakeup_secondary_cpu() → send_wakeup_ipi()

示例

  • 当 CPU 进入深度睡眠,需要用 IPI_WAKEUP 唤醒
arch_send_wakeup_ipi_mask(cpumask);

5. IPI_IRQ_WORK

作用

  • 让目标 CPU 执行 deferred IRQ work(延迟的中断工作),常用于软中断或异步任务。

适用场景

  • 异步中断处理(如 irq_work_run()
  • 时钟同步、RCU 任务、日志处理等

调用路径

irq_work_queue_on() → arch_send_call_function_single_ipi()

示例

  • 在一个 CPU 上触发 IRQ_WORK
irq_work_queue(&work);

6. IPI_TIMER

作用

  • 用于目标 CPU 处理定时器事件,主要在 NO_HZ 模式下使用。

适用场景

  • NO_HZ 模式下的 tickless 计时
  • 全局时钟同步
  • 调度器 tick 处理

调用路径

tick_receive_broadcast() → clockevents_handle_nohz_tick()

示例

  • 在 NO_HZ 模式下,某 CPU 可能需要被 IPI_TIMER 唤醒来更新时间
clockevents_handle_nohz_tick();

7. IPI_CPU_CRASH_STOP

作用

  • 用于紧急情况(如内核崩溃)时,通知所有 CPU 立即停止执行,通常在 panic() 期间使用。

适用场景

  • Kernel panic 处理
  • 系统紧急关机
  • 避免崩溃后其他 CPU 继续执行

调用路径

smp_send_stop() → native_send_ipi_all()

示例

  • 当系统 panic 时,停止所有 CPU
smp_send_stop();

总结

IPI 类型 作用 适用场景
IPI_CALL_FUNC 让目标 CPU 执行回调函数 TLB 刷新、SMP 通信、跨 CPU 调用
IPI_RESCHEDULE 让目标 CPU 立即重新调度 负载均衡、任务迁移、高优先级任务
IPI_CPU_STOP 让目标 CPU 立即停止 CPU hotplug、系统关机
IPI_WAKEUP 唤醒目标 CPU(如果处于休眠状态) 处理器电源管理、CPU 休眠唤醒
IPI_IRQ_WORK 让目标 CPU 处理延迟的 IRQ 任务 软中断、RCU 任务
IPI_TIMER 让目标 CPU 处理定时器事件 NO_HZ 模式、tickless 计时
IPI_CPU_CRASH_STOP 紧急停止所有 CPU,通常用于 panic Kernel panic 处理

每种 IPI 都有特定的用途,最常见的是 IPI_RESCHEDULE(调度 IPI)和 IPI_CALL_FUNC(跨 CPU 调用)。如果你在 simpleperfftrace 看到过多的某种 IPI,可以根据上面的表格判断可能的原因。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/909719.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

一个测试工程师的实战笔记:我是如何在Postman和Apipost之间做出选择的?

作为一家金融科技公司的测试负责人,我每天要处理数十个需要加密验签的接口。从最开始的Postman,到后来的Apipost,让我重新思考:我们需要的究竟是一个代码编辑器,还是一个真正懂测试者的智能工具? 一、当加密需求被Postman的脚本支配 1、密码字段MD5加密 去年接手支付系统…

【ABP】项目示例(7)——数据播种

数据种子 在上一章节中,已经对仓储层和应用层进行了单元测试,在这一章节中,进行数据播种 大多数程序正常运行都需要依赖于初始数据,依赖于数据库的程序基本都是如此 例如需要有一个初始的管理员用户或者一个管理员角色,用来进行登录系统,像这种主要用于生产环境中的数据播…

kettle从入门到精通 第九十四课 ETL之kettle MySQL Bulk Loader大批量高性能数据写入

1、在使用kettle时如果对表输出性能要求,可以考虑用mysql 批量加载步骤,该步骤可以实现每秒5万+的数据同步(该数据仅是基于我本人的笔记本,若是服务器则效率更高),如下图所示: 2、原理 知其然知其所以然,之所以MySQL Bulk Loader速度如此之快是因为MySQL 批量加载器使用…

Web开发SpringBoot流程性的学习----回顾补充2(YApi)

Vue简述 Vue 是一套前端框架,免除原生JavaScript中的DOM操作,简化书写。 基于MVVM(Model-View-ViewModel)思想,实现数据的双向绑定,将编程的关注点放在数据上。 Vue2官网:https://v2.cn.vuejs.org/生命周期(Vue3已不同)AJAX 概念: Asynchronous JavaScript And XML,异步的…

4.1日报

今天完善了那个多条件查询 虽然没有做成知网那么高级的 但是查询功能已经很完善// 1. 政策标题精确查询(可根据需求改为like模糊查询)if (StringUtils.hasText(policyTitle)) {queryWrapper.like(Policy::getName, policyTitle);}// 2. 政策内容全文检索if (StringUtils.hasT…

MCP (Model Context Protocol)初体验:企业数据与大模型融合初探

简介 模型上下文协议(Model Context Protocol,简称MCP)是一种创新的开放标准协议,旨在解决大语言模型(LLM)与外部数据和工具之间的连接问题。它为AI应用提供了一种统一、标准化的方式来访问和处理实时数据,使模型不再局限于训练时获得的静态知识。 MCP由Anthropic首次提…

Redis高级篇-多级缓存

Redis高级篇-多级缓存Redis高级篇-多级缓存 1.什么是多级缓存 传统的缓存策略一般是请求到达Tomcat后,先查询Redis,如果未命中则查询数据库,如图:存在下面的问题: •请求要经过Tomcat处理,Tomcat的性能成为整个系统的瓶颈 •Redis缓存失效时,会对数据库产生冲击 多级缓存…

Redis安装说明

Redis安装说明Redis安装说明 大多数企业都是基于Linux服务器来部署项目,而且Redis官方也没有提供Windows版本的安装包。因此课程中我们会基于Linux系统来安装Redis. 此处选择的Linux版本为CentOS 7. Redis的官方网站地址:https://redis.io/ 1.单机安装Redis 1.1.安装Redis依赖…

Redis入门篇

Redis入门篇基础篇Redis 开篇导读 理想课程 小伙伴们理想的课程一定是能够通过讲解的方式,得到如下这些启发,我们的课程会从基础到精通,从redis小白,到redis大牛,还在等什么,这套课程一定就是你最适合你的课程~1.Redis简单介绍 Redis是一种键值型的NoSql数据库,这里有两…

安装Canal

安装Canal安装和配置Canal 下面我们就开启mysql的主从同步机制,让Canal来模拟salve 1.开启MySQL主从 Canal是基于MySQL的主从同步功能,因此必须先开启MySQL的主从功能才可以。 这里以之前用Docker运行的mysql为例: 1.1.开启binlog 打开mysql容器挂载的日志文件,我的在/tmp/…

团队项目

项目 内容这个作业属于哪个课程 软件工程这个作业要求在哪里 作业要求这个作业的目标 学习团队项目协作开发过程🚀团队展示 一、团队组成 队名:404 Not Found 成员组成:姓名 学号周戈 3123004164张荣辉 3123004162杨超民 3123004161饶博勋 3123004152李永胜 3123004148陈曦…