聊聊HystrixPropertiesStrategy

本文主要研究一下HystrixPropertiesStrategy

HystrixPropertiesStrategy

hystrix-core-1.5.12-sources.jar!/com/netflix/hystrix/strategy/properties/HystrixPropertiesStrategy.java

/**
 * Abstract class with default implementations of factory methods for properties used by various components of Hystrix.
 * <p>
 * See {@link HystrixPlugins} or the Hystrix GitHub Wiki for information on configuring plugins: <a
 * href="https://github.com/Netflix/Hystrix/wiki/Plugins">https://github.com/Netflix/Hystrix/wiki/Plugins</a>.
 */
public abstract class HystrixPropertiesStrategy {

    /**
     * Construct an implementation of {@link HystrixCommandProperties} for {@link HystrixCommand} instances with {@link HystrixCommandKey}.
     * <p>
     * <b>Default Implementation</b>
     * <p>
     * Constructs instance of {@link HystrixPropertiesCommandDefault}.
     * 
     * @param commandKey
     *            {@link HystrixCommandKey} representing the name or type of {@link HystrixCommand}
     * @param builder
     *            {@link com.netflix.hystrix.HystrixCommandProperties.Setter} with default overrides as injected from the {@link HystrixCommand} implementation.
     *            <p>
     *            The builder will return NULL for each value if no override was provided.
     * @return Implementation of {@link HystrixCommandProperties}
     */
    public HystrixCommandProperties getCommandProperties(HystrixCommandKey commandKey, HystrixCommandProperties.Setter builder) {
        return new HystrixPropertiesCommandDefault(commandKey, builder);
    }

    /**
     * Cache key used for caching the retrieval of {@link HystrixCommandProperties} implementations.
     * <p>
     * Typically this would return <code>HystrixCommandKey.name()</code> but can be done differently if required.
     * <p>
     * For example, null can be returned which would cause it to not cache and invoke {@link #getCommandProperties} for each {@link HystrixCommand} instantiation (not recommended).
     * <p>
     * <b>Default Implementation</b>
     * <p>
     * Returns {@link HystrixCommandKey#name()}
     * 
     * @param commandKey command key used in determining command's cache key
     * @param builder builder for {@link HystrixCommandProperties} used in determining command's cache key
     * @return String value to be used as the cache key of a {@link HystrixCommandProperties} implementation.
     */
    public String getCommandPropertiesCacheKey(HystrixCommandKey commandKey, HystrixCommandProperties.Setter builder) {
        return commandKey.name();
    }

    /**
     * Construct an implementation of {@link HystrixThreadPoolProperties} for {@link HystrixThreadPool} instances with {@link HystrixThreadPoolKey}.
     * <p>
     * <b>Default Implementation</b>
     * <p>
     * Constructs instance of {@link HystrixPropertiesThreadPoolDefault}.
     * 
     * @param threadPoolKey
     *            {@link HystrixThreadPoolKey} representing the name or type of {@link HystrixThreadPool}
     * @param builder
     *            {@link com.netflix.hystrix.HystrixThreadPoolProperties.Setter} with default overrides as injected via {@link HystrixCommand} to the {@link HystrixThreadPool} implementation.
     *            <p>
     *            The builder will return NULL for each value if no override was provided.
     * 
     * @return Implementation of {@link HystrixThreadPoolProperties}
     */
    public HystrixThreadPoolProperties getThreadPoolProperties(HystrixThreadPoolKey threadPoolKey, HystrixThreadPoolProperties.Setter builder) {
        return new HystrixPropertiesThreadPoolDefault(threadPoolKey, builder);
    }

    /**
     * Cache key used for caching the retrieval of {@link HystrixThreadPoolProperties} implementations.
     * <p>
     * Typically this would return <code>HystrixThreadPoolKey.name()</code> but can be done differently if required.
     * <p>
     * For example, null can be returned which would cause it to not cache and invoke {@link #getThreadPoolProperties} for each {@link HystrixThreadPool} instantiation (not recommended).
     * <p>
     * <b>Default Implementation</b>
     * <p>
     * Returns {@link HystrixThreadPoolKey#name()}
     *
     * @param threadPoolKey thread pool key used in determining thread pool's cache key
     * @param builder builder for {@link HystrixThreadPoolProperties} used in determining thread pool's cache key
     * @return String value to be used as the cache key of a {@link HystrixThreadPoolProperties} implementation.
     */
    public String getThreadPoolPropertiesCacheKey(HystrixThreadPoolKey threadPoolKey, HystrixThreadPoolProperties.Setter builder) {
        return threadPoolKey.name();
    }

    /**
     * Construct an implementation of {@link HystrixCollapserProperties} for {@link HystrixCollapser} instances with {@link HystrixCollapserKey}.
     * <p>
     * <b>Default Implementation</b>
     * <p>
     * Constructs instance of {@link HystrixPropertiesCollapserDefault}.
     * 
     * @param collapserKey
     *            {@link HystrixCollapserKey} representing the name or type of {@link HystrixCollapser}
     * @param builder
     *            {@link com.netflix.hystrix.HystrixCollapserProperties.Setter} with default overrides as injected to the {@link HystrixCollapser} implementation.
     *            <p>
     *            The builder will return NULL for each value if no override was provided.
     * 
     * @return Implementation of {@link HystrixCollapserProperties}
     */
    public HystrixCollapserProperties getCollapserProperties(HystrixCollapserKey collapserKey, HystrixCollapserProperties.Setter builder) {
        return new HystrixPropertiesCollapserDefault(collapserKey, builder);
    }

    /**
     * Cache key used for caching the retrieval of {@link HystrixCollapserProperties} implementations.
     * <p>
     * Typically this would return <code>HystrixCollapserKey.name()</code> but can be done differently if required.
     * <p>
     * For example, null can be returned which would cause it to not cache and invoke {@link #getCollapserProperties} for each {@link HystrixCollapser} instantiation (not recommended).
     * <p>
     * <b>Default Implementation</b>
     * <p>
     * Returns {@link HystrixCollapserKey#name()}
     *
     * @param collapserKey collapser key used in determining collapser's cache key
     * @param builder builder for {@link HystrixCollapserProperties} used in determining collapser's cache key
     * @return String value to be used as the cache key of a {@link HystrixCollapserProperties} implementation.
     */
    public String getCollapserPropertiesCacheKey(HystrixCollapserKey collapserKey, HystrixCollapserProperties.Setter builder) {
        return collapserKey.name();
    }

    /**
     * Construct an implementation of {@link com.netflix.hystrix.HystrixTimerThreadPoolProperties} for configuration of the timer thread pool
     * that handles timeouts and collapser logic.
     * <p>
     * Constructs instance of {@link HystrixPropertiesTimerThreadPoolDefault}.
     *
     *
     * @return Implementation of {@link com.netflix.hystrix.HystrixTimerThreadPoolProperties}
     */
    public HystrixTimerThreadPoolProperties getTimerThreadPoolProperties() {
        return new HystrixPropertiesTimerThreadPoolDefault();
    }
}

提供获取HystrixCommandProperties、HystrixThreadPoolProperties、HystrixCollapserProperties、HystrixTimerThreadPoolProperties的方法

HystrixCommandProperties

hystrix-core-1.5.12-sources.jar!/com/netflix/hystrix/HystrixCommandProperties.java

/**
 * Properties for instances of {@link HystrixCommand}.
 * <p>
 * Default implementation of methods uses Archaius (https://github.com/Netflix/archaius)
 */
public abstract class HystrixCommandProperties {
    private static final Logger logger = LoggerFactory.getLogger(HystrixCommandProperties.class);

    /* defaults */
    /* package */ static final Integer default_metricsRollingStatisticalWindow = 10000;// default => statisticalWindow: 10000 = 10 seconds (and default of 10 buckets so each bucket is 1 second)
    private static final Integer default_metricsRollingStatisticalWindowBuckets = 10;// default => statisticalWindowBuckets: 10 = 10 buckets in a 10 second window so each bucket is 1 second
    private static final Integer default_circuitBreakerRequestVolumeThreshold = 20;// default => statisticalWindowVolumeThreshold: 20 requests in 10 seconds must occur before statistics matter
    private static final Integer default_circuitBreakerSleepWindowInMilliseconds = 5000;// default => sleepWindow: 5000 = 5 seconds that we will sleep before trying again after tripping the circuit
    private static final Integer default_circuitBreakerErrorThresholdPercentage = 50;// default => errorThresholdPercentage = 50 = if 50%+ of requests in 10 seconds are failures or latent then we will trip the circuit
    private static final Boolean default_circuitBreakerForceOpen = false;// default => forceCircuitOpen = false (we want to allow traffic)
    /* package */ static final Boolean default_circuitBreakerForceClosed = false;// default => ignoreErrors = false 
    private static final Integer default_executionTimeoutInMilliseconds = 1000; // default => executionTimeoutInMilliseconds: 1000 = 1 second
    private static final Boolean default_executionTimeoutEnabled = true;
    private static final ExecutionIsolationStrategy default_executionIsolationStrategy = ExecutionIsolationStrategy.THREAD;
    private static final Boolean default_executionIsolationThreadInterruptOnTimeout = true;
    private static final Boolean default_executionIsolationThreadInterruptOnFutureCancel = false;
    private static final Boolean default_metricsRollingPercentileEnabled = true;
    private static final Boolean default_requestCacheEnabled = true;
    private static final Integer default_fallbackIsolationSemaphoreMaxConcurrentRequests = 10;
    private static final Boolean default_fallbackEnabled = true;
    private static final Integer default_executionIsolationSemaphoreMaxConcurrentRequests = 10;
    private static final Boolean default_requestLogEnabled = true;
    private static final Boolean default_circuitBreakerEnabled = true;
    private static final Integer default_metricsRollingPercentileWindow = 60000; // default to 1 minute for RollingPercentile 
    private static final Integer default_metricsRollingPercentileWindowBuckets = 6; // default to 6 buckets (10 seconds each in 60 second window)
    private static final Integer default_metricsRollingPercentileBucketSize = 100; // default to 100 values max per bucket
    private static final Integer default_metricsHealthSnapshotIntervalInMilliseconds = 500; // default to 500ms as max frequency between allowing snapshots of health (error percentage etc)
    //......
}

提供了hystrix command的相关参数计默认值

HystrixThreadPoolProperties

hystrix-core-1.5.12-sources.jar!/com/netflix/hystrix/HystrixThreadPoolProperties.java

/**
 * Properties for instances of {@link HystrixThreadPool}.
 * <p>
 * Default implementation of methods uses Archaius (https://github.com/Netflix/archaius)
 *
 * Note a change in behavior in 1.5.7.  Prior to that version, the configuration for 'coreSize' was used to control
 * both coreSize and maximumSize.  This is a fixed-size threadpool that can never give up an unused thread.  In 1.5.7+,
 * the values can diverge, and if you set coreSize < maximumSize, threads can be given up (subject to the keep-alive
 * time)
 *
 * It is OK to leave maximumSize unset using any version of Hystrix.  If you do, then maximum size will default to
 * core size and you'll have a fixed-size threadpool.
 *
 * If you accidentally set maximumSize < coreSize, then maximum will be raised to coreSize
 * (this prioritizes keeping extra threads around rather than inducing threadpool rejections)
 */
public abstract class HystrixThreadPoolProperties {

    /* defaults */
    static int default_coreSize = 10;            // core size of thread pool
    static int default_maximumSize = 10;         // maximum size of thread pool
    static int default_keepAliveTimeMinutes = 1; // minutes to keep a thread alive
    static int default_maxQueueSize = -1;        // size of queue (this can't be dynamically changed so we use 'queueSizeRejectionThreshold' to artificially limit and reject)
                                                 // -1 turns it off and makes us use SynchronousQueue
    static boolean default_allow_maximum_size_to_diverge_from_core_size = false; //should the maximumSize config value get read and used in configuring the threadPool
                                                                                 //turning this on should be a conscious decision by the user, so we default it to false

    static int default_queueSizeRejectionThreshold = 5; // number of items in queue
    static int default_threadPoolRollingNumberStatisticalWindow = 10000; // milliseconds for rolling number
    static int default_threadPoolRollingNumberStatisticalWindowBuckets = 10; // number of buckets in rolling number (10 1-second buckets)

    private final HystrixProperty<Integer> corePoolSize;
    private final HystrixProperty<Integer> maximumPoolSize;
    private final HystrixProperty<Integer> keepAliveTime;
    private final HystrixProperty<Integer> maxQueueSize;
    private final HystrixProperty<Integer> queueSizeRejectionThreshold;
    private final HystrixProperty<Boolean> allowMaximumSizeToDivergeFromCoreSize;

    private final HystrixProperty<Integer> threadPoolRollingNumberStatisticalWindowInMilliseconds;
    private final HystrixProperty<Integer> threadPoolRollingNumberStatisticalWindowBuckets;
    //......
}

提供了hystrix thread pool的相关参数计默认值

HystrixCollapserProperties

hystrix-core-1.5.12-sources.jar!/com/netflix/hystrix/HystrixCollapserProperties.java

/**
 * Properties for instances of {@link HystrixCollapser}.
 * <p>
 * Default implementation of methods uses Archaius (https://github.com/Netflix/archaius)
 */
public abstract class HystrixCollapserProperties {

    /* defaults */
    private static final Integer default_maxRequestsInBatch = Integer.MAX_VALUE;
    private static final Integer default_timerDelayInMilliseconds = 10;
    private static final Boolean default_requestCacheEnabled = true;
    /* package */ static final Integer default_metricsRollingStatisticalWindow = 10000;// default => statisticalWindow: 10000 = 10 seconds (and default of 10 buckets so each bucket is 1 second)
    private static final Integer default_metricsRollingStatisticalWindowBuckets = 10;// default => statisticalWindowBuckets: 10 = 10 buckets in a 10 second window so each bucket is 1 second
    private static final Boolean default_metricsRollingPercentileEnabled = true;
    private static final Integer default_metricsRollingPercentileWindow = 60000; // default to 1 minute for RollingPercentile
    private static final Integer default_metricsRollingPercentileWindowBuckets = 6; // default to 6 buckets (10 seconds each in 60 second window)
    private static final Integer default_metricsRollingPercentileBucketSize = 100; // default to 100 values max per bucket

    private final HystrixProperty<Integer> maxRequestsInBatch;
    private final HystrixProperty<Integer> timerDelayInMilliseconds;
    private final HystrixProperty<Boolean> requestCacheEnabled;
    private final HystrixProperty<Integer> metricsRollingStatisticalWindowInMilliseconds; // milliseconds back that will be tracked
    private final HystrixProperty<Integer> metricsRollingStatisticalWindowBuckets; // number of buckets in the statisticalWindow
    private final HystrixProperty<Boolean> metricsRollingPercentileEnabled; // Whether monitoring should be enabled
    private final HystrixProperty<Integer> metricsRollingPercentileWindowInMilliseconds; // number of milliseconds that will be tracked in RollingPercentile
    private final HystrixProperty<Integer> metricsRollingPercentileWindowBuckets; // number of buckets percentileWindow will be divided into
    private final HystrixProperty<Integer> metricsRollingPercentileBucketSize; // how many values will be stored in each percentileWindowBucket
    //......
}

提供了hystrix collapser相关参数计默认值

HystrixTimerThreadPoolProperties

hystrix-core-1.5.12-sources.jar!/com/netflix/hystrix/HystrixTimerThreadPoolProperties.java

/**
 * Properties for Hystrix timer thread pool.
 * <p>
 * Default implementation of methods uses Archaius (https://github.com/Netflix/archaius)
 */
public abstract class HystrixTimerThreadPoolProperties {

    private final HystrixProperty<Integer> corePoolSize;

    protected HystrixTimerThreadPoolProperties() {
        this(new Setter().withCoreSize(Runtime.getRuntime().availableProcessors()));
    }
    //......
}

提供了hystrix timer threadpool相关参数,主要是corePoolSize,默认是Runtime.getRuntime().availableProcessors()

HystrixPropertiesChainedProperty

hystrix-core-1.5.12-sources.jar!/com/netflix/hystrix/strategy/properties/HystrixPropertiesChainedProperty.java

    public static abstract class ChainBuilder<T> {
        
        private ChainBuilder() {
            super();        
        }
        
        private List<HystrixDynamicProperty<T>> properties = 
                new ArrayList<HystrixDynamicProperty<T>>();
        
        
        public ChainBuilder<T> add(HystrixDynamicProperty<T> property) {
            properties.add(property);
            return this;
        }
        
        public ChainBuilder<T> add(String name, T defaultValue) {
            properties.add(getDynamicProperty(name, defaultValue, getType()));
            return this;
        }
        
        public HystrixDynamicProperty<T> build() {
            if (properties.size() < 1) throw new IllegalArgumentException();
            if (properties.size() == 1) return properties.get(0);
            List<HystrixDynamicProperty<T>> reversed = 
                    new ArrayList<HystrixDynamicProperty<T>>(properties);
            Collections.reverse(reversed);
            ChainProperty<T> current = null;
            for (HystrixDynamicProperty<T> p : reversed) {
                if (current == null) {
                    current = new ChainProperty<T>(p);
                }
                else {
                    current = new ChainProperty<T>(p, current);
                }
            }
            
            return new ChainHystrixProperty<T>(current);
            
        }
        
        protected abstract Class<T> getType();
        
    }

这里build返回的是HystrixDynamicProperty的实现ChainHystrixProperty,具体是由HystrixDynamicProperties来获取

HystrixDynamicProperties

hystrix-core-1.5.12-sources.jar!/com/netflix/hystrix/strategy/properties/HystrixDynamicProperties.java

/**
 * A hystrix plugin (SPI) for resolving dynamic configuration properties. This
 * SPI allows for varying configuration sources.
 * 
 * The HystrixPlugin singleton will load only one implementation of this SPI
 * throught the {@link ServiceLoader} mechanism.
 * 
 * @author agentgt
 *
 */
public interface HystrixDynamicProperties {
    
    /**
     * Requests a property that may or may not actually exist.
     * @param name property name, never <code>null</code>
     * @param fallback default value, maybe <code>null</code>
     * @return never <code>null</code>
     */
    public HystrixDynamicProperty<String> getString(String name, String fallback);
    /**
     * Requests a property that may or may not actually exist.
     * @param name property name, never <code>null</code>
     * @param fallback default value, maybe <code>null</code>
     * @return never <code>null</code>
     */
    public HystrixDynamicProperty<Integer> getInteger(String name, Integer fallback);
    /**
     * Requests a property that may or may not actually exist.
     * @param name property name, never <code>null</code>
     * @param fallback default value, maybe <code>null</code>
     * @return never <code>null</code>
     */
    public HystrixDynamicProperty<Long> getLong(String name, Long fallback);
    /**
     * Requests a property that may or may not actually exist.
     * @param name property name
     * @param fallback default value
     * @return never <code>null</code>
     */
    public HystrixDynamicProperty<Boolean> getBoolean(String name, Boolean fallback);
    
    /**
     * @ExcludeFromJavadoc
     */
    public static class Util {
        /**
         * A convenience method to get a property by type (Class).
         * @param properties never <code>null</code>
         * @param name never <code>null</code>
         * @param fallback maybe <code>null</code>
         * @param type never <code>null</code>
         * @return a dynamic property with type T.
         */
        @SuppressWarnings("unchecked")
        public static <T> HystrixDynamicProperty<T> getProperty(
                HystrixDynamicProperties properties, String name, T fallback, Class<T> type) {
            return (HystrixDynamicProperty<T>) doProperty(properties, name, fallback, type);
        }
        
        private static HystrixDynamicProperty<?> doProperty(
                HystrixDynamicProperties delegate, 
                String name, Object fallback, Class<?> type) {
            if(type == String.class) {
                return delegate.getString(name, (String) fallback);
            }
            else if (type == Integer.class) {
                return delegate.getInteger(name, (Integer) fallback);
            }
            else if (type == Long.class) {
                return delegate.getLong(name, (Long) fallback);
            }
            else if (type == Boolean.class) {
                return delegate.getBoolean(name, (Boolean) fallback);
            }
            throw new IllegalStateException();
        }
    }
    
}

这个接口只是规范了获取动态参数的一些方法

HystrixPlugins.resolveDynamicProperties

hystrix-core-1.5.12-sources.jar!/com/netflix/hystrix/strategy/HystrixPlugins.java

    private static HystrixDynamicProperties resolveDynamicProperties(ClassLoader classLoader, LoggerSupplier logSupplier) {
        HystrixDynamicProperties hp = getPluginImplementationViaProperties(HystrixDynamicProperties.class, 
                HystrixDynamicPropertiesSystemProperties.getInstance());
        if (hp != null) {
            logSupplier.getLogger().debug(
                    "Created HystrixDynamicProperties instance from System property named "
                    + "\"hystrix.plugin.HystrixDynamicProperties.implementation\". Using class: {}", 
                    hp.getClass().getCanonicalName());
            return hp;
        }
        hp = findService(HystrixDynamicProperties.class, classLoader);
        if (hp != null) {
            logSupplier.getLogger()
                    .debug("Created HystrixDynamicProperties instance by loading from ServiceLoader. Using class: {}", 
                            hp.getClass().getCanonicalName());
            return hp;
        }
        hp = HystrixArchaiusHelper.createArchaiusDynamicProperties();
        if (hp != null) {
            logSupplier.getLogger().debug("Created HystrixDynamicProperties. Using class : {}", 
                    hp.getClass().getCanonicalName());
            return hp;
        }
        hp = HystrixDynamicPropertiesSystemProperties.getInstance();
        logSupplier.getLogger().info("Using System Properties for HystrixDynamicProperties! Using class: {}", 
                hp.getClass().getCanonicalName());
        return hp;
    }

这个方法去决定使用哪个HystrixDynamicProperties的实现类,优先级如下:

  • hystrix.plugin.HystrixDynamicProperties.implementation指定的实现类
  • 通过ServiceLoader找到的HystrixDynamicProperties的实现类
  • 使用com.netflix.hystrix.strategy.properties.archaius.HystrixDynamicPropertiesArchaius实现
  • 使用系统变量HystrixDynamicPropertiesSystemProperties

小结

HystrixPropertiesStrategy提供给开发者去自定义hystrix各个组件的配置,没有找到任何实现的话,则使用代码里头默认的参数值。目前这个版本的代码默认寻找到的HystrixDynamicProperties实现是HystrixDynamicPropertiesArchaius。

doc

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,189评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,577评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,857评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,703评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,705评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,620评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,995评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,656评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,898评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,639评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,720评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,395评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,982评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,953评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,195评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,907评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,472评论 2 342

推荐阅读更多精彩内容