<?xml version="1.0" encoding="utf-8" ?><rss version="2.0"><channel><title><![CDATA[qq_45966902的博客]]></title><description><![CDATA[]]></description><link>https://blog.youkuaiyun.com/qq_45966902</link><language>zh-cn</language><generator>https://blog.youkuaiyun.com/</generator><copyright><![CDATA[Copyright &copy; qq_45966902]]></copyright><item><title><![CDATA[大型电商网站设计——商品详情页面静态化]]></title><link>https://blog.youkuaiyun.com/qq_45966902/article/details/123171581</link><guid>https://blog.youkuaiyun.com/qq_45966902/article/details/123171581</guid><author>qq_45966902</author><pubDate>Sun, 27 Feb 2022 22:30:32 +0800</pubDate><description><![CDATA[分布式系统的cap理论首先把分布式系统中的三个特性进行了如下归纳：
1.一致性© : 在分布式系统中的所有数据备份，在同一时刻是否是同样的值(等同于所有节点访问同一份最新的数据副本)
2.可用性(A) : 在集群中一部分节点故障后，集群整体是否还能响应客户端的读写请求(对数据更新具备高可用性)
3.分区容错§ : 以实际效果而言，分区相当于对通信的时限要求。系统如果不能在时限内达成数据一致性，就意味着发生了分区的情况，必须就
当前操作在C和A之间做出选择。
应用数据静态化架构高性能单页web应用
在电商网站]]></description><category></category></item><item><title><![CDATA[Redis设计与实现（十）—— 哨兵]]></title><link>https://blog.youkuaiyun.com/qq_45966902/article/details/123082836</link><guid>https://blog.youkuaiyun.com/qq_45966902/article/details/123082836</guid><author>qq_45966902</author><pubDate>Wed, 23 Feb 2022 11:03:06 +0800</pubDate><description><![CDATA[哨兵的核心功能是主节点的自动故障转移

监控：哨兵会不断地检查主节点和从节点是否运作正常。
自动故障转移：当主节点不能正常工作时，哨兵会开始自动故障转移操作，它会将失效主节点的其中 一个从节点升级为新的主节点，并让其他从节点改为复制新的主节点。
配置提供者：客户端在初始化时，通过连接哨兵来获得当前Redis服务的主节点地址。
通知：哨兵可以将故障转移的结果发送给客户端。

在我们的哨兵架构中，主要会有两种节点组成：哨兵节点和数据节点：
哨兵节点：哨兵系统由一个或多个哨兵节点组成，哨兵节点是特殊的redis节]]></description><category></category></item><item><title><![CDATA[Redis设计与实现（九）—— 主从复制]]></title><link>https://blog.youkuaiyun.com/qq_45966902/article/details/123051874</link><guid>https://blog.youkuaiyun.com/qq_45966902/article/details/123051874</guid><author>qq_45966902</author><pubDate>Mon, 21 Feb 2022 18:14:10 +0800</pubDate><description><![CDATA[主从复制是值将一台Redis的数据，复制到另一台从节点上，数据的复制是单向的，只能由主节点到从节点
主从复制的作用：
- 数据冗余：主从复制实现数据的热备，是除了持久化之外的一种数据冗余方式
- 故障恢复：当主节点出现问题后，从节点可以提供服务，实现快速恢复
- 负载均衡：在主从复制的基础上，可以配合读写分离，然后可以由主节点提供写，从节点读，分担负载
- 高可用基石：集群等的基石

...]]></description><category></category></item><item><title><![CDATA[Redis设计与实现（八）—— 持久化]]></title><link>https://blog.youkuaiyun.com/qq_45966902/article/details/123051388</link><guid>https://blog.youkuaiyun.com/qq_45966902/article/details/123051388</guid><author>qq_45966902</author><pubDate>Mon, 21 Feb 2022 17:20:28 +0800</pubDate><description><![CDATA[为什么需要持久化？
因为Redis是内存数据库，数据都是存储在内存中，为了避免进程退出导致数据的永久丢失，需要定期将Redis中的数据以某种形式(数据或命令)从内存保存到硬盘；当下次Redis重启时，利用持久化文件实现数据恢复。除此之外，为了进行灾难备份，可以将持久化文件拷贝到一个远程位置。
Redis分为两种持久化机制，RDB和AOF
RDB将当前数据快照保存到硬盘，AOF则是将每次执行的写命令保存到硬盘（类似于MySQL的binlog）；由于AOF持久化的实时性更好，即当进程意外退出时丢失的数据更少，因]]></description><category></category></item><item><title><![CDATA[Redis设计与实现（七）—— 压缩列表]]></title><link>https://blog.youkuaiyun.com/qq_45966902/article/details/123048923</link><guid>https://blog.youkuaiyun.com/qq_45966902/article/details/123048923</guid><author>qq_45966902</author><pubDate>Mon, 21 Feb 2022 16:01:38 +0800</pubDate><description><![CDATA[压缩列表是 Redis 为了节约内存而开发的， 由一系列特殊编码的连续内存块组成的顺序型（sequential）数据结构。一个压缩列表可以包含任意多个节点（entry）， 每个节点可以保存一个字节数组或者一个整数值。如图所示

压缩列表构成

zlbytes：长度是4字节，用于记录整个压缩链表占用的内存字节数，在对压缩列表进行内存重分配， 或者计算 zlend 的位置时使用。
zltail：长度是4字节，记录压缩列表表尾节点距离压缩列表的起始地址有多少字节，根据这个偏移量，程序可以不用遍历就能确定表尾节点的]]></description><category></category></item><item><title><![CDATA[Redis设计与实现（六）—— 跳表]]></title><link>https://blog.youkuaiyun.com/qq_45966902/article/details/123048024</link><guid>https://blog.youkuaiyun.com/qq_45966902/article/details/123048024</guid><author>qq_45966902</author><pubDate>Mon, 21 Feb 2022 15:33:38 +0800</pubDate><description><![CDATA[跳表是一个空间换时间的一个结构，他会增加很多指针，利用指针来快速定位，解决了链表查询时间是O(N)的难题，跳表平均的查询时O(logN)，最坏是O(N)，N是跳表的长度，我们来看看他的实现

我们可以看到我们的跳表的整体实现结构，最左边的是zskiplist，包含了以下属性

head：指向跳表的头节点
tail：指向跳表的尾节点
level：记录跳表中最大层数
length：跳表的长度

typedef struct zskiplist {

    // 表头节点和表尾节点
    struct zsk]]></description><category></category></item><item><title><![CDATA[常见灾备技术]]></title><link>https://blog.youkuaiyun.com/qq_45966902/article/details/123037503</link><guid>https://blog.youkuaiyun.com/qq_45966902/article/details/123037503</guid><author>qq_45966902</author><pubDate>Sun, 20 Feb 2022 23:29:33 +0800</pubDate><description><![CDATA[一、系统可用性
要想理解异地多活，我们需要从架构设计的原则说起。
现如今，我们开发一个软件系统，对其要求越来越高，如果你了解一些「架构设计」的要求，就知道一个好的软件架构应该遵循以下 3 个原则：

高性能
高可用
易扩展

其中，高性能意味着系统拥有更大流量的处理能力，更低的响应延迟。例如 1 秒可处理 10W 并发请求，接口响应时间 5 ms 等等。
易扩展表示系统在迭代新功能时，能以最小的代价去扩展，系统遇到流量压力时，可以在不改动代码的前提下，去扩容系统。
而「高可用」这个概念，看起来很抽象，怎么理]]></description><category></category></item><item><title><![CDATA[Redis设计与实现（五）—— 哈希表]]></title><link>https://blog.youkuaiyun.com/qq_45966902/article/details/123030131</link><guid>https://blog.youkuaiyun.com/qq_45966902/article/details/123030131</guid><author>qq_45966902</author><pubDate>Sun, 20 Feb 2022 14:00:44 +0800</pubDate><description><![CDATA[一、哈希表概述
在Redis中，哈希表用的很多，首先是我们的数据库，数据库表采用的就是两张哈希表，用于扩容转化，然后我们的数据类型，像Hash和Set两种类型都有Hash的编码类型，然后接下来说说Hash表
二、哈希表结构
哈希表
typedef struct dictht {
    // 哈希表数组
    dictEntry **table;

    // 哈希表大小
    unsigned long size;

    // 哈希表大小掩码，用于计算索引值
    // 总是等于 size -]]></description><category></category></item><item><title><![CDATA[Redis设计与实现（四）—— 链表]]></title><link>https://blog.youkuaiyun.com/qq_45966902/article/details/123029968</link><guid>https://blog.youkuaiyun.com/qq_45966902/article/details/123029968</guid><author>qq_45966902</author><pubDate>Sun, 20 Feb 2022 13:39:13 +0800</pubDate><description><![CDATA[我们的链表编码在Redis的List中有使用到，学过java或者数据结构的人很容易理解，Redis中就是做的一个双向链表，包含头结点，尾节点，然后有ListNode作为节点的描述
LinkedList结构
ListNode
typedef struct listNode {

    // 前置节点
    struct listNode *prev;

    // 后置节点
    struct listNode *next;

    // 节点的值
    void *value;

} listN]]></description><category></category></item><item><title><![CDATA[Redis设计与实现（三）—— SDS]]></title><link>https://blog.youkuaiyun.com/qq_45966902/article/details/123028298</link><guid>https://blog.youkuaiyun.com/qq_45966902/article/details/123028298</guid><author>qq_45966902</author><pubDate>Sun, 20 Feb 2022 13:16:01 +0800</pubDate><description><![CDATA[一、SDS概述
在Redis中，String应该是用的最多的类型了，我们的Key是String类型，由SDS实现，String有SDS，raw，int三种，我们可以把string看成抽象类，然后SDS，raw，int分别是实现类，因为C语言的字符串中有很多使用受限的地方，所以Redis提出了动态字符串SDS
二、SDS结构
struct sdshdr {
    // 记录 buf 数组中已使用字节的数量
    // 等于 SDS 所保存字符串的长度
    int len;

    // 记录 buf]]></description><category></category></item><item><title><![CDATA[Redis设计与实现（二）—— RedisObject]]></title><link>https://blog.youkuaiyun.com/qq_45966902/article/details/123028094</link><guid>https://blog.youkuaiyun.com/qq_45966902/article/details/123028094</guid><author>qq_45966902</author><pubDate>Sun, 20 Feb 2022 11:03:55 +0800</pubDate><description><![CDATA[一、概述
Redis提供了多种基本数据类型和高级的数据类型，然后每种都有多种实现，Redis自己内部会进行判断应该使用哪种编码，当我们的数据放入Redis后，会被包装成RedisObject，然后存入，来看看RedisObject的结构吧
二、RedisObject结构
当我们执行了set hello world的时候，会产生如下的结构

dictEntry：Redis的数据库是一张Hash表，然后里面会包含键值对，可以简单理解为java的HashMap，然后他中间包含了指向Key和Value的指针，以及下]]></description><category></category></item><item><title><![CDATA[Redis设计与实现（一）——内存模型]]></title><link>https://blog.youkuaiyun.com/qq_45966902/article/details/123027926</link><guid>https://blog.youkuaiyun.com/qq_45966902/article/details/123027926</guid><author>qq_45966902</author><pubDate>Sun, 20 Feb 2022 10:48:20 +0800</pubDate><description><![CDATA[一、Redis内存统计
Redis是一个基于内存的缓存中间件，所以，我们可能需要去查看Redis的内存使用情况，我们可以使用info命令来查看内存占用
info memory
info命令可以显示redis服务器的许多信息，包括服务器基本信息、CPU、内存、持久化、客户端连接信息等等；memory是参数，表示只显示内存相关的信息。
二、Redis内存划分
Redis是一个基于内存的中间件，所以对于我们需要存储的数据，肯定是需要占用内存的，但是Redis是一个进程，是在不断运行的，所以肯定也会有其他需要的内存]]></description><category></category></item><item><title><![CDATA[来看看缓存]]></title><link>https://blog.youkuaiyun.com/qq_45966902/article/details/122938425</link><guid>https://blog.youkuaiyun.com/qq_45966902/article/details/122938425</guid><author>qq_45966902</author><pubDate>Sat, 19 Feb 2022 21:31:49 +0800</pubDate><description><![CDATA[什么是缓存？
缓存时对原始数据的一个复制的副本，我们一般将数据缓存起来以便于备用，常常用来加速读取
缓存有什么用？
用来提升读取的速度，优化系统的吞吐量
以我们的java和mysql之间进行交互为例子，我们从mysql中读取数据，需要进行IO，如果忽略mysql自己的Buffer pool中的缓存，把mysql的每次读取都看成一次IO，那么当我们多次查询同一个数据的时候，需要进行N次IO，IO性能有限，所以我们引入本地缓存或者分布式缓存，不再从磁盘上去进行IO，而是从内存中读取，内存读取比IO普遍要快，对于]]></description><category></category></item><item><title><![CDATA[多态的原理]]></title><link>https://blog.youkuaiyun.com/qq_45966902/article/details/122893110</link><guid>https://blog.youkuaiyun.com/qq_45966902/article/details/122893110</guid><author>qq_45966902</author><pubDate>Sat, 12 Feb 2022 15:27:08 +0800</pubDate><description><![CDATA[首先，在了解多态的原理之前，先了解下面的这些概念来帮助理解
方法区：在JVM内存模型中，主要的部分之一，和堆区一样，是线程共享的区域，一般用来存放类信息，常量，静态变量，即时代码编译器编译后的代码

...]]></description><category></category></item><item><title><![CDATA[深入理解JAVA反射]]></title><link>https://blog.youkuaiyun.com/qq_45966902/article/details/122883183</link><guid>https://blog.youkuaiyun.com/qq_45966902/article/details/122883183</guid><author>qq_45966902</author><pubDate>Fri, 11 Feb 2022 17:35:28 +0800</pubDate><description><![CDATA[深入理解JAVA反射
JAVA反射机制是在运行状态中，对于任意一个类，都能够知道这个类的所有属性和方法，对于任意一个对象，都能够调用它的任意一个方法和属性。这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
下面是反射的一段简单的使用
public class Relections {
    public static void main(String[] args) throws Exception {
		//获取Class的三种方法
        //在这里会去利用Clas]]></description><category></category></item><item><title><![CDATA[Semaphore源码解析]]></title><link>https://blog.youkuaiyun.com/qq_45966902/article/details/122880498</link><guid>https://blog.youkuaiyun.com/qq_45966902/article/details/122880498</guid><author>qq_45966902</author><pubDate>Fri, 11 Feb 2022 15:24:53 +0800</pubDate><description><![CDATA[Semaphore源码解析
简介
Semaphore是常用的同步工具之一，我们设置n，代表同一时间最多只有n个线程在访问
这个工具依赖AQS实现，所以在看源码前推荐先去看AQS的介绍，方便理解
public class SemaphoneTest {
	private Semaphore semaphore = new Semaphore(5);
	private ThreadPoolExecutor executor = new ThreadPoolExecutor(10, 15, 60, TimeUni]]></description><category></category></item><item><title><![CDATA[阻塞队列（三）—— LinkedBlockingDeque源码]]></title><link>https://blog.youkuaiyun.com/qq_45966902/article/details/122878024</link><guid>https://blog.youkuaiyun.com/qq_45966902/article/details/122878024</guid><author>qq_45966902</author><pubDate>Fri, 11 Feb 2022 14:23:46 +0800</pubDate><description><![CDATA[标题LinkedBlockingDeque源码
简介
LinkedBlockingDeque是一个双端队列，可以消费队头以及队尾的元素，我们可以设定最大容量，但是设定好后不可改变，因为被final修饰了，然后没有设置的话默认是Integer的最大值，只有一把锁和两个条件队列
下面来看看源码
源码
首先是重要内部类
	//Node节点
    static final class Node&lt;E&gt; {
        //元素value
        E item;

        //前继节点]]></description><category></category></item><item><title><![CDATA[阻塞队列（二）——LinkedBlockingQueue源码]]></title><link>https://blog.youkuaiyun.com/qq_45966902/article/details/122874589</link><guid>https://blog.youkuaiyun.com/qq_45966902/article/details/122874589</guid><author>qq_45966902</author><pubDate>Fri, 11 Feb 2022 10:58:21 +0800</pubDate><description><![CDATA[标题LinkedBlockingQueue源码
简介
LinkedBlockingQueue是一个

基于单向链表实现的阻塞队列，
是先进先出的，
然后至少包含一个元素，
同时不支持null值的元素，
持有两把锁，分别用于管控队头出队，队尾入队

然后来看他的源码
静态内部类
	//静态内部类
    static class Node&lt;E&gt; {
        //元素
        E item;

        //下一个Node节点
        Node&lt;E&gt; nex]]></description><category></category></item><item><title><![CDATA[线程池源码解析]]></title><link>https://blog.youkuaiyun.com/qq_45966902/article/details/122855479</link><guid>https://blog.youkuaiyun.com/qq_45966902/article/details/122855479</guid><author>qq_45966902</author><pubDate>Thu, 10 Feb 2022 14:53:25 +0800</pubDate><description><![CDATA[线程池源码解析
线程池的作用
一方面当执行大量异步任务时候线程池能够提供较好的性能，在不使用线程池的时候，每当需要执行异步任务时候是直接 new 一线程进行运行，而线程的创建和销毁是需要开销的。使用线程池时候，线程池里面的线程是可复用的，不会每次执行异步任务时候都重新创建和销毁线程。
另一方面线程池提供了一种资源限制和管理的手段，比如可以限制线程的个数，动态新增线程等，每个 ThreadPoolExecutor 也保留了一些基本的统计数据，比如当前线程池完成的任务数目等。
ThreadPoolExecuto]]></description><category></category></item><item><title><![CDATA[CountDownLatch源码解析]]></title><link>https://blog.youkuaiyun.com/qq_45966902/article/details/122843295</link><guid>https://blog.youkuaiyun.com/qq_45966902/article/details/122843295</guid><author>qq_45966902</author><pubDate>Wed, 09 Feb 2022 15:49:13 +0800</pubDate><description><![CDATA[CountDownLatch源码解析
CountDownLatch 允许一个或多个线程等待其他线程完成操作。
使用示例
public class CountDownLatchTest {

    public static void main(String[] args) {
        final CountDownLatch latch = new CountDownLatch(2);
        System.out.println("主线程开始执行…… ……");
        //第一]]></description><category></category></item></channel></rss>