07-Redis 事件

Redis 事件

一、文件事件

  • Redis是一个事件驱动程序,Redis中包含文件时间和时间时间,本文主要针对文件事件。Redis通过套接字与客户端或者其他Redis进行连接,文件事件就是对套接字操作的抽象,所有的通信都会产生相应的文件事件,服务器通过监听文件事件并处理事件来完成对应的网络通信操作;

1.1 文件事件处理器

  • Redis基于Reactor模型开发了自己的网络事件处理器,这个处理器也称为文件事件处理器;
1.1.1 构成
  • 文件事件由四部分构成:套接字、IO多路复用程序、文件事件分派器和事件处理器;
  • 套接字:一个套接字可以理解为一个客户端连接,每一个套接字的动作比如:连接、应答、写入、读取和关闭都会产生对应的事件;
  • IO多路复用程序:IO多路复用程序管理多个套接字,因此可能并发的产生事件,IO多路复用程序将产生事件的套接字放到一个有序的同步队列中;
  • 文件事件分派器:分派器从队列取出套接字,将套接字事件交给对应的事件处理器处理, 处理完毕之后IO多路复用模块才会传入下一个套接字到同步队列;
  • 事件处理器:处理对应的事件,代码上一个事件处理器对应一个函数;

在这里插入图片描述

1.1.2 IO多路复用的实现
  • IO多路复用程序在底层上是基于系统函数select、epoll、evport和kqueue来实现的,因为每一种系统函数都可以实现IO多路复用,因此Redis对于每一个系统函数在一个单独的文件中实现,因此底层可以很方便的切换,这也带来了很好的兼容性,程序在编译期间会自动选择系统中性能最好的IO多路复用函数来作为底层实现。

在这里插入图片描述

  • 下面是参考文档中的一张图片,画的很好,体现了Redis在不同平台的底层IO复用函数的选择

image

1.2 事件类型

  • 读事件(AE_READABLE):客户端写、关闭、连接都会对Redis产生读事件;
  • 写事件(AE_WRITABLE):客户端读时,对Redis产生写事件;
PS:Redis事件处理器可以处理读写事件,若同时产生,则优先处理读事件
  • 一个事件循环过程

在这里插入图片描述

二、时间事件

2.1 时间事件类型

  • Redis中时间事件分为2种,一种是定时事件,只会在给定时间执行一次;
  • 另一种是周期性事件,程序会周期性的执行

2.2 时间事件数据结构

  • Redis中时间事件对应的数据结构包括三个字段:id(递增且唯一)、when(表示执行的时间)、timeProc(时间事件处理器)
Redis根据时间事件处理器的返回值判断是周期时间还是定时事件,然后更新when的值,以此种方
式来支持两种时间事件类型

2.3 实现

  • Redis由时间事件执行器来执行时间事件,所有的时间事件以无序链表形式保存,因此需要遍历整个链表来执行所有的时间事件。不过这个并不会影响性能,因为Redis中的时间事件是很少的,就只有一两个。

2.3 时间事件serverCorn

  • serverCorn默认周期性的每100ms执行一次,2.8以后执行配置。

三、参考

2025-09-19 13:11:07.204 [lettuce-nioEventLoop-4-1] DEBUG io.lettuce.core.protocol.CommandHandler - [channel=0x69b8c689, /127.0.0.1:22669 -> localhost/127.0.0.1:6379, epid=0x1, chid=0x1] write(ctx, AsyncCommand [type=DEL, output=IntegerOutput [output=null, error='null'], commandType=io.lettuce.core.protocol.Command], promise) 2025-09-19 13:11:07.205 [lettuce-nioEventLoop-4-1] DEBUG io.lettuce.core.protocol.CommandEncoder - [channel=0x69b8c689, /127.0.0.1:22669 -> localhost/127.0.0.1:6379] writing command AsyncCommand [type=DEL, output=IntegerOutput [output=null, error='null'], commandType=io.lettuce.core.protocol.Command] 2025-09-19 13:11:07.205 [lettuce-nioEventLoop-4-1] DEBUG io.lettuce.core.protocol.CommandHandler - [channel=0x69b8c689, /127.0.0.1:22669 -> localhost/127.0.0.1:6379, epid=0x1, chid=0x1] Received: 4 bytes, 1 commands in the stack 2025-09-19 13:11:07.205 [lettuce-nioEventLoop-4-1] DEBUG io.lettuce.core.protocol.CommandHandler - [channel=0x69b8c689, /127.0.0.1:22669 -> localhost/127.0.0.1:6379, epid=0x1, chid=0x1] Stack contains: 1 commands 2025-09-19 13:11:07.206 [lettuce-nioEventLoop-4-1] DEBUG io.lettuce.core.protocol.RedisStateMachine - Decode done, empty stack: true 2025-09-19 13:11:07.209 [lettuce-nioEventLoop-4-1] DEBUG io.lettuce.core.protocol.CommandHandler - [channel=0x69b8c689, /127.0.0.1:22669 -> localhost/127.0.0.1:6379, epid=0x1, chid=0x1] Completing command LatencyMeteredCommand [type=DEL, output=IntegerOutput [output=1, error='null'], commandType=io.lettuce.core.protocol.AsyncCommand] 2025-09-19 13:11:07.209 [scheduling-1] DEBUG o.s.data.redis.core.RedisConnectionUtils - Closing Redis Connection. 2025-09-19 13:11:07.210 [scheduling-1] INFO c.hvlink.service.impl.SyncPlanProtocolServiceImpl - ======================结束了===========================计划协议同步任务锁已释放 2025-09-19 13:11:07.212 [scheduling-1] DEBUG o.s.jdbc.datasource.DataSourceTransactionManager - Initiating transaction rollback 2025-09-19 13:11:07.212 [scheduling-1] DEBUG o.s.jdbc.datasource.DataSourceTransactionManager - Rolling back JDBC transaction on Connection [ConnectionID:1 ClientConnectionId: 99d645c0-e5d6-4b9d-a421-952766829756] 2025-09-19 13:11:07.224 [scheduling-1] DEBUG o.s.jdbc.datasource.DataSourceTransactionManager - Releasing JDBC Connection [ConnectionID:1 ClientConnectionId: 99d645c0-e5d6-4b9d-a421-952766829756] after transaction 2025-09-19 13:11:07.226 [scheduling-1] ERROR o.s.s.support.TaskUtils$LoggingErrorHandler - Unexpected error occurred in scheduled task java.lang.RuntimeException: java.lang.IllegalArgumentException: Result Maps collection does not contain value for com.hvlink.entity.dto.order.PurchaseOrderMainDTO at com.hvlink.service.impl.SyncPlanProtocolServiceImpl.syncPurchaseOrderData(SyncPlanProtocolServiceImpl.java:189) at com.hvlink.service.impl.SyncPlanProtocolServiceImpl$$FastClassBySpringCGLIB$$fba6dd9d.invoke(<generated>) at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218) at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:792) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:762) at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:123) at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:388) at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:119) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:762) at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:707) at com.hvlink.service.impl.SyncPlanProtocolServiceImpl$$EnhancerBySpringCGLIB$$38999a59.syncPurchaseOrderData(<generated>) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at org.springframework.scheduling.support.ScheduledMethodRunnable.run(ScheduledMethodRunnable.java:84) at org.springframework.scheduling.support.DelegatingErrorHandlingRunnable.run(DelegatingErrorHandlingRunnable.java:54) at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:308) at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(ScheduledThreadPoolExecutor.java:180) at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:294) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) at java.lang.Thread.run(Thread.java:750) Caused by: java.lang.IllegalArgumentException: Result Maps collection does not contain value for com.hvlink.entity.dto.order.PurchaseOrderMainDTO at com.baomidou.mybatisplus.core.MybatisConfiguration$StrictMap.get(MybatisConfiguration.java:454) at com.baomidou.mybatisplus.core.MybatisConfiguration.getResultMap(MybatisConfiguration.java:293) at org.apache.ibatis.builder.MapperBuilderAssistant.getStatementResultMaps(MapperBuilderAssistant.java:394) at org.apache.ibatis.builder.MapperBuilderAssistant.addMappedStatement(MapperBuilderAssistant.java:285) at org.apache.ibatis.builder.xml.XMLStatementBuilder.parseStatementNode(XMLStatementBuilder.java:113) at org.apache.ibatis.session.Configuration.lambda$buildAllStatements$2(Configuration.java:914) at java.util.Collection.removeIf(Collection.java:414) at org.apache.ibatis.session.Configuration.buildAllStatements(Configuration.java:913) at com.baomidou.mybatisplus.core.MybatisConfiguration.hasStatement(MybatisConfiguration.java:359) at org.apache.ibatis.session.Configuration.hasStatement(Configuration.java:885) at org.apache.ibatis.binding.MapperMethod$SqlCommand.resolveMappedStatement(MapperMethod.java:257) at org.apache.ibatis.binding.MapperMethod$SqlCommand.<init>(MapperMethod.java:227) at com.baomidou.mybatisplus.core.override.MybatisMapperMethod.<init>(MybatisMapperMethod.java:50) at com.baomidou.mybatisplus.core.override.MybatisMapperProxy.lambda$cachedInvoker$0(MybatisMapperProxy.java:111) at java.util.concurrent.ConcurrentHashMap.computeIfAbsent(ConcurrentHashMap.java:1660) at com.baomidou.mybatisplus.core.toolkit.CollectionUtils.computeIfAbsent(CollectionUtils.java:115) at com.baomidou.mybatisplus.core.override.MybatisMapperProxy.cachedInvoker(MybatisMapperProxy.java:98) at com.baomidou.mybatisplus.core.override.MybatisMapperProxy.invoke(MybatisMapperProxy.java:89) at com.sun.proxy.$Proxy116.queryExistingApprovalCodes(Unknown Source) at com.hvlink.service.impl.SyncPlanProtocolServiceImpl.getLatestOrderDetailsList(SyncPlanProtocolServiceImpl.java:541) at com.hvlink.service.impl.SyncPlanProtocolServiceImpl.syncPurchaseOrderData(SyncPlanProtocolServiceImpl.java:139) ... 25 common frames omitted 2025-09-19 13:11:07.251 [RMI TCP Connection(1)-2.0.0.1] DEBUG o.springframework.jdbc.datasource.DataSourceUtils - Fetching JDBC Connection from DataSource 2025-09-19 13:11:07.261 [RMI TCP Connection(1)-2.0.0.1] DEBUG o.springframework.jdbc.datasource.DataSourceUtils - Fetching JDBC Connection from DataSource 2025-09-19 13:11:07.546 [RMI TCP Connection(1)-2.0.0.1] INFO com.alibaba.druid.pool.DruidDataSource - {dataSource-2} inited 2025-09-19 13:11:07.680 [RMI TCP Connection(1)-2.0.0.1] DEBUG o.springframework.jdbc.datasource.DataSourceUtils - Fetching JDBC Connection from DataSource 2025-09-19 13:11:07.705 [RMI TCP Connection(1)-2.0.0.1] DEBUG o.springframework.jdbc.datasource.DataSourceUtils - Fetching JDBC Connection from DataSource 2025-09-19 13:11:07.706 [RMI TCP Connection(1)-2.0.0.1] DEBUG o.springframework.jdbc.datasource.DataSourceUtils - Fetching JDBC Connection from DataSource 2025-09-19 13:11:07.741 [RMI TCP Connection(1)-2.0.0.1] DEBUG o.springframework.jdbc.datasource.DataSourceUtils - Fetching JDBC Connection from DataSource 2025-09-19 13:11:07.741 [RMI TCP Connection(1)-2.0.0.1] DEBUG o.springframework.jdbc.datasource.DataSourceUtils - Fetching JDBC Connection from DataSource 2025-09-19 13:11:07.892 [boundedElastic-1] DEBUG io.lettuce.core.RedisClient - Trying to get a Redis connection for: redis://localhost 2025-09-19 13:11:07.893 [boundedElastic-1] DEBUG io.lettuce.core.RedisClient - Resolved SocketAddress localhost:6379 using redis://localhost 2025-09-19 13:11:07.893 [boundedElastic-1] DEBUG io.lettuce.core.AbstractRedisClient - Connecting to Redis at localhost:6379 2025-09-19 13:11:07.895 [lettuce-nioEventLoop-4-2] DEBUG io.lettuce.core.protocol.CommandHandler - [channel=0x3f3b2d91, [id: 0x2d015132] (inactive), epid=0x2, chid=0x2] channelRegistered() 2025-09-19 13:11:07.897 [lettuce-nioEventLoop-4-2] DEBUG io.lettuce.core.protocol.CommandHandler - [channel=0x3f3b2d91, /127.0.0.1:22683 -> localhost/127.0.0.1:6379, epid=0x2, chid=0x2] write(ctx, AsyncCommand [type=HELLO, output=GenericMapOutput [output=null, error='null'], commandType=io.lettuce.core.protocol.Command], promise) 2025-09-19 13:11:07.897 [lettuce-nioEventLoop-4-2] DEBUG io.lettuce.core.protocol.CommandEncoder - [channel=0x3f3b2d91, /127.0.0.1:22683 -> localhost/127.0.0.1:6379] writing command AsyncCommand [type=HELLO, output=GenericMapOutput [output=null, error='null'], commandType=io.lettuce.core.protocol.Command] 2025-09-19 13:11:07.897 [lettuce-nioEventLoop-4-2] DEBUG io.lettuce.core.protocol.CommandHandler - [channel=0x3f3b2d91, /127.0.0.1:22683 -> localhost/127.0.0.1:6379, epid=0x2, chid=0x2] Received: 30 bytes, 1 commands in the stack 2025-09-19 13:11:07.897 [lettuce-nioEventLoop-4-2] DEBUG io.lettuce.core.protocol.CommandHandler - [channel=0x3f3b2d91, /127.0.0.1:22683 -> localhost/127.0.0.1:6379, epid=0x2, chid=0x2] Stack contains: 1 commands 2025-09-19 13:11:07.897 [lettuce-nioEventLoop-4-2] DEBUG io.lettuce.core.protocol.RedisStateMachine - Decode done, empty stack: true 2025-09-19 13:11:07.900 [lettuce-nioEventLoop-4-2] DEBUG io.lettuce.core.protocol.CommandHandler - [channel=0x3f3b2d91, /127.0.0.1:22683 -> localhost/127.0.0.1:6379, epid=0x2, chid=0x2] Completing command LatencyMeteredCommand [type=HELLO, output=GenericMapOutput [output=null, error='ERR unknown command 'HELLO''], commandType=io.lettuce.core.protocol.AsyncCommand] 2025-09-19 13:11:07.900 [lettuce-nioEventLoop-4-2] DEBUG io.lettuce.core.protocol.CommandHandler - [channel=0x3f3b2d91, /127.0.0.1:22683 -> localhost/127.0.0.1:6379, epid=0x2, chid=0x2] write(ctx, AsyncCommand [type=PING, output=StatusOutput [output=null, error='null'], commandType=io.lettuce.core.protocol.Command], promise) 2025-09-19 13:11:07.900 [lettuce-nioEventLoop-4-2] DEBUG io.lettuce.core.protocol.CommandEncoder - [channel=0x3f3b2d91, /127.0.0.1:22683 -> localhost/127.0.0.1:6379] writing command AsyncCommand [type=PING, output=StatusOutput [output=null, error='null'], commandType=io.lettuce.core.protocol.Command] 2025-09-19 13:11:07.901 [lettuce-nioEventLoop-4-2] DEBUG io.lettuce.core.protocol.CommandHandler - [channel=0x3f3b2d91, /127.0.0.1:22683 -> localhost/127.0.0.1:6379, epid=0x2, chid=0x2] Received: 7 bytes, 1 commands in the stack 2025-09-19 13:11:07.901 [lettuce-nioEventLoop-4-2] DEBUG io.lettuce.core.protocol.CommandHandler - [channel=0x3f3b2d91, /127.0.0.1:22683 -> localhost/127.0.0.1:6379, epid=0x2, chid=0x2] Stack contains: 1 commands 2025-09-19 13:11:07.927 [lettuce-nioEventLoop-4-2] DEBUG io.lettuce.core.protocol.RedisStateMachine - Decode done, empty stack: true 2025-09-19 13:11:07.927 [lettuce-nioEventLoop-4-2] DEBUG io.lettuce.core.protocol.CommandHandler - [channel=0x3f3b2d91, /127.0.0.1:22683 -> localhost/127.0.0.1:6379, epid=0x2, chid=0x2] Completing command LatencyMeteredCommand [type=PING, output=StatusOutput [output=PONG, error='null'], commandType=io.lettuce.core.protocol.AsyncCommand] 2025-09-19 13:11:07.927 [lettuce-nioEventLoop-4-2] DEBUG io.lettuce.core.protocol.CommandHandler - [channel=0x3f3b2d91, /127.0.0.1:22683 -> localhost/127.0.0.1:6379, epid=0x2, chid=0x2] channelActive() 2025-09-19 13:11:07.927 [lettuce-nioEventLoop-4-2] DEBUG io.lettuce.core.protocol.DefaultEndpoint - [channel=0x3f3b2d91, /127.0.0.1:22683 -> localhost/127.0.0.1:6379, epid=0x2] activateEndpointAndExecuteBufferedCommands 0 command(s) buffered 2025-09-19 13:11:07.927 [lettuce-nioEventLoop-4-2] DEBUG io.lettuce.core.protocol.DefaultEndpoint - [channel=0x3f3b2d91, /127.0.0.1:22683 -> localhost/127.0.0.1:6379, epid=0x2] activating endpoint 2025-09-19 13:11:07.927 [lettuce-nioEventLoop-4-2] DEBUG io.lettuce.core.protocol.DefaultEndpoint - [channel=0x3f3b2d91, /127.0.0.1:22683 -> localhost/127.0.0.1:6379, epid=0x2] flushCommands() 2025-09-19 13:11:07.927 [lettuce-nioEventLoop-4-2] DEBUG io.lettuce.core.protocol.DefaultEndpoint - [channel=0x3f3b2d91, /127.0.0.1:22683 -> localhost/127.0.0.1:6379, epid=0x2] flushCommands() Flushing 0 commands 2025-09-19 13:11:07.927 [lettuce-nioEventLoop-4-2] DEBUG io.lettuce.core.protocol.ConnectionWatchdog - [channel=0x3f3b2d91, /127.0.0.1:22683 -> localhost/127.0.0.1:6379, last known addr=localhost/127.0.0.1:6379] channelActive() 2025-09-19 13:11:07.927 [lettuce-nioEventLoop-4-2] DEBUG io.lettuce.core.protocol.CommandHandler - [channel=0x3f3b2d91, /127.0.0.1:22683 -> localhost/127.0.0.1:6379, epid=0x2, chid=0x2] channelActive() done 2025-09-19 13:11:07.927 [lettuce-nioEventLoop-4-2] DEBUG io.lettuce.core.AbstractRedisClient - Connecting to Redis at localhost:6379: Success 2025-09-19 13:11:07.988 [boundedElastic-1] DEBUG io.lettuce.core.RedisChannelHandler - dispatching command SubscriptionCommand [type=INFO, output=StatusOutput [output=null, error='null'], commandType=io.lettuce.core.protocol.Command] 2025-09-19 13:11:07.988 [boundedElastic-1] DEBUG io.lettuce.core.protocol.DefaultEndpoint - [channel=0x3f3b2d91, /127.0.0.1:22683 -> localhost/127.0.0.1:6379, epid=0x2] write() writeAndFlush command SubscriptionCommand [type=INFO, output=StatusOutput [output=null, error='null'], commandType=io.lettuce.core.protocol.Command] 2025-09-19 13:11:07.997 [lettuce-nioEventLoop-4-2] DEBUG io.lettuce.core.protocol.CommandHandler - [channel=0x3f3b2d91, /127.0.0.1:22683 -> localhost/127.0.0.1:6379, epid=0x2, chid=0x2] write(ctx, SubscriptionCommand [type=INFO, output=StatusOutput [output=null, error='null'], commandType=io.lettuce.core.protocol.Command], promise) 2025-09-19 13:11:07.997 [boundedElastic-1] DEBUG io.lettuce.core.protocol.DefaultEndpoint - [channel=0x3f3b2d91, /127.0.0.1:22683 -> localhost/127.0.0.1:6379, epid=0x2] write() done 2025-09-19 13:11:07.998 [lettuce-nioEventLoop-4-2] DEBUG io.lettuce.core.protocol.CommandEncoder - [channel=0x3f3b2d91, /127.0.0.1:22683 -> localhost/127.0.0.1:6379] writing command SubscriptionCommand [type=INFO, output=StatusOutput [output=null, error='null'], commandType=io.lettuce.core.protocol.Command] 2025-09-19 13:11:07.999 [lettuce-nioEventLoop-4-2] DEBUG io.lettuce.core.protocol.CommandHandler - [channel=0x3f3b2d91, /127.0.0.1:22683 -> localhost/127.0.0.1:6379, epid=0x2, chid=0x2] Received: 365 bytes, 1 commands in the stack 2025-09-19 13:11:07.999 [lettuce-nioEventLoop-4-2] DEBUG io.lettuce.core.protocol.CommandHandler - [channel=0x3f3b2d91, /127.0.0.1:22683 -> localhost/127.0.0.1:6379, epid=0x2, chid=0x2] Stack contains: 1 commands 2025-09-19 13:11:07.999 [lettuce-nioEventLoop-4-2] DEBUG io.lettuce.core.protocol.RedisStateMachine - Decode done, empty stack: true 2025-09-19 13:11:08.005 [lettuce-nioEventLoop-4-2] DEBUG io.lettuce.core.protocol.CommandHandler - [channel=0x3f3b2d91, /127.0.0.1:22683 -> localhost/127.0.0.1:6379, epid=0x2, chid=0x2] Completing command LatencyMeteredCommand [type=INFO, output=StatusOutput [output=# Server redis_version:3.0.504 redis_git_sha1:00000000 redis_git_dirty:0 redis_build_id:a4f7a6e86f2d60b3 redis_mode:standalone os:Windows arch_bits:64 multiplexing_api:WinSock_IOCP process_id:904 run_id:a7d2e2bdc458123d1f1f741d8bf2bf35dcd84801 tcp_port:6379 uptime_in_seconds:187271 uptime_in_days:2 hz:10 lru_clock:13428203 config_file: , error='null'], commandType=io.lettuce.core.RedisPublisher$SubscriptionCommand]
最新发布
09-20
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值