深入了解分布式锁 导学篇

Posted 南方有东靡

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了深入了解分布式锁 导学篇相关的知识,希望对你有一定的参考价值。

文章简介

该文章基于超卖为为主线 ,解决在多线程的情况下解决超卖问题的解决方案 ,并且对其各个解决方案方案的优缺点进行分析。

文章内容 介绍

该文章刚开始以超卖问题为主线 先介绍单机本地储存情况下通过JVM本地锁去解决超卖问题,接着深入企业场景 数据在mysql 的情况下如何解决高并发对mysql数据库中进行有序操作防止出现脏读的问题,接着引入 非关系型数据情况下 如何处理集群 服务和线程之间 操作有序性的问题 通过redis 乐观锁和redis hash+lua 脚本 zookeeper 节点性质去处理。

学习成果

可以一定程度上基本的分布式锁的原理和使用有着较为深入的理解 熟练使用redis 和 zookeeper 进行分布式锁的实现 并且对高并发下超卖问题有着深入理解。

文章重点

该文章主要以以下几大方面 解决超卖问题的解决方案 :
1、基于JVM本地机制:基于Lock和synchorinzed 关键字 实现在单机且无数据库情况下解决超卖问题。
2、基于Mysql的锁机制:悲观锁机制、乐观锁机制 利用mysql 基于save delete update insert 等操作的原子性进行解决超卖问题。
3、基于redis 本身的乐观锁机制解决超卖问题 基于exec watch mulitic 等命令行为基础解决超卖的问题。
4、 在多服务情况下redis 分布式解决 超卖 基于 redisson 框架实现分布式情况下超卖 可重入的问题,基于hash+lua 脚本手动实现分布式锁的加锁 解锁和可重入锁 自动续期的问题。
5、基于Zookeeper 原始框架下 实现分布式情况下超卖问题。 通过创造临时节点不可重复原理实现自旋锁, 基于临时可序列化节点+监听机制实现Zookeeper的堵塞锁。
6、基于Mysql实现分布式锁(企业没有用过)通过id 加lockname 进行锁的排他,通过设置ThreadId 和 serverd 进行具体业务记录 通过locationTime进行定时任务的记录。

技术构成

1、环境要求:jdk1.8,Maven3.0+
2、开发工具 idea nginx
3、 测试工具 :jmeter
4、该项目Maven 开发环境

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.example</groupId>
    <artifactId>distribution-Lock-Learning</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>distribution-Lock-Learning</name>
    <description>distribution-Lock-Learning</description>
    <properties>
        <java.version>1.8</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.5.1</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <dependency>
            <groupId>org.redisson</groupId>
            <artifactId>redisson</artifactId>
            <version>3.16.1</version>
        </dependency>
        <dependency>
            <groupId>net.coobird</groupId>
            <artifactId>thumbnailator</artifactId>
            <version>0.4.11</version>
        </dependency>
        <dependency>
            <groupId>commons-lang</groupId>
            <artifactId>commons-lang</artifactId>
            <version>2.6</version>
        </dependency>
        <dependency>
            <groupId>org.apache.zookeeper</groupId>
            <artifactId>zookeeper</artifactId>
            <version>3.7.0</version>
            <exclusions>
                <exclusion>
                    <groupId>org.slf4j</groupId>
                    <artifactId>slf4j-log4j12</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.apache.curator</groupId>
            <artifactId>curator-framework</artifactId>
            <version>4.3.0</version>
            <exclusions>
                <exclusion>
                    <groupId>org.apache.zookeeper</groupId>
                    <artifactId>zookeeper</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.apache.curator</groupId>
            <artifactId>curator-recipes</artifactId>
            <version>4.3.0</version>
            <exclusions>
                <exclusion>
                    <groupId>org.apache.zookeeper</groupId>
                    <artifactId>zookeeper</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
    </dependencies>
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-dependencies</artifactId>
            <version>2.2.2.RELEASE</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>8</source>
                    <target>8</target>
                </configuration>
            </plugin>
        </plugins>
    </build>
    <repositories>
        <repository>
            <id>spring-milestones</id>
            <name>Spring Milestones</name>
            <url>https://repo.spring.io/milestone</url>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </repository>
        <repository>
            <id>spring-snapshots</id>
            <name>Spring Snapshots</name>
            <url>https://repo.spring.io/snapshot</url>
            <releases>
                <enabled>false</enabled>
            </releases>
        </repository>
    </repositories>
    <pluginRepositories>
        <pluginRepository>
            <id>spring-milestones</id>
            <name>Spring Milestones</name>
            <url>https://repo.spring.io/milestone</url>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </pluginRepository>
        <pluginRepository>
            <id>spring-snapshots</id>
            <name>Spring Snapshots</name>
            <url>https://repo.spring.io/snapshot</url>
            <releases>
                <enabled>false</enabled>
            </releases>
        </pluginRepository>
    </pluginRepositories>

</project>

用Kotlin撸一个图片压缩插件ImageSlimming-导学篇

简述: 很久没有发布Kotlin的实战相关的内容,这段时间在折腾Intellij IDEA的插件开发,折腾出了几个小插件,因为最近公司业务分离,原来堆在基础业务那边模块,都以模块的形式抽离出来,独立仓库管理。那么就是各种打包,jenkins打包配置模块特别麻烦,所以想着是否可以开发一个AndroidStudio插件,我可以写代码和构建发布包同时进行,想想都美滋滋,所以才去研究了下插件的开发。摸清插件开发套路后,其实也觉得挺简单,然后发现很多地方都可以用插件自动化实现,顿时有种发现新大陆赶脚。这次我要讲是如何从零开始,使用Kotlin撸一个AndroidStudio图片压缩插件,本系列文章总三篇:《用Kotlin撸一个图片压缩插件ImageSlimming-导学篇》、《用Kotlin撸一个图片压缩插件ImageSlimming-插件基础篇》、《用Kotlin撸一个图片压缩插件ImageSlimming-实战篇》

一、为什么要撸一个图片压缩插件?

我们在项目开发过程中常会使用图片,一般开发者都不会直接把设计切的图片放入到项目中,而是会去压缩一下,那么一般会去TinyPng网页端压缩一遍,你一般会先把要压缩的图片拖进去,然后又一张张把图片点击下载下来,是不是感觉特别的浪费时间,是不是需要把浪费的时间省下来,然后就愉快地早点下班啦。如果你还没有使用过TinyPng,那么这个插件也许适合你。

用Kotlin撸一个图片压缩插件ImageSlimming-导学篇(一)

然后这段时间正研究插件,所以决定试试,其实很简单的。因为TinyPng提供develop api,可以方便实现图片压缩。这次插件也就是利用了它的API开发的。

二、插件的基本描述

ImageSlimming是一个基于TinyPng API开发的图片压缩的IDEA工具插件,采用的是Kotlin语言开发以及Java Swing框架设计UI界面。可运行在AndroidStudio,Intellij IDEA,WebStorm等JetBrains全家桶系列IDE中。

三、插件支持的功能

  • 1、支持整个目录中的图片批量压缩,只需要指定图片源目录和压缩的输出目录即可

  • 2、支持单张或者选定多张图片文件进行压缩

  • 3、支持png,jpg格式图片

  • 4、支持输入目录和输出目录二次选择功能,减少繁琐指定相同的目录

  • 5、支持指定输入文件的前缀,也即是批量文件添加前缀名,以及前缀名二次选择功能

  • 6、图片压缩过程中,仍然继续coding, 工作并行执行

四、插件开发使用到的技术点

  • 1、Intellij Idea 插件开发基础知识

  • 2、插件开发中执行一个后台线程任务Task.Backgroundable的使用

  • 3、Intellij Idea open api 的使用

  • 4、Kotlin 开发基础知识

  • 5、Kotlin中扩展函数的封装

  • 6、Kotlin中Lambda表达式的使用

  • 7、Kotlin中函数式API的使用

  • 8、Kotlin中IO操作API的使用

  • 9、Java中Swing UI框架的基本使用

  • 10、TinyPng API基本使用

五、插件的使用步骤

  • 1、首先,按照Plugin通用安装方式,安装好对应的插件,可以直接在jetbrains仓库中搜索ImageSlimming,安装重启即可。
    重启后发现有如图插件,就说明安装成功。

    用Kotlin撸一个图片压缩插件ImageSlimming-导学篇(一)

  • 2、然后点击插件,第一次需要你填入TinyPng APIKEY,由于插件图片压缩主要借助于TinyPng Api, 所以需要使用者去TinyPng官网申请 https://tinypng.com/developers

用Kotlin撸一个图片压缩插件ImageSlimming-导学篇(一)

  • 3、输入申请到ApiKey后,插件会自动验证KEY的合法性,检测通过后会弹出压缩图片界面

用Kotlin撸一个图片压缩插件ImageSlimming-导学篇(一)

  • 4、选择源目录也就是原图片目录,输出目录也就是压缩后图片存放目录,当然也可以指定特定某张或某些图片文件作为输入源,

用Kotlin撸一个图片压缩插件ImageSlimming-导学篇(一)

  • 5、是否指定输出文件前缀名,该功能主要适用于在Android中多模块开发的时候,每个模块图片资源名不能重复,所以每个模块图片前缀不一样,这里可以指定输出文件前缀。

用Kotlin撸一个图片压缩插件ImageSlimming-导学篇(一)

  • 6、点击OK就开始压缩了,此时压缩过程你可以继续你的coding,最后压缩完毕会以对话框提示。

用Kotlin撸一个图片压缩插件ImageSlimming-导学篇(一)

  • 7、压缩结果

用Kotlin撸一个图片压缩插件ImageSlimming-导学篇(一)

  • 8、为了减少指定输入输出目录次数以及文件前缀的次数,会把每次用户使用过的目录给缓存起来,以及下次直接选择使用,也就是前面说的二次选择功能。

六、插件源码和插件包下载

插件包下载: https://github.com/BayMikyou/ImageSlimming/blob/feature-develop/ImageSlimming.zip




以上是关于深入了解分布式锁 导学篇的主要内容,如果未能解决你的问题,请参考以下文章

用Kotlin撸一个图片压缩插件ImageSlimming-导学篇

1-1 Python服务端工程师面试指导-课程导学篇

带你深入理解 Redis分布式锁...

Go语言开发分布式任务调度 轻松搞定高性能Crontab

这才叫细:带你深入理解Redis分布式锁

Java 中利用 redis 实现一个分布式锁服务