Share
Embed
Transcript
87 slides
-
• sane development environment, integrated with a language • ability
to develop and evaluate things on the fly • ease maintenance production • scalability (doh) • integration with well-known / existing tools • good, stable runtime • runtime debugging toolkit • performance What are you looking for? Friday, October 26, 12 -
• Leiningen, Clojure build tool https://github.com/technomancy/leiningen • repl just run
`lein repl` in your console • emacs (it’s written in lisp, you know?) excellent nrepl and (older thing) clojure-swank, paredit-mode, formatting • nrepl get to the guts of runtime • VisualVm and the rest of Java goodness like jmap, jstack, jstat etc etc etc Sane development environment Friday, October 26, 12 -
• JMX java management extensions • nrepl • JVM configuration/tuning
• No shared mutable state • No locks • Pure functions -> same input -> same output • Easy composition and pipelining Easy maintenance in production Friday, October 26, 12 -
• Baseline performance • Utilization of all processor resources anyone
can eat out all the memory, right? • Painless parallel execution • Memory efficiency as far as it is possible with lisps, of course. in my mind that was mostly about structural sharing & persistent DS • JIT / inlining Scalability You keep using that word. I do not think it means what you think it means. (voice in my head) Friday, October 26, 12 -
• Very, very good Java interop options • Most of
libraries are either ported to Clojure, or use Java library underneath • Your favorite Java application container / web server • Jar packaging / public / private Maven repositories • Not to replace, but to complement your existing JVM toolkit Integration Friday, October 26, 12 -
(def a ‘(1 2 3)) 3 a 2 1 Friday,
October 26, 12 -
(def a ‘(1 2 3)) (def b (cons 4 a))
3 a 2 1 b 4 Friday, October 26, 12 -
(def a ‘(1 2 3)) (def b (cons 4 a))
(def c (cons 5 (rest a)) 3 a 2 1 b 4 c 5 Friday, October 26, 12 -
• doesn’t have anything to do with disk persistence •
efficient creation of “modified” versions • structural sharing • inherently thread & iteration-safe will not mutate in a middle • immutable modification yields new coll • composite Persistent DSs? Friday, October 26, 12 -
(def a (atom {})) (swap! a assoc :b 1) a
{} @reference value {:b 1} Friday, October 26, 12 -
(def a (atom {})) (swap! a assoc :b 1) a
{} @reference value {:b 1} Friday, October 26, 12 -
(def a (atom {})) (swap! a assoc :b 1) a
{} @reference value {:b 1} Friday, October 26, 12 -
(swap! a assoc :b 1) attributes for it Mutating func
Friday, October 26, 12 -
(def a (atom {})) (swap! a assoc :b 1) (swap!
a assoc :c 2) a @reference {:b 1} Friday, October 26, 12 -
(def a (atom {})) (swap! a assoc :b 1) (swap!
a assoc :c 2) a @reference {:b 1} {:b 1 :c 2 } Friday, October 26, 12 -
(def a (atom {})) (swap! a assoc :b 1) (swap!
a assoc :c 2) a @reference {:b 1} {:b 1 :c 2 } Structural sharing Friday, October 26, 12 -
(def a (atom {})) (swap! a assoc :b 1) (swap!
a assoc :c 2) a @reference {:b 1} {:b 1 :c 2 } Friday, October 26, 12 -
• reference, not value • refs / agents / atoms
/ vars • transactional memory access yes, with retries • no user locks, no deadlocks • mutation through pure function • coordinated • readers can read value at any point in time STM?.. Friday, October 26, 12 -
(let [[first-item second-item third-item :as all-items] [1 2 3]] (println
(format "First item: %d" first-item)) (println (format "Second item: %d" second-item)) (println (format "Third item: %d" third-item)) (println (format "All items: %s" all-items))) ;; First item: 1 ;; Second item: 2 ;; Third item: 3 ;; All items: [1 2 3] Friday, October 26, 12 -
;; Get application identifier (defn get-locator ([app env] (keyword (str
app "_" env))) ;; (get-locator “my-cool-app” “production”) ;; => :my-cool-app_production (defn get-or-create-store ([locator] (if-let [store (get @events locator)] ;; If the store does exists return reference to it store (do ;; If the store does not exist yet, create it (swap! events assoc locator (ref [])) (get @events locator)))) ([app env] (get-or-create-store (get-locator app env))) Friday, October 26, 12 -
{ ;; Md5 hash of an event, that uniquely identifies
it :md5 "cd0e351d2eefdf0f79e0b55a0efe543b", ;; Arbitrary additional info :additional_info {:execution_time 0.5469999, :url “http://mysite.com/page0” }, ;; Event Type identifier (404, exception, page load time) :type "page_load", ;; Dispatcher host name :hostname "dc0-web01", ;; Time when event was received :received_at ..., ;; Tags assigned to the event :tags ["metrics" "performance"] } Friday, October 26, 12 -
(defn add [m app env] (let [store (get-or-create-store app env)]
;; Start a transaction (dosync ;; It doesn’t really matter in which order we receive ;; events, as we receive them very often. So let’s use ;; commute. (conj) is commutative, so we will get (almost) ;; same result no matter what was the order of the received ;; events (commute store conj m)))) Friday, October 26, 12 -
(.start (Thread. ^Runnable (fn [] (udp/connect {:port 1234 :host "0.0.0.0"})))))
Java Thread Type hint Friday, October 26, 12 -
(map (fn [[k v]] (distinct (map (fn [event] (:host event))
@v))) @events) Iterate through collection, generates lazy seq Destructuring Destructuring Friday, October 26, 12 -
(map (fn [[k v]] (distinct (map (fn [event] (:host event))
@v))) @events) k is now a locator :my-cool-app_production ... v is now a reference to events collection Friday, October 26, 12 -
(map (fn [[k v]] (distinct (map (fn [event] (:host event))
@v))) @events) take :host from every event Friday, October 26, 12 -
(map (fn [[k v]] (distinct (map (fn [event] (:host event))
@v))) @events) now, only distinct :host values from what we’ve got Friday, October 26, 12 -
(map (fn [[k v]] (distinct (map (fn [event] (:host event))
@v))) @events) both events hash is in atom per- application/environment vector is in ref, we need to dereference them Friday, October 26, 12 -
(defn- apply-to-values [map function] (into {} (for [[key value] map]
[key (function value)]))) Friday, October 26, 12 -
(zipmap (keys @events) (map (fn [[locator c]] (let [collection @c
types-grouped (group-by #(:type %) collection)] (apply-to-values types-grouped (fn [app-with-type] {:count (count all-with-type)})))) @events)) v group all the events by type Friday, October 26, 12 -
{"exception": [{:type "exception" :md5 ... :additional_info ... :hostname ... :received_at
... :tags ... } {:type "exception" :md5 ... :additional_info ... :hostname ... :received_at ... :tags ... }] "404": [{:type "404" :md5 ... :additional_info ... :hostname ... :received_at ... :tags ... } {:type "404" :md5 ... :additional_info ... :hostname ... :received_at ... :tags ... }]} group all the events by type Friday, October 26, 12 -
(zipmap (keys @events) (map (fn [[locator c]] (let [collection @c
types-grouped (group-by #(:type %) collection)] (apply-to-values types-grouped (fn [app-with-type] {:count (count all-with-type)})))) @events)) apply fn to all values of a hash Friday, October 26, 12 -
{:my_webapp_production {"404" {:count 25540}, "page_load" {:count 4557}, "exception" {:count 473}}
:rests_api_production {"stats" {:count 264}}, :my_webapp_staging {"404" {:count 2344}}, :worker {"memory_usage" {:count 17006}}} results! Friday, October 26, 12 -
(declare ^:dynamic *collection*) (defmacro with-coll-filtered [app env flt & body]
`(let [store# (deref (get-or-create-store ~app ~env))] (binding [*collection* (filter ~flt store#)] ~@body))) declare a dynamic variable. thread and scope local. Friday, October 26, 12 -
(declare ^:dynamic *collection*) (defmacro with-coll-filtered [app env flt & body]
`(let [store# (deref (get-or-create-store ~app ~env))] (binding [*collection* (filter ~flt store#)] ~@body))) macro that will filter the collection for us, and put results for execution in binding Friday, October 26, 12 -
(declare ^:dynamic *collection*) (defmacro with-coll-filtered [app env flt & body]
`(let [store# (deref (get-or-create-store ~app ~env))] (binding [*collection* (filter ~flt store#)] ~@body))) body will be evaluated in scope of binding so we could operate the filtered collection without referencing it elsewhere Friday, October 26, 12 -
(declare ^:dynamic *collection*) (defmacro with-coll-filtered [app env flt & body]
`(let [store# (deref (get-or-create-store ~app ~env))] (binding [*collection* (filter ~flt store#)] ~@body))) filter function is applied to all entries, and only those that match will make it to *collection* Friday, October 26, 12 -
(with-coll-filtered "my-web-app" "production" #(= "page_load" (:type %)) (let [page-load-times (map
(fn [i] (get-in i [:additional_info :execution_time])) *collection*)] (/ (apply + page-load-times) (count page-load-times)))) filter by page_load type get only execution times sum! count average Friday, October 26, 12 -
Monger MongoDB client for a more civilized age: friendly, flexible
and with batteries included https://github.com/michaelklishin/monger http://clojuremongodb.info/ Friday, October 26, 12 -
• Clojure is concise, performant and productive • Amazing for
processing (big) data • Big set of available tools • Tools are easy-to-use, next-level • Will change the way you write programs • Benefits ahead Takeaway Friday, October 26, 12 -
Also by ClojureWerkz Langohr Feature-rich Clojure RabbitMQ client that embraces
AMQP 0.9.1 Model https://github.com/michaelklishin/langohr Friday, October 26, 12 -
Also by ClojureWerkz Welle An expressive Clojure client for Riak
https://github.com/michaelklishin/welle http://clojureriak.info/ Friday, October 26, 12 -
Also by ClojureWerkz Neocons A feature rich idiomatic Clojure client
for the Neo4J REST API https://github.com/michaelklishin/neocons http://clojureneo4j.info/ Friday, October 26, 12 -
Also by ClojureWerkz Quartzite A powerful scheduling library for Clojure*
https://github.com/michaelklishin/quartzite http://clojurequartz.info/ *now comes with Quartz-Mongodb and Quartzite-REST Friday, October 26, 12 -
ifesdjeen clojurewerkz / / michaelklishin / Also, you should follow
Friday, October 26, 12