【柳州打车app源码】【phpqq业务源码】【hoorayos 源码下载】redis 源码学习

时间:2024-12-24 08:10:17 编辑:13张棋牌源码 来源:asyncio源码分析

1.redis源码学习-quicklist篇
2.服务器开发学习中间件:Redis 码学缓存中间件
3.redis7.0源码阅读:Redis中的IO多线程(线程池)
4.到底如何在spring中使用redis

redis 源码学习

redis源码学习-quicklist篇

       Redis源码中的quicklist是ziplist优化版的双端链表,旨在提高内存效率和操作效率。码学ziplist虽然内存使用率高,码学但查找和增删操作的码学最坏时间复杂度可能达到O(n^2),这与Redis高效数据处理的码学要求不符。quicklist通过每个节点独立的码学柳州打车app源码ziplist结构,降低了更新复杂度,码学同时保持了内存使用率。码学

       quicklist的码学基本结构包括:头节点(head)、尾节点(tail)、码学entry总数(count)、码学节点总数(len)、码学容量指示(fill)、码学压缩深度(compress)、码学以及用于内存管理的码学bookmarks。节点结构包括双向链表的prev和next,ziplist的引用zl,ziplist的字节数sz、item数count、phpqq业务源码以及ziplist类型(raw或lzf压缩)和尝试压缩标志(attempted_compress)。

       核心操作函数如create用于初始化节点,insert则根据需求执行头插法或尾插法。delete则简单地从链表中移除节点,释放相关内存。quicklist的优化重点在于ziplist,理解了ziplist的工作原理,quicklist的数据结构理解就相对容易了。

服务器开发学习中间件:Redis 缓存中间件

       为什么需要缓存中间件?

       在网站的用户量增加,引发并发量提升的情况下,频繁查询数据库会导致页面显示缓慢,服务器与数据库压力增大。如果页面展示数据更新不频繁,为了加速页面显示与减轻服务器负担,应考虑使用缓存。缓存位于应用程序与物理数据源之间,主要目的是减少应用程序对物理数据源的访问频率,从而提高应用性能。hoorayos 源码下载缓存存储的数据是对物理数据源的复制,应用程序在运行时从缓存读写数据,在特定时刻或事件时同步缓存与物理数据源的数据。

       使用缓存遵循高层次缓存原则,推荐使用页面缓存。

       Redis简介

       Redis是一个键值存储系统,支持多种数据类型,包括字符串、链表、集合、有序集合和哈希表。它支持多种操作,如push、pop、add、remove、并集、交集、清新导航源码差集等。支持排序,与Memcached类似,数据存于内存中,通过周期性写入磁盘或追加记录文件实现持久化,并支持主从同步。

       Redis是一个高性能的键值数据库,能很好地补充Memcached的不足,某些情况下可以替代关系数据库。提供多种语言客户端,使用便利。

       Redis特性

       速度快、持久化、高可用。

       为何如此快?如何使用?

       Redis存储机制

       Redis采用Snapshot和AOF两种持久化方式。数据均存储在内存中。

       Snapshot工作原理

       先存储内存,当数据达到设定阈值时触发一次DUMP操作,redhat coreutils 源码将变化的数据一次性写入RDB文件。

       AOF工作原理

       先存内存,存储时调用fsync完成日志记录,日志文件基于Redis网络交互协议,可配置存储频率,避免阻塞。

       存储模式性能与安全

       Snapshot方式性能高于AOF,原因:Snapshot一次性写入,效率高;AOF实时或准实时存储,效率低。

       AOF数据安全优于Snapshot,原因:Snapshot数据依赖时间积累,长时间不写入RDB数据丢失;AOF配置策略实现最小数据丢失与高恢复能力。

       Redis中的Rewrite功能缩小日志文件大小。

       数据结构及使用场景

       字符串:用于缓存、计数、锁、ID生成。

       哈希:适合存储对象,每个字段与值映射,适合存储多亿键值对。

       列表:有序字符串集合,支持插入、弹出、读取指定范围或下标元素。

       集合:存储无重复元素的集合,适合分类聚合,复杂度O(1)。

       有序集合:集合加分数排序,用于成绩排名等。

       技术总结

       介绍了Redis的存储模式与数据结构,分析了性能与安全特性,并列举了应用场景。

       参考资料

       详细阅读原文:Redis数据详解:源码阅读、数据组织、数据存储

       Redis 6.0后支持的io多线程工作原理分析

       全面解析Redis事务:实现zpop、lua脚本、EVALSHA、ACID特性与异步连接

       LinuxC/C++服务器开发/架构师面试题、学习资料、教学视频和学习路线图(包含C/C++、Linux、golang等技术)

redis7.0源码阅读:Redis中的IO多线程(线程池)

       Redis服务端处理客户端请求时,采用单线程模型执行逻辑操作,然而读取和写入数据的操作则可在IO多线程模型中进行。在Redis中,命令执行发生在单线程环境中,而数据的读取与写入则通过线程池进行。一个命令从客户端接收,解码成具体命令,根据该命令生成结果后编码并回传至客户端。

       Redis配置文件redis.conf中可设置开启IO多线程。通过设置`io-threads-do-reads yes`开启多线程,同时配置`io-threads 2`来创建两个线程,其中一个是主线程,另一个为IO线程。在网络处理文件networking.c中,`stopThreadedIOIfNeeded`函数会判断当前需要执行的命令数是否超过线程数,若少于线程数,则不开启多线程模式,便于调试。

       要进入IO多线程模式,运行redis-server命令,然后在调试界面设置断点在networking.c的`readQueryFromClient`函数中。使用redis-cli输入命令时,可以观察到两个线程在运行,一个为主线程,另一个为IO线程。

       相关视频推荐帮助理解线程池在Redis中的应用,包括手写线程池及线程池在后端开发中的实际应用。学习资源包括C/C++ Linux服务器开发、后台架构师技术等领域,需要相关资料可加入交流群获取免费分享。

       在Redis中,IO线程池实现中,主要包括以下步骤:

       读取任务的处理通过`postponeClientRead`函数,判断是否启用IO多线程模式,将任务加入到待执行任务队列。

       主线程执行`postponeClientRead`函数,将待读客户端任务加入到读取任务队列。在多线程模式下,任务被添加至队列中,由IO线程后续执行。

       多线程读取IO任务`handleClientsWithPendingReadsUsingThreads`通过解析协议进行数据读取,与写入任务的多线程处理机制相似。

       多线程写入IO任务`handleClientsWithPendingWritesUsingThreads`包括判断是否需要启动IO多线程、负载均衡分配任务到不同IO线程、启动IO子线程执行写入操作、等待IO线程完成写入任务等步骤。负载均衡通过将任务队列中的任务均匀分配至不同的线程消费队列中,实现无锁化操作。

       线程调度部分包含开启和关闭IO线程的功能。在`startThreadedIO`中,每个IO线程持有锁,若主线程释放锁,线程开始工作,IO线程标识设置为活跃状态。而在`stopThreadedIO`中,若主线程获取锁,则IO线程等待并停止,IO线程标识设置为非活跃状态。

到底如何在spring中使用redis

       1. Redis使用场景

       Redis是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。

       æˆ‘们都知道,在日常的应用中,数据库瓶颈是最容易出现的。数据量太大和频繁的查询,由于磁盘IO性能的局限性,导致项目的性能越来越低。

       è¿™æ—¶å€™ï¼ŒåŸºäºŽå†…存的缓存框架,就能解决我们很多问题。例如Memcache,Redis等。将一些频繁使用的数据放入缓存读取,大大降低了数据库的负担。提升了系统的性能。

       å…¶å®žï¼Œå¯¹äºŽhibernate的二级缓存,是同样的道理。利用内存高速的读写速度,来解决硬盘的瓶颈。

       2. 配置使用redis

       é¦–先,我们需要引入基本的jar包。maven中的基本引用如下:

       ã€€ã€€ã€€ã€€<dependency>

        <groupId>org.springframework.data</groupId>

        <artifactId>spring-data-redis</artifactId>

        <version>1.4.2.RELEASE</version>

        </dependency>

        <dependency>

        <groupId>redis.clients</groupId>

        <artifactId>jedis</artifactId>

        <version>2.6.2</version>

        </dependency>

       ç„¶åŽï¼Œåœ¨applicationContext中配置如下:

       <bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig">

        <property name="maxIdle" value="${ redis.maxIdle}" />

        <property name="maxTotal" value="${ redis.maxActive}" />

        <property name="maxWaitMillis" value="${ redis.maxWait}" />

        <property name="testOnBorrow" value="${ redis.testOnBorrow}" />

        </bean>

        <bean id="connectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory" p:host-name="${ redis.host}" p:port="${ redis.port}" p:password="${ redis.pass}"

        p:pool-config-ref="poolConfig" />

        <bean id="stringSerializer" class="org.springframework.data.redis.serializer.StringRedisSerializer"/>

        <!-- 开启事务,可以通过transcational注解控制 -->

        <bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate">

        <property name="connectionFactory" ref="connectionFactory" />

        <property name="keySerializer" ref="stringSerializer" />

        <property name="enableTransactionSupport" value="true" />

        </bean>

       å¯¹äºŽhibernate的配置可知,第一个poolconfig是对连接池的配置。包括最大连接数,队列数,存活时间,最大等待时间等等,还有一些额外的配置,请直接点击JedisPoolConfig类源码,进行查看。

       è¿™äº›é…ç½®çš„意思如果不明白的话,一定要去把线程池好好学习下。

       ç¬¬ä¸€ä¸ªé…ç½®æ˜¯è¿žæŽ¥å·¥åŽ‚,顾名思义,最基本的使用一定是对连接的打开和关闭。我们需要为其配置redis服务器的账户密码,端口号。(这里还可以配置数据库的index,但是我使用时候一直使用redis的默认数据库,也就是第0个)

       æœ€åŽä¸€ä¸ªé…ç½®ç‰¹åˆ«é‡è¦ã€‚这个类似于spring提供的HibernateDaoSupport。

       æŽ¥ä¸‹æ¥ï¼Œå…¨éƒ¨è®²è§£éƒ½å°†å›´ç»•è¿™ä¸ªç±»å±•å¼€ã€‚

       3. RedisTemplate的使用

       è¿™ä¸ªç±»ä½œä¸ºä¸€ä¸ªæ¨¡ç‰ˆç±»ï¼Œæä¾›äº†å¾ˆå¤šå¿«é€Ÿä½¿ç”¨redis的api,而不需要自己来维护连接,事务。

       æœ€åˆçš„时候,我创建的BaseRedisDao是继承自这个类的。继承的好处是我的每个Dao中,都可以自由的控制序列化器,自由的控制自己是否需要事务,这个先不需要了解,跟着我目前的这种配置方法来即可。

       template提供了一系列的operation,比如valueOperation,HashOperation,ListOperation,SetOperation等,用来操作不同数据类型的Redis。

       å¹¶ä¸”,RedisTemplate还提供了对应的*OperationsEditor,用来通过RedisTemplate直接注入对应的Operation。我们暂时不讲这个。

       å¯¹äºŽä¸‹é¢çš„test1方法,我们暂时不用考虑,先了解通过RedisTemplate来使用connection操作Redis。

       Test代码如下:

       package cn.test.spjedis;

       import javax.annotation.Resource;

       import org.junit.Test;

       import org.junit.runner.RunWith;

       import org.springframework.beans.factory.annotation.Autowired;

       import org.springframework.dao.DataAccessException;

       import org.springframework.data.redis.connection.RedisConnection;

       import org.springframework.data.redis.core.RedisCallback;

       import org.springframework.data.redis.core.RedisTemplate;

       import org.springframework.data.redis.core.ValueOperations;

       import org.springframework.test.context.ContextConfiguration;

       import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

       import com.cn.redis2.dao.IncrDao;

       @RunWith(SpringJUnit4ClassRunner.class)

       @ContextConfiguration(locations = "classpath:applicationContext.xml")

       public class TestRedis {

        @Resource(name = "redisTemplate")

        private RedisTemplate<String, String> template; // inject the template as ListOperations

        //至于这个为什么可以注入。需要参考AbstractBeanFactory doGetBean

        //super.setValue(((RedisOperations) value).opsForValue());就这一行代码 依靠一个editor

        @Resource(name = "redisTemplate")

        private ValueOperations<String, Object> vOps;

        public void testSet(){

        template.execute(new RedisCallback<Boolean>() {

        @Override

        public Boolean doInRedis(RedisConnection connection) throws DataAccessException {

        byte [] key = "tempkey".getBytes();

        byte[] value = "tempvalue".getBytes();

        connection.set(key, value);

        return true;

        }

        });

        }

        public void testSet1(){

        vOps.set("tempkey", "tempvalue");

        }

        @Autowired

        private IncrDao incr;

       @Test

        public void addLink() {

        System.out.println(incr.incr());

        System.out.println(incr.get());

        }

       }

       è¿™ä¸ªæ˜¯å¯¹String类型插入的两个测试。test方法中,使用了模版类提交回调(RedisCallBack)的方法来使用jedis connection操作数据。这一部分,有没有似曾相识呢?

       HibernateTemplate的HibernateCallback,以及Hibernate Session类中的doWork以及doReturningWork方法,都是使用了这样的机制,方便对于连接或者session的统一管理。

       public int excuteHqlUpdate(final String hql,final Object ...params){

        return getHibernateTemplate().executeWithNativeSession(new HibernateCallback<Integer>() {

        @Override

        @SuppressWarnings("unchecked")

        public Integer doInHibernate(Session session) throws HibernateException {

        Query queryObject = session.createQuery(hql);

        if (params != null) {

        for (int i = 0; i < params.length; i++) {

        queryObject.setParameter(i, params[i]);

        }

        }

        return queryObject.executeUpdate();

        }

        });

        }