PART1:Redis:类似于持久化的HashMap,因为两个都存的是键值对嘛。所以Redis是个啥呢,其实Redis就是一个C语言的编写的key-value存储系统
。
redis(Remote Dictionary Server)是一款高性能的NOSQL系列的Key-Value类型(用C语言开发的一个开源的高性能键值对(key-value)数据库)的非关系型数据库(记住哦,Redis可以用作数据库、缓存以及消息中间件MQ)
- 服务器中的数据库:Redis服务器将所有数据库都保存在服务器状态redis.h/redisServer结构的db数组中,
db数组的每个项都是一个redis.h/redisDb结构,每个redisDb结构代表一个数据库
:/* Redis database representation. There are multiple databases identified * by integers from 0 (the default database) up to the max configured * database. The database number is the 'id' field in the structure. */ typedef struct redisDb { // 数据库键空间,保存着数据库中的所有键值对 dict *dict; /* The keyspace for this DB */ // 键的过期时间,字典的键为键,字典的值为过期事件 UNIX 时间戳 dict *expires; /* Timeout of keys with a timeout set */ // 正处于阻塞状态的键 dict *blocking_keys; /* Keys with clients waiting for data (BLPOP) */ // 可以解除阻塞的键 dict *ready_keys; /* Blocked keys that received a PUSH */ // 正在被 WATCH 命令监视的键 dict *watched_keys; /* WATCHED keys for MULTI/EXEC CAS */ struct evictionPoolEntry *eviction_pool; /* Eviction pool of keys */ // 数据库号码 int id; /* Database ID */ // 数据库的键的平均 TTL ,统计信息 long long avg_ttl; /* Average TTL, just for stats */ } redisDb;
- 在初始化服务器时,程序会根据服务器状态的dbnum属性来决定应该创建多少个数据库:dbnum属性的值由服务器配置的database选项决定,
默认情况下, 该选项的值为16,所以Redis服务器默认会创建16个数据库
。
- 切换数据库:每个Redis客户端都有自己的目标数据库,每当客户端执行数据库写命令或者数据库读命令的时候,目标数据库就会成为这些命令的操作对象。
默认情况下,Redis客户端的目标数据库为0号数据库,但客户端可以通过执行SELECT命令来切换目标数据库。
通过修改redisClient.db指针,让它指向服务器中的不同数据库,从 而实现切换目标数据库的功能——这就是SELECT命令的实现原理
。- 在服务器内部,客户端状态redisClient结构的db属性记录了客户端当前的目标数据库,这个属性是一个指向redisDb结构的指针:redisClient.db指针指向redisServer.db数组的其中一个元素,而被指向的元素就是客户端的目标数据库。
/* With multiplexing we need to take per-client state. * Clients are taken in a liked list. * * 因为 I/O 复用的缘故,需要为每个客户端维持一个状态。 * * 多个客户端状态被服务器用链表连接起来。 */ typedef struct redisClient { // 套接字描述符 int fd; // 当前正在使用的数据库 redisDb *db; // 当前正在使用的数据库的 id (号码) int dictid; // 客户端的名字 robj *name; /* As set by CLIENT SETNAME */ // 查询缓冲区 sds querybuf; // 查询缓冲区长度峰值 size_t querybuf_peak; /* Recent (100ms or more) peak of querybuf size */ // 参数数量 int argc; // 参数对象数组 robj **argv; // 记录被客户端执行的命令 struct redisCommand *cmd, *lastcmd; // 请求的类型:内联命令还是多条命令 int reqtype; // 剩余未读取的命令内容数量 int multibulklen; /* number of multi bulk arguments left to read */ // 命令内容的长度 long bulklen; /* length of bulk argument in multi bulk request */ // 回复链表 list *reply; // 回复链表中对象的总大小 unsigned long reply_bytes; /* Tot bytes of objects in reply list */ // 已发送字节,处理 short write 用 int sentlen; /* Amount of bytes already sent in the current buffer or object being sent. */ // 创建客户端的时间 time_t ctime; /* Client creation time */ // 客户端最后一次和服务器互动的时间 time_t lastinteraction; /* time of the last interaction, used for timeout */ // 客户端的输出缓冲区超过软性限制的时间 time_t obuf_soft_limit_reached_time; // 客户端状态标志 int flags; /* REDIS_SLAVE | REDIS_MONITOR | REDIS_MULTI ... */ // 当 server.requirepass 不为 NULL 时 // 代表认证的状态 // 0 代表未认证, 1 代表已认证 int authenticated; /* when requirepass is non-NULL */ // 复制状态 int replstate; /* replication state if this is a slave */ // 用于保存主服务器传来的 RDB 文件的文件描述符 int repldbfd; /* replication DB file descriptor */ // 读取主服务器传来的 RDB 文件的偏移量 off_t repldboff; /* replication DB file offset */ // 主服务器传来的 RDB 文件的大小 off_t repldbsize; /* replication DB file size */ sds replpreamble; /* replication DB preamble. */ // 主服务器的复制偏移量 long long reploff; /* replication offset if this is our master */ // 从服务器最后一次发送 REPLCONF ACK 时的偏移量 long long repl_ack_off; /* replication ack offset, if this is a slave */ // 从服务器最后一次发送 REPLCONF ACK 的时间 long long repl_ack_time;/* replication ack time, if this is a slave */ // 主服务器的 master run ID // 保存在客户端,用于执行部分重同步 char replrunid[REDIS_RUN_ID_SIZE+1]; /* master run id if this is a master */ // 从服务器的监听端口号 int slave_listening_port; /* As configured with: SLAVECONF listening-port */ // 事务状态 multiState mstate; /* MULTI/EXEC state */ // 阻塞类型 int btype; /* Type of blocking op if REDIS_BLOCKED. */ // 阻塞状态 blockingState bpop; /* blocking state */ // 最后被写入的全局复制偏移量 long long woff; /* Last write global replication offset. */ // 被监视的键 list *watched_keys; /* Keys WATCHED for MULTI/EXEC CAS */ // 这个字典记录了客户端所有订阅的频道 // 键为频道名字,值为 NULL // 也即是,一个频道的集合 dict *pubsub_channels; /* channels a client is interested in (SUBSCRIBE) */ // 链表,包含多个 pubsubPattern 结构 // 记录了所有订阅频道的客户端的信息 // 新 pubsubPattern 结构总是被添加到表尾 list *pubsub_patterns; /* patterns a client is interested in (SUBSCRIBE) */ sds peerid; /* Cached peer ID. */ /* Response buffer */ // 回复偏移量 int bufpos; // 回复缓冲区 char buf[REDIS_REPLY_CHUNK_BYTES]; } redisClient;
- 数据库键空间:Redis是一个键值对(key-value pair)数据库服务器,服务器中的每个数据库都由一个redis.h/redisDb结构表示,其中,
redisDb结构的dict字典保存了数据库中的所有键值对,我们将这个字典称为键空间(key space)
:- 键空间的键也就是数据库的键,每个键都是一个字符串对象
- 键空间的值也就是数据库的值,每个值可以是字符串对象、列表对象、哈希表对象、集合对象和有序集合对象中的任意一种Redis对 象。
- 数据库的键空间是一个字典,所以所有针对数据库的操作,比如添加一个键值对到数据库,或者从数据库中删除一个键值对,又或者在数据库中获取某个键值对等,实际上都是通过对键空间字典进行操作来实现的。
- 添加一个新键值对到数据库,实际上就是将一个新键值对添加到键空间字典里面,其中键为字符串对象,而值则为任意一种类型的Redis 对象。
- 删除数据库中的一个键,实际上就是在键空间里面删除键所对应的键值对对象。
- 用于清空整个数据库的FLUSHDB命令,就是通过删除键空间中的所有键值对来实现的。
- 对一个数据库键进行更新,实际上就是对键空间里面键所对应的值对象进行更新,根据值对象的类型不同,更新的具体方法也会有所不同。
- 对一个数据库键进行取值,实际上就是在键空间中取出键所对应的值对象,根据值对象的类型不同,具体的取值方法也会有所不同。
- 用于随机返回数据库中某个键的RANDOMKEY命令,就是通过在键空间中随机返回一个键来实现的。
- 用于返回数据库键数量的DBSIZE命令,就是通过返回键空 间中包含的键值对的数量来实现的。
- 读写键空间时的维护操作:当使用Redis命令对数据库进行读写时,
服务器不仅会对键空间执行指定的读写操作,还会执行一些额外的维护操作
。- 额外的维护操作包括:
- 在读取一个键之后(
读操作和写操作都要对键进行读取
),服务器会根据键是否存在来**更新服务器的键空间命中(hit)次数或键空间不命中(miss)次数
**,这两个值可以在INFO stats命令的keyspace_hits属性和keyspace_misses属性中查看。 - 在读取一个键之后,服务器会更新键的LRU(最后一次使用)时间,这个值可以用于计算键的闲置时间,使用OBJECT idletime命令可以查看键key的闲置时间。
- 如果服务器在读取一个键时发现该键已经过期,
那么服务器会先删除这个过期键,然后才执行余下的其他操作
。 - 如果有客户端使用WATCH命令监视了某个键,那么服务器在对被监视的键进行修改之后,会将这个键标记为脏(dirty),从而让事务程序注意到这个键已经被修改过
- 服务器
每次修改一个键
之后,都会对脏(dirty)键计数器的值增1
,这个计数器会触发服务器的持久化以及复制操作
。 - 如果服务器开启了数据库通知功能,那么在对键进行修改之后, 服务器将按配置发送相应的数据库通知
- 在读取一个键之后(
- 额外的维护操作包括:
- 在初始化服务器时,程序会根据服务器状态的dbnum属性来决定应该创建多少个数据库:dbnum属性的值由服务器配置的database选项决定,
struct redisServer {
/* General */
// 配置文件的绝对路径
char *configfile; /* Absolute config file path, or NULL */
// serverCron() 每秒调用的次数
int hz; /* serverCron() calls frequency in hertz */
// 数据库。一个数组,保存着服务器中的所有数据库
redisDb *db;
// 命令表(受到 rename 配置选项的作用)
dict *commands; /* Command table */
// 命令表(无 rename 配置选项的作用)
dict *orig_commands; /* Command table before command renaming. */
// 事件状态
aeEventLoop *el;
// 最近一次使用时钟
unsigned lruclock:REDIS_LRU_BITS; /* Clock for LRU eviction */
// 关闭服务器的标识
int shutdown_asap; /* SHUTDOWN needed ASAP */
// 在执行 serverCron() 时进行渐进式 rehash
int activerehashing; /* Incremental rehash in serverCron() */
// 是否设置了密码
char *requirepass; /* Pass for AUTH command, or NULL */
// PID 文件
char *pidfile; /* PID file path */
// 架构类型
int arch_bits; /* 32 or 64 depending on sizeof(long) */
// serverCron() 函数的运行次数计数器
int cronloops; /* Number of times the cron function run */
// 本服务器的 RUN ID
char runid[REDIS_RUN_ID_SIZE+1]; /* ID always different at every exec. */
// 服务器是否运行在 SENTINEL 模式
int sentinel_mode; /* True if this instance is a Sentinel. */
/* Networking */
// TCP 监听端口
int port; /* TCP listening port */
int tcp_backlog; /* TCP listen() backlog */
// 地址
char *bindaddr[REDIS_BINDADDR_MAX]; /* Addresses we should bind to */
// 地址数量
int bindaddr_count; /* Number of addresses in server.bindaddr[] */
// UNIX 套接字
char *unixsocket; /* UNIX socket path */
mode_t unixsocketperm; /* UNIX socket permission */
// 描述符
int ipfd[REDIS_BINDADDR_MAX]; /* TCP socket file descriptors */
// 描述符数量
int ipfd_count; /* Used slots in ipfd[] */
// UNIX 套接字文件描述符
int sofd; /* Unix socket file descriptor */
int cfd[REDIS_BINDADDR_MAX];/* Cluster bus listening socket */
int cfd_count; /* Used slots in cfd[] */
// 一个链表,保存了所有客户端状态结构
list *clients; /* List of active clients */
// 链表,保存了所有待关闭的客户端
list *clients_to_close; /* Clients to close asynchronously */
// 链表,保存了所有从服务器,以及所有监视器
list *slaves, *monitors; /* List of slaves and MONITORs */
// 服务器的当前客户端,仅用于崩溃报告
redisClient *current_client; /* Current client, only used on crash report */
int clients_paused; /* True if clients are currently paused */
mstime_t clients_pause_end_time; /* Time when we undo clients_paused */
// 网络错误
char neterr[ANET_ERR_LEN]; /* Error buffer for anet.c */
// MIGRATE 缓存
dict *migrate_cached_sockets;/* MIGRATE cached sockets */
/* RDB / AOF loading information */
// 这个值为真时,表示服务器正在进行载入
int loading; /* We are loading data from disk if true */
// 正在载入的数据的大小
off_t loading_total_bytes;
// 已载入数据的大小
off_t loading_loaded_bytes;
// 开始进行载入的时间
time_t loading_start_time;
off_t loading_process_events_interval_bytes;
/* Fast pointers to often looked up command */
// 常用命令的快捷连接
struct redisCommand *delCommand, *multiCommand, *lpushCommand, *lpopCommand,
*rpopCommand;
/* Fields used only for stats */
// 服务器启动时间
time_t stat_starttime; /* Server start time */
// 已处理命令的数量
long long stat_numcommands; /* Number of processed commands */
// 服务器接到的连接请求数量
long long stat_numconnections; /* Number of connections received */
// 已过期的键数量
long long stat_expiredkeys; /* Number of expired keys */
// 因为回收内存而被释放的过期键的数量
long long stat_evictedkeys; /* Number of evicted keys (maxmemory) */
// 成功查找键的次数
long long stat_keyspace_hits; /* Number of successful lookups of keys */
// 查找键失败的次数
long long stat_keyspace_misses; /* Number of failed lookups of keys */
// 已使用内存峰值
size_t stat_peak_memory; /* Max used memory record */
// 最后一次执行 fork() 时消耗的时间
long long stat_fork_time; /* Time needed to perform latest fork() */
// 服务器因为客户端数量过多而拒绝客户端连接的次数
long long stat_rejected_conn; /* Clients rejected because of maxclients */
// 执行 full sync 的次数
long long stat_sync_full; /* Number of full resyncs with slaves. */
// PSYNC 成功执行的次数
long long stat_sync_partial_ok; /* Number of accepted PSYNC requests. */
// PSYNC 执行失败的次数
long long stat_sync_partial_err;/* Number of unaccepted PSYNC requests. */
/* slowlog */
// 保存了所有慢查询日志的链表
list *slowlog; /* SLOWLOG list of commands */
// 下一条慢查询日志的 ID
long long slowlog_entry_id; /* SLOWLOG current entry ID */
// 服务器配置 slowlog-log-slower-than 选项的值
long long slowlog_log_slower_than; /* SLOWLOG time limit (to get logged) */
// 服务器配置 slowlog-max-len 选项的值
unsigned long slowlog_max_len; /* SLOWLOG max number of items logged */
size_t resident_set_size; /* RSS sampled in serverCron(). */
/* The following two are used to track instantaneous "load" in terms
* of operations per second. */
// 最后一次进行抽样的时间
long long ops_sec_last_sample_time; /* Timestamp of last sample (in ms) */
// 最后一次抽样时,服务器已执行命令的数量
long long ops_sec_last_sample_ops; /* numcommands in last sample */
// 抽样结果
long long ops_sec_samples[REDIS_OPS_SEC_SAMPLES];
// 数组索引,用于保存抽样结果,并在需要时回绕到 0
int ops_sec_idx;
/* Configuration */
// 日志可见性
int verbosity; /* Loglevel in redis.conf */
// 客户端最大空转时间
int maxidletime; /* Client timeout in seconds */
// 是否开启 SO_KEEPALIVE 选项
int tcpkeepalive; /* Set SO_KEEPALIVE if non-zero. */
int active_expire_enabled; /* Can be disabled for testing purposes. */
size_t client_max_querybuf_len; /* Limit for client query buffer length */
int dbnum; /* Total number of configured DBs */
int daemonize; /* True if running as a daemon */
// 客户端输出缓冲区大小限制
// 数组的元素有 REDIS_CLIENT_LIMIT_NUM_CLASSES 个
// 每个代表一类客户端:普通、从服务器、pubsub,诸如此类
clientBufferLimitsConfig client_obuf_limits[REDIS_CLIENT_LIMIT_NUM_CLASSES];
/* AOF persistence */
// AOF 状态(开启/关闭/可写)
int aof_state; /* REDIS_AOF_(ON|OFF|WAIT_REWRITE) */
// 所使用的 fsync 策略(每个写入/每秒/从不)
int aof_fsync; /* Kind of fsync() policy */
char *aof_filename; /* Name of the AOF file */
int aof_no_fsync_on_rewrite; /* Don't fsync if a rewrite is in prog. */
int aof_rewrite_perc; /* Rewrite AOF if % growth is > M and... */
off_t aof_rewrite_min_size; /* the AOF file is at least N bytes. */
// 最后一次执行 BGREWRITEAOF 时, AOF 文件的大小
off_t aof_rewrite_base_size; /* AOF size on latest startup or rewrite. */
// AOF 文件的当前字节大小
off_t aof_current_size; /* AOF current size. */
int aof_rewrite_scheduled; /* Rewrite once BGSAVE terminates. */
// 负责进行 AOF 重写的子进程 ID
pid_t aof_child_pid; /* PID if rewriting process */
// AOF 重写缓存链表,链接着多个缓存块
list *aof_rewrite_buf_blocks; /* Hold changes during an AOF rewrite. */
// AOF 缓冲区
sds aof_buf; /* AOF buffer, written before entering the event loop */
// AOF 文件的描述符
int aof_fd; /* File descriptor of currently selected AOF file */
// AOF 的当前目标数据库
int aof_selected_db; /* Currently selected DB in AOF */
// 推迟 write 操作的时间
time_t aof_flush_postponed_start; /* UNIX time of postponed AOF flush */
// 最后一直执行 fsync 的时间
time_t aof_last_fsync; /* UNIX time of last fsync() */
time_t aof_rewrite_time_last; /* Time used by last AOF rewrite run. */
// AOF 重写的开始时间
time_t aof_rewrite_time_start; /* Current AOF rewrite start time. */
// 最后一次执行 BGREWRITEAOF 的结果
int aof_lastbgrewrite_status; /* REDIS_OK or REDIS_ERR */
// 记录 AOF 的 write 操作被推迟了多少次
unsigned long aof_delayed_fsync; /* delayed AOF fsync() counter */
// 指示是否需要每写入一定量的数据,就主动执行一次 fsync()
int aof_rewrite_incremental_fsync;/* fsync incrementally while rewriting? */
int aof_last_write_status; /* REDIS_OK or REDIS_ERR */
int aof_last_write_errno; /* Valid if aof_last_write_status is ERR */
/* RDB persistence */
// 自从上次 SAVE 执行以来,数据库被修改的次数
long long dirty; /* Changes to DB from the last save */
// BGSAVE 执行前的数据库被修改次数
long long dirty_before_bgsave; /* Used to restore dirty on failed BGSAVE */
// 负责执行 BGSAVE 的子进程的 ID
// 没在执行 BGSAVE 时,设为 -1
pid_t rdb_child_pid; /* PID of RDB saving child */
struct saveparam *saveparams; /* Save points array for RDB */
int saveparamslen; /* Number of saving points */
char *rdb_filename; /* Name of RDB file */
int rdb_compression; /* Use compression in RDB? */
int rdb_checksum; /* Use RDB checksum? */
// 最后一次完成 SAVE 的时间
time_t lastsave; /* Unix time of last successful save */
// 最后一次尝试执行 BGSAVE 的时间
time_t lastbgsave_try; /* Unix time of last attempted bgsave */
// 最近一次 BGSAVE 执行耗费的时间
time_t rdb_save_time_last; /* Time used by last RDB save run. */
// 数据库最近一次开始执行 BGSAVE 的时间
time_t rdb_save_time_start; /* Current RDB save start time. */
// 最后一次执行 SAVE 的状态
int lastbgsave_status; /* REDIS_OK or REDIS_ERR */
int stop_writes_on_bgsave_err; /* Don't allow writes if can't BGSAVE */
/* Propagation of commands in AOF / replication */
redisOpArray also_propagate; /* Additional command to propagate. */
/* Logging */
char *logfile; /* Path of log file */
int syslog_enabled; /* Is syslog enabled? */
char *syslog_ident; /* Syslog ident */
int syslog_facility; /* Syslog facility */
/* Replication (master) */
int slaveseldb; /* Last SELECTed DB in replication output */
// 全局复制偏移量(一个累计值)
long long master_repl_offset; /* Global replication offset */
// 主服务器发送 PING 的频率
int repl_ping_slave_period; /* Master pings the slave every N seconds */
// backlog 本身
char *repl_backlog; /* Replication backlog for partial syncs */
// backlog 的长度
long long repl_backlog_size; /* Backlog circular buffer size */
// backlog 中数据的长度
long long repl_backlog_histlen; /* Backlog actual data length */
// backlog 的当前索引
long long repl_backlog_idx; /* Backlog circular buffer current offset */
// backlog 中可以被还原的第一个字节的偏移量
long long repl_backlog_off; /* Replication offset of first byte in the
backlog buffer. */
// backlog 的过期时间
time_t repl_backlog_time_limit; /* Time without slaves after the backlog
gets released. */
// 距离上一次有从服务器的时间
time_t repl_no_slaves_since; /* We have no slaves since that time.
Only valid if server.slaves len is 0. */
// 是否开启最小数量从服务器写入功能
int repl_min_slaves_to_write; /* Min number of slaves to write. */
// 定义最小数量从服务器的最大延迟值
int repl_min_slaves_max_lag; /* Max lag of <count> slaves to write. */
// 延迟良好的从服务器的数量
int repl_good_slaves_count; /* Number of slaves with lag <= max_lag. */
/* Replication (slave) */
// 主服务器的验证密码
char *masterauth; /* AUTH with this password with master */
// 主服务器的地址
char *masterhost; /* Hostname of master */
// 主服务器的端口
int masterport; /* Port of master */
// 超时时间
int repl_timeout; /* Timeout after N seconds of master idle */
// 主服务器所对应的客户端
redisClient *master; /* Client that is master for this slave */
// 被缓存的主服务器,PSYNC 时使用
redisClient *cached_master; /* Cached master to be reused for PSYNC. */
int repl_syncio_timeout; /* Timeout for synchronous I/O calls */
// 复制的状态(服务器是从服务器时使用)
int repl_state; /* Replication status if the instance is a slave */
// RDB 文件的大小
off_t repl_transfer_size; /* Size of RDB to read from master during sync. */
// 已读 RDB 文件内容的字节数
off_t repl_transfer_read; /* Amount of RDB read from master during sync. */
// 最近一次执行 fsync 时的偏移量
// 用于 sync_file_range 函数
off_t repl_transfer_last_fsync_off; /* Offset when we fsync-ed last time. */
// 主服务器的套接字
int repl_transfer_s; /* Slave -> Master SYNC socket */
// 保存 RDB 文件的临时文件的描述符
int repl_transfer_fd; /* Slave -> Master SYNC temp file descriptor */
// 保存 RDB 文件的临时文件名字
char *repl_transfer_tmpfile; /* Slave-> master SYNC temp file name */
// 最近一次读入 RDB 内容的时间
time_t repl_transfer_lastio; /* Unix time of the latest read, for timeout */
int repl_serve_stale_data; /* Serve stale data when link is down? */
// 是否只读从服务器?
int repl_slave_ro; /* Slave is read only? */
// 连接断开的时长
time_t repl_down_since; /* Unix time at which link with master went down */
// 是否要在 SYNC 之后关闭 NODELAY ?
int repl_disable_tcp_nodelay; /* Disable TCP_NODELAY after SYNC? */
// 从服务器优先级
int slave_priority; /* Reported in INFO and used by Sentinel. */
// 本服务器(从服务器)当前主服务器的 RUN ID
char repl_master_runid[REDIS_RUN_ID_SIZE+1]; /* Master run id for PSYNC. */
// 初始化偏移量
long long repl_master_initial_offset; /* Master PSYNC offset. */
/* Replication script cache. */
// 复制脚本缓存
// 字典
dict *repl_scriptcache_dict; /* SHA1 all slaves are aware of. */
// FIFO 队列
list *repl_scriptcache_fifo; /* First in, first out LRU eviction. */
// 缓存的大小
int repl_scriptcache_size; /* Max number of elements. */
/* Synchronous replication. */
list *clients_waiting_acks; /* Clients waiting in WAIT command. */
int get_ack_from_slaves; /* If true we send REPLCONF GETACK. */
/* Limits */
int maxclients; /* Max number of simultaneous clients */
unsigned long long maxmemory; /* Max number of memory bytes to use */
int maxmemory_policy; /* Policy for key eviction */
int maxmemory_samples; /* Pricision of random sampling */
/* Blocked clients */
unsigned int bpop_blocked_clients; /* Number of clients blocked by lists */
list *unblocked_clients; /* list of clients to unblock before next loop */
list *ready_keys; /* List of readyList structures for BLPOP & co */
/* Sort parameters - qsort_r() is only available under BSD so we
* have to take this state global, in order to pass it to sortCompare() */
int sort_desc;
int sort_alpha;
int sort_bypattern;
int sort_store;
/* Zip structure config, see redis.conf for more information */
size_t hash_max_ziplist_entries;
size_t hash_max_ziplist_value;
size_t list_max_ziplist_entries;
size_t list_max_ziplist_value;
size_t set_max_intset_entries;
size_t zset_max_ziplist_entries;
size_t zset_max_ziplist_value;
size_t hll_sparse_max_bytes;
time_t unixtime; /* Unix time sampled every cron cycle. */
long long mstime; /* Like 'unixtime' but with milliseconds resolution. */
/* Pubsub */
// 字典,键为频道,值为链表
// 链表中保存了所有订阅某个频道的客户端
// 新客户端总是被添加到链表的表尾
dict *pubsub_channels; /* Map channels to list of subscribed clients */
// 这个链表记录了客户端订阅的所有模式的名字
list *pubsub_patterns; /* A list of pubsub_patterns */
int notify_keyspace_events; /* Events to propagate via Pub/Sub. This is an
xor of REDIS_NOTIFY... flags. */
/* Cluster */
int cluster_enabled; /* Is cluster enabled? */
mstime_t cluster_node_timeout; /* Cluster node timeout. */
char *cluster_configfile; /* Cluster auto-generated config file name. */
struct clusterState *cluster; /* State of the cluster */
int cluster_migration_barrier; /* Cluster replicas migration barrier. */
/* Scripting */
// Lua 环境
lua_State *lua; /* The Lua interpreter. We use just one for all clients *
// 复制执行 Lua 脚本中的 Redis 命令的伪客户端
redisClient *lua_client; /* The "fake client" to query Redis from Lua */
// 当前正在执行 EVAL 命令的客户端,如果没有就是 NULL
redisClient *lua_caller; /* The client running EVAL right now, or NULL */
// 一个字典,值为 Lua 脚本,键为脚本的 SHA1 校验和
dict *lua_scripts; /* A dictionary of SHA1 -> Lua scripts */
// Lua 脚本的执行时限
mstime_t lua_time_limit; /* Script timeout in milliseconds */
// 脚本开始执行的时间
mstime_t lua_time_start; /* Start time of script, milliseconds time */
// 脚本是否执行过写命令
int lua_write_dirty; /* True if a write command was called during the
execution of the current script. */
// 脚本是否执行过带有随机性质的命令
int lua_random_dirty; /* True if a random command was called during the
execution of the current script. */
// 脚本是否超时
int lua_timedout; /* True if we reached the time limit for script
execution. */
// 是否要杀死脚本
int lua_kill; /* Kill the script if true. */
/* Assert & bug reporting */
char *assert_failed;
char *assert_file;
int assert_line;
int bug_report_start; /* True if bug report header was already logged. */
int watchdog_period; /* Software watchdog period in ms. 0 = off */
};
- Redis优缺点:【Redis本质上
是一个Key-Value类型的内存数据库
,很像Memcached,整个数据库加载在内存当中操作,定期通过异步操作把数据库中的数据flush到硬盘上进行保存
。】
- 为什么要用Redis做缓存?或者说Redis做缓存的优点
- 从高并发上来说:直接操作缓存能够承受的请求是远远大于直接访问数据库的,所以我们可以考虑把数据库中的部分数据转移到缓存中去,这样用户的一部分请求会直接到缓存这里而不用经过数据库。
- 从高性能上来说:用户第一次访问数据库中的某些数据。 因为是从硬盘上读取的所以这个过程会比较慢。将该用户访问的数据存在缓存中,下一次再访问这些数据的时候就可以直接从缓存中获取了。操作缓存就是直接操作内存,所以速度相当快。如果数据库中的对应数据改变的之后,同步改变缓存中相应的数据。
- Redis配置文件:redis.conf(启动就是靠这个配置文件)
- 单位对大小写不敏感
- 引入其他配置文件
- 后面集群会在这里修改端口信息哦
- Redis默认不是后台启动(也就是以一个守护进程的方式开启Redis),所以咱们为了方便修改一下配置文件让Redis可以在后台启动
- 日志相关
- 数据库数量
- 快照配置(持久化(在规定的时间内执行了多少次操作就会进行持久化到文件或者说生成快照)那里需要配置)。持久化那里需要咱们自己配置这三行参数
- 先进入配置文件所在地(记得尽量别动/opt/re…/redis.conf,用咱们复制过来的),改好配置文件后:用这个改好的配置文件启动redis-server:redis-server Redisconfig/redis.conf
- 启动好之后,用redis-cli连接,默认是localhost不用写,端口是6379
- 确认一下咱们的两个redis的服务器和客户端两个进程都开启了
- 单位对大小写不敏感
- 是通过这个文件来进行性能测试的
- 举个例子,测试一下有100个并发连接,每个连接有100000个请求:redis-benchmark -h localhost -p 6379 -c 100 -n 100000
- 举个例子,测试一下有100个并发连接,每个连接有100000个请求:redis-benchmark -h localhost -p 6379 -c 100 -n 100000
- Redis有16个数据库,默认使用的是第0个,可以用SELECT进行切换数据库
高性能MySQL
mysql技术内幕
巨人的肩膀:https://www.javalearn.cn
B站各位大佬
Redis设计与实现