qiubo's life

Stay Hungry, Stay Foolish


  • 首页

  • 关于

  • 标签

  • 分类

  • 归档

  • 搜索

2014年06月Reading Notes

发表于 2014-06-28 | 分类于 java

Awesome Sysadmin

https://github.com/kahun/awesome-sysadmin

系统管理员的开源资源,资源暴多,技术选型时参考.

Tengine

http://dmsimard.com/2014/06/21/a-use-case-of-tengine-a-drop-in-replacement-and-fork-of-nginx/

使用tengine来做LB,通过Tengine的unbuffered requests特性实现了上传性能提升.

不过我自己装tengine启动就遇到了问题.

the configuration file //Users/bohr/software/tengine/conf/nginx.conf syntax is ok
nginx: [emerg] mkdir() "//Users/bohr/software/tengine/logs/access.log" failed (21: Is a directory)
configuration file //Users/bohr/software/tengine/conf/nginx.conf test failed

服务器操作系统应该选择 Debian/Ubuntu 还是 CentOS?

http://www.zhihu.com/question/19599986

生产环境选择操作系统还是要慎重.现在我厂在线上用ubuntu,遇到过几次诡异事件(服务器无缘无故挂了,没有任何日志,时间跳变),看了这篇文章,SA应该会把线上的linux服务器统一了吧.

web-starter-kit

https://github.com/google/web-starter-kit

Web Starter Kit is a starting point for multi-screen web development. It encompasses opinionated recommendations on boilerplate and tooling for building an experience that works great across multiple devices.

微服务:分解应用以实现可部署性和可扩展性

http://www.infoq.com/cn/articles/microservices-intro
http://microservices.io/index.html

文章讨论了整体架构和微服务构架的优缺点.对于大型应用而言,微服务架构当然是首选.

API网关模式用于解耦应用客户端和微服务.我们可能没有考虑对不同的客户端提供不同粒度的服务(不同客户端的网络环境不一样).

对于非强一致性数据要求的场景,事件驱动的异步更新(服务发布事件声明有些数据发生了变化,其他的服务订阅这些事件并更新它们的数据)解耦了事件的生产者和消费者,简化了开发也提升了可用性.某应用,很多配置数据都存在memcache中,一笔业务需要查询缓存>5次,每次都要去查,感觉很不爽.还是使用本地缓存+事件驱动的异步更新来做比较好.

2014年05月Reading Notes

发表于 2014-05-29 | 分类于 java

面向GC的Java编程

http://coolshell.cn/articles/11541.html

好文,总结的很不错.

spring boot Initializr

http://start.spring.io/

有了这个,创建spring boot项目就快了.

OOM Killer

很早听说OOM Killer这个东东,感觉很神秘.而且以前分析某次线上故障,我得出的结论是OOM Killer,但是没有找到日志,囧!最近在玩vagrant,用的ubuntu box,虚拟机内存分配512m,某应用配置jvm内存-Xms256M -Xmx512m -XX:PermSize=64m -XX:MaxPermSize=256m.应用在启动过程中日志刷了一会儿就不动了,command+c结束后,console报出:

INFO: Initializing Spring root WebApplicationContext
^C./tomcat.sh: line 6:  7649 Killed                  nohup mvn clean tomcat7:run -Dspring.profiles.active=$env -Dsys.name=$sysname > "$logfile" 2>&1 < /dev/null

找了很久,在/var/log/syslog发现如下日志:

May 22 09:47:41 vagrant-ubuntu-saucy-64 kernel: [ 5499.448534] Out of memory: Kill process 7649 (java) score 788 or sacrifice child
May 22 09:47:41 vagrant-ubuntu-saucy-64 kernel: [ 5499.449012] Killed process 7649 (java) total-vm:1460964kB, anon-rss:407220kB, file-rss:0kB

这篇文章解释如何处理oom

vagrant

https://github.com/astaxie/Go-in-Action/blob/master/ebook/zh/01.2.md

http://blog.segmentfault.com/fenbox/1190000000264347

http://docs.vagrantup.com/v2/getting-started/index.html

如果mac环境下虚拟机出现Failed to load VMMR0.r0 (VERR_SUPLIB_WORLD_WRITABLE),执行sudo chmod o-w /Applications再试试.

构建高可用系统的常用招数

http://bluedavy.me/?p=468

大牛的总结,分享+总结下:

  1. 监控和报警

    监控和报警能提前发现问题/缩短故障时间,前提是得能正确的评估监控点.

  2. SPoF(Single Point of Failure)

    单点故障也分层次的,不过我们coder一般只关注服务层面.服务尽量做到无状态,只需要做负载就ok了.不能做成无状态的就需要做集群了.实在不行的就做成主备.

  3. 解耦

    后端业务通过消息/事件来解耦(Eventbus也不错),前端页面模块化,互相不影响.

  4. 隔离

    隔离既要防止依赖的系统之间相互影响(防止故障传播),也要防止同一节点上的不同服务相互影响(资源隔离).

    宏观层面,区分服务重要性,如果都能服务化就好做了.不同服务可以选择配置不同个数的服务节点.重要的,访问量大的就多加点节点.这需要监控系统能准确评估服务访问情况.

    微观层面,在服务内部,服务对外提供的能力一般通过线程池大小和请求队列长度来控制.在这里,大不一定就好,多也不定就好.

  1. 容灾

    这里谈了几点:超时控制/非关键业务自动降级(用dubbo实现就很方便)/手动降级/自恢复能力(比如druid连接池)/自我保护能力

自己补充点,快速故障恢复能力(日志很重要)/避免人为故障(减少开发人员犯错误的机会)/简单可依赖(能简单做的就绝对不玩花哨)

Uses MySQL to store schema-less data

http://backchannel.org/blog/friendfeed-schemaless-mysql

如何用mysql来存储schema-less的数据,实现很简单.

数据表:

CREATE TABLE entities (
    added_id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
    id BINARY(16) NOT NULL,
        updated TIMESTAMP NOT NULL,
    body MEDIUMBLOB,
    UNIQUE KEY (id),
    KEY (updated)
) ENGINE=InnoDB;

假如内容是:

{
    "id": "71f0c4d2291844cca2df6f486e96e37c",
    "user_id": "f48b0440ca0c4f66991c4d5f6a078eaf",
    "feed_id": "f48b0440ca0c4f66991c4d5f6a078eaf",
    "title": "We just launched a new backend system for FriendFeed!",
    "link": "http://friendfeed.com/e/71f0c4d2-2918-44cc-a2df-6f486e96e37c",
    "published": 1235697046,
    "updated": 1235697046,
}

如果要给title建立索引,创建新表

CREATE TABLE index_title (
    title varchar(100) ,
    entity_id BINARY(16) NOT NULL UNIQUE,
       PRIMARY KEY (user_id, entity_id)
) ENGINE=InnoDB;

查询的时候先从索引表查出entity_id,然后在去entities表查询详细数据.可以存储数据为text,方便数据库直接操作(必要性不是很大,text太占内存了),当然最好还是存储压缩后的二进制数据.不是经常改动的数据,应用层在加上一层cache.

索引可以异步建立,定时任务周期性的去找updated的新数据.

为什么tomcat应用三分钟还关不掉

这种问题一般是因为还有非deamon线程在容器关闭时没有正确的关闭导致的.可以在执行tomcat shutdown脚本后,jstack线程栈,看下还有哪些非deamon线程在执行.

应用使用线程持一定要记得关闭线程池,可以用spring提供的.

<bean id="taskExecutor"
      class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
    <property name="corePoolSize" value="10"/>
    <property name="keepAliveSeconds" value="200"/>
    <property name="maxPoolSize" value="50"/>
    <property name="queueCapacity" value="1000"/>
    <property name="awaitTerminationSeconds" value="60"/>
    <property name="waitForTasksToCompleteOnShutdown" value="true"/>
</bean>

注意最后面两个参数.

The New RBAC: Resource-Based Access Control

最近看看shiro的相关资料,看到这篇文章.以前也隐隐约约思考过权限控制,也感觉RBAC控制粒度太粗了.作者提到Explicit Access Control概念,通过资源来解耦角色,控制粒度更细.从权限的分配角度来说,这样使用也更方便,可以把权限分配到某个用户/某个组/某个角色.

当然,我们把资源的权限和角色一一对于,角色有层次关系并且可以继承,RBAC也可以胜任细粒度的权限控制.

maven 传递依赖检查

发表于 2014-05-28 | 分类于 java

传递依赖检查

我们通过maven插件org.apache.maven.plugins:maven-enforcer-plugin启用<requireUpperBoundDeps/>
来检查传递依赖是否高于直接依赖,如果传递依赖的版本比直接依赖的版本高,则打包失败.

<requireUpperBoundDeps/>解释如下:

IF:

    A-->B1-->C2

    A-->C1

    C2>C1

THEN:

    throw Exception;

我觉得这个检查很有必要,但是解析的范围太宽了.一个项目依赖了很多的开源组件,我们最好是限制这个检查只检查我们自己的jar包.

修改插件默认行为,在org.apache.maven.plugins.enforcer.RequireUpperBoundDeps$RequireUpperBoundDepsVisitor#containsConflicts中加入:

String key=  resolvedPair.constructKey();
if(key!=null && !key.startsWith("com.xxx")){//不检查groupId中包括非com.xxx开头的jar包
      return false;
}    

demo

下面说下检查出来的提示信息分析,比如下面的情况:

Failed while enforcing RequireUpperBoundDeps. The error(s) are [
    Require upper bound dependencies error for xxx.interchange:interchange-facade-settle:1.0.0.20121009 paths to dependency are:
    +-xxx.ppm:ppm-integration:1.0.1.6
          +-xxx.interchange:interchange-facade-settle:1.0.0.20121009
    and
    +-xxx.ppm:ppm-integration:1.0.1.6
          +-xxx.core.payengine:payengine-facade:2.0.0.20140314
                +-xxx.interchange:interchange-facade-settle:1.0.0.20121009 (managed) <-- xxx.interchange:interchange-facade-settle:1.3.0.20140303

第一个告诉我们ppm-integration–>interchange-facade-settle:1.0.0.20121009.

第二个告诉我们ppm-integration–>payengine-facade:2.0.0.20140314–>interchange-facade-settle:1.3.0.20140303

根据maven 最短路径优先原则,ppm-integration最终会依赖interchange-facade-settle:1.0.0.20121009.但是payengine-facade:2.0.0.20140314它依赖interchange-facade-settle:1.3.0.20140303.如果classpath中只有interchange-facade-settle:1.0.0.20121009,运行时payengine-facade就有可能报找不到类,找不到方法之类的错误.

遇到这样的场景,最好是修改我们项目的直接依赖,让ppm-integration–>interchange-facade-settle:1.3.0.20140303,然后测试下是否ok.

烦人的cxf unexpected element 异常

发表于 2014-05-15 | 分类于 java

1.背景

当cxf传输的数据对象结构变化时,比如请求对象减少了字段,响应对象增加了字段,在jaxb unmarsh时会抛出异常,导致接口访问失败.

javax.xml.bind.UnmarshalException: unexpected element (uri:"", local:"name"). Expected elements are <{}name>

上面这是一个典型的unexpected element异常,如果cxf客户端请求中多了一个name属性,或者cxf服务端响应中多了一个name属性,都会导致此异常.

2.源代码分析

翻了下源代码:

com.sun.xml.bind.v2.runtime.unmarshaller.StructureLoader#childElement检查是否是新增属性

 @Override
public void childElement(UnmarshallingContext.State state, TagName arg) throws SAXException {
    ChildLoader child = childUnmarshallers.get(arg.uri,arg.local);
    if(child==null) {//检查是否新增属性
        child = catchAll;
        if(child==null) {
            super.childElement(state,arg);
            return;
        }
    }

    state.loader = child.loader;
    state.receiver = child.receiver;
}

在com.sun.xml.bind.v2.runtime.unmarshaller.Loader中检查是否处理此问题

 public void childElement(UnmarshallingContext.State state, TagName ea) throws SAXException {
    // notify the error, then recover by ignoring the whole element.
    reportUnexpectedChildElement(ea, true);
    state.loader = Discarder.INSTANCE;
    state.receiver = null;
}

@SuppressWarnings({"StringEquality"})
protected final void reportUnexpectedChildElement(TagName ea, boolean canRecover) throws SAXException {
    if(canRecover && !UnmarshallingContext.getInstance().parent.hasEventHandler())
    //这里默认会有个EventHandler,不会直接忽略此问题
        // this error happens particurly often (when input documents contain a lot of unexpected elements to be ignored),
        // so don't bother computing all the messages and etc if we know that
        // there's no event handler to receive the error in the end. See #286 
        return;
     //下面的代码抛出异常
    if(ea.uri!=ea.uri.intern() || ea.local!=ea.local.intern())
        reportError(Messages.UNINTERNED_STRINGS.format(), canRecover );
    else
        reportError(Messages.UNEXPECTED_ELEMENT.format(ea.uri,ea.local,computeExpectedElements()), canRecover );
}

在org.apache.cxf.jaxb.io.DataReaderImpl#createUnmarshaller中设置了EventHandler,注意这里的veventHandler,默认是没有的.

if (setEventHandler) {
            um.setEventHandler(new WSUIDValidationHandler(veventHandler));
}

org.apache.cxf.jaxb.io.DataReaderImpl.WSUIDValidationHandler的代码很简单:

private static class WSUIDValidationHandler implements ValidationEventHandler {
    ValidationEventHandler origHandler;
    WSUIDValidationHandler(ValidationEventHandler o) {
        origHandler = o;
    }

    public boolean handleEvent(ValidationEvent event) {
        String msg = event.getMessage();
        System.out.println("WSUIDValidationHandler"+msg);
        if (msg != null
                && msg.contains(":Id")
                && (msg.startsWith("cvc-type.3.1.1: ")
                || msg.startsWith("cvc-type.3.2.2: ")
                || msg.startsWith("cvc-complex-type.3.1.1: ")
                || msg.startsWith("cvc-complex-type.3.2.2: "))) {
            return true;
        }
        if (origHandler != null) {
            return origHandler.handleEvent(event);
        }
        return false;
    }
}

先自己处理,自己处理不了的交给origHandler,那我们只需要自己构建一个javax.xml.bind.ValidationEventHandler来专门处理unexpected element异常,问题就得到了解决.

org.apache.cxf.jaxb.io.DataReaderImpl#setProperty中有段代码:

veventHandler = (ValidationEventHandler)m.getContextualProperty("jaxb-validation-event-handler");
       if (veventHandler == null) {
           veventHandler = databinding.getValidationEventHandler();
       }

如果配置了jaxb-validation-event-handler属性,就可以让我们自己的javax.xml.bind.ValidationEventHandler来处理此异常.也可以设置setEventHandler为false,不设置异常处理器,忽略所有unmarsh异常,不过这样我感觉太暴力了点,这样做也忽略了org.apache.cxf.jaxb.io.DataReaderImpl.WSUIDValidationHandler的逻辑,点儿都不科学.

3.实现

上面分析清楚了,实现就很简单,实现javax.xml.bind.ValidationEventHandler

public class IgnoreUnexpectedElementValidationEventHandler implements ValidationEventHandler {
        private static final Logger logger = LoggerFactory.getLogger(IgnoreUnexpectedElementValidationEventHandler.class);

        @Override
        public boolean handleEvent(ValidationEvent event) {
                String msg = event.getMessage();
                if (msg != null && msg.startsWith("unexpected element")) {
                    logger.warn("{}", msg);
                    return true;
             }
              return false;
        }
}

在cxf:bus中配置下就ok

  <cxf:bus>
    <cxf:properties>
        <entry key="jaxb-validation-event-handler">
            <bean class="IgnoreUnexpectedElementValidationEventHandler"/>
        </entry>
    </cxf:properties>
</cxf:bus>

建议只在线上环境启用此东东,线下还是不要开启,早点发现问题是好事.

java对象属性复制

发表于 2014-05-13 | 分类于 java

java对象属性复制的工具类很多,常用的有org.springframework.beans.BeanUtils#copyProperties,org.apache.commons.beanutils.BeanUtils#copyProperties,这两个都是通过反射实现的,性能嘛,你关心TA就在那里,你不关心TA还是在那里.

阅读全文 »

2014年04月Reading Notes

发表于 2014-04-01 | 分类于 java

oh-my-zsh

https://github.com/robbyrussell/oh-my-zsh/wiki/Plugins-Overview

https://github.com/robbyrussell/oh-my-zsh/wiki/Themes

zsh才是王道啊,各种插件,很爽.

我用colored-man colorize sublime mvn terminalapp插件.theme用avit,再装上Solarized Dark,prefect!!!

阅读全文 »

2014年03月Reading Notes

发表于 2014-03-07 | 分类于 java

Volatile Vs Static in JAVA

http://malalanayake.wordpress.com/2013/09/12/volatile-vs-static-in-java/

volatile能保证原子性和可见性.对static field的内存模型认识不足导致有些概念模糊了.内存结构见图:

阅读全文 »

2014年02月Reading Notes

发表于 2014-02-19 | 分类于 java

HTTP/1.1 Upgrade header

http://en.wikipedia.org/wiki/HTTP/1.1_Upgrade_header

通过http upgrade header来实现协议转换,比如把http协议转换为websocket协议.wildfly走得更远,8080端口支持HTTP (Servlet, JAX-RS, JAX-WS), Web Sockets, HTTP Upgraded Remoting (EJB Invocation, Remote JNDI).这篇文章讲述了一些细节.

When should I not kill -9 a process?

http://unix.stackexchange.com/questions/8916/when-should-i-not-kill-9-a-process

Generally, you should use kill -15 before kill -9 to give the target process a chance to clean up after itself.

Java里快如闪电的线程间通讯

http://www.infoq.com/cn/articles/High-Performance-Java-Inter-Thread-Communications

多线程中,锁是一个很大的性能开销.如果采用无锁实现,会发现原来世界可以更美好.

elasticsearch中文学习文档

https://github.com/medcl/elasticsearch-rtf

http://tanjianna.diandian.com/post/2013-07-27/elasticsearch-study

elasticsearch中文发行版,针对中文集成了相关插件,并带有Demo,方便新手学习,或者在生产环境中直接使用

elasticsearch中文学习文档

http://webappchecklist.com/
Web开发者必备:Web应用检查清单

Cache coherence

http://en.wikipedia.org/wiki/Cache_coherence

In a shared memory multiprocessor system with a separate cache memory for each processor, it is possible to have many copies of any one instruction operand: one copy in the main memory and one in each cache memory. When one copy of an operand is changed, the other copies of the operand must be changed also.

Cache coherence is the discipline that ensures that changes in the values of shared operands are propagated throughout the system in a timely fashion.

高性能、高流量Java Web站点打造的22条建议

http://www.csdn.net/article/2013-12-20/2817861-22-recommendations-for-building-effective-high-traffic-web-application

  • 通过使用类似Lucene的索引器做表的索引,使用一个允许在结果集上做基于其他字段的查询.

    对于复杂的查询,在数据库中直接做是很影响性能的,通过使用搜索引擎,能减轻数据库的压力.

  • 考虑使用Oracle或者MySQL分片

    数据量大时,做分片能获得不错的性能提升.

  • 不要使用session stickiness

    会话粘滞会带来一系列的问题.我们的分布式session方案中,默认要求LB启用会话粘滞,这样做的目的是能让本地缓存生效.当需要failover时,才去后端memcached中取数据.能同时兼顾性能和高可用.

  • 终止反向代理商的SSL

    在反向代理或者LB上卸载ssl,能够减轻web应用服务器的压力.

  • 拥抱一切“reactor”

序列化框架选型

发表于 2014-01-26 | 分类于 java

序列化框架选型

分布式应用中,序列化很关键,选择一个合适的序列化框架能给分布式应用带来性能红利,还能减少不必要的麻烦.本文仅仅从我遇到的一些实际问题来说明序列化的选型.更深入部分也可以参考java序列化

序列化框架的性能可以参考jvm-serializers,Kryo的性能还是很牛叉的.

除了性能,还要考虑兼容性/序列化后的大小.如果仅仅考虑性能,我们选择Kryo就足够了.但是Kryo有些用着不爽的地方,比如不是线程安全的/兼容性.

1.兼容性

字段增删不兼容,这个问题有时候很麻烦.比如用memache做缓存,把对象序列化后存入memcache,如果出现字段增删的情况,必须在服务重启的时候把缓存清空,不然就会导致灰常严重的BUG.但是如果应用服务器有多台,这个问题还是避免不了.总会有个时间窗口会出现不同服务器上的同一个应用有不同的类版本,仍然可能会出现灰常严重的BUG.

现在的Kryo提供了兼容性的支持,使用CompatibleFieldSerializer.class,在kryo.writeClassAndObject写入的信息如下:

class name|field lenght|field1 name|field2 name|field1 value| filed2 value

读入kryo.readClassAndObject时,会先读入field names.然后匹配当前反序列化类的field和顺序,构造结果.

子类和父类中有同名的字段时,kryo反序列化会丢失字段值,出现问题的原因和hessian出问题一样.

给kryo提交了一个improvement,在初始化类型信息时,去掉父类中重复名称的field.

2.线程安全

非线程安全也很好处理,每次都new对象出来,当然这样不是最佳的使用方式.通过线程变量来解决会比较合理,保证了性能还能提供很方便使用的工具类.

3.如何生成对象

对于没有无参构造器的类来说,生成新对象是个问题,可以使用java内部的机制来new一个对象。
可以参考下KryoReflectionFactorySupport的实现方式

4.性能

下面测试了java下的各种序列化实现方式的性能

0 Serialisation    write=4,206ns read=16,945ns total=21,151ns
 1 Serialisation    write=3,626ns read=18,205ns total=21,831ns
0 MemoryByteBuffer write=270ns read=324ns total=594ns
 1 MemoryByteBuffer write=270ns read=330ns total=600ns
 0 MemoryByteBufferWithNativeOrder  write=357ns read=360ns total=717ns
 1 MemoryByteBufferWithNativeOrder  write=323ns read=359ns total=682ns
 0 DirectByteBuffer write=236ns read=325ns total=561ns
 1 DirectByteBuffer write=231ns read=301ns total=532ns
 0 DirectByteBufferWithNativeOrder  write=261ns read=310ns total=571ns
 1 DirectByteBufferWithNativeOrder  write=243ns read=290ns total=533ns
 0 UnsafeMemory write=28ns read=82ns total=110ns
 1 UnsafeMemory write=24ns read=75ns total=99ns
 0 kryo write=373ns read=348ns total=721ns
 1 kryo write=390ns read=386ns total=776ns
 0 kryoWithCompatibleFields write=1,037ns read=1,625ns total=2,662ns
 1 kryoWithCompatibleFields write=1,038ns read=1,657ns total=2,695ns
 0 kryoWithCompatibleFieldsAndDuplicateFieldAccept  write=1,077ns read=1,560ns total=2,637ns
 1 kryoWithCompatibleFieldsAndDuplicateFieldAccept  write=1,064ns read=1,583ns total=2,647ns
 0 kryoWithUnsafe   write=164ns read=204ns total=368ns
 1 kryoWithUnsafe   write=168ns read=210ns total=378ns
 0 fastjson write=1,942ns read=5,834ns total=7,776ns
 1 fastjson write=1,873ns read=5,879ns total=7,752ns

每种序列化执行1000000次,并且有预热. 各组数据相对比较,可以得出一些结论:

  • 直接调用unsafe,最快,但是最麻烦
  • java自带的序列化很慢,最好不要用
  • kryo2.22提供的unsafe支持,性能非常卓越
  • kryo兼容性序列化器,开销挺大.写需要写入字段名,读的时候还需要做匹配撮合,读比写慢
  • fastjson也挺快的,兼容性\跨语言互操性俱佳.

序列化后的字节大小可以参考jvm-serializers

2014年01月Reading Notes

发表于 2014-01-16 | 分类于 java

LINUX上MYSQL优化三板斧

http://www.woqutech.com/?p=1200

讲了如何优化linux mysql服务器,主要讲了操作系统层面的优化

  • CPU方面

    关闭电源保护模式(充分利用cpu资源)

  • 内存:

    vm.swappiness = 0 (尽量少swap)

    关闭numa (在NUMA架构下,本地内存的访问和非本地内存的访问代价是不一样的)

  • 文件系统:

    用noatime(不用更新文件的access time),nobarrier(不用文件系统强制底层设备刷新缓存,由RAID卡或者Flash卡来保证)挂载系统

    IO调度策略修改为deadline。(IO调度策略采用deadline,它是非公平的调度策略,但是能兼顾一个请求不会在队列中等待太久导致饿死)

Java Multi-Threading and Concurrency Interview Questions with Answers

http://www.journaldev.com/1162/java-multi-threading-concurrency-interview-questions-with-answers

虽然是面试题,但是讲了很多java线程中的基础概念

禁用Spotlight后,Alfred找不到app

个人感觉Alfred要比spotlight好用得多,特别是装了某些workflows后,操作效率明显提高.本着不要浪费性能的原则,参考MAC OS X 关闭 spotlight 降温的大法把spotlight服务给全禁用掉了.

用了两天感觉不对,一些常用软件在Alfred中找不到,官方回答了Can Alfred work without Spotlight enabled?,看来还得启用spotlight才行.悲剧的是降温大法里面提到的启用办法老是报错.下面的命令能解决这个问题:

sudo mv Search2.bundle/ Search.bundle/
sudo launchctl load -w /System/Library/LaunchDaemons/com.apple.metadata.mds.plist
sudo mdutil -a -i on

markdown中出现了特殊字符导致blog一直不更新

前几天写了一篇博文,提交到github后,一直主页都刷不出来,以为是github出问题了.专门去twiter看了下,没有发现风吹草动,这下必须得把测试预览环境搭建起来.

sudo gem install jekyll
#安装markdwon解析插件
sudo gem install rdiscount
#切换到项目路径
cd bohrqiu.github.com
#启动jekyll服务并监听文件变动
jekyll serve --watch

启动起来后,居然看到markdown解析失败了

| Maruku tells you:
+-----
| Malformed HTML starting at "<v2,则打包失败)"
| -----
| gin`来规范传递依赖,要求当前依赖的版本和传递依赖版本一样或者比传递依赖版本高(比如A->Cv1 ,A->D->Cv2,如果v1<v2,则打包失败)EOF

没想到<符号还不能直接使用~~!

git api 总结

git很久没有用了,加上现在有github的客户端,基本上把命令都忘完了,偶然看到
@heiniuhaha 妹纸总结的git api,太详细了,收了.

1…4567
qiubo

qiubo

Keep running!

66 日志
2 分类
76 标签
Links
  • qiuduo
  • daidai
  • bingwei
© 2013 — 2019 qiubo
由 Hexo 强力驱动
|
主题 — NexT.Gemini v5.1.4