薛定谔的风口猪

站在巨人的肩膀上学习,猪都能看得很远

RocketMQ——组件

rocketmq部署

RocketMQ服务端的组件有三个,NameServer,Broker,FilterServer(可选,部署于和Broker同一台机器)

下面分别介绍三个组件:

Name Server

Name Server是RocketMQ的寻址服务。用于把Broker的路由信息做聚合。用户端依靠Name Server决定去获取对应topic的路由信息,从而决定对哪些Broker做连接。

  • Name Server是一个几乎无状态的结点,Name Server之间采取share-nothing的设计,互不通信。

  • 对于一个Name Server集群列表,客户端连接Name Server的时候,只会选择随机连接一个结点,以做到负载均衡。

  • Name Server所有状态都从Broker上报而来,本身不存储任何状态,所有数据均在内存。

  • 如果中途所有Name Server全都挂了,影响到路由信息的更新,不会影响和Broker的通信。

Broker

Broker是处理消息存储,转发等处理的服务器。

  • Broker以group分开,每个group只允许一个master,若干个slave。
  • 只有master才能进行写入操作,slave不允许。
  • slave从master中同步数据。同步策略取决于master的配置,可以采用同步双写,异步复制两种。
  • 客户端消费可以从master和slave消费。在默认情况下,消费者都从master消费,在master挂后,客户端由于从Name Server中感知到Broker挂机,就会从slave消费。
  • Broker向所有的NameServer结点建立长连接,注册Topic信息。

Filter Server(可选)

RocketMQ可以允许消费者上传一个Java类给Filter Server进行过滤。

  • Filter Server只能起在Broker所在的机器
  • 可以有若干个Filter Server进程
  • 拉取消息的时候,消息先经过Filter Server,Filter Server靠上传的Java类过滤消息后才推给Consumer消费。
  • 客户端完全可以消费消息的时候做过滤,不需要Filter Server
  • FilterServer存在的目的是用Broker的CPU资源换取网卡资源。因为Broker的瓶颈往往在网卡,而且CPU资源很闲。在客户端过滤会导致无需使用的消息在占用网卡资源。
  • 使用 Java class上传作为过滤表达式是一个双刃剑——一方面方便了应用的过滤操作且节省网卡资源,另一方面也带来了服务器端的安全风险。这就需要应用来保证过滤代码安全——例如在过滤程序里尽可能不做申请大内存,创建线程等操作。避免 Broker 服务器资源泄漏。

在IntilliJ中运行Maven的Tomcat项目

对于一个Maven项目,如果又是一个tomcat项目,在运行tomcat之前应该要进行Maven的构建。

以下是步骤:

1.新建一个Maven Run/Debug configuration:

新建一个Maven Run/Debug configuration

2.在Tomcat Run/Debug Configuration中新增#1的阶段在”Before Launch”中

在Tomcat Run/Debug Configuration中新增#1的阶段在"Before Launch"中

如何优雅地停止运行中的内嵌Tomcat的Spring Boot应用

你很可能根据https://spring.io/guides/gs/rest-service/搭起了一个Spring的Rest服务,然后打包成了jar包,不需要容器就可以在生成环境下通过运行jar包启动一个Web服务。

但这样的服务怎么样正确的停止呢?或许你只是简单的kill -9对应的进程,但实际上,有更优雅的方式。

Spring Boot里面有一个spring-boot-starter-actuator的项目,可以监控和管理Spring Boot应用。其中暴露了很多endpoint,可以方便的检测应用的健康情况。其中有一个shutdown的endpoint可以优雅地停止应用。

通过VM参数指定本地log4j配置文件,Spring Boot

Spring Boot有预设的日志配置逻辑(具体参看:这里), 如果是log4j的话,以下文件会被加载:

log4j-spring.properties, log4j-spring.xml, log4j.properties , log4j.xml

有时候我们项目的log4j配置文件配置的是生产环境,每次本地调试又不想改会本地的调试配置,若希望通过VM参数去修改此文件,按照之前的参数-Dlog4j.configuration(非Spring Boot项目请看这里通过VM参数选择本地log4j配置文件),在Spring Boot的项目中并不生效。

若需要指定另外的文件,需要用Spring Boot指定的配置:-Dlogging.config

-Dlogging.config=D:\project\git_repo\prome-data\src\main\resources\log4j-debug.properties

即可在本地运行时选择本地的配置文件进行日志配置。

避免写出不走索引的SQL, MySQL

在MySQL中,并不是你建立了索引,并且你在SQL中使用到了该列,MySQL就肯定会使用到那些索引的,有一些情况很可能在你不知不觉中,你就“成功的避开了”MySQL的所有索引。

现假设有t_stu表,age,sname上建立了索引

索引列参与计算

如果where条件中age列中使用了计算,则不会使用该索引

SELECT `sname` FROM `t_stu` WHERE `age`=20;-- 会使用索引
SELECT `sname` FROM `t_stu` WHERE `age`+10=30;-- 不会使用索引!!因为所有索引列参与了计算
SELECT `sname` FROM `t_stu` WHERE `age`=30-10;-- 会使用索引

故,如果需要计算,千万不要计算到索引列,想方设法让其计算到表达式的另一边去。

索引列使用了函数

同样的道理,索引列使用了函数,一样会导致相同的后果

SELECT `sname` FROM `stu` WHERE concat(`sname`,'abc') ='Jaskeyabc'; -- 不会使用索引,因为使用了函数运算,原理与上面相同
SELECT `sname` FROM `stu` WHERE `sname` =concat('Jaskey','abc'); -- 会使用索引

索引列使用了Like %XXX

SELECT * FROM `houdunwang` WHERE `uname` LIKE '前缀就走索引%' -- 走索引
SELECT * FROM `houdunwang` WHERE `uname` LIKE '后缀不走索引%' -- 不走索引

所以当需要搜索email列中.com结尾的字符串而email上希望走索引时候,可以考虑数据库存储一个反向的内容reverse_email

SELECT * FROM `table` WHERE `reverse_email` LIKE REVERSE('%.com'); -- 走索引

注:以上如果你使用REVERSE(email) = REVERSE('%.com'),一样得不到你想要的结果,因为你在索引列email列上使用了函数,MySQL不会使用该列索引

同样的,索引列上使用正则表达式也不会走索引。

字符串列与数字直接比较

这是一个坑,假设有一张表,里面的a列是一个字符char类型,且a上建立了索引,你用它与数字类型做比较判断的话:

 CREATE TABLE `t1` (`a` char(10));

 SELECT * FROM `t1` WHERE `a`='1' -- 走索引
 SELECT * FROM `t2` WHERE `a`=1 -- 字符串和数字比较,不走索引!

但是如果那个表那个列是一个数字类型,拿来和字符类型的做比较,则不会影响到使用索引

 CREATE TABLE `t2` (`b` int);

 SELECT * FROM `t2` WHERE `b`='1' -- 虽然b是数字类型,和'1'比较依然走索引

但是,无论如何,这种额外的隐式类型转换都是开销,而且由于有字符和数字比就不走索引的情况,故建议避免一切隐式类型转换

尽量避免 OR 操作

select * from dept where dname='jaskey' or loc='bj' or deptno=45 --如果条件中有or,即使其中有条件带索引也不会使用。换言之,就是要求使用的所有字段,都必须建立索引

所以除非每个列都建立了索引,否则不建议使用OR,在多列OR中,可以考虑用UNION 替换

select * from dept where dname='jaskey' union
select * from dept where loc='bj' union
select * from dept where deptno=45

Git中只merge部分commit

cherry-pick

在Git 1.7.2以上的版本引入了一个 cheery-pick的命令可以只merge 部分的commit而不用直接把整个分支merge过来

git cherry-pick <commit 号>

如:

git cherry-pick e43a6fd3e94888d76779ad79fb568ed180e5fcdf

这样就只会把这个e43a6fd3e94888d76779ad79fb568ed180e5fcdf commit的内容pull到当前的分支,不过你会得到一个新的commit。 这样就可以按需merge需要的commit,而不需要的就可以直接废弃咯。

多个commit:

可以用空格指定多个commit:

git cherry-pick A B C D E F

CSS实现垂直居中

CSS垂直居中真是一个令人头疼的事,最近遇到了一个较为简单且通用的方法,总结如下:

1.无需要设置自己高度,和父容器高度, 利用绝对定位只需要以下三行:

parentElement{
    position:relative;
}
childElement{
    position: absolute;
    top: 50%;
    transform: translateY(-50%);
}

2.若只有父容器下只有一个元素,且父元素设置了高度,则只需要使用相对定位即可

parentElement{
    height:xxx;
}
.childElement {
  position: relative;
  top: 50%;
  transform: translateY(-50%);
}

例子猛击:DEMO


Flex布局

如果你不需要兼容老式浏览器(例如IE9及以下),使用Flex布局可以非常轻松实现

浏览器支持如下: Flex的支持性

样式:

parentElement{
    display:flex;/*Flex布局*/
    display: -webkit-flex; /* Safari */
    align-items:center;/*交叉轴居中,这里由于flex-direction默认是row,即垂直居中*/
}

注意,设为Flex布局以后,子元素的float、clear和vertical-align属性将失效

例子猛击:Flex demo


Flex教程可参考这里

Octopress 博文中引入javascript文件/HTML文件

.markdown文件中是可以引入javascript甚至是html文件的,这样以后博文里面插入代码运行结果写demo就很方便了。

以下是具体方法,并带一个例子

引入Javascript

语法:

<script type="text/javascript" src="/path/to/file.js"></script>

例如: 在 source 中的404.markdown 中 加入:

<script type="text/javascript" src="http://www.qq.com/404/search_children.js" charset="utf-8></script>

即可在404页面中跳转到腾讯的公益页面

引入HTML文件

以下为引入后的样本实例:

.markdown文件中,在需要引入HTML文件的地方写上:

’{‘%include demo/include_HTML_demo.html +’%’}’ (注:去掉其中的单引号)

HTML代码即会导入,若内嵌JavaScript脚本,也会自动导入允许。

这里你看到的区域都是外部导入的HTML文件,尝试点击这里,会发现有脚本运行.

点我试试看

注:由于octopress已经引入了jQuery,故本页面无须额外引入jQuery.

Jackson 操作JSON

Maven 支持:

  <repositories>
    <repository>
        <id>codehaus</id>
        <url>http://repository.codehaus.org/org/codehaus</url>
    </repository>
  </repositories>

  <dependencies>
    <dependency>
        <groupId>org.codehaus.jackson</groupId>
        <artifactId>jackson-mapper-asl</artifactId>
        <version>1.8.5</version>
    </dependency>
  </dependencies>

需要进行JSON操作的转换,仅需要一个ObjectMapper对象 ObjectMapper mapper = new ObjectMapper();

转换为对象时候,使用read相关方法,转换为JSON字符串时,使用write相关方法。

Java object to JSON

ObjectMapper mapper = new ObjectMapper();
mapper.writeValue(new File("c:\\user.json"), user);//写到文件,User 有get set 方法的POJO

大多数情况下,我们只需要一个JSON字符串,可以使用StringWriter作为参数的重载的writeValue方法:

StringWriter sw =new StringWriter();
ObjectMapper mapper = new ObjectMapper();
mapper.writeValue(sw, user);//写到StringWriter
String JSON = sw.toString();
sw.close();

也可以直接使用writeValueAsString ,其内部使用的也是StringWriter的。

ObjectMapper mapper = new ObjectMapper();
String JSON  = mapper.writeValueAsString(user));//直接转为String 类型的JSON

JSON to Java object

ObjectMapper mapper = new ObjectMapper();
User user = mapper.readValue(new File("c:\\user.json"), User.class);//User 有get set 方法的POJO

集合操作

Map/List to JSON

和普通对象一样,使用(同样,可以使用重载方法)

objectMapper.writeValue(new File(jsonFilePath), mapObject);
objectMapper.writeValue(new File(jsonFilePath), listObject);

JSON to Map/List/数组

     Map<String, Object> mapObject = mapper.readValue(new File('c:\\user.json'),
                new TypeReference<Map<String, Object>>() {});//使用TypeReference, 注意末尾有{}



     List<String> listObject = mapper.readValue(new File('c:\\user.json'),
                new TypeReference<List<String>(){});//使用TypeReference, 注意末尾有{}


     String[] array = mapper.readValue(new File('c:\\user.json'),
                String[].class);//使用class对象

修改IntelliJ的快捷键中的CTRL+Y为Redo操作

IntelliJ是一个非常强大的IDE,但是对于长期习惯Windows用户,里面有些快捷键非常不好。最典型的就是CTRL+Y,在IntelliJ里面CTRL+Y是删除操作,可是我们习惯与CTRL+Y是Redo(重做)操作。

可以用以下方式修改这些快捷键,注:适用如IDEA, PyCharm等IDE:

  1. 进入Settings(快捷键:CTRL+ALT+S,或者SHITT*2出Search Everywhere中搜索settings进入)
  2. 左边菜单选择KeyMap(可搜索)
  3. 选择默认的keymaps(IntelliJ的),然后选择copy出一份新的,在新的keymaps里面修改
  4. 在新的keymaps里面的Main Menu-->Edit-->Redo 右键选择 Add Keyboard Shortcut
  5. 键盘按CTRL+Y (修改的快捷键)
  6. OK
  7. 选择 “Remove” ,当窗口提示: “the shortcut is already assigned to other actions. Do you want to remove other assignments?”
  8. Apply