(Translated by https://www.hiragana.jp/)
GitHub - huhuics/joice: Java分布式开发平台:Spring, Spring MVC, MyBatis, Dubbo, Redis, Shiro权限管理, Quartz分布式调度, RocketMQ通信, 本地缓存, Redis缓存, 分布式缓存, 分布式事务
Skip to content
/ joice Public

Java分布ぶんぷしき开发平台ひらだい:Spring, Spring MVC, MyBatis, Dubbo, Redis, Shiro权限管理かんり, Quartz分布ぶんぷしき调度, RocketMQ通信つうしん, 本地ほんじ缓存, Redis缓存, 分布ぶんぷしき缓存, 分布ぶんぷ式事しきじ

Notifications You must be signed in to change notification settings

huhuics/joice

Repository files navigation

Joice

License

いち. joice项目简介

  • joice使用しようSpringかまち开发てき分布ぶんぷしきけい统架构。
  • 使用しようMaven对项进行块化管理かんりひさげだか目的もくてきえき开发せい、扩展せい
  • 公共こうきょうこうのう:AOP、缓存、もと类、公共こうきょう配置はいち工具こうぐ类等。
  • けい统功のう:权限ひかえせい、调度管理かんり分布ぶんぷ式事しきじ务、RPC。
  • 扩展せい动态扩展しゅうぐん节点,节点间通过DubboMQ进行通信つうしん

. 主要しゅようこうのう

1.かずすえ

Druidすうすえ库连せっ,监控すうすえ库访问性能せいのう,统计SQL执行性能せいのうすうすえ库密码加みつ

  • かずすえ库密码加みつ和解わかいみつよういたりょうcom.alibaba.druid.filter.config.ConfigToolsさいじょういち个类扩展com.alibaba.druid.pool.DruidDataSourceそく具体ぐたいだい码实现在org.joice.service.datasource.DecryptDruidDataSource

2.持久じきゅう

MyBatis持久じきゅう;AOPきり换数すえ库实现读うつしぶん离。

  • 读写ぶん离实际上动态きり换数すえ库。扩展org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSourceざい每次まいじすうすえ库调ようぜん确定すうすえげん具体ぐたいだい码实现在org.joice.service.aspect.ChooseDataSource

3.MVC

もと于Spring MVC注解ちゅうかい,REST风格Controller。Exception统一管理かんり。    

4.调度

Spring + Quartz,以查询、おさむあらため周期しゅうき、暂停、删除、しんぞうたてそく执行、查询执行记录とう

5.もと于Sessionてきこく际化提示ていじしんいき,责任链模しきてき本地ほんじ语言拦截

未完みかん

6.Shiroとう录、URL权限管理かんりかい管理かんり强制きょうせい结束かい

未完みかん

7.缓存Session

未完みかん

注解ちゅうかいredis缓存すうすえ,Spring-sessionredis实现分布ぶんぷしきsessionどうじゅう启服务会话不丢失。  

8.RocketMQ

RocketMQ识点总结

对于分布ぶんぷ式事しきじ务的实现,つね见的一致いっちせい算法さんぽう(如二阶段提交)耗时长、效率こうりつてい一般いっぱん使用しようMQらい实现すうすえてきさい一致いっちせい

大事だいじ务 = 小事しょうじ务 + MQ

以转账为れいゆう两个账号よう进行转账操作そうさ,两个账号ぶんぞくA、B两个不同ふどうけい统,ゆう两个不同ふどうてきすうすえ库,Aよう扣钱,Bよう钱,如何いか证数すえ一致いっちせい

すえさい终上めんてきおもえ:Aけい统扣钱,しかきさき发消いき给中间件,Bけい接收せっしゅう此消いき,进行钱。ただし这里ゆう两个问题:Aさき扣钱,きさき发送消息しょうそく?还是さき发送消息しょうそくきさき扣钱?

かり设Aせん扣钱,さい发送消息しょうそく 如果扣钱成功せいこうただし网络异常,发送消息しょうそくしつ败,じゅう试依しかしつ败,怎么办?

かり设Aせん发送消息しょうそくさい扣钱 如果消息しょうそく发送成功せいこうただし扣钱しつ败,消息しょうそくまた不能ふのう撤回てっかい,怎么办?

结论:ただよう发送消息しょうそく扣钱这两个操作そうさ原子げんしてき,无论谁先谁后,みやこただしゆう问题てき这个问题应该如何いかかい决?

8.1 错误てき方案ほうあん

“发送消息しょうそく”这个网络调用扣钱ざい同一どういつ个事务中,如果发送消息しょうそくしつ败,扣钱动回滚,这不就保证这两个操作そうさてき原子げんしせい吗?这个方案ほうあん错误てき理由りゆう如下:

  • 发送消息しょうそくしつ败,发送かた并不知道ともみち消息しょうそくちゅう间件しんてきぼつゆうおさむいた,还是消息しょうそくやめ经收いたただかえしかいresponseてき时候しつ败了

    如果やめ经收いたりょう消息しょうそくただしかえしかいresponseてき时候しつ败,如果Aけい统执ぎょうかい滚,则会导致Aけい统的钱没ゆう扣,Bけい统的钱却增加ぞうかりょう

  • 网络调用ざいDBごと务前めん可能かのうかいいん为网络的のべ时,而导致DB长事务,严重てき时候かい阻塞せい个DB,风险很大  

8.2 方案ほうあん1——业务かた自己じこ实现

如果消息しょうそくちゅう间件ぼつゆうこと消息しょうそくこうのうれい使用しようてきKafka,如何いかかい决这个问题?

かい决方あん如下:

(1) Producerはしじゅん备一张消いきひょう扣钱update DB插入そうにゅう消息しょうそく这两个操作そうさざいいち个事务里めん

(2) じゅん备一个后だいほどじょてい时把消息しょうそくひょうちゅうてきmessage发送给消いきちゅう间件,しつ败了,就不断ふだんじゅう试,まこと许消いきじゅう复

(3) Consumer接收せっしゅう消息しょうそく并做こう幂等处理

该方あんてき缺点けってん需要じゅよう额外设计消息しょうそくひょうどう时还よう开发一个后台任务扫码本地消息,这将导致消息しょうそく处理业务逻辑耦合。

8.3 方案ほうあん2——RocketMQごと务消いき

RocketMQてき一个特性是能够发送“こと消息しょうそく”,すんでかい决上文中ぶんちゅう问题,また不和ふわ业务耦合。

RocketMQ消息しょうそくてき发送ぶんなりりょう2个阶だんPrepare阶段 确认阶段具体ぐたいらい说分为3个步骤:

(1) 发送Prepared消息しょうそく

(2) 执行本地ほんじごと务

(3) すえ本地ほんじごと务执ぎょう结果成功せいこうあるしつ败,确认ある取消とりけしPrepared消息しょうそく

如果ぜん两步成功せいこうりょうさいきさきいちしつ败,怎么办?RocketMQかい定期ていき扫描所有しょゆうPrepared消息しょうそく,询问发送かた消息しょうそく确认发出还是取消とりけし发送?(RocketMQ 3.2版本はんぽん以后取消とりけしりょう消息しょうそくかい查功のう

ざいjoiceなかうつしりょう一个数据最终一致性的例子:

よう户下单购买商品しょうひんhttp://localhost:8089/joice-web/order/toOrder), けい统需よう完成かんせい两件ごと:扣减よう户账户余额和创建订单。这两个动さく显然よう原子げんしてきjoice-web完成かんせい扣减よう户余额,joice-service完成かんせい创建订单。joice-web消息しょうそくてき发送しゃ,joice-service消息しょうそくてきけし费者。しめせ图如

8.4 顺序消息しょうそく

证消いきゆうじょさい简单てき方法ほうほうせい产者--MQ--しょう费者一对一对一的关系。ただし这个げんせいかいせい约消いきちゅう间件てき吞吐りょう通常つうじょうじょう况下しょう费者个的,いん存在そんざいしょう费者じゅう复消费的じょう况,RocketMQ要求ようきゅうきゃく户端自己じこ做消费幂とうひかえせい么RocketMQ如何いか实现顺序消息しょうそくてき呢?

だま认情况下,なま产者さいよう轮询てき方式ほうしきはた消息しょうそくとう递到ごと个队れつまい个消费者实例すえ订阅てきTopic平均へいきん分配ぶんぱいごと个consumer queue,どういち个queueちゅう,RocketMQ证消いきFIFO顺序てき。这样,ざいなま产者はし,如果のう顺序消息しょうそく发送いたどういち个consumer queueちゅう么消いき就是ゆうじょてき下面かめん以下いか单这一操作说明生产者顺序消息是如何发送的:

    //RocketMQどおり过MessageQueueSelectorちゅう实现てき算法さんぽうらい确定消息しょうそく发送いた哪一个队れつじょう
    //RocketMQだま提供ていきょうりょう两种MessageQueueSelector实现:ずいつくえ/Hash
    //此处すえ业务实现自己じこてきMessageQueueSelector:订单ごうしょうどうてき消息しょうそくかいさききさき发送いたどおり过一个队れつちゅう
    SendResult result = rocketMqProducer.getDefaultMQProducer().send(message, new MessageQueueSelector() {
        @Override
        public MessageQueue select(List<MessageQueue> mqs, Message msg, Object arg) { //此处てきargさんすう就是下面かめん传入てきorderId
            int id = (int) arg;
            int index = id % mqs.size();
            return mqs.get(index);
        }
    }, orderId);

订单ごう运算,以此确定此消いきとう递到哪个队列ちゅうそくあいどう订单ごうてき消息しょうそく ----> ゆうしょうどう结果 ----> とう递到しょうどう队列。结果可能かのう这样てき

joice开发りょう一个顺序消息例子,拟用户注さつ并发送两个消息しょうそく,一个消息是发往邮件系统,另一个是发往账户系统。消息しょうそくせい产者UserRegisterMqProducerService

9.にちこころざし

logbackしるしこころざしどう时基于时间和文わぶんけん大小だいしょう分割ぶんかつ志文しぶみけん。    

10.缓存

  • 本地ほんじ缓存:もとConcurrentHashMap实现,实现类在MapCacheMapCacheDaemon一个守护线程,支持しじ对Mapてき缓存持久じきゅう、缓存失效しっこう策略さくりゃくとうとう使用しよう方式ほうしき参考さんこう MapCache测试用例ようれい

  • Redis缓存:もとShardedJedis实现,实现类在ShardedJedisCache

开发这个缓存ちゅう间件てきはつ衷是为了减少缓存操作そうさてきだい码与业务逻辑かい耦,Spring Cacheてき思想しそう使用しようAOP + Annotationとうわざ术实现缓そんあずか业务逻辑てきかい耦,ざい需要じゅよう对查询结はて进行缓存てき地方ちほう使用しようorg.joice.cache.annotation.Cacheable标记。

10.1 すうすえにゅう缓存

    @Cacheable
    public BizPayOrder getById(Long id) {
        BizPayOrder order = bizPayOrderMapper.selectByPrimaryKey(id);
        LogUtil.info(logger, "订单查询结果,order={0}", order);
        return order;
    }

    @Cacheable(key = "'payOrderService_getById_'+#args[0].id", condition = "#args[0].id>3")
    public BizPayOrder getById(BizPayOrder order) {
        Long id = order.getId();
        BizPayOrder ret = bizPayOrderMapper.selectByPrimaryKey(id);
        LogUtil.info(logger, "订单查询结果,order={0}", ret);
        return ret;
    }
  • 如果てい义key,则该缓存使用しよう生成せいせいてきkey。生成せいせいてき规则はた类名、方法ほうほうめいまいりすう值一起计算其hashcode,这也意味いみ如果使用しようだま生成せいせいてきkeyはた支持しじ删除。 注意ちゅうい 如果使用しよう生成せいせいkey,切点せってん处的方法ほうほうさんすう如果基本きほん类型而是对象,则该对象必须继承org.joice.cache.to.BaseTO,这样ただようさんすう值每一致いっち生成せいせいてきhashcode就是しょうどうてき

  • 此外,key支持しじSpring ELおもて达式,condition也支持しじ

  • 为了つきりょう减少ないそん使用しよう对网络带宽的压力,joice-cache实现りょうもとHessianてき序列じょれつ工具こうぐ,开发しゃ也可以通过实现org.joice.cache.serializer.Serializer<T>せっこうくだり扩展

10.2 おさむあらため缓存

    @CacheDel(items = { @CacheDelItem(key = "'payOrderService_getById_'+#args[0].id") }, condition = "#retVal == true")
    public boolean updateOrder(BizPayOrder order) {
        return bizPayOrderMapper.updateByPrimaryKey(order) == 1;
    }
  • とう需要じゅようおさむあらため缓存时,为避めん缓存あずかかずすえ库双うつし不一致ふいっちさい取的とりてき策略さくりゃくさきおさむあらためすうすえ库,成功せいこう以后さい删除缓存。为什么?

  • 实际业务场景ちゅうおさむあらため一条数据库数据可能涉及删除多条缓存数据,ゆえ@CacheDel注解ちゅうかいちゅう需要じゅよう设置@CacheDelItemかず组,いち@CacheDelItem表示ひょうじ一条需要删除缓存的数据

  • とうおさむあらためすうすえ成功せいこう以后才能さいのう删除缓存,@CacheDel以通过设おけconditionらいひかえせいcondition支持しじSpring ELおもて达式

10.3 缓存设计关键てん

10.3.1 缓存かい满,满了怎么办?

论上らい说,ずい缓存すうすえてきえきぞうざい容量ようりょう有限ゆうげんてきじょう况下,缓存肯定こうていゆう一天いってんかい满,如何いか应对?
① 选择あい适的缓存丢弃策略さくりゃく,如FIFO、LRU、LFU
② 针对とうぜん设置てき容量ようりょう,设置适当警戒けいかい值,如10G缓存,とう缓存すうすえいた达8G时发报警,ひさげぜん扩容
③ 给缓そん设置过期时间

10.3.2 缓存いやまこと许丢しつ?丢失りょう怎么办?

すえ业务场景判断はんだんいやまこと许丢しつ,如果まこと许,需要じゅよう持久じきゅうこうのうてき缓存ふく务来支持しじ,如Redis,还可すえ业务对丢しつ时间てきようにん,选择さら具体ぐたいてき持久じきゅう策略さくりゃく如ReidsてきRDBAOF。

10.3.3 缓存“击穿”问题

  • 概念がいねん存在そんざいぼう个时间点过期,恰好かっこうざい这个时间てん对这个keyゆう大量たいりょうてき并发请求过来,这些请求发现缓存过期一般都会从数据库加载数据并回设缓存,这个时候だい并发てき请求可能かのうかいまどか间把きさきはしすうすえ库压垮

  • 如何いかかい决: 常用じょうようてき做法使用しようmutex。简单らい说就とう缓存失效しっこう时,りつそくlodad DB,而是さき使用しよう缓存工具こうぐてきぼう些带成功せいこう操作そうさかえしかい值的操作そうさ如RedisてきSETNX命令めいれいsetいち个mutex key,とう操作そうさかえしかい成功せいこう时,さい进行load DBてき操作そうさ并回设缓そんいや则就じゅう试get缓存てき方法ほうほう算法さんぽう伪代码如:    

public String get(key) {
      String value = redis.get(key);
      if (value == null) { //缓存值过
          //设置ちょう时时间,防止ぼうしdel操作そうさしつ败的时候,した缓存过期いちちょく不能ふのうload db
          if (redis.setnx(key_mutex, 1, 3 * 60) == 1) {  //代表だいひょう设置成功せいこう
               value = db.get(key);
                      redis.set(key, value, expire_secs);
                      redis.del(key_mutex);
              } else {  //这个时候代表だいひょうどう时候てき其他线程やめ经load db并回设到缓存りょう,这时こうじゅう试获取缓存值即
                      sleep(50);
                      get(key);  //じゅう
              }
          } else {
              return value;      
          }
  }

さん. 启动

さきざいMySQLちゅう导入joice.sqlぶんけんしかきさきさいざいjoice-serviceてきresources-->configおさむあらためなり自己じこてき配置はいちぶんけん
ほん项目需要じゅようZookeeper,ActiveMQ

[joice-service] --> Run as --> Maven build... --> tomcat7:run

だい码在逐步かんなか

About

Java分布ぶんぷしき开发平台ひらだい:Spring, Spring MVC, MyBatis, Dubbo, Redis, Shiro权限管理かんり, Quartz分布ぶんぷしき调度, RocketMQ通信つうしん, 本地ほんじ缓存, Redis缓存, 分布ぶんぷしき缓存, 分布ぶんぷ式事しきじ

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published