diff --git a/Gemfile b/Gemfile
new file mode 100644
index 0000000..4fe3d6e
--- /dev/null
+++ b/Gemfile
@@ -0,0 +1,7 @@
+# frozen_string_literal: true
+
+source "https://gems.ruby-china.com"
+
+# gem "rails"
+
+gem "jekyll"
\ No newline at end of file
diff --git a/Gemfile.lock b/Gemfile.lock
new file mode 100644
index 0000000..cf02486
--- /dev/null
+++ b/Gemfile.lock
@@ -0,0 +1,69 @@
+GEM
+ remote: https://gems.ruby-china.com/
+ specs:
+ addressable (2.8.1)
+ public_suffix (>= 2.0.2, < 6.0)
+ colorator (1.1.0)
+ concurrent-ruby (1.1.10)
+ em-websocket (0.5.3)
+ eventmachine (>= 0.12.9)
+ http_parser.rb (~> 0)
+ eventmachine (1.2.7)
+ ffi (1.15.5)
+ forwardable-extended (2.6.0)
+ http_parser.rb (0.8.0)
+ i18n (1.12.0)
+ concurrent-ruby (~> 1.0)
+ jekyll (4.3.1)
+ addressable (~> 2.4)
+ colorator (~> 1.0)
+ em-websocket (~> 0.5)
+ i18n (~> 1.0)
+ jekyll-sass-converter (>= 2.0, < 4.0)
+ jekyll-watch (~> 2.0)
+ kramdown (~> 2.3, >= 2.3.1)
+ kramdown-parser-gfm (~> 1.0)
+ liquid (~> 4.0)
+ mercenary (>= 0.3.6, < 0.5)
+ pathutil (~> 0.9)
+ rouge (>= 3.0, < 5.0)
+ safe_yaml (~> 1.0)
+ terminal-table (>= 1.8, < 4.0)
+ webrick (~> 1.7)
+ jekyll-sass-converter (2.2.0)
+ sassc (> 2.0.1, < 3.0)
+ jekyll-watch (2.2.1)
+ listen (~> 3.0)
+ kramdown (2.4.0)
+ rexml
+ kramdown-parser-gfm (1.1.0)
+ kramdown (~> 2.0)
+ liquid (4.0.3)
+ listen (3.7.1)
+ rb-fsevent (~> 0.10, >= 0.10.3)
+ rb-inotify (~> 0.9, >= 0.9.10)
+ mercenary (0.4.0)
+ pathutil (0.16.2)
+ forwardable-extended (~> 2.6)
+ public_suffix (5.0.1)
+ rb-fsevent (0.11.2)
+ rb-inotify (0.10.1)
+ ffi (~> 1.0)
+ rexml (3.2.3)
+ rouge (4.0.0)
+ safe_yaml (1.0.5)
+ sassc (2.4.0)
+ ffi (~> 1.9)
+ terminal-table (3.0.2)
+ unicode-display_width (>= 1.1.1, < 3)
+ unicode-display_width (2.3.0)
+ webrick (1.7.0)
+
+PLATFORMS
+ x86_64-linux
+
+DEPENDENCIES
+ jekyll
+
+BUNDLED WITH
+ 2.3.26
diff --git a/_config.yml b/_config.yml
index e29a5c1..d9557ce 100644
--- a/_config.yml
+++ b/_config.yml
@@ -4,8 +4,6 @@ timezone: 'Asia/shanghai'
encoding: 'utf-8'
url: https://feling.net
-plugins:
- - jekyll-sitemap
collections:
posts:
diff --git a/_includes/goTop.html b/_includes/goTop.html
index 29d1410..23e0a77 100644
--- a/_includes/goTop.html
+++ b/_includes/goTop.html
@@ -7,7 +7,7 @@
$('div.go-top').hide();
});
$('#content').scroll(function() {
- if ($(window).scrollTop() > 400)
+ if ($('#content').scrollTop() > 400)
$('div.go-top').show();
else
$('div.go-top').hide();
diff --git a/_includes/head.html b/_includes/head.html
index 65d8224..c6ed25f 100644
--- a/_includes/head.html
+++ b/_includes/head.html
@@ -59,7 +59,6 @@ body {
}
#content {
padding: 10px 10px 0px 10px;
- overflow: initial;
}
footer {
margin-top: 10px;
diff --git a/_includes/header.html b/_includes/header.html
index 5923aae..3a0c998 100644
--- a/_includes/header.html
+++ b/_includes/header.html
@@ -15,12 +15,12 @@
{% if page.url contains "/redis/" %}class="uk-active"{% endif %}
{% if page.url contains "/timestamp/" %}class="uk-active"{% endif %}
>开发小工具
-
博客
+ 笔记
- - 博客首页
+ - 笔记
- 网页版 redis 客户端
diff --git a/_posts/2015-05-17-project-http-proxy.md b/_posts/2015-05-17-project-http-proxy.md
index c67b6fc..17b4be1 100644
--- a/_posts/2015-05-17-project-http-proxy.md
+++ b/_posts/2015-05-17-project-http-proxy.md
@@ -282,7 +282,7 @@ def do_tunnel(host, port, soc):
return
soc.send(TUNNEL_OK)
thread.start_new_thread(dock_socket, (soc, cos, False))
- thread.start_new_thread(dock_socket, (cos, soc, False))
+ thread.start_new_thread(dock_socket, (cos, soc, True))
```
diff --git a/_posts/2015-05-22-git-config.md b/_posts/2015-05-22-git-config.md
index 57cf7c1..ba4135f 100644
--- a/_posts/2015-05-22-git-config.md
+++ b/_posts/2015-05-22-git-config.md
@@ -9,7 +9,7 @@ tags: [git]
## .gitconfig
-```
+```sh
[user]
name = chenyan
email = chenyan@feling.net
diff --git a/_posts/2021-11-28-review-2021.md b/_posts/2021-11-28-review-2021.md
deleted file mode 100644
index 6d98215..0000000
--- a/_posts/2021-11-28-review-2021.md
+++ /dev/null
@@ -1,10 +0,0 @@
----
-layout: pages
-title: 2021 回顾下近几年, 重新出发
-categories: 杂谈
-published: false
----
-
-
-* 文章目录
-{:toc}
\ No newline at end of file
diff --git a/_posts/2021-12-07-hdd.md b/_posts/2021-12-07-hdd.md
index 48d4d32..ad3f5b6 100644
--- a/_posts/2021-12-07-hdd.md
+++ b/_posts/2021-12-07-hdd.md
@@ -7,10 +7,12 @@ tags: [os, middleware, hdd]
## 引言
+---
固态硬盘已经出现n年了, 大概还是价格的原因, 工程师们依旧与机械硬盘奋战着. 举几个例子, 感受下 if else 之外的代码乐趣.
## QMQ 中针对硬盘IO的优化
+---
qmq 是去哪儿网自研的消息队列. 相比于 RabbitMQ, Kafka 等消息中间件, qmq 在复杂业务场景的适用性上拥有绝对的优势. 延迟消息, 广播消息, tag过滤, 轨迹跟踪, 事物消息, Consumer扩容 这些在使用其他消息队列时让人叫苦连天的特性, 对qmq来说都不是事儿.
@@ -30,6 +32,7 @@ qmq 是去哪儿网自研的消息队列. 相比于 RabbitMQ, Kafka 等消息中
## MYSQL 数据多了查询就会慢吗?
+---
有过这样的压测经历, 压测前需要造数据量, 在mysql单表中插入了几千万条数据, 但是这些数据都是跑不通接口跑不通业务流程的脏假数据. 然后手动生成了一份可用的数据, 压测时就用这一份能跑通流程的数据作参数来压.
diff --git a/_posts/2021-12-09-exquisite-redis.md b/_posts/2021-12-09-exquisite-redis.md
index 4e79cc1..3878992 100644
--- a/_posts/2021-12-09-exquisite-redis.md
+++ b/_posts/2021-12-09-exquisite-redis.md
@@ -1,24 +1,147 @@
---
layout: pages
-title: redis 的使用可以再精致点--锁, 击穿, 穿透, 雪崩
+title: redis 的调用可以再精致点
categories: 杂谈
tags: [middleware, redis]
-published: false
---
-## 分布式锁
-消息折叠
-redission islock 其他线程锁着也是true。
+
+## 分布式锁
+---
+
+### 消息折叠
+
+“折叠” 这个词,也是回福州工作后才接触的概念。用得太久,以至于现在如果让我重新给它起个名字,都毫无灵感了。具体的场景例子是这样的:在课程业务中,学习进度的计算是一个实时性不太敏感,计算量又很重的逻辑。但前面触发进度计算的地方隐匿在系统各处,恨不得一秒触发一百次进度百分比的更新。好在中间的位置有个收口,大家都是通过同一个MQ消息触发的进度计算。于是在消息的生产者这边加了折叠逻辑, 也就是同一个学员同一个课程的进度计算,一分钟内只发送一条。多余的消息给它吞掉(忽略)。
+
+
+实现的原理, 就是用 userId + courseId 作为key,给它上个redis分布式锁。同时把消息也改成延时一分钟的。
+
+
+上锁的代码是五年前的人写的。某一天,我们压测过程中发现,有个毛刺,一分钟一根,就是来自这个MQ消息。打开代码一看。。哎。。 get()、set() 分开调用的,真的是批哩一点的并发概念都没有啊。
+
+
+像这种地方,改成 setnx() 也就够了。但自己心里要清楚,只从技术角度看,分布式锁的实现还可以再深入很多步,做得更精致。如果有条件,应该把这类代码放入公共包里给更高级的开发人员维护。
+
+
+### redission
+
+我一直是反感 redission 的(同样反感 spring-data),恰恰是因为它的 开源、活力、长期的积累。导致它的模型复杂而庞大。它实现了完整的 jdk 定义的锁的接口。
+
+我一直期待,遇到一个场景,是下面这三个接口方法不够用的。
+
+```java
+lock()
+tryLock()
+unlock()
+```
+
+何必引入完整的jdk接口实现呢?团队里的人都那么牛逼,hold得住嘛?
+
+这天,时间大概在一年一度的组织架构调整期间,收到一个原本是其他小组维护的服务,组织架构调整调过来的,代码来了但人没来。里面有段bug是这样的。
+
+```java
+RLock xLock = null, xxLock = null;
+try {
+ xLock = redissonClient.getFairLock("lockKey0");
+ xLock.lock(10, TimeUnit.SECONDS);
+ ...
+ xLock.unlock()
+ ...
+ xxLock = redissonClient.getFairLock("lockKey1");
+ xxLock.lock(10, TimeUnit.SECONDS);
+ ...
+ xxLock.unlock()
+ ...
+} catch (Throwable e) {
+ ...
+} finally {
+ if (null != xLock && xLock.isLocked()) {
+ xLock.unlock();
+ }
+ if (null != xxLock && xxLock.isLocked()) {
+ xxLock.unlock();
+ }
+}
+```
+
+它试图用 `xxLock.isLocked()` 判断 “自己是否加锁成功了”,但 `xxLock.isLocked()` 却完全不是这个语义,被别人锁着也是 true。
+
+这是一位应届生职级的同学,可能还未系统学习过jdk里的并发包,心还大到敢直接顾名思义,也没有点进去看源码注释的习惯。编码习惯也不好,一边希望减小锁的粒度,混在业务代码中途调 unLock(),一边又把 try catch 的范围放到最大。
+
+
## 击穿
+---
+
+击穿的意思, 是
@cacheable
+
+
+
## 穿透
+---
+
+
## 雪崩
+---
## keys *
+---
+
+但凡是有点自主学习能力,看过官网的。。。命令介绍里那么黑的加粗说明。
+
+
+
+## 以一己之力,发明了MemoryCache
+---
+
+跟前面讲的消息折叠里遇到的bug一样, 也是五六年前的老代码了。顺带跑个题,讲讲一个OOM的事情吧。那个服务大概启动一两周左右,内存就满了,fgc也回收不掉,只能重启。
+
+把内存dump下来,看到占内存最多的,除了日志打印,就都是同一个sql语句的缓存。特点是 where 条件里包含 `in (?, ? ...)` , 这里面的 `?` 可能有上万个, 而且不是固定数量。
+
+ORM 框架会把sql语句缓存下来,但是因为 `?` 的个数有几万种可能,就缓存了几万遍。
+
+ORM 框架是动不了了,在用的低版本的没法处理这个问题, 又不敢升级版本。保底咱还能把 `?` 分批,多执行几次sql,至少让内存不爆是吧。但我又挣扎了一下,想看看完整的业务逻辑,感觉不会有什么功能是必须要用这么奇葩的sql实现的。结果就发现,相关的数据库操作明显有优化过一波的痕迹,mysql前面加过一层redis,确认这个sql查询是没删干净的,直接删了就完事。
+
+回到正题,"mysql前面加过一层redis", 它是怎么加的呢,业务逻辑已经记不清了, 但我永远忘不了,它把 list 类型的数据整个 get() 出来, 添加一个元素,再 set() 回去。
+
+
+## 缓存与DB的数据一致性
+---
+
+有这么个不解之谜,缓存里的内容和数据库中的数据不一致了。并且这部分的代码很新,很清晰。
+
+读接口用的 @Cacheable 注解,实现了先从缓存取, 如果缓存里没有再走数据库,还会把数据库里取到的放进缓存里。
+
+写接口用的 @CacheEvict 注解,实现了修改完数据库之后删除缓存。
+
+已经是相对较优的实现了,再追求更强的一致性,就得去权衡代价和收益了。最终这个bug是被切了无法复现,手动清下缓存,改小了缓存有效期 就算结了。
+
+
+咱们从理论上猜一下可能有哪些场景会导致数据不一致。
+
+1. 数据库主从延迟。写接口更新了主库,删除了缓存。读接口从从库里取出来的还是旧数据,并把旧数据又放进了缓存。
+2. 读接口 发现缓存里没数据, 走到数据库里去取,取完卡了一下,还没来得及放进缓存。写接口 更新完数据,删完缓存。读接口 从卡住的状态恢复过来,把旧数据放进了缓存。
+
+关键的因素有两个,这两个因素构成了主要矛盾。
+
+一是 读写两个接口之间的通信,只通过缓存的有无来交换信息,信息量不够。
+
+二是 把缓存的修改操作分给了两个接口,这就需要更多信息量的交换才能协作。
+
+我们不好去完全断开两个接口之间的通信与协作, 因为除了数据的新旧,他们还在沟通哪些数据应该进缓存。
+
+所以就只好增加信息量,
+
+1. (写接口,可以多说点)假设数据中有version字段表示数据的版本。写接口 数据更新时,删除缓存的主体内容,但保留最新的version值。读接口就能根据版本号,判断要放进缓存的是不是旧数据。
+
+2. (读接口,也要有主观能动性)。时不时的抽查下数据质量,不能说缓存里有数据就 100% 认为是合格的数据。那检查抽取样本的标准呢...(哎...越搞越复杂了)
+
+
+----
* 文章目录
{:toc}
\ No newline at end of file
diff --git a/_posts/2022-01-01-about-calendar.md b/_posts/2022-01-01-about-calendar.md
index 83d033e..ccc2cc8 100644
--- a/_posts/2022-01-01-about-calendar.md
+++ b/_posts/2022-01-01-about-calendar.md
@@ -6,7 +6,11 @@ published: false
---
-## 不完美
+## 前言
+
+不必追求完美。
+
+
diff --git a/_posts/2022-12-11-book-list.md b/_posts/2022-12-11-book-list.md
new file mode 100644
index 0000000..e447137
--- /dev/null
+++ b/_posts/2022-12-11-book-list.md
@@ -0,0 +1,65 @@
+---
+layout: pages
+title: 书单
+categories: 杂谈
+---
+
+
+看过五六年的书,有些一点也想不起来的书中的内容或名字了。列个单子记一下吧。
+
+
+---
+
+三四郎。外面,有好多世界。明明是一百年前的大学生活,完全感受不到时间的距离。
+
+月亮与六便士。八卦流言不分时代与国界。我都没想过安度晚年,你凭啥呀。
+
+刺猬的优雅。你有一个很好的藏身之所。还把生命停在了最美好的时刻。
+
+非自然死亡。就是因为无法分开才会发生这些案件的。
+
+秒速五厘米
+
+夏目友人帐
+
+人类简史
+
+数学之美
+
+四月是你的谎言
+
+---
+
+深入理解 Java 虚拟机
+
+大型网站系统与 Java 中间件实践
+
+---
+
+西决。揉面团。
+
+东霓
+
+南音
+
+后来的事。 ?
+
+三体
+
+活着
+
+白夜行
+
+一九八四。她说两块钱。
+
+美丽的新世界
+
+百年孤独
+
+天才在左疯子在右
+
+西厢记。银样镴枪头。
+
+浮生六记
+
+小王子。
diff --git a/base64/index.html b/base64/index.html
index 72385d5..3667705 100644
--- a/base64/index.html
+++ b/base64/index.html
@@ -88,7 +88,7 @@ description: 在线 Base64 编码、解码。支持文字、图片。智能适
autofocus spellcheck="false" v-model="base64" v-on:input="onInputBase64">
-
+
拖拽图片到此处 / 点击上传图片
diff --git a/index.html b/index.html
index 45ca2a1..533a11f 100644
--- a/index.html
+++ b/index.html
@@ -59,7 +59,7 @@
@@ -225,31 +225,6 @@
-
+
@@ -569,4 +569,18 @@ description: 更直观的了解接口返回值格式、结构。格式化、高
$('.header-extend-item').appendTo('#header-extend')
+
+
diff --git a/redis/index.html b/redis/index.html
index 2a121e2..a895bd2 100644
--- a/redis/index.html
+++ b/redis/index.html
@@ -4,7 +4,7 @@ layout: default_tool
keywords: [redis, redis GUI, redis client, redis 客户端]
description: fredis 是一个网页版 redis 客户端,基于“ws2s项目”开发。有基本的GUI图形界面,能编辑保存服务器信息、提供 redis 命令行终端、保存历史命令。所有数据存储在 localStorage, 保证数据安全。
---
-