• Dubbo+Zookeeper


    如果产品服务的业务量不是很大,业务又不是特别繁杂,功能模块的拆分颗粒度就不需要太细,也就没必要上微服务。因为微服务的运维治理复杂度及服务器资源开销代价是难以想象的。

    本编简述下如何使用Dubbo+Zookeeper即可实现传统的分布式服务,并且支持高并发高可用场景下的动态扩容。


    有关Dubbo的介绍,就无需多言了,它是一款高性能、轻量级的开源Java RPC框架(Remote Procedure Call Protocol 远程过程调用协议),它提供了三大核心能力:面向接口的远程方法调用,智能容错和负载均衡,以及服务自动注册和发现。

    准备工作:

    1. 搭建springboot脚手架并成功运行,可参考历史分享springboot+mybatis

    2. 启动Zookeeper服务(作为Dubbo的服务注册协调中心)(搭建配置ZK服务,后续会在运维章节另行讲述)

    1. maven添加Dubbo及ZK依赖

    <properties>    <zk-curator.version>4.0.1zk-curator.version>properties>    <dependencies>        <dependency>        <groupId>com.alibaba.bootgroupId>        <artifactId>dubbo-spring-boot-starterartifactId>        <version>0.2.0version>    dependency>            <dependency>        <groupId>org.apache.zookeepergroupId>        <artifactId>zookeeperartifactId>        <version>3.4.13version>    dependency>    <dependency>        <groupId>com.github.sgroschupfgroupId>        <artifactId>zkclientartifactId>        <version>0.1version>    dependency>            <dependency>        <groupId>org.apache.curatorgroupId>        <artifactId>curator-frameworkartifactId>        <version>${zk-curator.version}version>    dependency>    <dependency>        <groupId>org.apache.curatorgroupId>        <artifactId>curator-recipesartifactId>        <version>${zk-curator.version}version>    dependency>dependencies>
    

    2.Dubbo配置

    2.1 yml

    #dubbodubbo:  application:    name: demo-user  registry:    addresszookeeper://192.168.2.7:2181?backup=192.168.2.8:2181,192.168.2.9:2181    file: /dubbo/demo-user/cache    protocol: zookeeper    check: false  protocol:    name: dubbo    port: 28102  scan:    base-packages: com.demo.user.service.dubbo  consumer:    check: false    timeout: 10000    retries: 0    #ZK locklock:  zk-servers: 192.168.2.7:2181,192.168.2.8:2181,192.168.2.9:2181

    2.2 开启dubbo服务注解扫描

    import com.alibaba.dubbo.config.spring.context.annotation.EnableDubbo;import org.springframework.boot.autoconfigure.SpringBootApplication;@EnableDubbo@SpringBootApplicationpublic class DemoUserApplication {    public static void main(String[] args) {        SpringApplication.run(DemoUserApplication.class, args);    }}

    3.Dubbo调用

    3.1 dubbo service provider

    import lombok.extern.slf4j.Slf4j;import com.alibaba.dubbo.config.annotation.Service;@Slf4j@Service // 注意该@Service注解是alibaba包下的,不要错引用了Spring包下的public class UserDubboServiceImpl implements UserDubboService {}

    3.2 dubbo service consumer

    import com.alibaba.dubbo.config.annotation.Reference;import lombok.extern.slf4j.Slf4j;import org.springframework.stereotype.Service;@Slf4j@Servicepublic class OrderServiceImpl extends BaseServiceImpl         implements OrderService {            @Reference // 引用注入dubbo服务service bean     private UserDubboService userDubboService;}

    4.ZK分布式锁

    4.1 zk lock 配置

    import lombok.extern.slf4j.Slf4j;import org.apache.curator.framework.CuratorFramework;import org.apache.curator.framework.CuratorFrameworkFactory;import org.apache.curator.framework.recipes.locks.InterProcessSemaphoreMutex;import org.apache.curator.framework.state.ConnectionState;import org.apache.curator.framework.state.ConnectionStateListener;import org.apache.curator.retry.ExponentialBackoffRetry;import org.springframework.beans.factory.InitializingBean;import org.springframework.beans.factory.annotation.Value;import org.springframework.context.annotation.Configuration;import java.util.concurrent.TimeUnit;/** * 分布式锁: * 注意该锁不能重入,即不可有嵌套锁*/@Slf4j@Configuration  // 注意该组件需被springboot扫描注册成beanpublic class DistributedLock implements InitializingBean {​    private static CuratorFramework curator = null;    private static ThreadLocal<InterProcessSemaphoreMutex> localLock = new ThreadLocal<>();    @Value("${lock.zk-servers}")    private String zkServers;
    1. private static final String basePath = "/lock/";​
    2.   /**
    3.   * bean添加到spring容器后,在完成bean实例化后才会执行该方法 
    4.   */
    1. @Override
    2.   public void afterPropertiesSet() {
    if (curator == null) { curator = CuratorFrameworkFactory.builder().sessionTimeoutMs(30000).connectionTimeoutMs(30000) .retryPolicy(new ExponentialBackoffRetry(1000, Integer.MAX_VALUE)).connectString(zkServers).build(); curator.getConnectionStateListenable().addListener(new ZKListener()); curator.start(); } } /** * 不等待,遇锁直接退出 * * @param key * @return */ public static boolean acquire(String key) { try { InterProcessSemaphoreMutex lock = new InterProcessSemaphoreMutex(DistributedLock.curator, basePath + key); lock.acquire(); localLock.set(lock); } catch (Exception e) { log.warn("DistributedLock acquire error", e); return false; } return true; } /** * 排队等待 * * @param key * @param timeout * @return */ public static boolean acquire(String key, long timeout) { try { InterProcessSemaphoreMutex lock = new InterProcessSemaphoreMutex(DistributedLock.curator, basePath + key); lock.acquire(timeout, TimeUnit.SECONDS); localLock.set(lock); } catch (Exception e) { log.warn("DistributedLock acquire error", e); return false; } return true; } /** * 排队等待 * * @param key * @param timeout * @return */ public static boolean acquire(String key, long timeout, TimeUnit unit) { try { InterProcessSemaphoreMutex lock = new InterProcessSemaphoreMutex(DistributedLock.curator, basePath + key); lock.acquire(timeout, unit); localLock.set(lock); } catch (Exception e) { log.warn("DistributedLock acquire error", e); return false; } return true; } /** * 释放锁 */ public static void release() { try { InterProcessSemaphoreMutex lock = localLock.get(); if (lock != null && lock.isAcquiredInThisProcess()) { lock.release(); } } catch (Exception e) { log.warn("DistributedLock release error", e); } } /** * zk监听器 */ public class ZKListener implements ConnectionStateListener { @Override public void stateChanged(CuratorFramework client, ConnectionState state) { if (ConnectionState.LOST.equals(state)) { // 连接丢失 log.warn("==ZK LOCK== DistributedLock lost session with zookeeper"); } else if (ConnectionState.CONNECTED.equals(state)) { // 连接新建 log.warn("==ZK LOCK== DistributedLock connected with zookeeper"); } else if (ConnectionState.RECONNECTED.equals(state)) { // 重新连接 log.warn("==ZK LOCK== DistributedLock reconnected with zookeeper"); } } } /** * 分布式锁业务类型 */ public enum LockType {        PRODUCT_INVENTORY }}

    4.2 zk lock 使用

        // 加锁,    String lockKey = DistributedLock.LockType.PRODUCT_INVENTORY + "/" + productId;    try{        if(DistributedLock.acquire(lockKey, 3)){           // todo something 抢购排队下单,扣减商品库存        }    }catch(Exception e){        log.error("userId = {}, couponId = {}, 下单失败:{}", userId, productId, e.getMessage());        throw new Exception("下单失败", e);    }finally{        DistributedLock.release();    }    // service 方法中抛出异常,回滚事务    throw new CommonException("下单失败");
    

    5.CAP理论

    一个分布式系统最多只能同时满足一致性(Consistency)、可用性(Availability)和分区容错性(Partition tolerance)这三项中的两项,也即不可能三角CAP理论。

    既然是分布式服务,自然需要具备分区容错性。除此之外,用户更多的是需要服务的可用性,至于一致性方面,目前常用的折中解决方案是,选择最终一致性​。​

    以上关于后端服务常用的框架技术及一些相关中间件都已整理完毕,后续会更新基于SpringCloud Alibaba的微服务有关章节。

  • 相关阅读:
    Vue超详宝典-上部(万字长文--硬核发布)
    Node.js
    简历石层大海,为何今年秋招那么难?技术面考官想听啥?
    Shell脚本大全
    Rust语言有些情况一直卡住的解决方法
    IB考试45分是如何做到的?
    [基础库Numpy] 技能树总结:一篇文章学会Numpy库
    js 事件循环
    什么是分布式软件系统
    python | xlsxwriter,一个实用的 Python 库!
  • 原文地址:https://blog.csdn.net/CaBCo/article/details/125995847